Compare commits
108 Commits
04cb08f303
...
d79c6b5694
Author | SHA1 | Date |
---|---|---|
the-real-herowl | d79c6b5694 | |
the-real-herowl | bfa2d4d11f | |
teknomunk | e072a6c172 | |
the-real-herowl | b33f7974ad | |
marro | 4dc5d0939c | |
the-real-herowl | 32b334322b | |
grorp | 88c3c4558b | |
grorp | 3954acdfb7 | |
grorp | 02b354f54a | |
grorp | cb624fe1d9 | |
grorp | bd9ab16762 | |
kno10 | fb3c85e289 | |
kno10 | f6f5481f30 | |
the-real-herowl | c428fa576b | |
teknomunk | a46833eaa4 | |
teknomunk | 3514fe211f | |
teknomunk | 94d9e4c881 | |
teknomunk | 6b1aa43238 | |
teknomunk | cfdef2435a | |
teknomunk | 49c8ae2fa0 | |
teknomunk | 6ada1a3477 | |
teknomunk | 189a2c62ad | |
teknomunk | 981cddddd4 | |
teknomunk | 66b5a369f1 | |
teknomunk | 4eda77acd1 | |
teknomunk | afc270195a | |
teknomunk | 8f53074b58 | |
teknomunk | 70e8ba9a89 | |
teknomunk | 6741c5a809 | |
teknomunk | d09791db7b | |
teknomunk | 354160e9e6 | |
teknomunk | cf1325d466 | |
teknomunk | 7112369917 | |
teknomunk | e6e13bdc67 | |
teknomunk | 42d37210c5 | |
teknomunk | c3a33ea2c2 | |
teknomunk | 7f6d456a32 | |
teknomunk | 44d154f594 | |
teknomunk | eb6131b037 | |
teknomunk | 3c2f2593db | |
teknomunk | 9e6d49dd38 | |
teknomunk | 4a865fa2df | |
teknomunk | 55b4d3d5ee | |
teknomunk | 09bcf3d22b | |
teknomunk | 57678e31bc | |
teknomunk | d5684ca305 | |
teknomunk | a4f1ccd0ee | |
teknomunk | 1e0f7618ba | |
teknomunk | f44102c238 | |
teknomunk | 5b1fcf76f6 | |
kabou | f61a7ab4cb | |
kabou | 4449f74742 | |
kabou | ba1e0e4301 | |
kabou | 7938fba4a5 | |
kabou | 8acddab74f | |
kabou | c2c7df820f | |
kabou | e5cf4bd225 | |
kabou | 810051c591 | |
kabou | ae56a864d0 | |
kabou | 7ddcf3f93f | |
kabou | e8d965e21a | |
kabou | 8855246dd4 | |
kabou | 3889abbaf4 | |
kabou | f6235e8e92 | |
kabou | 2190080832 | |
kabou | ea1d52baab | |
kabou | fdc7f4634d | |
kabou | bde0d9b238 | |
teknomunk | f644d37332 | |
kabou | 17f2d85de9 | |
kabou | d07e8d9536 | |
kabou | 5d2fa8072a | |
kabou | 2d8bb12fad | |
kabou | 69032c3222 | |
kabou | 71e6fa9646 | |
kabou | 9ea52ce9b3 | |
kabou | 0422635047 | |
kno10 | b540e6c77b | |
kno10 | d49426d453 | |
the-real-herowl | 2b7b7f1872 | |
kno10 | b5afa34469 | |
kno10 | ebf6cf32e8 | |
kno10 | a8318f6600 | |
kno10 | fa7a7f4e81 | |
kno10 | c097c65262 | |
kno10 | 220a7b06e6 | |
kno10 | 540a070c59 | |
kno10 | 78a958db4e | |
kno10 | e9453d6210 | |
kno10 | 9376cf92b1 | |
kno10 | c4030115c4 | |
kno10 | e1ace4ad01 | |
the-real-herowl | e3b7847df1 | |
Mikita Wiśniewski | f86a641dfa | |
Mikita Wiśniewski | 084741b733 | |
Mikita Wiśniewski | d5bc0613d8 | |
Loveaabb | f26c34e65f | |
Loveaabb | 04e29c5796 | |
Elias Åström | 45ae170447 | |
Elias Åström | d0d1217dec | |
Elias Åström | cffc8e0145 | |
the-real-herowl | b136cbf9bb | |
the-real-herowl | e6d8d840db | |
Mikita Wiśniewski | 78125f425a | |
cora | cb1999414b | |
Mikita Wiśniewski | 41b188caea | |
kno10 | ae7995d195 | |
kno10 | e293cbe631 |
|
@ -1131,3 +1131,25 @@ if not vector.in_area then
|
||||||
(pos.z >= min.z) and (pos.z <= max.z)
|
(pos.z >= min.z) and (pos.z <= max.z)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Traces along a line of nodes vertically to find the next possition that isn't an allowed node
|
||||||
|
---@param pos The position to start tracing from
|
||||||
|
---@param dir The direction to trace in. 1 is up, -1 is down, all other values are not allowed.
|
||||||
|
---@param allowed_nodes A set of node names to trace along.
|
||||||
|
---@param limit The maximum number of steps to make. Defaults to 16 if nil or missing
|
||||||
|
---@return Three return values:
|
||||||
|
--- the position of the next node that isn't allowed or nil if no such node was found,
|
||||||
|
--- the distance from the start where that node was found,
|
||||||
|
--- the node table if a node was found
|
||||||
|
function mcl_util.trace_nodes(pos, dir, allowed_nodes, limit)
|
||||||
|
if (dir ~= -1) and (dir ~= 1) then return nil, 0, nil end
|
||||||
|
limit = limit or 16
|
||||||
|
|
||||||
|
for i = 1,limit do
|
||||||
|
pos = vector.offset(pos, 0, dir, 0)
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
if not allowed_nodes[node.name] then return pos, i, node end
|
||||||
|
end
|
||||||
|
|
||||||
|
return nil, limit, nil
|
||||||
|
end
|
||||||
|
|
|
@ -318,6 +318,12 @@ function minetest.handle_node_drops(pos, drops, digger)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Special node drops (crushing) when digging with a hammer
|
||||||
|
local hammer = tooldef.groups.hammer
|
||||||
|
if hammer and hammer > 0 and nodedef._vl_crushing_drop then
|
||||||
|
drops = nodedef._vl_crushing_drop
|
||||||
|
end
|
||||||
|
|
||||||
if tool and nodedef._mcl_fortune_drop and enchantments.fortune then
|
if tool and nodedef._mcl_fortune_drop and enchantments.fortune then
|
||||||
local fortune_level = enchantments.fortune
|
local fortune_level = enchantments.fortune
|
||||||
local fortune_drop = nodedef._mcl_fortune_drop
|
local fortune_drop = nodedef._mcl_fortune_drop
|
||||||
|
|
|
@ -522,10 +522,11 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
local is_player = hitter:is_player()
|
local is_player = hitter:is_player()
|
||||||
local mob_pos = self.object:get_pos()
|
local mob_pos = self.object:get_pos()
|
||||||
local player_pos = hitter:get_pos()
|
local player_pos = hitter:get_pos()
|
||||||
|
local weapon = hitter:get_wielded_item()
|
||||||
|
|
||||||
if is_player then
|
if is_player then
|
||||||
-- is mob out of reach?
|
-- is mob out of reach?
|
||||||
if vector.distance(mob_pos, player_pos) > 3 then
|
if vector.distance(mob_pos, player_pos) > (weapon:get_definition().range or 3) then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
-- is mob protected?
|
-- is mob protected?
|
||||||
|
@ -572,7 +573,6 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
|
|
||||||
|
|
||||||
-- punch interval
|
-- punch interval
|
||||||
local weapon = hitter:get_wielded_item()
|
|
||||||
local punch_interval = 1.4
|
local punch_interval = 1.4
|
||||||
|
|
||||||
-- exhaust attacker
|
-- exhaust attacker
|
||||||
|
@ -733,6 +733,7 @@ function mob_class:on_punch(hitter, tflp, tool_capabilities, dir)
|
||||||
if hitter and is_player then
|
if hitter and is_player then
|
||||||
local wielditem = hitter:get_wielded_item()
|
local wielditem = hitter:get_wielded_item()
|
||||||
kb = kb + 9 * mcl_enchanting.get_enchantment(wielditem, "knockback")
|
kb = kb + 9 * mcl_enchanting.get_enchantment(wielditem, "knockback")
|
||||||
|
kb = kb + 9 * minetest.get_item_group(wielditem:get_name(), "hammer")
|
||||||
-- add player velocity to mob knockback
|
-- add player velocity to mob knockback
|
||||||
local hv = hitter:get_velocity()
|
local hv = hitter:get_velocity()
|
||||||
local dir_dot = (hv.x * dir.x) + (hv.z * dir.z)
|
local dir_dot = (hv.x * dir.x) + (hv.z * dir.z)
|
||||||
|
|
|
@ -5,6 +5,7 @@ local validate_vector = mcl_util.validate_vector
|
||||||
local active_particlespawners = {}
|
local active_particlespawners = {}
|
||||||
local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
|
local disable_blood = minetest.settings:get_bool("mobs_disable_blood")
|
||||||
local DEFAULT_FALL_SPEED = -9.81*1.5
|
local DEFAULT_FALL_SPEED = -9.81*1.5
|
||||||
|
local PI_THIRD = math.pi / 3 -- 60 degrees
|
||||||
|
|
||||||
local PATHFINDING = "gowp"
|
local PATHFINDING = "gowp"
|
||||||
|
|
||||||
|
@ -294,86 +295,66 @@ function mcl_mobs:set_animation(self, anim)
|
||||||
self:set_animation(anim)
|
self:set_animation(anim)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function dir_to_pitch(dir)
|
local function who_are_you_looking_at (self, dtime)
|
||||||
--local dir2 = vector.normalize(dir)
|
if self.order == "sleep" then
|
||||||
local xz = math.abs(dir.x) + math.abs(dir.z)
|
self._locked_object = nil
|
||||||
return -math.atan2(-dir.y, xz)
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local function who_are_you_looking_at (self, dtime)
|
|
||||||
local pos = self.object:get_pos()
|
|
||||||
|
|
||||||
local stop_look_at_player_chance = math.random(833/self.curiosity)
|
|
||||||
-- was 10000 - div by 12 for avg entities as outside loop
|
-- was 10000 - div by 12 for avg entities as outside loop
|
||||||
|
local stop_look_at_player = math.random() * 833 <= self.curiosity
|
||||||
local stop_look_at_player = stop_look_at_player_chance == 1
|
|
||||||
|
|
||||||
if self.attack then
|
if self.attack then
|
||||||
if not self.target_time_lost then
|
self._locked_object = not self.target_time_lost and self.attack or nil
|
||||||
self._locked_object = self.attack
|
|
||||||
else
|
|
||||||
self._locked_object = nil
|
|
||||||
end
|
|
||||||
elseif self.following then
|
elseif self.following then
|
||||||
self._locked_object = self.following
|
self._locked_object = self.following
|
||||||
elseif self._locked_object then
|
elseif self._locked_object then
|
||||||
if stop_look_at_player then
|
if stop_look_at_player then self._locked_object = nil end
|
||||||
--minetest.log("Stop look: ".. self.name)
|
|
||||||
self._locked_object = nil
|
|
||||||
end
|
|
||||||
elseif not self._locked_object then
|
elseif not self._locked_object then
|
||||||
if mcl_util.check_dtime_timer(self, dtime, "step_look_for_someone", 0.2) then
|
if mcl_util.check_dtime_timer(self, dtime, "step_look_for_someone", 0.2) then
|
||||||
--minetest.log("Change look check: ".. self.name)
|
local pos = self.object:get_pos()
|
||||||
|
|
||||||
-- For the wither this was 20/60=0.33, so probably need to rebalance and divide rates.
|
|
||||||
-- but frequency of check isn't good as it is costly. Making others too infrequent requires testing
|
|
||||||
local chance = 150/self.curiosity
|
|
||||||
|
|
||||||
if chance < 1 then chance = 1 end
|
|
||||||
local look_at_player_chance = math.random(chance)
|
|
||||||
|
|
||||||
-- was 5000 but called in loop based on entities. so div by 12 as estimate avg of entities found,
|
|
||||||
-- then div by 20 as less freq lookup
|
|
||||||
|
|
||||||
local look_at_player = look_at_player_chance == 1
|
|
||||||
|
|
||||||
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 8)) do
|
for _, obj in pairs(minetest.get_objects_inside_radius(pos, 8)) do
|
||||||
if obj:is_player() and vector.distance(pos, obj:get_pos()) < 4 then
|
if obj:is_player() and vector.distance(pos, obj:get_pos()) < 4 then
|
||||||
--minetest.log("Change look to player: ".. self.name)
|
|
||||||
self._locked_object = obj
|
self._locked_object = obj
|
||||||
break
|
break
|
||||||
elseif obj:is_player() or (obj:get_luaentity() and obj:get_luaentity().name == self.name and self ~= obj:get_luaentity()) then
|
elseif obj:is_player() or (obj:get_luaentity() and self ~= obj:get_luaentity() and obj:get_luaentity().name == self.name) then
|
||||||
if look_at_player then
|
-- For the wither this was 20/60=0.33, so probably need to rebalance and divide rates.
|
||||||
--minetest.log("Change look to mob: ".. self.name)
|
-- but frequency of check isn't good as it is costly. Making others too infrequent requires testing
|
||||||
|
-- was 5000 but called in loop based on entities. so div by 12 as estimate avg of entities found,
|
||||||
|
-- then div by 20 as less freq lookup
|
||||||
|
if math.random() * 150 <= self.curiosity then
|
||||||
self._locked_object = obj
|
self._locked_object = obj
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function mob_class:check_head_swivel(dtime)
|
function mob_class:check_head_swivel(dtime)
|
||||||
if not self.head_swivel or type(self.head_swivel) ~= "string" then return end
|
if not self.head_swivel or type(self.head_swivel) ~= "string" then return end
|
||||||
|
|
||||||
|
|
||||||
who_are_you_looking_at(self, dtime)
|
who_are_you_looking_at(self, dtime)
|
||||||
|
|
||||||
local final_rotation = vector.zero()
|
local newr, oldp, oldr = vector.zero(), nil, nil
|
||||||
local oldp,oldr = self.object:get_bone_position(self.head_swivel)
|
if self.object.get_bone_override then -- minetest >= 5.9
|
||||||
|
local ov = self.object:get_bone_override(self.head_swivel)
|
||||||
if self._locked_object and (self._locked_object:is_player() or self._locked_object:get_luaentity()) and self._locked_object:get_hp() > 0 then
|
oldp, oldr = ov.position.vec, ov.rotation.vec
|
||||||
local _locked_object_eye_height = 1.5
|
else -- minetest < 5.9
|
||||||
if self._locked_object:get_luaentity() then
|
oldp, oldr = self.object:get_bone_position(self.head_swivel)
|
||||||
_locked_object_eye_height = self._locked_object:get_luaentity().head_eye_height
|
oldr = vector.apply(oldr, math.rad) -- old API uses radians
|
||||||
end
|
end
|
||||||
if self._locked_object:is_player() then
|
|
||||||
_locked_object_eye_height = self._locked_object:get_properties().eye_height
|
local locked_object = self._locked_object
|
||||||
|
if locked_object and (locked_object:is_player() or locked_object:get_luaentity()) and locked_object:get_hp() > 0 then
|
||||||
|
local _locked_object_eye_height = 1.5
|
||||||
|
if locked_object:is_player() then
|
||||||
|
_locked_object_eye_height = locked_object:get_properties().eye_height
|
||||||
|
elseif locked_object:get_luaentity() then
|
||||||
|
_locked_object_eye_height = locked_object:get_luaentity().head_eye_height
|
||||||
end
|
end
|
||||||
if _locked_object_eye_height then
|
if _locked_object_eye_height then
|
||||||
|
|
||||||
local self_rot = self.object:get_rotation()
|
local self_rot = self.object:get_rotation()
|
||||||
-- If a mob is attached, should we really be messing with what they are looking at?
|
-- If a mob is attached, should we really be messing with what they are looking at?
|
||||||
-- Should this be excluded?
|
-- Should this be excluded?
|
||||||
|
@ -381,38 +362,46 @@ function mob_class:check_head_swivel(dtime)
|
||||||
self_rot = self.object:get_attach():get_rotation()
|
self_rot = self.object:get_attach():get_rotation()
|
||||||
end
|
end
|
||||||
|
|
||||||
local player_pos = self._locked_object:get_pos()
|
local ps = self.object:get_pos()
|
||||||
local direction_player = vector.direction(vector.add(self.object:get_pos(), vector.new(0, self.head_eye_height*.7, 0)), vector.add(player_pos, vector.new(0, _locked_object_eye_height, 0)))
|
ps.y = ps.y + self.head_eye_height * .7
|
||||||
local mob_yaw = math.deg(-(-(self_rot.y)-(-minetest.dir_to_yaw(direction_player))))+self.head_yaw_offset
|
local pt = locked_object:get_pos()
|
||||||
local mob_pitch = math.deg(-dir_to_pitch(direction_player))*self.head_pitch_multiplier
|
pt.y = pt.y + _locked_object_eye_height
|
||||||
|
local dir = vector.direction(ps, pt)
|
||||||
|
local mob_yaw = self_rot.y + math.atan2(dir.x, dir.z) + self.head_yaw_offset
|
||||||
|
local mob_pitch = math.asin(-dir.y) * self.head_pitch_multiplier
|
||||||
|
|
||||||
if (mob_yaw < -60 or mob_yaw > 60) and not (self.attack and self.state == "attack" and not self.runaway) then
|
if (mob_yaw < -PI_THIRD or mob_yaw > PI_THIRD) and not (self.attack and self.state == "attack" and not self.runaway) then
|
||||||
final_rotation = vector.multiply(oldr, 0.9)
|
newr = vector.multiply(oldr, 0.9)
|
||||||
elseif self.attack and self.state == "attack" and not self.runaway then
|
elseif self.attack and self.state == "attack" and not self.runaway then
|
||||||
if self.head_yaw == "y" then
|
if self.head_yaw == "y" then
|
||||||
final_rotation = vector.new(mob_pitch, mob_yaw, 0)
|
newr = vector.new(mob_pitch, mob_yaw, 0)
|
||||||
elseif self.head_yaw == "z" then
|
elseif self.head_yaw == "z" then
|
||||||
final_rotation = vector.new(mob_pitch, 0, -mob_yaw)
|
newr = vector.new(mob_pitch, 0, -mob_yaw)
|
||||||
end
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
if self.head_yaw == "y" then
|
if self.head_yaw == "y" then
|
||||||
final_rotation = vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, ((mob_yaw-oldr.y)*.3)+oldr.y, 0)
|
newr = vector.new((mob_pitch-oldr.x)*.3+oldr.x, (mob_yaw-oldr.y)*.3+oldr.y, 0)
|
||||||
elseif self.head_yaw == "z" then
|
elseif self.head_yaw == "z" then
|
||||||
final_rotation = vector.new(((mob_pitch-oldr.x)*.3)+oldr.x, 0, -(((mob_yaw-oldr.y)*.3)+oldr.y)*3)
|
newr = vector.new((mob_pitch-oldr.x)*.3+oldr.x, 0, ((mob_yaw-oldr.y)*.3+oldr.y)*-3)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif not self._locked_object and math.abs(oldr.y) > 3 and math.abs(oldr.x) < 3 then
|
elseif not locked_object and math.abs(oldr.y) > 0.05 and math.abs(oldr.x) < 0.05 then
|
||||||
final_rotation = vector.multiply(oldr, 0.9)
|
newr = vector.multiply(oldr, 0.9)
|
||||||
else
|
|
||||||
--final_rotation = vector.new(0,0,0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_util.set_bone_position(self.object,self.head_swivel, vector.new(0,self.bone_eye_height,self.horizontal_head_height), final_rotation)
|
-- 0.02 is about 1.14 degrees tolerance, to update less often
|
||||||
|
local newp = vector.new(0, self.bone_eye_height, self.horizontal_head_height)
|
||||||
|
if math.abs(oldr.x-newr.x) + math.abs(oldr.y-newr.y) + math.abs(oldr.z-newr.z) < 0.02 and vector.equals(oldp, newp) then return end
|
||||||
|
if self.object.get_bone_override then -- minetest >= 5.9
|
||||||
|
self.object:set_bone_override(self.head_swivel, {
|
||||||
|
position = { vec = newp, absolute = true },
|
||||||
|
rotation = { vec = newr, absolute = true } })
|
||||||
|
else -- minetest < 5.9
|
||||||
|
-- old API uses degrees not radians
|
||||||
|
self.object:set_bone_position(self.head_swivel, newp, vector.apply(newr, math.deg))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function mob_class:set_animation_speed()
|
function mob_class:set_animation_speed()
|
||||||
|
|
|
@ -141,7 +141,7 @@ function mcl_mobs.register_mob(name, def)
|
||||||
local final_def = {
|
local final_def = {
|
||||||
use_texture_alpha = def.use_texture_alpha,
|
use_texture_alpha = def.use_texture_alpha,
|
||||||
head_swivel = def.head_swivel or nil, -- bool to activate this function
|
head_swivel = def.head_swivel or nil, -- bool to activate this function
|
||||||
head_yaw_offset = def.head_yaw_offset or 0, -- for wonkey model bones
|
head_yaw_offset = math.rad(def.head_yaw_offset or 0), -- for wonkey model bones
|
||||||
head_pitch_multiplier = def.head_pitch_multiplier or 1, --for inverted pitch
|
head_pitch_multiplier = def.head_pitch_multiplier or 1, --for inverted pitch
|
||||||
bone_eye_height = def.bone_eye_height or 1.4, -- head bone offset
|
bone_eye_height = def.bone_eye_height or 1.4, -- head bone offset
|
||||||
head_eye_height = def.head_eye_height or def.bone_eye_height or 0, -- how hight aproximatly the mobs head is fromm the ground to tell the mob how high to look up at the player
|
head_eye_height = def.head_eye_height or def.bone_eye_height or 0, -- how hight aproximatly the mobs head is fromm the ground to tell the mob how high to look up at the player
|
||||||
|
|
|
@ -928,8 +928,6 @@ end
|
||||||
-- falling and fall damage
|
-- falling and fall damage
|
||||||
-- returns true if mob died
|
-- returns true if mob died
|
||||||
function mob_class:falling(pos, moveresult)
|
function mob_class:falling(pos, moveresult)
|
||||||
if moveresult and moveresult.touching_ground then return false end
|
|
||||||
|
|
||||||
if self.fly and self.state ~= "die" then
|
if self.fly and self.state ~= "die" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -952,7 +950,13 @@ function mob_class:falling(pos, moveresult)
|
||||||
new_acceleration = vector.new(0, DEFAULT_FALL_SPEED, 0)
|
new_acceleration = vector.new(0, DEFAULT_FALL_SPEED, 0)
|
||||||
elseif v.y <= 0 and v.y > self.fall_speed then
|
elseif v.y <= 0 and v.y > self.fall_speed then
|
||||||
-- fall downwards at set speed
|
-- fall downwards at set speed
|
||||||
|
if moveresult and moveresult.touching_ground then
|
||||||
|
-- when touching ground, retain a minimal gravity to keep the touching_ground flag
|
||||||
|
-- but also to not get upwards acceleration with large dtime when on bouncy ground
|
||||||
|
new_acceleration = vector.new(0, self.fall_speed * 0.01, 0)
|
||||||
|
else
|
||||||
new_acceleration = vector.new(0, self.fall_speed, 0)
|
new_acceleration = vector.new(0, self.fall_speed, 0)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
-- stop accelerating once max fall speed hit
|
-- stop accelerating once max fall speed hit
|
||||||
new_acceleration =vector.zero()
|
new_acceleration =vector.zero()
|
||||||
|
|
|
@ -72,17 +72,23 @@ local axolotl = {
|
||||||
fly = true,
|
fly = true,
|
||||||
fly_in = { "mcl_core:water_source", "mclx_core:river_water_source" },
|
fly_in = { "mcl_core:water_source", "mclx_core:river_water_source" },
|
||||||
breathes_in_water = true,
|
breathes_in_water = true,
|
||||||
jump = true,
|
jump = false, -- would get them out of the water too often
|
||||||
damage = 2,
|
damage = 2,
|
||||||
reach = 2,
|
reach = 2,
|
||||||
attack_type = "dogfight",
|
attack_type = "dogfight",
|
||||||
attack_animals = true,
|
attack_animals = true,
|
||||||
specific_attack = {
|
specific_attack = {
|
||||||
"extra_mobs_cod",
|
"mobs_mc:cod",
|
||||||
"extra_mobs_glow_squid",
|
"mobs_mc:glow_squid",
|
||||||
"extra_mobs_salmon",
|
"mobs_mc:salmon",
|
||||||
"extra_mobs_tropical_fish",
|
"mobs_mc:tropical_fish",
|
||||||
"mobs_mc_squid"
|
"mobs_mc:squid",
|
||||||
|
"mobs_mc:zombie", -- todo: only drowned?
|
||||||
|
"mobs_mc:baby_zombie",
|
||||||
|
"mobs_mc:husk",
|
||||||
|
"mobs_mc:baby_husk",
|
||||||
|
"mobs_mc:guardian_elder",
|
||||||
|
"mobs_mc:guardian",
|
||||||
},
|
},
|
||||||
runaway = true,
|
runaway = true,
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,12 +7,13 @@ local S = minetest.get_translator("mobs_mc")
|
||||||
--###################
|
--###################
|
||||||
|
|
||||||
|
|
||||||
local function get_texture(self)
|
local function get_texture(self, prev)
|
||||||
local on_name = self.standing_on
|
local standing_on = minetest.registered_nodes[self.standing_on]
|
||||||
|
-- TODO: we do not have access to param2 here (color palette index) yet
|
||||||
local texture
|
local texture
|
||||||
local texture_suff = ""
|
local texture_suff = ""
|
||||||
if on_name and on_name ~= "air" then
|
if standing_on and (standing_on.walkable or standing_on.groups.liquid) then
|
||||||
local tiles = minetest.registered_nodes[on_name].tiles
|
local tiles = standing_on.tiles
|
||||||
if tiles then
|
if tiles then
|
||||||
local tile = tiles[1]
|
local tile = tiles[1]
|
||||||
local color
|
local color
|
||||||
|
@ -25,7 +26,7 @@ local function get_texture(self)
|
||||||
texture = tile
|
texture = tile
|
||||||
end
|
end
|
||||||
if not color then
|
if not color then
|
||||||
color = minetest.colorspec_to_colorstring(minetest.registered_nodes[on_name].color)
|
color = minetest.colorspec_to_colorstring(standing_on.color)
|
||||||
end
|
end
|
||||||
if color then
|
if color then
|
||||||
texture_suff = "^[multiply:" .. color .. "^[hsl:0:0:20"
|
texture_suff = "^[multiply:" .. color .. "^[hsl:0:0:20"
|
||||||
|
@ -33,14 +34,19 @@ local function get_texture(self)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not texture or texture == "" then
|
if not texture or texture == "" then
|
||||||
texture = "vl_stalker_default.png"
|
-- try to keep last texture when, e.g., falling
|
||||||
|
if prev and (not (not self.attack)) == (string.find(prev, "vl_mobs_stalker_overlay_angry.png") ~= nil) then
|
||||||
|
return prev
|
||||||
end
|
end
|
||||||
texture = texture:gsub("([\\^:\\[])","\\%1") -- escape texture modifiers
|
texture = "vl_stalker_default.png"
|
||||||
texture = "([combine:16x24:0,0=(" .. texture .. "):0,16=(" .. texture ..")".. texture_suff
|
|
||||||
if self.attack then
|
|
||||||
texture = texture .. ")^vl_mobs_stalker_overlay_angry.png"
|
|
||||||
else
|
else
|
||||||
texture = texture .. ")^vl_mobs_stalker_overlay.png"
|
texture = texture:gsub("([\\^:\\[])", "\\%1") -- escape texture modifiers
|
||||||
|
texture = "(vl_stalker_default.png^[combine:16x24:0,0=(" .. texture .. "):0,16=(" .. texture .. ")" .. texture_suff .. ")"
|
||||||
|
end
|
||||||
|
if self.attack then
|
||||||
|
texture = texture .. "^vl_mobs_stalker_overlay_angry.png"
|
||||||
|
else
|
||||||
|
texture = texture .. "^vl_mobs_stalker_overlay.png"
|
||||||
end
|
end
|
||||||
return texture
|
return texture
|
||||||
end
|
end
|
||||||
|
@ -132,7 +138,7 @@ mcl_mobs.register_mob("mobs_mc:stalker", {
|
||||||
self:boom(mcl_util.get_object_center(self.object), self.explosion_strength)
|
self:boom(mcl_util.get_object_center(self.object), self.explosion_strength)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local new_texture = get_texture(self)
|
local new_texture = get_texture(self, self._stalker_texture)
|
||||||
if self._stalker_texture ~= new_texture then
|
if self._stalker_texture ~= new_texture then
|
||||||
self.object:set_properties({textures={new_texture, "mobs_mc_empty.png"}})
|
self.object:set_properties({textures={new_texture, "mobs_mc_empty.png"}})
|
||||||
self._stalker_texture = new_texture
|
self._stalker_texture = new_texture
|
||||||
|
|
|
@ -418,6 +418,18 @@ minetest.register_on_joinplayer(function(player)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
---@param player mt.PlayerObjectRef
|
||||||
|
local function is_touch_enabled(playername)
|
||||||
|
-- Minetest < 5.7.0 support
|
||||||
|
if not minetest.get_player_window_information then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local window = minetest.get_player_window_information(playername)
|
||||||
|
-- Always return a boolean (not nil) to avoid false-negatives when
|
||||||
|
-- comparing to a boolean later.
|
||||||
|
return window and window.touch_controls or false
|
||||||
|
end
|
||||||
|
|
||||||
---@param player mt.PlayerObjectRef
|
---@param player mt.PlayerObjectRef
|
||||||
function mcl_inventory.set_creative_formspec(player)
|
function mcl_inventory.set_creative_formspec(player)
|
||||||
local playername = player:get_player_name()
|
local playername = player:get_player_name()
|
||||||
|
@ -566,8 +578,10 @@ function mcl_inventory.set_creative_formspec(player)
|
||||||
bg_img = "crafting_creative_inactive" .. button_bg_postfix[this_tab] .. ".png"
|
bg_img = "crafting_creative_inactive" .. button_bg_postfix[this_tab] .. ".png"
|
||||||
end
|
end
|
||||||
return table.concat({
|
return table.concat({
|
||||||
"style[" .. this_tab .. ";border=false;bgimg=;bgimg_pressed=;noclip=true]",
|
"style[" .. this_tab .. ";border=false;bgimg=;bgimg_pressed=]",
|
||||||
"image[" .. offset[this_tab] .. ";1.5,1.44;" .. bg_img .. "]",
|
"style[" .. this_tab .. "_outer;border=false;bgimg=" .. bg_img ..
|
||||||
|
";bgimg_pressed=" .. bg_img .. "]",
|
||||||
|
"button[" .. offset[this_tab] .. ";1.5,1.44;" .. this_tab .. "_outer;]",
|
||||||
"item_image_button[" .. boffset[this_tab] .. ";1,1;" .. tab_icon[this_tab] .. ";" .. this_tab .. ";]",
|
"item_image_button[" .. boffset[this_tab] .. ";1,1;" .. tab_icon[this_tab] .. ";" .. this_tab .. ";]",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
@ -577,11 +591,21 @@ function mcl_inventory.set_creative_formspec(player)
|
||||||
caption = "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, filtername[name])) .. "]"
|
caption = "label[0.375,0.375;" .. F(C(mcl_formspec.label_color, filtername[name])) .. "]"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local touch_enabled = is_touch_enabled(playername)
|
||||||
|
players[playername].last_touch_enabled = touch_enabled
|
||||||
|
|
||||||
local formspec = table.concat({
|
local formspec = table.concat({
|
||||||
"formspec_version[6]",
|
"formspec_version[6]",
|
||||||
"size[13,8.75]",
|
-- Original formspec height was 8.75, increased to include tab buttons.
|
||||||
|
-- This avoids tab buttons going off-screen with high scaling values.
|
||||||
|
"size[13,11.43]",
|
||||||
|
-- Use as much space as possible on mobile - the tab buttons are a lot
|
||||||
|
-- of padding already.
|
||||||
|
touch_enabled and "padding[-0.015,-0.015]" or "",
|
||||||
|
|
||||||
"style_type[image;noclip=true]",
|
"no_prepend[]", mcl_vars.gui_nonbg, mcl_vars.gui_bg_color,
|
||||||
|
"background9[0,1.34;13,8.75;mcl_base_textures_background9.png;;7]",
|
||||||
|
"container[0,1.34]",
|
||||||
|
|
||||||
-- Hotbar
|
-- Hotbar
|
||||||
mcl_formspec.get_itemslot_bg_v4(0.375, 7.375, 9, 1),
|
mcl_formspec.get_itemslot_bg_v4(0.375, 7.375, 9, 1),
|
||||||
|
@ -638,6 +662,7 @@ function mcl_inventory.set_creative_formspec(player)
|
||||||
"set_focus[search;true]",
|
"set_focus[search;true]",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
formspec = formspec .. "container_end[]"
|
||||||
if pagenum then formspec = formspec .. "p" .. tostring(pagenum) end
|
if pagenum then formspec = formspec .. "p" .. tostring(pagenum) end
|
||||||
player:set_inventory_formspec(formspec)
|
player:set_inventory_formspec(formspec)
|
||||||
end
|
end
|
||||||
|
@ -655,54 +680,54 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
|
|
||||||
local name = player:get_player_name()
|
local name = player:get_player_name()
|
||||||
|
|
||||||
if fields.blocks then
|
if fields.blocks or fields.blocks_outer then
|
||||||
if players[name].page == "blocks" then return end
|
if players[name].page == "blocks" then return end
|
||||||
set_inv_page("blocks", player)
|
set_inv_page("blocks", player)
|
||||||
page = "blocks"
|
page = "blocks"
|
||||||
elseif fields.deco then
|
elseif fields.deco or fields.deco_outer then
|
||||||
if players[name].page == "deco" then return end
|
if players[name].page == "deco" then return end
|
||||||
set_inv_page("deco", player)
|
set_inv_page("deco", player)
|
||||||
page = "deco"
|
page = "deco"
|
||||||
elseif fields.redstone then
|
elseif fields.redstone or fields.redstone_outer then
|
||||||
if players[name].page == "redstone" then return end
|
if players[name].page == "redstone" then return end
|
||||||
set_inv_page("redstone", player)
|
set_inv_page("redstone", player)
|
||||||
page = "redstone"
|
page = "redstone"
|
||||||
elseif fields.rail then
|
elseif fields.rail or fields.rail_outer then
|
||||||
if players[name].page == "rail" then return end
|
if players[name].page == "rail" then return end
|
||||||
set_inv_page("rail", player)
|
set_inv_page("rail", player)
|
||||||
page = "rail"
|
page = "rail"
|
||||||
elseif fields.misc then
|
elseif fields.misc or fields.misc_outer then
|
||||||
if players[name].page == "misc" then return end
|
if players[name].page == "misc" then return end
|
||||||
set_inv_page("misc", player)
|
set_inv_page("misc", player)
|
||||||
page = "misc"
|
page = "misc"
|
||||||
elseif fields.nix then
|
elseif fields.nix or fields.nix_outer then
|
||||||
set_inv_page("all", player)
|
set_inv_page("all", player)
|
||||||
page = "nix"
|
page = "nix"
|
||||||
elseif fields.food then
|
elseif fields.food or fields.food_outer then
|
||||||
if players[name].page == "food" then return end
|
if players[name].page == "food" then return end
|
||||||
set_inv_page("food", player)
|
set_inv_page("food", player)
|
||||||
page = "food"
|
page = "food"
|
||||||
elseif fields.tools then
|
elseif fields.tools or fields.tools_outer then
|
||||||
if players[name].page == "tools" then return end
|
if players[name].page == "tools" then return end
|
||||||
set_inv_page("tools", player)
|
set_inv_page("tools", player)
|
||||||
page = "tools"
|
page = "tools"
|
||||||
elseif fields.combat then
|
elseif fields.combat or fields.combat_outer then
|
||||||
if players[name].page == "combat" then return end
|
if players[name].page == "combat" then return end
|
||||||
set_inv_page("combat", player)
|
set_inv_page("combat", player)
|
||||||
page = "combat"
|
page = "combat"
|
||||||
elseif fields.mobs then
|
elseif fields.mobs or fields.mobs_outer then
|
||||||
if players[name].page == "mobs" then return end
|
if players[name].page == "mobs" then return end
|
||||||
set_inv_page("mobs", player)
|
set_inv_page("mobs", player)
|
||||||
page = "mobs"
|
page = "mobs"
|
||||||
elseif fields.brew then
|
elseif fields.brew or fields.brew_outer then
|
||||||
if players[name].page == "brew" then return end
|
if players[name].page == "brew" then return end
|
||||||
set_inv_page("brew", player)
|
set_inv_page("brew", player)
|
||||||
page = "brew"
|
page = "brew"
|
||||||
elseif fields.matr then
|
elseif fields.matr or fields.matr_outer then
|
||||||
if players[name].page == "matr" then return end
|
if players[name].page == "matr" then return end
|
||||||
set_inv_page("matr", player)
|
set_inv_page("matr", player)
|
||||||
page = "matr"
|
page = "matr"
|
||||||
elseif fields.inv then
|
elseif fields.inv or fields.inv_outer then
|
||||||
if players[name].page == "inv" then return end
|
if players[name].page == "inv" then return end
|
||||||
page = "inv"
|
page = "inv"
|
||||||
elseif fields.search == "" and not fields.creative_next and not fields.creative_prev then
|
elseif fields.search == "" and not fields.creative_next and not fields.creative_prev then
|
||||||
|
@ -818,3 +843,19 @@ minetest.register_on_player_inventory_action(function(player, action, inventory,
|
||||||
player:get_inventory():set_stack("main", inventory_info.index, stack)
|
player:get_inventory():set_stack("main", inventory_info.index, stack)
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- This is necessary because get_player_window_information may return nil in
|
||||||
|
-- on_joinplayer.
|
||||||
|
-- (Also, Minetest plans to add support for toggling touchscreen mode in-game.)
|
||||||
|
minetest.register_globalstep(function(dtime)
|
||||||
|
for _, player in pairs(minetest.get_connected_players()) do
|
||||||
|
local name = player:get_player_name()
|
||||||
|
|
||||||
|
if minetest.is_creative_enabled(name) then
|
||||||
|
local touch_enabled = is_touch_enabled(name)
|
||||||
|
if touch_enabled ~= players[name].last_touch_enabled then
|
||||||
|
mcl_inventory.set_creative_formspec(player)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
--- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
--- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
||||||
|
|
||||||
-- CONSTS
|
-- CONSTS
|
||||||
local DOUBLE_DROP_CHANCE = 8
|
|
||||||
-- Used everywhere. Often this is just the name, but it makes sense to me as BAMBOO, because that's how I think of it...
|
|
||||||
-- "BAMBOO" goes here.
|
|
||||||
local BAMBOO = "mcl_bamboo:bamboo"
|
local BAMBOO = "mcl_bamboo:bamboo"
|
||||||
local BAMBOO_ENDCAP_NAME = "mcl_bamboo:bamboo_endcap"
|
local BAMBOO_ENDCAP_NAME = "mcl_bamboo:bamboo_endcap"
|
||||||
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
||||||
|
@ -16,7 +13,7 @@ local BAMBOO_PLANK = BAMBOO .. "_plank"
|
||||||
local modname = minetest.get_current_modname()
|
local modname = minetest.get_current_modname()
|
||||||
local S = minetest.get_translator(modname)
|
local S = minetest.get_translator(modname)
|
||||||
local node_sound = mcl_sounds.node_sound_wood_defaults()
|
local node_sound = mcl_sounds.node_sound_wood_defaults()
|
||||||
local pr = PseudoRandom((os.time() + 15766) * 12) -- switched from math.random() to PseudoRandom because the random wasn't very random.
|
local pr = PseudoRandom((os.time() + 15766) * 12)
|
||||||
|
|
||||||
local on_rotate
|
local on_rotate
|
||||||
if minetest.get_modpath("screwdriver") then
|
if minetest.get_modpath("screwdriver") then
|
||||||
|
@ -31,38 +28,16 @@ local bamboo_def = {
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
groups = {handy = 1, axey = 1, choppy = 1, dig_by_piston = 1, plant = 1, non_mycelium_plant = 1, flammable = 3},
|
groups = {handy = 1, axey = 1, choppy = 1, dig_by_piston = 1, plant = 1, non_mycelium_plant = 1, flammable = 3},
|
||||||
sounds = node_sound,
|
sounds = node_sound,
|
||||||
|
drop = BAMBOO,
|
||||||
drop = {
|
|
||||||
max_items = 1,
|
|
||||||
-- From the API:
|
|
||||||
-- max_items: Maximum number of item lists to drop.
|
|
||||||
-- The entries in 'items' are processed in order. For each:
|
|
||||||
-- Item filtering is applied, chance of drop is applied, if both are
|
|
||||||
-- successful the entire item list is dropped.
|
|
||||||
-- Entry processing continues until the number of dropped item lists
|
|
||||||
-- equals 'max_items'.
|
|
||||||
-- Therefore, entries should progress from low to high drop chance.
|
|
||||||
items = {
|
|
||||||
-- Examples:
|
|
||||||
{
|
|
||||||
-- 1 in DOUBLE_DROP_CHANCE chance of dropping.
|
|
||||||
-- Default rarity is '1'.
|
|
||||||
rarity = DOUBLE_DROP_CHANCE,
|
|
||||||
items = {BAMBOO .. " 2"},
|
|
||||||
},
|
|
||||||
{
|
|
||||||
-- 1 in 1 chance of dropping. (Note: this means that it will drop 100% of the time.)
|
|
||||||
-- Default rarity is '1'.
|
|
||||||
rarity = 1,
|
|
||||||
items = {BAMBOO},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
inventory_image = "mcl_bamboo_bamboo_shoot.png",
|
inventory_image = "mcl_bamboo_bamboo_shoot.png",
|
||||||
wield_image = "mcl_bamboo_bamboo_shoot.png",
|
wield_image = "mcl_bamboo_bamboo_shoot.png",
|
||||||
_mcl_blast_resistance = 1,
|
_mcl_blast_resistance = 1,
|
||||||
_mcl_hardness = 1,
|
_mcl_hardness = 1,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
return mcl_bamboo.grow_bamboo(pos, true)
|
||||||
|
end,
|
||||||
node_box = {
|
node_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {
|
fixed = {
|
||||||
|
@ -86,7 +61,6 @@ local bamboo_def = {
|
||||||
on_rotate = on_rotate,
|
on_rotate = on_rotate,
|
||||||
|
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
|
||||||
if not pointed_thing then
|
if not pointed_thing then
|
||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
@ -241,9 +215,6 @@ local bamboo_def = {
|
||||||
if node_above and ((bamboo_node and bamboo_node > 0) or node_above.name == BAMBOO_ENDCAP_NAME) then
|
if node_above and ((bamboo_node and bamboo_node > 0) or node_above.name == BAMBOO_ENDCAP_NAME) then
|
||||||
minetest.remove_node(new_pos)
|
minetest.remove_node(new_pos)
|
||||||
minetest.sound_play(node_sound.dug, sound_params, true)
|
minetest.sound_play(node_sound.dug, sound_params, true)
|
||||||
if pr:next(1, DOUBLE_DROP_CHANCE) == 1 then
|
|
||||||
minetest.add_item(new_pos, istack)
|
|
||||||
end
|
|
||||||
minetest.add_item(new_pos, istack)
|
minetest.add_item(new_pos, istack)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
@ -253,10 +224,12 @@ minetest.register_node(BAMBOO, bamboo_def)
|
||||||
local bamboo_top = table.copy(bamboo_def)
|
local bamboo_top = table.copy(bamboo_def)
|
||||||
bamboo_top.groups = {not_in_creative_inventory = 1, handy = 1, axey = 1, choppy = 1, dig_by_piston = 1, plant = 1, non_mycelium_plant = 1, flammable = 3}
|
bamboo_top.groups = {not_in_creative_inventory = 1, handy = 1, axey = 1, choppy = 1, dig_by_piston = 1, plant = 1, non_mycelium_plant = 1, flammable = 3}
|
||||||
bamboo_top.tiles = {"mcl_bamboo_endcap.png"}
|
bamboo_top.tiles = {"mcl_bamboo_endcap.png"}
|
||||||
bamboo_top.drawtype = "plantlike_rooted" --"plantlike"
|
|
||||||
--bamboo_top.paramtype2 = "meshoptions"
|
-- bamboo_top.drawtype = "plantlike_rooted" --"plantlike"
|
||||||
--bamboo_top.param2 = 2
|
bamboo_top.drawtype = "plantlike"
|
||||||
-- bamboo_top.waving = 2
|
bamboo_top.paramtype2 = "meshoptions"
|
||||||
|
bamboo_top.param2 = 2
|
||||||
|
bamboo_top.waving = 2
|
||||||
bamboo_top.special_tiles = {{name = "mcl_bamboo_endcap.png"}}
|
bamboo_top.special_tiles = {{name = "mcl_bamboo_endcap.png"}}
|
||||||
bamboo_top.nodebox = nil
|
bamboo_top.nodebox = nil
|
||||||
bamboo_top.selection_box = nil
|
bamboo_top.selection_box = nil
|
||||||
|
|
|
@ -9,8 +9,6 @@ local SIDE_SCAFFOLDING = false
|
||||||
local SIDE_SCAFFOLD_NAME = "mcl_bamboo:scaffolding_horizontal"
|
local SIDE_SCAFFOLD_NAME = "mcl_bamboo:scaffolding_horizontal"
|
||||||
-- ---------------------------------------------------------------------------
|
-- ---------------------------------------------------------------------------
|
||||||
local SCAFFOLDING_NAME = "mcl_bamboo:scaffolding"
|
local SCAFFOLDING_NAME = "mcl_bamboo:scaffolding"
|
||||||
-- Used everywhere. Often this is just the name, but it makes sense to me as BAMBOO, because that's how I think of it...
|
|
||||||
-- "BAMBOO" goes here.
|
|
||||||
local BAMBOO = "mcl_bamboo:bamboo"
|
local BAMBOO = "mcl_bamboo:bamboo"
|
||||||
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
||||||
|
|
||||||
|
|
|
@ -44,6 +44,10 @@ mcl_bamboo.bamboo_index = {
|
||||||
"mcl_bamboo:bamboo_2",
|
"mcl_bamboo:bamboo_2",
|
||||||
"mcl_bamboo:bamboo_3",
|
"mcl_bamboo:bamboo_3",
|
||||||
}
|
}
|
||||||
|
mcl_bamboo.bamboo_set = {}
|
||||||
|
for _,key in pairs(mcl_bamboo.bamboo_index) do
|
||||||
|
mcl_bamboo.bamboo_set[key] = true
|
||||||
|
end
|
||||||
|
|
||||||
function mcl_bamboo.is_bamboo(node_name)
|
function mcl_bamboo.is_bamboo(node_name)
|
||||||
local index = table.indexof(mcl_bamboo.bamboo_index, node_name)
|
local index = table.indexof(mcl_bamboo.bamboo_index, node_name)
|
||||||
|
@ -94,172 +98,84 @@ end
|
||||||
--]]
|
--]]
|
||||||
|
|
||||||
function mcl_bamboo.grow_bamboo(pos, bonemeal_applied)
|
function mcl_bamboo.grow_bamboo(pos, bonemeal_applied)
|
||||||
|
local log = mcl_bamboo.mcl_log
|
||||||
local node_above = minetest.get_node(vector.offset(pos, 0, 1, 0))
|
local node_above = minetest.get_node(vector.offset(pos, 0, 1, 0))
|
||||||
mcl_bamboo.mcl_log("Grow bamboo called; bonemeal: " .. tostring(bonemeal_applied))
|
log("Grow bamboo called; bonemeal: " .. tostring(bonemeal_applied))
|
||||||
|
|
||||||
if not bonemeal_applied and mcl_bamboo.is_bamboo(node_above.name) ~= false then
|
if not bonemeal_applied then
|
||||||
return false -- short circuit this function if we're trying to grow (std) the bamboo and it's not the top shoot.
|
-- Only allow natural growth at the top of the bamboo
|
||||||
end
|
if mcl_bamboo.is_bamboo(node_above.name) ~= false then return false end
|
||||||
if minetest.get_node_light(pos) < 8 then
|
|
||||||
return false
|
-- Don't perform natual growth in low light
|
||||||
|
if minetest.get_node_light(pos) < 8 then return false end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- variables used in more than one spot.
|
-- Determine the location of soil
|
||||||
local first_shoot
|
|
||||||
local chk_pos
|
|
||||||
local soil_pos
|
local soil_pos
|
||||||
local node_name = ""
|
soil_pos,a,b = mcl_util.trace_nodes(pos, -1, mcl_bamboo.bamboo_set, BAMBOO_MAX_HEIGHT - 1)
|
||||||
local dist = 0
|
|
||||||
local node_below
|
|
||||||
-- -------------------
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; checking for soil: ")
|
-- No soil found, return false so that bonemeal isn't used
|
||||||
-- the soil node below the bamboo.
|
if not soil_pos then return false end
|
||||||
for py = -1, BAMBOO_SOIL_DIST, -1 do
|
log("Grow bamboo; soil found. ")
|
||||||
chk_pos = vector.offset(pos, 0, py, 0)
|
|
||||||
node_name = minetest.get_node(chk_pos).name
|
-- Find the first bamboo shoot and retrieve data about it
|
||||||
if mcl_bamboo.is_dirt(node_name) then
|
local first_shoot = vector.offset(soil_pos, 0, 1, 0)
|
||||||
soil_pos = chk_pos
|
local first_shoot_meta = minetest.get_meta(first_shoot)
|
||||||
break
|
|
||||||
|
-- Get or initialize bamboo height
|
||||||
|
local height = (first_shoot_meta and first_shoot_meta:get_int("height", -1)) or -1
|
||||||
|
if height == -1 then
|
||||||
|
height = rand(BAM_MAX_HEIGHT_STPCHK + 1, BAM_MAX_HEIGHT_TOP + 1)
|
||||||
|
first_shoot_meta:set_int("height", height)
|
||||||
end
|
end
|
||||||
if mcl_bamboo.is_bamboo(node_name) == false then
|
log("Grow bamboo; height: " .. height)
|
||||||
break
|
|
||||||
end
|
-- Locate the bamboo tip
|
||||||
end
|
local bamboo_tip,actual_height,bamboo_tip_node = mcl_util.trace_nodes(first_shoot, 1, mcl_bamboo.bamboo_set, height - 1)
|
||||||
-- requires knowing where the soil node is.
|
log("Current height: "..tostring(actual_height))
|
||||||
if soil_pos == nil then
|
|
||||||
return false -- returning false means don't use up the bonemeal.
|
-- Short circuit growth if the bamboo is already finished growing
|
||||||
|
if not bamboo_tip or not actual_height or actual_height >= height then
|
||||||
|
log("Bamboo is already as large as it can grow")
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; soil found. ")
|
-- Now that we are actually going to add nodes, initialize some more information
|
||||||
local grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
local first_shoot_node_name = minetest.get_node(first_shoot).name
|
||||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
|
||||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE) -- because yeah, not truly random, or even a good prng.
|
|
||||||
grow_amount = rand(1, GROW_DOUBLE_CHANCE)
|
|
||||||
local init_height = rand(BAM_MAX_HEIGHT_STPCHK + 1, BAM_MAX_HEIGHT_TOP + 1)
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; random height: " .. init_height)
|
|
||||||
|
|
||||||
node_name = ""
|
-- If applying bonemeal, randomly grow two segments instead of one
|
||||||
|
local grow_amount = 1
|
||||||
-- update: add randomized max height to first node's meta data.
|
|
||||||
first_shoot = vector.offset(soil_pos, 0, 1, 0)
|
|
||||||
local meta = minetest.get_meta(first_shoot)
|
|
||||||
node_below = minetest.get_node(first_shoot).name
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; checking height meta ")
|
|
||||||
-- check the meta data for the first node, to see how high to make the stalk.
|
|
||||||
if not meta then
|
|
||||||
-- if no metadata, set the metadata!!!
|
|
||||||
meta:set_int("height", init_height)
|
|
||||||
end
|
|
||||||
local height = meta:get_int("height", -1)
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; meta-height: " .. height)
|
|
||||||
if height <= 10 then
|
|
||||||
height = init_height
|
|
||||||
meta:set_int("height", init_height)
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; height: " .. height)
|
|
||||||
|
|
||||||
-- Bonemeal: Grows the bamboo by 1-2 stems. (per the minecraft wiki.)
|
|
||||||
if bonemeal_applied then
|
if bonemeal_applied then
|
||||||
-- handle applying bonemeal.
|
local rng = PcgRandom(minetest.hash_node_position(pos) + minetest.get_us_time())
|
||||||
for py = 1, BAM_MAX_HEIGHT_TOP do
|
if rng:next(1, GROW_DOUBLE_CHANGE) == 1 then
|
||||||
-- find the top node of bamboo.
|
grow_amount = 2
|
||||||
chk_pos = vector.offset(pos, 0, py, 0)
|
|
||||||
node_name = minetest.get_node(chk_pos).name
|
|
||||||
dist = vector.distance(soil_pos, chk_pos)
|
|
||||||
if mcl_bamboo.is_bamboo(node_name) == false or node_name == BAMBOO_ENDCAP_NAME then
|
|
||||||
break
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
log("Growing up to "..grow_amount.." segments")
|
||||||
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; dist: " .. dist)
|
-- Perform bamboo growth
|
||||||
|
for i = 1,grow_amount do
|
||||||
if node_name == BAMBOO_ENDCAP_NAME then
|
-- Check for air to grow into
|
||||||
-- prevent overgrowth
|
local bamboo_tip_node = minetest.get_node(bamboo_tip)
|
||||||
return false
|
if not bamboo_tip_node or bamboo_tip_node.name ~= "air" then
|
||||||
|
-- Something is blocking growth, stop and signal that use bonemeal has been used if at least on segment has grown
|
||||||
|
return i ~= 1
|
||||||
end
|
end
|
||||||
|
|
||||||
-- check to see if we have a full stalk of bamboo.
|
if actual_height + 1 == height then
|
||||||
if dist >= height - 1 then
|
-- This is the end cap
|
||||||
if dist == height - 1 then
|
minetest.set_node(bamboo_tip, { name = BAMBOO_ENDCAP_NAME })
|
||||||
-- equals top of the stalk before the cap
|
return true
|
||||||
if node_name == "air" then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; Placing endcap")
|
|
||||||
minetest.set_node(vector.offset(chk_pos, 0, 1, 0), { name = BAMBOO_ENDCAP_NAME })
|
|
||||||
return true -- returning true means use up the bonemeal.
|
|
||||||
else
|
else
|
||||||
return false
|
-- This isn't the end cap, add a bamboo segment
|
||||||
end
|
minetest.set_node(bamboo_tip, { name = first_shoot_node_name })
|
||||||
else
|
actual_height = actual_height + 1
|
||||||
-- okay, we're higher than the end cap, fail out.
|
|
||||||
return false -- returning false means don't use up the bonemeal.
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- and now, the meat of the section... add bamboo to the stalk.
|
bamboo_tip = vector.offset(bamboo_tip, 0, 1, 0)
|
||||||
-- at this point, we should be lower than the generated maximum height. ~ about height -2 or lower.
|
|
||||||
if dist <= height - 2 then
|
|
||||||
if node_name == "air" then
|
|
||||||
-- here we can check to see if we can do up to 2 bamboo shoots onto the stalk
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; Placing bamboo.")
|
|
||||||
minetest.set_node(chk_pos, { name = node_below })
|
|
||||||
-- handle growing a second node.
|
|
||||||
if grow_amount == 2 then
|
|
||||||
chk_pos = vector.offset(chk_pos, 0, 1, 0)
|
|
||||||
if minetest.get_node(chk_pos).name == "air" then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; OOOH! It's twofer day!")
|
|
||||||
minetest.set_node(chk_pos, { name = node_below })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true -- exit out with a success. We've added 1-2 nodes, per the wiki.
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Non-Bonemeal growth.
|
return true
|
||||||
for py = 1, BAM_MAX_HEIGHT_TOP do
|
|
||||||
-- Find the topmost node above the stalk, and check it for "air"
|
|
||||||
chk_pos = vector.offset(pos, 0, py, 0)
|
|
||||||
node_below = minetest.get_node(pos).name
|
|
||||||
node_name = minetest.get_node(chk_pos).name
|
|
||||||
dist = vector.distance(soil_pos, chk_pos)
|
|
||||||
|
|
||||||
if node_name ~= "air" and mcl_bamboo.is_bamboo(node_name) == false then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
-- stop growing check. ie, handle endcap placement.
|
|
||||||
if dist >= height - 1 then
|
|
||||||
local above_node_name = minetest.get_node(vector.offset(chk_pos, 0, 1, 0)).name
|
|
||||||
if node_name == "air" and above_node_name == "air" then
|
|
||||||
if height - 1 == dist then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; Placing endcap")
|
|
||||||
minetest.set_node(chk_pos, { name = BAMBOO_ENDCAP_NAME })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
-- handle regular node placement.
|
|
||||||
-- find the air node above the top shoot. place a node. And then, if short enough,
|
|
||||||
-- check for second node placement.
|
|
||||||
if node_name == "air" then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; dist: " .. dist)
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; Placing bamboo.")
|
|
||||||
minetest.set_node(chk_pos, { name = node_below })
|
|
||||||
-- handle growing a second node. (1 in 32 chance.)
|
|
||||||
if grow_amount == 2 and dist <= height - 2 then
|
|
||||||
chk_pos = vector.offset(chk_pos, 0, 1, 0)
|
|
||||||
if minetest.get_node(chk_pos).name == "air" then
|
|
||||||
mcl_bamboo.mcl_log("Grow bamboo; OOOH! It's twofer day!")
|
|
||||||
minetest.set_node(chk_pos, { name = node_below })
|
|
||||||
end
|
|
||||||
end
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Add Groups function, courtesy of Warr1024.
|
-- Add Groups function, courtesy of Warr1024.
|
||||||
|
|
|
@ -7,8 +7,6 @@
|
||||||
|
|
||||||
-- LOCALS
|
-- LOCALS
|
||||||
local modname = minetest.get_current_modname()
|
local modname = minetest.get_current_modname()
|
||||||
-- Used everywhere. Often this is just the name, but it makes sense to me as BAMBOO, because that's how I think of it...
|
|
||||||
-- "BAMBOO" goes here.
|
|
||||||
local BAMBOO = "mcl_bamboo:bamboo"
|
local BAMBOO = "mcl_bamboo:bamboo"
|
||||||
|
|
||||||
mcl_bamboo = {}
|
mcl_bamboo = {}
|
||||||
|
|
|
@ -5,8 +5,6 @@
|
||||||
--- These are all of the fuel recipes and all of the crafting recipes, consolidated into one place.
|
--- These are all of the fuel recipes and all of the crafting recipes, consolidated into one place.
|
||||||
--- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
--- Copyright (C) 2022 - 2023, Michieal. See License.txt
|
||||||
|
|
||||||
-- Used everywhere. Often this is just the name, but it makes sense to me as BAMBOO, because that's how I think of it...
|
|
||||||
-- "BAMBOO" goes here.
|
|
||||||
local BAMBOO = "mcl_bamboo:bamboo"
|
local BAMBOO = "mcl_bamboo:bamboo"
|
||||||
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
local BAMBOO_PLANK = BAMBOO .. "_plank"
|
||||||
-- Craftings
|
-- Craftings
|
||||||
|
|
|
@ -2,4 +2,4 @@ name = mcl_beds
|
||||||
author = BlockMen
|
author = BlockMen
|
||||||
description =
|
description =
|
||||||
depends = playerphysics
|
depends = playerphysics
|
||||||
optional_depends = mcl_sounds, mcl_worlds, mcl_wool, mcl_dye, mcl_explosions, mcl_weather, mcl_spawn, doc, mesecons
|
optional_depends = mcl_sounds, mcl_worlds, mcl_wool, mcl_dye, mcl_explosions, mcl_weather, mcl_spawn, doc, mesecons, mesecons_mvps
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
|
||||||
|
# Bone meal API
|
||||||
|
Bonemealing callbacks and particle functions.
|
||||||
|
|
||||||
|
|
||||||
|
## _on_bone_meal(itemstack, placer, pointed_thing)
|
||||||
|
The bone meal API provides a callback definition that nodes can use to
|
||||||
|
register a handler that is executed when a bone meal item is used on it.
|
||||||
|
|
||||||
|
Nodes that wish to use the bone meal API should in their node registration
|
||||||
|
define a callback handler named `_on_bone_meal`.
|
||||||
|
|
||||||
|
Note that by registering the callback handler, the node declares that bone
|
||||||
|
meal can be used on it and as a result, when the user is not in creative
|
||||||
|
mode, the used bone meal is spent and taken from the itemstack passed to
|
||||||
|
the `on_place()` handler of the bone meal item used regardless of whether
|
||||||
|
the bone meal had an effect on the node and regardless of the result of
|
||||||
|
the callback handler.
|
||||||
|
|
||||||
|
It is for all intents and purposes up to the callback defined in the node to
|
||||||
|
decide how to handle the specific effect that bone meal has on that node.
|
||||||
|
|
||||||
|
The `_on_bone_meal` callback handler is a
|
||||||
|
|
||||||
|
`function(itemstack, placer, pointed_thing)`
|
||||||
|
|
||||||
|
Its arguments are:
|
||||||
|
* `itemstack`: the stack of bonem eal being applied
|
||||||
|
* `placer`: ObjectRef of the player who aplied the bone meal, can be nil!
|
||||||
|
* `pointed_thing`: exact pointing location (see Minetest API), where the
|
||||||
|
bone meal is applied
|
||||||
|
|
||||||
|
The return value of the handler function indicates if the bonemealing had
|
||||||
|
its intended effect. If `true`, 'bone meal particles' are spawned at the
|
||||||
|
position of the bonemealed node.
|
||||||
|
|
||||||
|
The `on_place` code in the bone meal item will spawn bone meal particles and
|
||||||
|
decrease the bone meal itemstack if the handler returned `true` and the
|
||||||
|
`placer` is not in creative mode.
|
||||||
|
|
||||||
|
|
||||||
|
## mcl_bone_meal.add_bone_meal_particle(pos, def)
|
||||||
|
Spawns standard or custom bone meal particles.
|
||||||
|
* `pos`: position, is ignored if you define def.minpos and def.maxpos
|
||||||
|
* `def`: (optional) particle definition; see minetest.add_particlespawner()
|
||||||
|
for more details.
|
||||||
|
|
||||||
|
## mcl_bone_meal.use_bone_meal(itemstack, placer, pointed_thing)
|
||||||
|
For use in on_rightclick handlers that need support bone meal processing in addition
|
||||||
|
to other behaviors. Before calling, verify that the player is wielding bone meal.
|
||||||
|
* `itemstack`: The stack of bone meal being used
|
||||||
|
* `placer`: ObjectRef of the player who aplied the bone meal, can be nil!
|
||||||
|
* `pointed_thing`: exact pointing location (see Minetest API), where the
|
||||||
|
bone meal is applied
|
||||||
|
|
||||||
|
Returns itemstack with one bone meal consumed if not in creative mode.
|
||||||
|
|
||||||
|
# Legacy API
|
||||||
|
The bone meal API also provides a legacy compatibility function. This
|
||||||
|
function is not meant to be continued and callers should migrate to the
|
||||||
|
newer bonemealing API.
|
||||||
|
|
||||||
|
## mcl_bone_meal.register_on_bone_meal_apply(function(pointed_thing, placer))
|
||||||
|
Called when the bone meal is applied anywhere.
|
||||||
|
* `pointed_thing`: exact pointing location (see Minetest API), where the
|
||||||
|
bone meal is applied
|
||||||
|
* `placer`: ObjectRef of the player who aplied the bone meal, can be nil!
|
||||||
|
This function is deprecated and will be removed at some time in the future.
|
||||||
|
Bone meal is not consumed unless the provided function returns true.
|
||||||
|
|
||||||
|
## mcl_dye.add_bone_meal_particle(pos, def)
|
||||||
|
## mcl_dye.register_on_bone_meal_apply(function(pointed_thing, user))
|
||||||
|
These shims in mcl_dye that point to corresponding legacy compatibility
|
||||||
|
functions in mcl_bone_meal remain for legacy callers that have not yet been
|
||||||
|
updated to the new API. These shims will be removed at some time in the
|
||||||
|
future.
|
|
@ -0,0 +1,156 @@
|
||||||
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local longdesc = S(
|
||||||
|
"Bone meal is a white dye and also useful as a fertilizer to " ..
|
||||||
|
"speed up the growth of many plants."
|
||||||
|
)
|
||||||
|
local usagehelp = S(
|
||||||
|
"Rightclick a sheep to turn its wool white. Rightclick a plant " ..
|
||||||
|
"to speed up its growth. Note that not all plants can be " ..
|
||||||
|
"fertilized like this. When you rightclick a grass block, tall " ..
|
||||||
|
"grass and flowers will grow all over the place."
|
||||||
|
)
|
||||||
|
|
||||||
|
mcl_bone_meal = {}
|
||||||
|
|
||||||
|
-- Bone meal particle API:
|
||||||
|
|
||||||
|
--- Spawns bone meal particles.
|
||||||
|
-- pos: where the particles spawn
|
||||||
|
-- def: particle spawner parameters, see minetest.add_particlespawner() for
|
||||||
|
-- details on these parameters.
|
||||||
|
--
|
||||||
|
function mcl_bone_meal.add_bone_meal_particle(pos, def)
|
||||||
|
def = def or {}
|
||||||
|
minetest.add_particlespawner({
|
||||||
|
amount = def.amount or 10,
|
||||||
|
time = def.time or 0.1,
|
||||||
|
minpos = def.minpos or vector.subtract(pos, 0.5),
|
||||||
|
maxpos = def.maxpos or vector.add(pos, 0.5),
|
||||||
|
minvel = def.minvel or vector.new(-0.01, 0.01, -0.01),
|
||||||
|
maxvel = def.maxvel or vector.new(0.01, 0.01, 0.01),
|
||||||
|
minacc = def.minacc or vector.new(0, 0, 0),
|
||||||
|
maxacc = def.maxacc or vector.new(0, 0, 0),
|
||||||
|
minexptime = def.minexptime or 1,
|
||||||
|
maxexptime = def.maxexptime or 4,
|
||||||
|
minsize = def.minsize or 0.7,
|
||||||
|
maxsize = def.maxsize or 2.4,
|
||||||
|
texture = "mcl_particles_bonemeal.png^[colorize:#00EE00:125",
|
||||||
|
glow = def.glow or 1,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Begin legacy bone meal API.
|
||||||
|
--
|
||||||
|
-- Compatibility code for legacy users of the old bone meal API.
|
||||||
|
-- This code will be removed at some time in the future.
|
||||||
|
--
|
||||||
|
mcl_bone_meal.bone_meal_callbacks = {}
|
||||||
|
|
||||||
|
-- Shims for the old API are still available in mcl_dye and defer to
|
||||||
|
-- the real functions in mcl_bone_meal.
|
||||||
|
--
|
||||||
|
function mcl_bone_meal.register_on_bone_meal_apply(func)
|
||||||
|
minetest.log("warning", "register_on_bone_meal_apply(func) is deprecated. Read mcl_bone_meal/API.md!")
|
||||||
|
local lines = string.split(debug.traceback(),"\n")
|
||||||
|
for _,line in ipairs(lines) do
|
||||||
|
minetest.log("warning",line)
|
||||||
|
end
|
||||||
|
table.insert(mcl_bone_meal.bone_meal_callbacks, func)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Legacy registered users of the old API are handled through this function.
|
||||||
|
--
|
||||||
|
local function legacy_apply_bone_meal(pointed_thing, placer)
|
||||||
|
-- Legacy API support
|
||||||
|
local callbacks = mcl_bone_meal.bone_meal_callbacks
|
||||||
|
for i = 1,#callbacks do
|
||||||
|
if callbacks[i](pointed_thing, placer) then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
-- End legacy bone meal API
|
||||||
|
|
||||||
|
function mcl_bone_meal.use_bone_meal(itemstack, placer, pointed_thing)
|
||||||
|
local positions = {pointed_thing.under, pointed_thing.above}
|
||||||
|
for i = 1,2 do
|
||||||
|
local pos = positions[i]
|
||||||
|
|
||||||
|
-- Check protection
|
||||||
|
if mcl_util.check_area_protection(pos, pointed_thing.above, placer) then return false end
|
||||||
|
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local ndef = minetest.registered_nodes[node.name]
|
||||||
|
local success = false
|
||||||
|
local consume
|
||||||
|
|
||||||
|
-- If the pointed node can be bonemealed, let it handle the processing.
|
||||||
|
if ndef and ndef._on_bone_meal then
|
||||||
|
success = ndef._on_bone_meal(itemstack, placer, {under = pos, above = vector.offset(pos, 0, 1, 0)})
|
||||||
|
consume = true
|
||||||
|
else
|
||||||
|
-- Otherwise try the legacy API.
|
||||||
|
success = legacy_apply_bone_meal(pointed_thing, placer)
|
||||||
|
consume = success
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Take the item
|
||||||
|
if consume then
|
||||||
|
-- Particle effects
|
||||||
|
mcl_bone_meal.add_bone_meal_particle(pos)
|
||||||
|
|
||||||
|
if not placer or not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||||
|
itemstack:take_item()
|
||||||
|
end
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
if success then return itemstack end
|
||||||
|
end
|
||||||
|
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_craftitem("mcl_bone_meal:bone_meal", {
|
||||||
|
description = S("Bone Meal"),
|
||||||
|
_tt_help = S("Speeds up plant growth"),
|
||||||
|
_doc_items_longdesc = longdesc,
|
||||||
|
_doc_items_usagehelp = usagehelp,
|
||||||
|
inventory_image = "mcl_bone_meal.png",
|
||||||
|
groups = {craftitem=1},
|
||||||
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
local ndef = minetest.registered_nodes[node.name]
|
||||||
|
|
||||||
|
-- Use pointed node's on_rightclick function first, if present.
|
||||||
|
if placer and not placer:get_player_control().sneak then
|
||||||
|
if ndef and ndef.on_rightclick then
|
||||||
|
local new_stack = mcl_util.call_on_rightclick(itemstack, placer, pointed_thing)
|
||||||
|
if new_stack and new_stack ~= itemstack then return new_stack end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return mcl_bone_meal.use_bone_meal(itemstack, placer, pointed_thing)
|
||||||
|
end,
|
||||||
|
_on_dispense = function(itemstack, pos, droppos, dropnode, dropdir)
|
||||||
|
local pointed_thing
|
||||||
|
if dropnode.name == "air" then
|
||||||
|
pointed_thing = {above = droppos, under = vector.offset(droppos, 0, -1 ,0)}
|
||||||
|
else
|
||||||
|
pointed_thing = {above = pos, under = droppos}
|
||||||
|
end
|
||||||
|
|
||||||
|
return mcl_bone_meal.use_bone_meal(itemstack, nil, pointed_thing)
|
||||||
|
end,
|
||||||
|
_dispense_into_walkable = true
|
||||||
|
})
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
output = "mcl_bone_meal:bone_meal 3",
|
||||||
|
recipe = {{"mcl_mobitems:bone"}},
|
||||||
|
})
|
|
@ -0,0 +1,5 @@
|
||||||
|
# textdomain: mcl_bone_meal
|
||||||
|
Bone Meal=Knochenmehl
|
||||||
|
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=Knochenmehl ist ein weißer Farbstoff und auch nützlich als Dünger, um das Wachstum vieler Pflanzen zu beschleunigen.
|
||||||
|
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Rechtsklicken Sie auf ein Schaf, um die Wolle weiß einzufärben. Rechtsklicken Sie auf eine Pflanze, um ihr Wachstum zu beschleunigen. Beachten Sie, dass nicht alle Pflanzen darauf ansprechen. Benutzen Sie es auf einem Grasblock, wächst viel hohes Gras und vielleicht auch ein paar Blumen.
|
||||||
|
Speeds up plant growth=Beschleunigt Pflanzenwachstum
|
|
@ -0,0 +1,5 @@
|
||||||
|
# textdomain: mcl_bone_meal
|
||||||
|
Bone Meal=Harina de hueso
|
||||||
|
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=La harina de hueso es un tinte blanco y también es útil como fertilizante para acelerar el crecimiento de muchas plantas.
|
||||||
|
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=RHaga clic derecho en una oveja para volver su lana blanca. Haga clic derecho en una planta para acelerar su crecimiento. Tenga en cuenta que no todas las plantas pueden ser fertilizadas de esta manera. Cuando haces clic derecho en un bloque de hierba, crecerán hierba alta y flores por todo el lugar.
|
||||||
|
Speeds up plant growth=Acelera el crecimiento de las plantas
|
|
@ -0,0 +1,5 @@
|
||||||
|
# textdomain: mcl_bone_meal
|
||||||
|
Bone Meal=Farine d'Os
|
||||||
|
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=La farine d'os est une teinture blanche et est également utile comme engrais pour accélérer la croissance de nombreuses plantes.
|
||||||
|
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Cliquez avec le bouton droit sur un mouton pour blanchir sa laine. Cliquez avec le bouton droit sur une plante pour accélérer sa croissance. Cependant, toutes les plantes ne peuvent pas être fertilisées de cette manière. Lorsque vous cliquez avec le bouton droit sur un bloc d'herbe, les hautes herbes et les fleurs poussent autour.
|
||||||
|
Speeds up plant growth=Accélère la croissance des plantes
|
|
@ -0,0 +1,5 @@
|
||||||
|
# textdomain: mcl_bone_meal
|
||||||
|
Bone Meal=Mączka kostna
|
||||||
|
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=Mączka kostna to biała farba i przydatny nawóz, który przyspiesza rośnięcie wielu roślin.
|
||||||
|
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Kliknij prawym na owcę, aby wybielić jej wełnę. Kliknij prawym na roślinę aby przyspieszyć jej wzrost. Zważ, że nie na wszystkie rośliny to tak działa. Gdy klikniesz prawym na blok trawy, wysoka trawa wyrośnie wokół.
|
||||||
|
Speeds up plant growth=Przyspiesza wzrost roślin
|
|
@ -0,0 +1,5 @@
|
||||||
|
# textdomain: mcl_bone_meal
|
||||||
|
Bone Meal=Костная мука
|
||||||
|
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=Костная мука является белым красителем. Она также полезна в качестве удобрения, чтобы увеличить скорость роста многих растений.
|
||||||
|
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Кликните правой по овце, чтобы сделать её шерсть белой. Кликните правой по растению, чтобы ускорить его рост. Имейте в виду, что не все растения можно удобрять таким способом. Если вы кликнете по травяному блоку, то на этом месте вырастет высокая трава и цветы.
|
||||||
|
Speeds up plant growth=Ускоряет рост растений
|
|
@ -0,0 +1,5 @@
|
||||||
|
# textdomain: mcl_bone_meal
|
||||||
|
Bone Meal=骨粉
|
||||||
|
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=骨粉是一種白色染料,也可作為肥料,加速許多植物的生長。
|
||||||
|
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=右鍵點擊一隻羊,使其羊毛變白。右鍵點擊一株植物以加快其生長速度。注意,不是所有的植物都能像這樣施肥。當你右鍵點擊一個草方時,高高的草和花會到處生長。
|
||||||
|
Speeds up plant growth=加速植物生長
|
|
@ -0,0 +1,5 @@
|
||||||
|
# textdomain: mcl_bone_meal
|
||||||
|
Bone Meal=
|
||||||
|
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=
|
||||||
|
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=
|
||||||
|
Speeds up plant growth=
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = mcl_bone_meal
|
||||||
|
description = Bone meal can be used as a fertilizer and as a dye.
|
||||||
|
author = kabou, teknomunk
|
Before Width: | Height: | Size: 165 B After Width: | Height: | Size: 165 B |
|
@ -35,6 +35,7 @@ local function random_arrow_positions(positions, placement)
|
||||||
end
|
end
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
mcl_bows.random_arrow_positions = random_arrow_positions
|
||||||
|
|
||||||
local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements")
|
local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements")
|
||||||
local mod_button = minetest.get_modpath("mesecons_button")
|
local mod_button = minetest.get_modpath("mesecons_button")
|
||||||
|
@ -257,10 +258,10 @@ function ARROW_ENTITY.on_step(self, dtime)
|
||||||
mcl_burning.set_on_fire(obj, 5)
|
mcl_burning.set_on_fire(obj, 5)
|
||||||
end
|
end
|
||||||
if not self._in_player and not self._blocked then
|
if not self._in_player and not self._blocked then
|
||||||
obj:punch(self.object, 1.0, {
|
mcl_util.deal_damage(obj, self._damage, {type = "arrow", source = self._shooter, direct = self.object})
|
||||||
full_punch_interval=1.0,
|
if self._extra_hit_func then
|
||||||
damage_groups={fleshy=self._damage},
|
self._extra_hit_func(obj)
|
||||||
}, self.object:get_velocity())
|
end
|
||||||
if obj:is_player() then
|
if obj:is_player() then
|
||||||
if not mcl_shields.is_blocking(obj) then
|
if not mcl_shields.is_blocking(obj) then
|
||||||
local placement
|
local placement
|
||||||
|
|
|
@ -1,6 +1,5 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
mcl_bows = {}
|
|
||||||
|
|
||||||
-- local arrows = {
|
-- local arrows = {
|
||||||
-- ["mcl_bows:arrow"] = "mcl_bows:arrow_entity",
|
-- ["mcl_bows:arrow"] = "mcl_bows:arrow_entity",
|
||||||
|
@ -168,7 +167,8 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
|
||||||
itemstack:get_meta():set_string("active", "true")
|
itemstack:get_meta():set_string("active", "true")
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
groups = {weapon=1,weapon_ranged=1,bow=1,enchantability=1},
|
groups = {weapon=1,weapon_ranged=1,bow=1,cannot_block=1,enchantability=1},
|
||||||
|
touch_interaction = "short_dig_long_place",
|
||||||
_mcl_uses = 385,
|
_mcl_uses = 385,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -216,7 +216,7 @@ for level=0, 2 do
|
||||||
wield_scale = mcl_vars.tool_wield_scale,
|
wield_scale = mcl_vars.tool_wield_scale,
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
range = 0, -- Pointing range to 0 to prevent punching with bow :D
|
range = 0, -- Pointing range to 0 to prevent punching with bow :D
|
||||||
groups = {not_in_creative_inventory=1, not_in_craft_guide=1, bow=1, enchantability=1},
|
groups = {not_in_creative_inventory=1, not_in_craft_guide=1, bow=1, cannot_block=1, enchantability=1},
|
||||||
-- Trick to disable digging as well
|
-- Trick to disable digging as well
|
||||||
on_use = function() return end,
|
on_use = function() return end,
|
||||||
on_drop = function(itemstack, dropper, pos)
|
on_drop = function(itemstack, dropper, pos)
|
||||||
|
@ -235,6 +235,7 @@ for level=0, 2 do
|
||||||
on_place = function(itemstack)
|
on_place = function(itemstack)
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
|
touch_interaction = "short_dig_long_place",
|
||||||
_mcl_uses = 385,
|
_mcl_uses = 385,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
@ -158,7 +158,8 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
|
||||||
itemstack:get_meta():set_string("active", "true")
|
itemstack:get_meta():set_string("active", "true")
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
groups = {weapon=1,weapon_ranged=1,crossbow=1,enchantability=1},
|
groups = {weapon=1,weapon_ranged=1,crossbow=1,cannot_block=1,enchantability=1},
|
||||||
|
touch_interaction = "short_dig_long_place",
|
||||||
_mcl_uses = 326,
|
_mcl_uses = 326,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -193,7 +194,8 @@ S("The speed and damage of the arrow increases the longer you charge. The regula
|
||||||
itemstack:get_meta():set_string("active", "true")
|
itemstack:get_meta():set_string("active", "true")
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
groups = {weapon=1,weapon_ranged=1,crossbow=1,enchantability=1,not_in_creative_inventory=1},
|
groups = {weapon=1,weapon_ranged=1,crossbow=1,cannot_block=1,enchantability=1,not_in_creative_inventory=1},
|
||||||
|
touch_interaction = "short_dig_long_place",
|
||||||
_mcl_uses = 326,
|
_mcl_uses = 326,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -238,7 +240,7 @@ for level=0, 2 do
|
||||||
wield_scale = mcl_vars.tool_wield_scale,
|
wield_scale = mcl_vars.tool_wield_scale,
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
range = 0, -- Pointing range to 0 to prevent punching with bow :D
|
range = 0, -- Pointing range to 0 to prevent punching with bow :D
|
||||||
groups = {not_in_creative_inventory=1, not_in_craft_guide=1, bow=1, enchantability=1},
|
groups = {not_in_creative_inventory=1, not_in_craft_guide=1, cannot_block=1, bow=1, enchantability=1},
|
||||||
-- Trick to disable digging as well
|
-- Trick to disable digging as well
|
||||||
on_use = function() return end,
|
on_use = function() return end,
|
||||||
on_drop = function(itemstack, dropper, pos)
|
on_drop = function(itemstack, dropper, pos)
|
||||||
|
@ -257,6 +259,7 @@ for level=0, 2 do
|
||||||
on_place = function(itemstack)
|
on_place = function(itemstack)
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
|
touch_interaction = "short_dig_long_place",
|
||||||
_mcl_uses = 385,
|
_mcl_uses = 385,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
mcl_bows = {}
|
||||||
|
|
||||||
--Bow
|
--Bow
|
||||||
dofile(minetest.get_modpath("mcl_bows") .. "/arrow.lua")
|
dofile(minetest.get_modpath("mcl_bows") .. "/arrow.lua")
|
||||||
dofile(minetest.get_modpath("mcl_bows") .. "/bow.lua")
|
dofile(minetest.get_modpath("mcl_bows") .. "/bow.lua")
|
||||||
|
|
|
@ -2,29 +2,34 @@ local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
mcl_cocoas = {}
|
mcl_cocoas = {}
|
||||||
|
|
||||||
-- Place cocoa
|
--- Place a cocoa pod.
|
||||||
local function cocoa_place(itemstack, placer, pt, plantname)
|
-- Attempt to place a cocoa pod on a jungle tree. Checks if attachment
|
||||||
|
-- point is a jungle tree and sets the correct orientation of the stem.
|
||||||
|
--
|
||||||
|
function mcl_cocoas.place(itemstack, placer, pt, plantname)
|
||||||
-- check if pointing at a node
|
-- check if pointing at a node
|
||||||
if not pt or pt.type ~= "node" then
|
if not pt or pt.type ~= "node" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local under = minetest.get_node(pt.under)
|
local node = minetest.get_node(pt.under)
|
||||||
|
|
||||||
-- return if any of the nodes are not registered
|
-- return if any of the nodes are not registered
|
||||||
if not minetest.registered_nodes[under.name] then
|
local def = minetest.registered_nodes[node.name]
|
||||||
|
if not def then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Am I right-clicking on something that has a custom on_rightclick set?
|
-- Am I right-clicking on something that has a custom on_rightclick set?
|
||||||
if placer and not placer:get_player_control().sneak then
|
if placer and not placer:get_player_control().sneak then
|
||||||
if minetest.registered_nodes[under.name] and minetest.registered_nodes[under.name].on_rightclick then
|
if def and def.on_rightclick then
|
||||||
return minetest.registered_nodes[under.name].on_rightclick(pt.under, under, placer, itemstack) or itemstack
|
local new_stack = mcl_util.call_on_rightclick(itemstack, placer, pt)
|
||||||
|
if new_stack and new_stack ~= itemstack then return new_stack end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check if pointing at jungle tree
|
-- Check if pointing at jungle tree
|
||||||
if under.name ~= "mcl_core:jungletree"
|
if node.name ~= "mcl_core:jungletree"
|
||||||
or minetest.get_node(pt.above).name ~= "air" then
|
or minetest.get_node(pt.above).name ~= "air" then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -39,9 +44,7 @@ local function cocoa_place(itemstack, placer, pt, plantname)
|
||||||
|
|
||||||
-- Add the node, set facedir and remove 1 item from the itemstack
|
-- Add the node, set facedir and remove 1 item from the itemstack
|
||||||
minetest.set_node(pt.above, {name = plantname, param2 = minetest.dir_to_facedir(clickdir)})
|
minetest.set_node(pt.above, {name = plantname, param2 = minetest.dir_to_facedir(clickdir)})
|
||||||
|
|
||||||
minetest.sound_play("default_place_node", {pos = pt.above, gain = 1.0}, true)
|
minetest.sound_play("default_place_node", {pos = pt.above, gain = 1.0}, true)
|
||||||
|
|
||||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||||
itemstack:take_item()
|
itemstack:take_item()
|
||||||
end
|
end
|
||||||
|
@ -49,111 +52,119 @@ local function cocoa_place(itemstack, placer, pt, plantname)
|
||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Attempts to grow a cocoa at pos, returns true when grown, returns false if there's no cocoa
|
--- Grows cocoa pod one size larger.
|
||||||
-- or it is already at full size
|
-- Attempts to grow a cocoa at pos, returns true when grown, returns false
|
||||||
|
-- if there's no cocoa or it is already at full size.
|
||||||
|
--
|
||||||
function mcl_cocoas.grow(pos)
|
function mcl_cocoas.grow(pos)
|
||||||
local node = minetest.get_node(pos)
|
local node = minetest.get_node(pos)
|
||||||
if node.name == "mcl_cocoas:cocoa_1" then
|
if node.name == "mcl_cocoas:cocoa_1" then
|
||||||
minetest.set_node(pos, {name = "mcl_cocoas:cocoa_2", param2 = node.param2})
|
minetest.set_node(pos, {name = "mcl_cocoas:cocoa_2", param2 = node.param2})
|
||||||
elseif node.name == "mcl_cocoas:cocoa_2" then
|
elseif node.name == "mcl_cocoas:cocoa_2" then
|
||||||
minetest.set_node(pos, {name = "mcl_cocoas:cocoa_3", param2 = node.param2})
|
minetest.set_node(pos, {name = "mcl_cocoas:cocoa_3", param2 = node.param2})
|
||||||
return true
|
else
|
||||||
end
|
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
-- Cocoa definition
|
-- only caller was mcl_dye, consider converting these into local functions.
|
||||||
-- 1st stage
|
local cocoa_place = mcl_cocoas.place
|
||||||
local crop_def = {
|
local cocoa_grow = mcl_cocoas.grow
|
||||||
description = S("Premature Cocoa Pod"),
|
|
||||||
|
-- Cocoa pod variant definitions.
|
||||||
|
--[[ TODO: Use a mesh for cocoas for perfect texture compability. ]]
|
||||||
|
local podinfo = {
|
||||||
|
{ desc = S("Premature Cocoa Pod"),
|
||||||
|
longdesc = S("Cocoa pods grow on the side of jungle trees in 3 stages."),
|
||||||
|
tiles = {
|
||||||
|
"mcl_cocoas_cocoa_stage_0.png",
|
||||||
|
},
|
||||||
|
n_box = {-0.125, -0.0625, 0.1875, 0.125, 0.25, 0.4375},
|
||||||
|
s_box = {-0.125, -0.0625, 0.1875, 0.125, 0.5, 0.5 },
|
||||||
|
},
|
||||||
|
{ desc = S("Medium Cocoa Pod"),
|
||||||
|
tiles = {
|
||||||
|
"mcl_cocoas_cocoa_stage_1.png",
|
||||||
|
},
|
||||||
|
n_box = {-0.1875, -0.1875, 0.0625, 0.1875, 0.25, 0.4375},
|
||||||
|
s_box = {-0.1875, -0.1875, 0.0625, 0.1875, 0.5, 0.5 },
|
||||||
|
},
|
||||||
|
{ desc = S("Mature Cocoa Pod"),
|
||||||
|
longdesc = S("A mature cocoa pod grew on a jungle tree to its full size and it is ready to be harvested for cocoa beans. It won't grow any further."),
|
||||||
|
tiles = {
|
||||||
|
"mcl_cocoas_cocoa_stage_2.png",
|
||||||
|
},
|
||||||
|
n_box = {-0.25, -0.3125, -0.0625, 0.25, 0.25, 0.4375},
|
||||||
|
s_box = {-0.25, -0.3125, -0.0625, 0.25, 0.5, 0.5 },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i = 1, 3 do
|
||||||
|
local def = {
|
||||||
|
description = podinfo[i].desc,
|
||||||
_doc_items_create_entry = true,
|
_doc_items_create_entry = true,
|
||||||
_doc_items_longdesc = S("Cocoa pods grow on the side of jungle trees in 3 stages."),
|
_doc_items_longdesc = podinfo[i].longdesc,
|
||||||
drawtype = "mesh",
|
|
||||||
mesh = "mcl_cocoas_cocoa_stage_0.obj",
|
|
||||||
tiles = {"mcl_cocoas_cocoa_stage_0.png"},
|
|
||||||
use_texture_alpha = minetest.features.use_texture_alpha_string_modes and "clip" or true,
|
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
sunlight_propagates = true,
|
|
||||||
paramtype2 = "facedir",
|
paramtype2 = "facedir",
|
||||||
walkable = true,
|
drawtype = "nodebox",
|
||||||
drop = "mcl_cocoas:cocoa_beans",
|
tiles = podinfo[i].tiles,
|
||||||
collision_box = {
|
use_texture_alpha = "clip",
|
||||||
|
node_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {
|
fixed = {
|
||||||
{-0.125, -0.0625, 0.1875, 0.125, 0.25, 0.4375}, -- Pod
|
podinfo[i].n_box, -- Pod
|
||||||
|
-- FIXME: This has a thickness of 0. Is this OK in Minetest?
|
||||||
|
{ 0, 0.25, 0.25, 0, 0.5, 0.5 }, }, -- Stem
|
||||||
},
|
},
|
||||||
|
collision_box = {
|
||||||
|
type = "fixed",
|
||||||
|
fixed = podinfo[i].n_box
|
||||||
},
|
},
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {
|
fixed = podinfo[i].s_box
|
||||||
{-0.125, -0.0625, 0.1875, 0.125, 0.5, 0.5}, -- Pod
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
groups = {
|
groups = {
|
||||||
handy = 1, axey = 1,
|
handy = 1, axey = 1, attached_node_facedir = 1,
|
||||||
dig_by_water = 1, destroy_by_lava_flow = 1, dig_by_piston = 1,
|
dig_by_water = 1, destroy_by_lava_flow = 1, dig_by_piston = 1,
|
||||||
attached_node_facedir=1,
|
cocoa = i, not_in_creative_inventory = 1,
|
||||||
not_in_creative_inventory=1,
|
|
||||||
cocoa=1
|
|
||||||
},
|
},
|
||||||
|
sunlight_propagates = true,
|
||||||
|
walkable = true,
|
||||||
|
drop = "mcl_cocoas:cocoa_beans",
|
||||||
sounds = mcl_sounds.node_sound_wood_defaults(),
|
sounds = mcl_sounds.node_sound_wood_defaults(),
|
||||||
on_rotate = false,
|
on_rotate = false,
|
||||||
_mcl_blast_resistance = 3,
|
_mcl_blast_resistance = 3,
|
||||||
_mcl_hardness = 0.2,
|
_mcl_hardness = 0.2,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
return cocoa_grow(pos)
|
||||||
|
end,
|
||||||
}
|
}
|
||||||
|
|
||||||
-- 2nd stage
|
if i == 2 then
|
||||||
minetest.register_node("mcl_cocoas:cocoa_1", table.copy(crop_def))
|
def._doc_items_longdesc = nil
|
||||||
|
def._doc_items_create_entry = false
|
||||||
|
end
|
||||||
|
if i == 3 then
|
||||||
|
def.drop = "mcl_cocoas:cocoa_beans 3"
|
||||||
|
def._on_bone_mealing = nil
|
||||||
|
end
|
||||||
|
|
||||||
crop_def.description = S("Medium Cocoa Pod")
|
minetest.register_node("mcl_cocoas:cocoa_" .. i, table.copy(def))
|
||||||
crop_def._doc_items_create_entry = false
|
end
|
||||||
crop_def.groups.cocoa = 2
|
|
||||||
crop_def.mesh = "mcl_cocoas_cocoa_stage_1.obj"
|
|
||||||
crop_def.tiles = {"mcl_cocoas_cocoa_stage_1.png"}
|
|
||||||
crop_def.collision_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.1875, -0.1875, 0.0625, 0.1875, 0.25, 0.4375}, -- Pod
|
|
||||||
},
|
|
||||||
}
|
|
||||||
crop_def.selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.1875, -0.1875, 0.0625, 0.1875, 0.5, 0.5},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
minetest.register_node("mcl_cocoas:cocoa_2", table.copy(crop_def))
|
|
||||||
|
|
||||||
-- Final stage
|
|
||||||
crop_def.description = S("Mature Cocoa Pod")
|
|
||||||
crop_def._doc_items_longdesc = S("A mature cocoa pod grew on a jungle tree to its full size and it is ready to be harvested for cocoa beans. It won't grow any further.")
|
|
||||||
crop_def._doc_items_create_entry = true
|
|
||||||
crop_def.groups.cocoa = 3
|
|
||||||
crop_def.mesh = "mcl_cocoas_cocoa_stage_2.obj"
|
|
||||||
crop_def.tiles = {"mcl_cocoas_cocoa_stage_2.png"}
|
|
||||||
crop_def.collision_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.25, -0.3125, -0.0625, 0.25, 0.25, 0.4375}, -- Pod
|
|
||||||
},
|
|
||||||
}
|
|
||||||
crop_def.selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.25, -0.3125, -0.0625, 0.25, 0.5, 0.5},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
crop_def.drop = "mcl_cocoas:cocoa_beans 3"
|
|
||||||
minetest.register_node("mcl_cocoas:cocoa_3", table.copy(crop_def))
|
|
||||||
|
|
||||||
minetest.register_craftitem("mcl_cocoas:cocoa_beans", {
|
minetest.register_craftitem("mcl_cocoas:cocoa_beans", {
|
||||||
description = S("Cocoa Beans"),
|
inventory_image = "mcl_cocoa_beans.png",
|
||||||
_tt_help = S("Grows at the side of jungle trees"),
|
_tt_help = S("Grows at the side of jungle trees"),
|
||||||
_doc_items_longdesc = S("Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye."),
|
_doc_items_longdesc = S("Cocoa beans can be used to plant cocoa, bake cookies or cract brown dye."),
|
||||||
_doc_items_usagehelp = S("Right click on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa."),
|
_doc_items_usagehelp = S("Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa."),
|
||||||
inventory_image = "mcl_cocoas_cocoa_beans.png",
|
description = S("Cocoa Beans"),
|
||||||
groups = {craftitem = 1, compostability = 65},
|
stack_max = 64,
|
||||||
|
groups = {
|
||||||
|
craftitem = 1, compostability = 65,
|
||||||
|
},
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
return cocoa_place(itemstack, placer, pointed_thing, "mcl_cocoas:cocoa_1")
|
return cocoa_place(itemstack, placer, pointed_thing, "mcl_cocoas:cocoa_1")
|
||||||
end,
|
end,
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Cocoa Beans=Kakaobohnen
|
Cocoa Beans=Kakaobohnen
|
||||||
Grows at the side of jungle trees=Wächst an der Seite von Dschungelbäumen
|
Grows at the side of jungle trees=Wächst an der Seite von Dschungelbäumen
|
||||||
Cocoa beans can be used to plant cocoa pods, bake chocolate cookies or craft brown dye.=Kakaobohnen können benutzt werden, um Kakao anzupflanzen, Kekse zu backen oder braune Farbstoffe herzustellen.
|
Cocoa beans can be used to plant cocoa pods, bake chocolate cookies or craft brown dye.=Kakaobohnen können benutzt werden, um Kakao anzupflanzen, Kekse zu backen oder braune Farbstoffe herzustellen.
|
||||||
Right click on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Rechtsklicken Sie an die Seite eines Dschungelbaumstamms (Dschungelholz), um eine junge Kakaoschote zu pflanzen.
|
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Rechtsklicken Sie auf ein Schaf, um die Wolle braun einzufärben. Rechtsklicken Sie an die Seite eines Dschungelbaumstamms (Dschungelholz), um eine junge Kakaoschote zu pflanzen.
|
||||||
Premature Cocoa Pod=Junge Kakaoschote
|
Premature Cocoa Pod=Junge Kakaoschote
|
||||||
Cocoa pods grow on the side of jungle trees in 3 stages.=Kakaoschoten wachsen an der Seite von Dschungelbäumen in 3 Stufen.
|
Cocoa pods grow on the side of jungle trees in 3 stages.=Kakaoschoten wachsen an der Seite von Dschungelbäumen in 3 Stufen.
|
||||||
Medium Cocoa Pod=Mittelgroße Kakaoschote
|
Medium Cocoa Pod=Mittelgroße Kakaoschote
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Cocoa Beans=Granos de cacao
|
Cocoa Beans=Granos de cacao
|
||||||
Grows at the side of jungle trees=Crece al lado de los árboles de la jungla
|
Grows at the side of jungle trees=Crece al lado de los árboles de la jungla
|
||||||
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=Los granos de cacao se pueden usar para plantar cacao, hornear galletas o hacer tintes marrones.
|
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=Los granos de cacao se pueden usar para plantar cacao, hornear galletas o hacer tintes marrones.
|
||||||
Right click on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Haga clic derecho en el costado del tronco de un árbol de la jungla para plantar un cacao joven.
|
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Haga clic derecho en una oveja para convertir su lana en marrón. Haga clic derecho en el costado del tronco de un árbol de la jungla para plantar un cacao joven.
|
||||||
Premature Cocoa Pod=Vaina de cacao prematura
|
Premature Cocoa Pod=Vaina de cacao prematura
|
||||||
Cocoa pods grow on the side of jungle trees in 3 stages.=Las vainas de cacao crecen al lado de los árboles de jungla en 3 etapas.
|
Cocoa pods grow on the side of jungle trees in 3 stages.=Las vainas de cacao crecen al lado de los árboles de jungla en 3 etapas.
|
||||||
Medium Cocoa Pod=Vaina de cacao mediana
|
Medium Cocoa Pod=Vaina de cacao mediana
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Cocoa Beans=Fèves de Cacao
|
Cocoa Beans=Fèves de Cacao
|
||||||
Grows at the side of jungle trees=Pousse à côté des arbres de la jungle
|
Grows at the side of jungle trees=Pousse à côté des arbres de la jungle
|
||||||
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=Les fèves de cacao peuvent être utilisées pour planter du cacao, faire des biscuits ou fabriquer de la teinture brune.
|
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=Les fèves de cacao peuvent être utilisées pour planter du cacao, faire des biscuits ou fabriquer de la teinture brune.
|
||||||
Right click on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Clic droit sur le côté d'un tronc d'arbre de la jungle (Bois Acajou) pour planter un jeune cacaoyer.
|
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Faites un clic droit sur un mouton pour brunir sa laine. Clic droit sur le côté d'un tronc d'arbre de la jungle (Bois Acajou) pour planter un jeune cacao.
|
||||||
Premature Cocoa Pod=Gousse de cacao prématurée
|
Premature Cocoa Pod=Gousse de cacao prématurée
|
||||||
Cocoa pods grow on the side of jungle trees in 3 stages.=Les cabosses de cacao poussent sur le côté des arbres d'Acajou en 3 étapes.
|
Cocoa pods grow on the side of jungle trees in 3 stages.=Les cabosses de cacao poussent sur le côté des arbres d'Acajou en 3 étapes.
|
||||||
Medium Cocoa Pod=Gousse de cacao moyenne
|
Medium Cocoa Pod=Gousse de cacao moyenne
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Cocoa Beans=Ziarna kakaowe
|
Cocoa Beans=Ziarna kakaowe
|
||||||
Grows at the side of jungle trees=Rośnie na boku tropikalnych drzew
|
Grows at the side of jungle trees=Rośnie na boku tropikalnych drzew
|
||||||
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=Ziarna kakaowe mogą być używane do sadzenia kakao, pieczenia ciasteczek lub robienia brązowego barwnika.
|
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=Ziarna kakaowe mogą być używane do sadzenia kakao, pieczenia ciasteczek lub robienia brązowego barwnika.
|
||||||
Right click on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Naciśnij prawym na boku tropikalnego pnia (Tropikalne drewno) aby zasadzić młode kakao.
|
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Naciśnij prawym aby zafarbować wełnę owcy na brązowo. Naciśnij prawym na boku tropikalnego pnia (Tropikalne drewno) aby zasadzić młode kakao.
|
||||||
Premature Cocoa Pod=Niedojrzała roślina kakao
|
Premature Cocoa Pod=Niedojrzała roślina kakao
|
||||||
Cocoa pods grow on the side of jungle trees in 3 stages.=Roślina kakao rośnie na bokach tropikalnych drzew w 3 etapach
|
Cocoa pods grow on the side of jungle trees in 3 stages.=Roślina kakao rośnie na bokach tropikalnych drzew w 3 etapach
|
||||||
Medium Cocoa Pod=Średnio-dojrzała roślina kakao
|
Medium Cocoa Pod=Średnio-dojrzała roślina kakao
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Cocoa Beans=Какао-бобы
|
Cocoa Beans=Какао-бобы
|
||||||
Grows at the side of jungle trees=Растут на стволах тропических деревьев
|
Grows at the side of jungle trees=Растут на стволах тропических деревьев
|
||||||
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=Какао-бобы можно использовать для посадки какао, выпечки печенья или изготовления коричневого красителя.
|
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=Какао-бобы можно использовать для посадки какао, выпечки печенья или изготовления коричневого красителя.
|
||||||
Right click on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Кликните правой по боковой части ствола тропического дерева, чтобы посадить молодое какао.
|
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Кликните правой по овце, чтобы сделать её шерсть коричневой. Кликните правой по боковой части ствола тропического дерева, чтобы посадить молодое какао.
|
||||||
Premature Cocoa Pod=Молодой стручок какао
|
Premature Cocoa Pod=Молодой стручок какао
|
||||||
Cocoa pods grow on the side of jungle trees in 3 stages.=Стручки какао растут на деревьях джунглей в 3 этапа.
|
Cocoa pods grow on the side of jungle trees in 3 stages.=Стручки какао растут на деревьях джунглей в 3 этапа.
|
||||||
Medium Cocoa Pod=Средний стручок какао
|
Medium Cocoa Pod=Средний стручок какао
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Cocoa Beans=可可豆
|
Cocoa Beans=可可豆
|
||||||
Grows at the side of jungle trees=在叢林木側生長
|
Grows at the side of jungle trees=在叢林木側生長
|
||||||
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=可可豆可用於種植可可、烘烤餅乾或製作棕色染料。
|
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=可可豆可用於種植可可、烘烤餅乾或製作棕色染料。
|
||||||
Right click on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=右鍵點擊叢林木的一側,可以種植一個可可。
|
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=右鍵點擊一隻羊,使其羊毛變成褐色。右鍵點擊叢林木的一側,可以種植一個可可。
|
||||||
Premature Cocoa Pod=成長中的可可豆莢(第1階段)
|
Premature Cocoa Pod=成長中的可可豆莢(第1階段)
|
||||||
Cocoa pods grow on the side of jungle trees in 3 stages.=可可莢果分3個階段生長在叢林樹的側面。
|
Cocoa pods grow on the side of jungle trees in 3 stages.=可可莢果分3個階段生長在叢林樹的側面。
|
||||||
Medium Cocoa Pod=成長中的可可豆莢(第2階段)
|
Medium Cocoa Pod=成長中的可可豆莢(第2階段)
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
Cocoa Beans=
|
Cocoa Beans=
|
||||||
Grows at the side of jungle trees=
|
Grows at the side of jungle trees=
|
||||||
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=
|
Cocoa beans can be used to plant cocoa, bake cookies or craft brown dye.=
|
||||||
Right click on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=
|
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=
|
||||||
Premature Cocoa Pod=
|
Premature Cocoa Pod=
|
||||||
Cocoa pods grow on the side of jungle trees in 3 stages.=
|
Cocoa pods grow on the side of jungle trees in 3 stages.=
|
||||||
Medium Cocoa Pod=
|
Medium Cocoa Pod=
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name = mcl_cocoas
|
name = mcl_cocoas
|
||||||
description = Cocoa pods which grow at jungle trees. Does not include cocoa beans.
|
description = Cocoa pods which grow at jungle trees. Does not include cocoa beans.
|
||||||
depends = mcl_sounds, mcl_core
|
depends = mcl_sounds, mcl_core, mcl_util
|
||||||
optional_depends = doc
|
optional_depends = doc
|
|
@ -48,6 +48,41 @@ local vector_offset = vector.offset
|
||||||
local is_protected = minetest.is_protected
|
local is_protected = minetest.is_protected
|
||||||
local record_protection_violation = minetest.record_protection_violation
|
local record_protection_violation = minetest.record_protection_violation
|
||||||
|
|
||||||
|
--- Math and node swap during compost progression
|
||||||
|
---@param pos Vector Position of the node
|
||||||
|
---@param node node
|
||||||
|
---@param chance integer Value of "compostability" group of inserted item
|
||||||
|
local function composter_progress_chance(pos, node, chance)
|
||||||
|
-- calculate leveling up chance
|
||||||
|
local rand = math.random(0,100)
|
||||||
|
if chance >= rand then
|
||||||
|
-- get current compost level
|
||||||
|
local level = registered_nodes[node.name]["_mcl_compost_level"]
|
||||||
|
-- spawn green particles above new layer
|
||||||
|
mcl_bone_meal.add_bone_meal_particle(vector_offset(pos, 0, level/8, 0))
|
||||||
|
-- update composter block
|
||||||
|
if level < 7 then
|
||||||
|
level = level + 1
|
||||||
|
else
|
||||||
|
level = "ready"
|
||||||
|
end
|
||||||
|
swap_node(pos, {name = "mcl_composters:composter_" .. level})
|
||||||
|
minetest.sound_play({name="default_grass_footstep", gain=0.4}, {
|
||||||
|
pos = pos,
|
||||||
|
gain= 0.4,
|
||||||
|
max_hear_distance = 16,
|
||||||
|
}, true)
|
||||||
|
-- a full composter becomes ready for harvest after one second
|
||||||
|
-- the block will get updated by the node timer callback set in node reg def
|
||||||
|
if level == 7 then
|
||||||
|
local timer = get_node_timer(pos)
|
||||||
|
if not timer:is_started() then
|
||||||
|
timer:start(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
--- Fill the composter when rightclicked.
|
--- Fill the composter when rightclicked.
|
||||||
--
|
--
|
||||||
-- `on_rightclick` handler for composter blocks of all fill levels except
|
-- `on_rightclick` handler for composter blocks of all fill levels except
|
||||||
|
@ -86,41 +121,6 @@ local function composter_add_item(pos, node, player, itemstack, pointed_thing)
|
||||||
return itemstack
|
return itemstack
|
||||||
end
|
end
|
||||||
|
|
||||||
--- Math and node swap during compost progression
|
|
||||||
---@param pos Vector Position of the node
|
|
||||||
---@param node node
|
|
||||||
---@param chance integer Value of "compostability" group of inserted item
|
|
||||||
function composter_progress_chance(pos, node, chance)
|
|
||||||
-- calculate leveling up chance
|
|
||||||
local rand = math.random(0,100)
|
|
||||||
if chance >= rand then
|
|
||||||
-- get current compost level
|
|
||||||
local level = registered_nodes[node.name]["_mcl_compost_level"]
|
|
||||||
-- spawn green particles above new layer
|
|
||||||
mcl_dye.add_bone_meal_particle(vector_offset(pos, 0, level/8, 0))
|
|
||||||
-- update composter block
|
|
||||||
if level < 7 then
|
|
||||||
level = level + 1
|
|
||||||
else
|
|
||||||
level = "ready"
|
|
||||||
end
|
|
||||||
swap_node(pos, {name = "mcl_composters:composter_" .. level})
|
|
||||||
minetest.sound_play({name="default_grass_footstep", gain=0.4}, {
|
|
||||||
pos = pos,
|
|
||||||
gain= 0.4,
|
|
||||||
max_hear_distance = 16,
|
|
||||||
}, true)
|
|
||||||
-- a full composter becomes ready for harvest after one second
|
|
||||||
-- the block will get updated by the node timer callback set in node reg def
|
|
||||||
if level == 7 then
|
|
||||||
local timer = get_node_timer(pos)
|
|
||||||
if not timer:is_started() then
|
|
||||||
timer:start(1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Update a full composter block to ready for harvesting.
|
--- Update a full composter block to ready for harvesting.
|
||||||
--
|
--
|
||||||
-- `on_timer` handler. The timer is set in function 'composter_add_item'
|
-- `on_timer` handler. The timer is set in function 'composter_add_item'
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
name = mcl_composters
|
name = mcl_composters
|
||||||
author = kabou
|
author = kabou
|
||||||
description = Composters can convert various organic items into bonemeal.
|
description = Composters can convert various organic items into bonemeal.
|
||||||
depends = mcl_core, mcl_sounds, mcl_dye, mcl_hoppers
|
depends = mcl_core, mcl_sounds, mcl_bone_meal, mcl_hoppers
|
||||||
optional_depends = doc
|
optional_depends = doc
|
||||||
|
|
|
@ -772,6 +772,7 @@ minetest.register_node("mcl_core:cobble", {
|
||||||
sounds = mcl_sounds.node_sound_stone_defaults(),
|
sounds = mcl_sounds.node_sound_stone_defaults(),
|
||||||
_mcl_blast_resistance = 6,
|
_mcl_blast_resistance = 6,
|
||||||
_mcl_hardness = 2,
|
_mcl_hardness = 2,
|
||||||
|
_vl_crushing_drop = { "mcl_core:gravel" }
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mcl_core:mossycobble", {
|
minetest.register_node("mcl_core:mossycobble", {
|
||||||
|
|
|
@ -280,6 +280,14 @@ function mcl_core.register_sapling(subname, description, longdesc, tt_help, text
|
||||||
nn == "mcl_core:podzol" or nn == "mcl_core:podzol_snow" or
|
nn == "mcl_core:podzol" or nn == "mcl_core:podzol_snow" or
|
||||||
nn == "mcl_core:dirt" or nn == "mcl_core:mycelium" or nn == "mcl_core:coarse_dirt"
|
nn == "mcl_core:dirt" or nn == "mcl_core:mycelium" or nn == "mcl_core:coarse_dirt"
|
||||||
end),
|
end),
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
-- Saplings: 45% chance to advance growth stage
|
||||||
|
if math.random(1,100) <= 45 then
|
||||||
|
return mcl_core.grow_sapling(pos, n)
|
||||||
|
end
|
||||||
|
end,
|
||||||
node_placement_prediction = "",
|
node_placement_prediction = "",
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
_mcl_hardness = 0,
|
_mcl_hardness = 0,
|
||||||
|
|
|
@ -5,6 +5,8 @@ local modpath = minetest.get_modpath(modname)
|
||||||
-- by debiankaios
|
-- by debiankaios
|
||||||
-- adapted for mcl2 by cora
|
-- adapted for mcl2 by cora
|
||||||
|
|
||||||
|
local MAXIMUM_VINE_HEIGHT = 25
|
||||||
|
|
||||||
local wood_slab_groups = {handy = 1, axey = 1, material_wood = 1, wood_slab = 1}
|
local wood_slab_groups = {handy = 1, axey = 1, material_wood = 1, wood_slab = 1}
|
||||||
local wood_stair_groups = {handy = 1, axey = 1, material_wood = 1, wood_stairs = 1}
|
local wood_stair_groups = {handy = 1, axey = 1, material_wood = 1, wood_stairs = 1}
|
||||||
|
|
||||||
|
@ -17,20 +19,35 @@ function generate_crimson_tree(pos)
|
||||||
end
|
end
|
||||||
|
|
||||||
function grow_vines(pos, moreontop, vine, dir)
|
function grow_vines(pos, moreontop, vine, dir)
|
||||||
|
-- Sanity checks
|
||||||
if dir == nil then dir = 1 end
|
if dir == nil then dir = 1 end
|
||||||
local n
|
if not moreontop or moreontop < 1 then return false end
|
||||||
repeat
|
|
||||||
pos = vector.offset(pos,0,dir,0)
|
local allowed_nodes = {}
|
||||||
n = minetest.get_node(pos)
|
allowed_nodes[vine] = true
|
||||||
if n.name == "air" then
|
|
||||||
for i=0,math.max(moreontop,1) do
|
-- Find the root, tip and calculate height
|
||||||
if minetest.get_node(pos).name == "air" then
|
local root,_,root_node = mcl_util.trace_nodes(pos, -dir, allowed_nodes, MAXIMUM_VINE_HEIGHT)
|
||||||
minetest.set_node(vector.offset(pos,0,i*dir,0),{name=vine})
|
if not root then return false end
|
||||||
|
local tip,height,tip_node = mcl_util.trace_nodes(vector.offset(root, 0, dir, 0), dir, allowed_nodes, MAXIMUM_VINE_HEIGHT)
|
||||||
|
if not tip then return false end
|
||||||
|
|
||||||
|
local res = false
|
||||||
|
for i = 1,moreontop do
|
||||||
|
-- Check if we can grow into this position
|
||||||
|
if height >= MAXIMUM_VINE_HEIGHT then return res end
|
||||||
|
if tip_node.name ~= "air" then return res end
|
||||||
|
|
||||||
|
-- Update world map data
|
||||||
|
minetest.set_node(tip, {name = vine})
|
||||||
|
|
||||||
|
-- Move to the next position and flag that growth has occured
|
||||||
|
tip = vector.offset(tip, 0, dir, 0)
|
||||||
|
tip_node = minetest.get_node(tip)
|
||||||
|
height = height + 1
|
||||||
|
res = true
|
||||||
end
|
end
|
||||||
end
|
return res
|
||||||
break
|
|
||||||
end
|
|
||||||
until n.name ~= "air" and n.name ~= vine
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local nether_plants = {
|
local nether_plants = {
|
||||||
|
@ -83,17 +100,20 @@ minetest.register_node("mcl_crimson:warped_fungus", {
|
||||||
light_source = 1,
|
light_source = 1,
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
node_placement_prediction = "",
|
node_placement_prediction = "",
|
||||||
on_rightclick = function(pos, node, pointed_thing, player, itemstack)
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
if pointed_thing:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
local pos = pointed_thing.under
|
||||||
local nodepos = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
|
local nodepos = minetest.get_node(vector.offset(pos, 0, -1, 0))
|
||||||
|
|
||||||
if nodepos.name == "mcl_crimson:warped_nylium" or nodepos.name == "mcl_nether:netherrack" then
|
if nodepos.name == "mcl_crimson:warped_nylium" or nodepos.name == "mcl_nether:netherrack" then
|
||||||
local random = math.random(1, 5)
|
local random = math.random(1, 5)
|
||||||
if random == 1 then
|
if random == 1 then
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
generate_warped_tree(pos)
|
generate_warped_tree(pos)
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
return false
|
||||||
end,
|
end,
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
})
|
})
|
||||||
|
@ -102,6 +122,12 @@ mcl_flowerpots.register_potted_flower("mcl_crimson:warped_fungus", {
|
||||||
name = "warped_fungus",
|
name = "warped_fungus",
|
||||||
desc = S("Warped Fungus"),
|
desc = S("Warped Fungus"),
|
||||||
image = "mcl_crimson_warped_fungus.png",
|
image = "mcl_crimson_warped_fungus.png",
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local n = has_nylium_neighbor(pointed_thing.under)
|
||||||
|
if n then
|
||||||
|
minetest.set_node(pointed_thing.under,n)
|
||||||
|
end
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mcl_crimson:twisting_vines", {
|
minetest.register_node("mcl_crimson:twisting_vines", {
|
||||||
|
@ -121,6 +147,9 @@ minetest.register_node("mcl_crimson:twisting_vines", {
|
||||||
fixed = { -3/16, -0.5, -3/16, 3/16, 0.5, 3/16 },
|
fixed = { -3/16, -0.5, -3/16, 3/16, 0.5, 3/16 },
|
||||||
},
|
},
|
||||||
node_placement_prediction = "",
|
node_placement_prediction = "",
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
return grow_vines(pointed_thing.under, math.random(1, 3),"mcl_crimson:twisting_vines")
|
||||||
|
end,
|
||||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||||
local pn = clicker:get_player_name()
|
local pn = clicker:get_player_name()
|
||||||
if clicker:is_player() and minetest.is_protected(vector.offset(pos,0,1,0), pn or "") then
|
if clicker:is_player() and minetest.is_protected(vector.offset(pos,0,1,0), pn or "") then
|
||||||
|
@ -141,26 +170,28 @@ minetest.register_node("mcl_crimson:twisting_vines", {
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif clicker:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
elseif clicker:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
||||||
if not minetest.is_creative_enabled(clicker:get_player_name()) then
|
return mcl_bone_meal.use_bone_meal(itemstack, clicker, {under=pos, above=pos})
|
||||||
itemstack:take_item()
|
|
||||||
end
|
|
||||||
grow_vines(pos, math.random(1, 3),"mcl_crimson:twisting_vines")
|
|
||||||
end
|
end
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
local under = pointed_thing.under
|
local under = pointed_thing.under
|
||||||
local above = pointed_thing.above
|
|
||||||
local unode = minetest.get_node(under)
|
local unode = minetest.get_node(under)
|
||||||
|
local unode_def = minetest.registered_nodes[unode.name]
|
||||||
|
|
||||||
|
local above = pointed_thing.above
|
||||||
|
local anode = minetest.get_node(above)
|
||||||
|
local anode_def = minetest.registered_nodes[anode.name]
|
||||||
|
|
||||||
if under.y < above.y then
|
if under.y < above.y then
|
||||||
minetest.set_node(above, {name = "mcl_crimson:twisting_vines"})
|
minetest.set_node(above, {name = "mcl_crimson:twisting_vines"})
|
||||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||||
itemstack:take_item()
|
itemstack:take_item()
|
||||||
end
|
end
|
||||||
else
|
elseif unode_def and unode_def.on_rightclick then
|
||||||
if unode.name == "mcl_crimson:twisting_vines" then
|
return unode_def.on_rightclick(under, unode, placer, itemstack, pointed_thing)
|
||||||
return minetest.registered_nodes[unode.name].on_rightclick(under, unode, placer, itemstack, pointed_thing)
|
elseif anode_def and anode_def.on_rightclick then
|
||||||
end
|
return unode_def.on_rightclick(above, anode, placer, itemstack, pointed_thing)
|
||||||
end
|
end
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
|
@ -168,7 +199,7 @@ minetest.register_node("mcl_crimson:twisting_vines", {
|
||||||
local above = vector.offset(pos,0,1,0)
|
local above = vector.offset(pos,0,1,0)
|
||||||
local abovenode = minetest.get_node(above)
|
local abovenode = minetest.get_node(above)
|
||||||
minetest.node_dig(pos, node, digger)
|
minetest.node_dig(pos, node, digger)
|
||||||
if abovenode.name == node.name and (not mcl_core.check_vines_supported(above, abovenode)) then
|
if abovenode.name == node.name then
|
||||||
minetest.registered_nodes[node.name].on_dig(above, node, digger)
|
minetest.registered_nodes[node.name].on_dig(above, node, digger)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
@ -211,6 +242,9 @@ minetest.register_node("mcl_crimson:weeping_vines", {
|
||||||
fixed = { -3/16, -0.5, -3/16, 3/16, 0.5, 3/16 },
|
fixed = { -3/16, -0.5, -3/16, 3/16, 0.5, 3/16 },
|
||||||
},
|
},
|
||||||
node_placement_prediction = "",
|
node_placement_prediction = "",
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
return grow_vines(pointed_thing.under, math.random(1, 3),"mcl_crimson:weeping_vines", -1)
|
||||||
|
end,
|
||||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||||
local pn = clicker:get_player_name()
|
local pn = clicker:get_player_name()
|
||||||
if clicker:is_player() and minetest.is_protected(vector.offset(pos,0,1,0), pn or "") then
|
if clicker:is_player() and minetest.is_protected(vector.offset(pos,0,1,0), pn or "") then
|
||||||
|
@ -231,26 +265,28 @@ minetest.register_node("mcl_crimson:weeping_vines", {
|
||||||
end
|
end
|
||||||
|
|
||||||
elseif clicker:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
elseif clicker:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
||||||
if not minetest.is_creative_enabled(clicker:get_player_name()) then
|
return mcl_bone_meal.use_bone_meal(itemstack, clicker, {under=pos, above=pos})
|
||||||
itemstack:take_item()
|
|
||||||
end
|
|
||||||
grow_vines(pos, math.random(1, 3),"mcl_crimson:weeping_vines", -1)
|
|
||||||
end
|
end
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
on_place = function(itemstack, placer, pointed_thing)
|
on_place = function(itemstack, placer, pointed_thing)
|
||||||
local under = pointed_thing.under
|
local under = pointed_thing.under
|
||||||
local above = pointed_thing.above
|
|
||||||
local unode = minetest.get_node(under)
|
local unode = minetest.get_node(under)
|
||||||
|
local unode_def = minetest.registered_nodes[unode.name]
|
||||||
|
|
||||||
|
local above = pointed_thing.above
|
||||||
|
local anode = minetest.get_node(above)
|
||||||
|
local anode_def = minetest.registered_nodes[anode.name]
|
||||||
|
|
||||||
if under.y > above.y then
|
if under.y > above.y then
|
||||||
minetest.set_node(above, {name = "mcl_crimson:weeping_vines"})
|
minetest.set_node(above, {name = "mcl_crimson:weeping_vines"})
|
||||||
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
if not minetest.is_creative_enabled(placer:get_player_name()) then
|
||||||
itemstack:take_item()
|
itemstack:take_item()
|
||||||
end
|
end
|
||||||
else
|
elseif unode_def and unode_def.on_rightclick then
|
||||||
if unode.name == "mcl_crimson:weeping_vines" then
|
return unode_def.on_rightclick(under, unode, placer, itemstack, pointed_thing)
|
||||||
return minetest.registered_nodes[unode.name].on_rightclick(under, unode, placer, itemstack, pointed_thing)
|
elseif anode_def and anode_def.on_rightclick then
|
||||||
end
|
return unode_def.on_rightclick(above, anode, placer, itemstack, pointed_thing)
|
||||||
end
|
end
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
|
@ -258,7 +294,7 @@ minetest.register_node("mcl_crimson:weeping_vines", {
|
||||||
local below = vector.offset(pos,0,-1,0)
|
local below = vector.offset(pos,0,-1,0)
|
||||||
local belownode = minetest.get_node(below)
|
local belownode = minetest.get_node(below)
|
||||||
minetest.node_dig(pos, node, digger)
|
minetest.node_dig(pos, node, digger)
|
||||||
if belownode.name == node.name and (not mcl_core.check_vines_supported(below, belownode)) then
|
if belownode.name == node.name then
|
||||||
minetest.registered_nodes[node.name].on_dig(below, node, digger)
|
minetest.registered_nodes[node.name].on_dig(below, node, digger)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
@ -393,6 +429,11 @@ minetest.register_node("mcl_crimson:warped_nylium", {
|
||||||
_mcl_hardness = 0.4,
|
_mcl_hardness = 0.4,
|
||||||
_mcl_blast_resistance = 0.4,
|
_mcl_blast_resistance = 0.4,
|
||||||
_mcl_silk_touch_drop = true,
|
_mcl_silk_touch_drop = true,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
spread_nether_plants(pointed_thing.under,node)
|
||||||
|
return true
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
--Stem bark, stripped stem and bark
|
--Stem bark, stripped stem and bark
|
||||||
|
@ -525,17 +566,21 @@ minetest.register_node("mcl_crimson:crimson_fungus", {
|
||||||
fixed = { -3/16, -0.5, -3/16, 3/16, -2/16, 3/16 },
|
fixed = { -3/16, -0.5, -3/16, 3/16, -2/16, 3/16 },
|
||||||
},
|
},
|
||||||
node_placement_prediction = "",
|
node_placement_prediction = "",
|
||||||
on_rightclick = function(pos, node, pointed_thing, player)
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
if pointed_thing:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
local pos = pointed_thing.under
|
||||||
local nodepos = minetest.get_node(vector.offset(pos, 0, -1, 0))
|
local nodepos = minetest.get_node(vector.offset(pos, 0, -1, 0))
|
||||||
if nodepos.name == "mcl_crimson:crimson_nylium" or nodepos.name == "mcl_nether:netherrack" then
|
if nodepos.name == "mcl_crimson:crimson_nylium" or nodepos.name == "mcl_nether:netherrack" then
|
||||||
local random = math.random(1, 5)
|
local random = math.random(1, 5)
|
||||||
if random == 1 then
|
if random == 1 then
|
||||||
minetest.remove_node(pos)
|
minetest.remove_node(pos)
|
||||||
generate_crimson_tree(pos)
|
generate_crimson_tree(pos)
|
||||||
|
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
-- Failed to spread nylium
|
||||||
|
return false
|
||||||
end,
|
end,
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
})
|
})
|
||||||
|
@ -682,6 +727,11 @@ minetest.register_node("mcl_crimson:crimson_nylium", {
|
||||||
_mcl_hardness = 0.4,
|
_mcl_hardness = 0.4,
|
||||||
_mcl_blast_resistance = 0.4,
|
_mcl_blast_resistance = 0.4,
|
||||||
_mcl_silk_touch_drop = true,
|
_mcl_silk_touch_drop = true,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
spread_nether_plants(pointed_thing.under,node)
|
||||||
|
return true
|
||||||
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
@ -723,19 +773,6 @@ minetest.register_craft({
|
||||||
mcl_stairs.register_stair("crimson_hyphae_wood", "mcl_crimson:crimson_hyphae_wood", wood_stair_groups, false, S("Crimson Stair"))
|
mcl_stairs.register_stair("crimson_hyphae_wood", "mcl_crimson:crimson_hyphae_wood", wood_stair_groups, false, S("Crimson Stair"))
|
||||||
mcl_stairs.register_slab("crimson_hyphae_wood", "mcl_crimson:crimson_hyphae_wood", wood_slab_groups, false, S("Crimson Slab"))
|
mcl_stairs.register_slab("crimson_hyphae_wood", "mcl_crimson:crimson_hyphae_wood", wood_slab_groups, false, S("Crimson Slab"))
|
||||||
|
|
||||||
mcl_dye.register_on_bone_meal_apply(function(pt,user)
|
|
||||||
if not pt.type == "node" then return end
|
|
||||||
local node = minetest.get_node(pt.under)
|
|
||||||
if node.name == "mcl_nether:netherrack" then
|
|
||||||
local n = has_nylium_neighbor(pt.under)
|
|
||||||
if n then
|
|
||||||
minetest.set_node(pt.under,n)
|
|
||||||
end
|
|
||||||
elseif node.name == "mcl_crimson:warped_nylium" or node.name == "mcl_crimson:crimson_nylium" then
|
|
||||||
spread_nether_plants(pt.under,node)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
label = "Turn Crimson Nylium and Warped Nylium below solid block into Netherrack",
|
label = "Turn Crimson Nylium and Warped Nylium below solid block into Netherrack",
|
||||||
nodenames = {"mcl_crimson:crimson_nylium","mcl_crimson:warped_nylium"},
|
nodenames = {"mcl_crimson:crimson_nylium","mcl_crimson:warped_nylium"},
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
# mcl_dye
|
|
||||||
|
|
||||||
# Bone meal API
|
|
||||||
Callback and particle functions.
|
|
||||||
|
|
||||||
## mcl_dye.add_bone_meal_particle(pos, def)
|
|
||||||
Spawns standard or custom bone meal particles.
|
|
||||||
* `pos`: position, is ignored if you define def.minpos and def.maxpos
|
|
||||||
* `def`: (optional) particle definition
|
|
||||||
|
|
||||||
## mcl_dye.register_on_bone_meal_apply(function(pointed_thing, user))
|
|
||||||
Called when the bone meal is applied anywhere.
|
|
||||||
* `pointed_thing`: exact pointing location (see Minetest API), where the bone meal is applied
|
|
||||||
* `user`: ObjectRef of the player who aplied the bone meal, can be nil!
|
|
|
@ -15,7 +15,6 @@ mcl_dye = {}
|
||||||
|
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
local math = math
|
|
||||||
local string = string
|
local string = string
|
||||||
|
|
||||||
-- Base color groups:
|
-- Base color groups:
|
||||||
|
@ -115,328 +114,23 @@ for _, row in pairs(dyes) do
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Bone meal code to be moved into its own mod.
|
-- Legacy support for things now in mcl_bone_meal.
|
||||||
|
-- These shims will at some time in the future be removed.
|
||||||
--
|
--
|
||||||
function mcl_dye.add_bone_meal_particle(pos, def)
|
function mcl_dye.add_bone_meal_particle(pos, def)
|
||||||
if not def then
|
minetest.log("warning", "mcl_dye.add_bone_meal_particles() is deprecated. Read mcl_bone_meal/API.md!")
|
||||||
def = {}
|
local lines = string.split(debug.traceback(),"\n")
|
||||||
|
for _,line in ipairs(lines) do
|
||||||
|
minetest.log("warning",line)
|
||||||
end
|
end
|
||||||
minetest.add_particlespawner({
|
mcl_bone_meal.add_bone_meal_particle(pos, def)
|
||||||
amount = def.amount or 10,
|
|
||||||
time = def.time or 0.1,
|
|
||||||
minpos = def.minpos or vector.subtract(pos, 0.5),
|
|
||||||
maxpos = def.maxpos or vector.add(pos, 0.5),
|
|
||||||
minvel = def.minvel or vector.new(-0.01, 0.01, -0.01),
|
|
||||||
maxvel = def.maxvel or vector.new(0.01, 0.01, 0.01),
|
|
||||||
minacc = def.minacc or vector.new(0, 0, 0),
|
|
||||||
maxacc = def.maxacc or vector.new(0, 0, 0),
|
|
||||||
minexptime = def.minexptime or 1,
|
|
||||||
maxexptime = def.maxexptime or 4,
|
|
||||||
minsize = def.minsize or 0.7,
|
|
||||||
maxsize = def.maxsize or 2.4,
|
|
||||||
texture = "mcl_particles_bonemeal.png^[colorize:#00EE00:125", -- TODO: real MC color
|
|
||||||
glow = def.glow or 1,
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
mcl_dye.bone_meal_callbacks = {}
|
|
||||||
|
|
||||||
function mcl_dye.register_on_bone_meal_apply(func)
|
function mcl_dye.register_on_bone_meal_apply(func)
|
||||||
table.insert(mcl_dye.bone_meal_callbacks, func)
|
minetest.log("warning", "mcl_dye.register_on_bone_meal_apply() is deprecated. Read mcl_bone_meal/API.md!")
|
||||||
|
mcl_bone_meal.register_on_bone_meal_apply(func)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function apply_bone_meal(pointed_thing, user)
|
|
||||||
-- Bone meal currently spawns all flowers found in the plains.
|
|
||||||
local flowers_table_plains = {
|
|
||||||
"mcl_flowers:dandelion",
|
|
||||||
"mcl_flowers:dandelion",
|
|
||||||
"mcl_flowers:poppy",
|
|
||||||
|
|
||||||
"mcl_flowers:oxeye_daisy",
|
|
||||||
"mcl_flowers:tulip_orange",
|
|
||||||
"mcl_flowers:tulip_red",
|
|
||||||
"mcl_flowers:tulip_white",
|
|
||||||
"mcl_flowers:tulip_pink",
|
|
||||||
"mcl_flowers:azure_bluet",
|
|
||||||
}
|
|
||||||
local flowers_table_simple = {
|
|
||||||
"mcl_flowers:dandelion",
|
|
||||||
"mcl_flowers:poppy",
|
|
||||||
}
|
|
||||||
local flowers_table_swampland = {
|
|
||||||
"mcl_flowers:blue_orchid",
|
|
||||||
}
|
|
||||||
local flowers_table_flower_forest = {
|
|
||||||
"mcl_flowers:dandelion",
|
|
||||||
"mcl_flowers:poppy",
|
|
||||||
"mcl_flowers:oxeye_daisy",
|
|
||||||
"mcl_flowers:tulip_orange",
|
|
||||||
"mcl_flowers:tulip_red",
|
|
||||||
"mcl_flowers:tulip_white",
|
|
||||||
"mcl_flowers:tulip_pink",
|
|
||||||
"mcl_flowers:azure_bluet",
|
|
||||||
"mcl_flowers:allium",
|
|
||||||
}
|
|
||||||
|
|
||||||
local pos = pointed_thing.under
|
|
||||||
local n = minetest.get_node(pos)
|
|
||||||
if n.name == "" then return false end
|
|
||||||
|
|
||||||
if mcl_util.check_area_protection(pos, pointed_thing.above, user) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, func in pairs(mcl_dye.bone_meal_callbacks) do
|
|
||||||
if func(pointed_thing, user) then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if minetest.get_item_group(n.name, "sapling") >= 1 then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
-- Saplings: 45% chance to advance growth stage
|
|
||||||
if math.random(1, 100) <= 45 then
|
|
||||||
if n.name == "mcl_cherry_blossom:cherrysapling" then
|
|
||||||
return mcl_cherry_blossom.generate_cherry_tree(pos) -- If cherry blossom sapling, run that callback instead.
|
|
||||||
else
|
|
||||||
return mcl_core.grow_sapling(pos, n)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif minetest.get_item_group(n.name, "mushroom") == 1 then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
-- Try to grow huge mushroom
|
|
||||||
|
|
||||||
-- Must be on a dirt-type block
|
|
||||||
local below = minetest.get_node({x = pos.x, y = pos.y - 1, z = pos.z})
|
|
||||||
if below.name ~= "mcl_core:mycelium" and below.name ~= "mcl_core:dirt" and minetest.get_item_group(below.name, "grass_block") ~= 1 and below.name ~= "mcl_core:coarse_dirt" and below.name ~= "mcl_core:podzol" then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Select schematic
|
|
||||||
local schematic, offset, height
|
|
||||||
if n.name == "mcl_mushrooms:mushroom_brown" then
|
|
||||||
schematic = minetest.get_modpath("mcl_mushrooms").."/schematics/mcl_mushrooms_huge_brown.mts"
|
|
||||||
offset = { x = -3, y = -1, z = -3 }
|
|
||||||
height = 8
|
|
||||||
elseif n.name == "mcl_mushrooms:mushroom_red" then
|
|
||||||
schematic = minetest.get_modpath("mcl_mushrooms").."/schematics/mcl_mushrooms_huge_red.mts"
|
|
||||||
offset = { x = -2, y = -1, z = -2 }
|
|
||||||
height = 8
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
-- 40% chance
|
|
||||||
if math.random(1, 100) <= 40 then
|
|
||||||
-- Check space requirements
|
|
||||||
for i=1,3 do
|
|
||||||
local cpos = vector.add(pos, {x=0, y=i, z=0})
|
|
||||||
if minetest.get_node(cpos).name ~= "air" then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local yoff = 3
|
|
||||||
local minp, maxp = {x=pos.x-3, y=pos.y+yoff, z=pos.z-3}, {x=pos.x+3, y=pos.y+yoff+(height-3), z=pos.z+3}
|
|
||||||
local diff = vector.subtract(maxp, minp)
|
|
||||||
diff = vector.add(diff, {x=1,y=1,z=1})
|
|
||||||
local totalnodes = diff.x * diff.y * diff.z
|
|
||||||
local goodnodes = minetest.find_nodes_in_area(minp, maxp, {"air", "group:leaves"})
|
|
||||||
if #goodnodes < totalnodes then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Place the huge mushroom
|
|
||||||
minetest.remove_node(pos)
|
|
||||||
local place_pos = vector.add(pos, offset)
|
|
||||||
local ok = minetest.place_schematic(place_pos, schematic, 0, nil, false)
|
|
||||||
return ok ~= nil
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
-- Wheat, Potato, Carrot, Pumpkin Stem, Melon Stem: Advance by 2-5 stages
|
|
||||||
elseif string.find(n.name, "mcl_farming:wheat_") then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
local stages = math.random(2, 5)
|
|
||||||
return mcl_farming:grow_plant("plant_wheat", pos, n, stages, true)
|
|
||||||
elseif string.find(n.name, "mcl_farming:potato_") then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
local stages = math.random(2, 5)
|
|
||||||
return mcl_farming:grow_plant("plant_potato", pos, n, stages, true)
|
|
||||||
elseif string.find(n.name, "mcl_farming:carrot_") then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
local stages = math.random(2, 5)
|
|
||||||
return mcl_farming:grow_plant("plant_carrot", pos, n, stages, true)
|
|
||||||
elseif string.find(n.name, "mcl_farming:pumpkin_") then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
local stages = math.random(2, 5)
|
|
||||||
return mcl_farming:grow_plant("plant_pumpkin_stem", pos, n, stages, true)
|
|
||||||
elseif string.find(n.name, "mcl_farming:melontige_") then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
local stages = math.random(2, 5)
|
|
||||||
return mcl_farming:grow_plant("plant_melon_stem", pos, n, stages, true)
|
|
||||||
elseif string.find(n.name, "mcl_farming:beetroot_") then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
-- Beetroot: 75% chance to advance to next stage
|
|
||||||
if math.random(1, 100) <= 75 then
|
|
||||||
return mcl_farming:grow_plant("plant_beetroot", pos, n, 1, true)
|
|
||||||
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
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
-- Cocoa: Advance by 1 stage
|
|
||||||
mcl_cocoas.grow(pos)
|
|
||||||
return true
|
|
||||||
elseif minetest.get_item_group(n.name, "grass_block") == 1 then
|
|
||||||
-- Grass Block: Generate tall grass and random flowers all over the place
|
|
||||||
for i = -7, 7 do
|
|
||||||
for j = -7, 7 do
|
|
||||||
for y = -1, 1 do
|
|
||||||
pos = vector.offset(pointed_thing.above, i, y, j)
|
|
||||||
n = minetest.get_node(pos)
|
|
||||||
local n2 = minetest.get_node(vector.offset(pos, 0, -1, 0))
|
|
||||||
|
|
||||||
if n.name ~= "" and n.name == "air" and (minetest.get_item_group(n2.name, "grass_block_no_snow") == 1) then
|
|
||||||
-- Randomly generate flowers, tall grass or nothing
|
|
||||||
if math.random(1, 100) <= 90 / ((math.abs(i) + math.abs(j)) / 2)then
|
|
||||||
-- 90% tall grass, 10% flower
|
|
||||||
mcl_dye.add_bone_meal_particle(pos, {amount = 4})
|
|
||||||
if math.random(1,100) <= 90 then
|
|
||||||
local col = n2.param2
|
|
||||||
minetest.add_node(pos, {name="mcl_flowers:tallgrass", param2=col})
|
|
||||||
else
|
|
||||||
local flowers_table
|
|
||||||
if mg_name == "v6" then
|
|
||||||
flowers_table = flowers_table_plains
|
|
||||||
else
|
|
||||||
local biome = minetest.get_biome_name(minetest.get_biome_data(pos).biome)
|
|
||||||
if biome == "Swampland" or biome == "Swampland_shore" or biome == "Swampland_ocean" or biome == "Swampland_deep_ocean" or biome == "Swampland_underground" then
|
|
||||||
flowers_table = flowers_table_swampland
|
|
||||||
elseif biome == "FlowerForest" or biome == "FlowerForest_beach" or biome == "FlowerForest_ocean" or biome == "FlowerForest_deep_ocean" or biome == "FlowerForest_underground" then
|
|
||||||
flowers_table = flowers_table_flower_forest
|
|
||||||
elseif biome == "Plains" or biome == "Plains_beach" or biome == "Plains_ocean" or biome == "Plains_deep_ocean" or biome == "Plains_underground" or biome == "SunflowerPlains" or biome == "SunflowerPlains_ocean" or biome == "SunflowerPlains_deep_ocean" or biome == "SunflowerPlains_underground" then
|
|
||||||
flowers_table = flowers_table_plains
|
|
||||||
else
|
|
||||||
flowers_table = flowers_table_simple
|
|
||||||
end
|
|
||||||
end
|
|
||||||
minetest.add_node(pos, {name=flowers_table[math.random(1, #flowers_table)]})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
|
|
||||||
-- Double flowers: Drop corresponding item
|
|
||||||
elseif n.name == "mcl_flowers:rose_bush" or n.name == "mcl_flowers:rose_bush_top" then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
minetest.add_item(pos, "mcl_flowers:rose_bush")
|
|
||||||
return true
|
|
||||||
elseif n.name == "mcl_flowers:peony" or n.name == "mcl_flowers:peony_top" then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
minetest.add_item(pos, "mcl_flowers:peony")
|
|
||||||
return true
|
|
||||||
elseif n.name == "mcl_flowers:lilac" or n.name == "mcl_flowers:lilac_top" then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
minetest.add_item(pos, "mcl_flowers:lilac")
|
|
||||||
return true
|
|
||||||
elseif n.name == "mcl_flowers:sunflower" or n.name == "mcl_flowers:sunflower_top" then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
minetest.add_item(pos, "mcl_flowers:sunflower")
|
|
||||||
return true
|
|
||||||
|
|
||||||
elseif n.name == "mcl_flowers:tallgrass" then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
-- Tall Grass: Grow into double tallgrass
|
|
||||||
local toppos = { x=pos.x, y=pos.y+1, z=pos.z }
|
|
||||||
local topnode = minetest.get_node(toppos)
|
|
||||||
if minetest.registered_nodes[topnode.name].buildable_to then
|
|
||||||
minetest.set_node(pos, { name = "mcl_flowers:double_grass", param2 = n.param2 })
|
|
||||||
minetest.set_node(toppos, { name = "mcl_flowers:double_grass_top", param2 = n.param2 })
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
--[[
|
|
||||||
Here for when Bonemeal becomes an api, there's code if needed for handling applying to bamboo.
|
|
||||||
-- Handle applying bonemeal to bamboo.
|
|
||||||
elseif mcl_bamboo.is_bamboo(n.name) then
|
|
||||||
local success = mcl_bamboo.grow_bamboo(pos, true)
|
|
||||||
if success then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
end
|
|
||||||
return success
|
|
||||||
--]]
|
|
||||||
elseif n.name == "mcl_flowers:fern" then
|
|
||||||
mcl_dye.add_bone_meal_particle(pos)
|
|
||||||
-- Fern: Grow into large fern
|
|
||||||
local toppos = { x=pos.x, y=pos.y+1, z=pos.z }
|
|
||||||
local topnode = minetest.get_node(toppos)
|
|
||||||
if minetest.registered_nodes[topnode.name].buildable_to then
|
|
||||||
minetest.set_node(pos, { name = "mcl_flowers:double_fern", param2 = n.param2 })
|
|
||||||
minetest.set_node(toppos, { name = "mcl_flowers:double_fern_top", param2 = n.param2 })
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
mcl_dye.apply_bone_meal = apply_bone_meal
|
|
||||||
|
|
||||||
-- Bone meal item registration.
|
|
||||||
--
|
|
||||||
-- To be moved into its own mod.
|
|
||||||
--
|
|
||||||
minetest.register_craftitem(":mcl_bone_meal:bone_meal", {
|
|
||||||
inventory_image = "mcl_bone_meal_bone_meal.png",
|
|
||||||
description = S("Bone Meal"),
|
|
||||||
_tt_help = S("Speeds up plant growth"),
|
|
||||||
_doc_items_longdesc = S("Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants."),
|
|
||||||
_doc_items_usagehelp = S("Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place."),
|
|
||||||
stack_max = 64,
|
|
||||||
on_place = function(itemstack, user, pointed_thing)
|
|
||||||
-- Use pointed node's on_rightclick function first, if present
|
|
||||||
local node = minetest.get_node(pointed_thing.under)
|
|
||||||
if user and not user:get_player_control().sneak then
|
|
||||||
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
|
||||||
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Use the bone meal on the ground
|
|
||||||
if (apply_bone_meal(pointed_thing, user) and (not minetest.is_creative_enabled(user:get_player_name()))) then
|
|
||||||
itemstack:take_item()
|
|
||||||
end
|
|
||||||
return itemstack
|
|
||||||
end,
|
|
||||||
_on_dispense = function(stack, pos, droppos, dropnode, dropdir)
|
|
||||||
-- Apply bone meal, if possible
|
|
||||||
local pointed_thing
|
|
||||||
if dropnode.name == "air" then
|
|
||||||
pointed_thing = { above = droppos, under = { x=droppos.x, y=droppos.y-1, z=droppos.z } }
|
|
||||||
else
|
|
||||||
pointed_thing = { above = pos, under = droppos }
|
|
||||||
end
|
|
||||||
local success = apply_bone_meal(pointed_thing, nil)
|
|
||||||
if success then
|
|
||||||
stack:take_item()
|
|
||||||
end
|
|
||||||
return stack
|
|
||||||
end,
|
|
||||||
_dispense_into_walkable = true
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_craft({
|
|
||||||
output = "mcl_bone_meal:bone_meal 3",
|
|
||||||
recipe = {{"mcl_mobitems:bone"}},
|
|
||||||
})
|
|
||||||
|
|
||||||
|
|
||||||
-- Dye creation recipes.
|
-- Dye creation recipes.
|
||||||
--
|
--
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
@ -609,19 +303,16 @@ minetest.register_craft({
|
||||||
output = "mcl_dye:magenta 2",
|
output = "mcl_dye:magenta 2",
|
||||||
recipe = {"mcl_dye:violet", "mcl_dye:pink"},
|
recipe = {"mcl_dye:violet", "mcl_dye:pink"},
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
type = "shapeless",
|
type = "shapeless",
|
||||||
output = "mcl_dye:pink 2",
|
output = "mcl_dye:pink 2",
|
||||||
recipe = {"mcl_dye:red", "mcl_dye:white"},
|
recipe = {"mcl_dye:red", "mcl_dye:white"},
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
type = "shapeless",
|
type = "shapeless",
|
||||||
output = "mcl_dye:cyan 2",
|
output = "mcl_dye:cyan 2",
|
||||||
recipe = {"mcl_dye:blue", "mcl_dye:dark_green"},
|
recipe = {"mcl_dye:blue", "mcl_dye:dark_green"},
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
type = "shapeless",
|
type = "shapeless",
|
||||||
output = "mcl_dye:violet 2",
|
output = "mcl_dye:violet 2",
|
||||||
|
|
|
@ -17,11 +17,3 @@ Magenta Dye=Magenta Farbstoff
|
||||||
Pink Dye=Rosa Farbstoff
|
Pink Dye=Rosa Farbstoff
|
||||||
This item is a dye which is used for dyeing and crafting.=Dieser Gegenstand ist ein Farbstoff, der zum Einfärben und in der Herstellung benutzt werden kann.
|
This item is a dye which is used for dyeing and crafting.=Dieser Gegenstand ist ein Farbstoff, der zum Einfärben und in der Herstellung benutzt werden kann.
|
||||||
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=Rechtsklicken Sie auf ein Schaf, um seine Wolle zu färben. Andere Dinge werden mit der Fertigung eingefärbt.
|
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=Rechtsklicken Sie auf ein Schaf, um seine Wolle zu färben. Andere Dinge werden mit der Fertigung eingefärbt.
|
||||||
Bone Meal=Knochenmehl
|
|
||||||
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=Knochenmehl ist ein weißer Farbstoff und auch nützlich als Dünger, um das Wachstum vieler Pflanzen zu beschleunigen.
|
|
||||||
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Rechtsklicken Sie auf ein Schaf, um die Wolle weiß einzufärben. Rechtsklicken Sie auf eine Pflanze, um ihr Wachstum zu beschleunigen. Beachten Sie, dass nicht alle Pflanzen darauf ansprechen. Benutzen Sie es auf einem Grasblock, wächst viel hohes Gras und vielleicht auch ein paar Blumen.
|
|
||||||
Cocoa beans are a brown dye and can be used to plant cocoas.=Kakaobohnen sind ein brauner Farbstoff und werden benutzt, um Kakao anzupflanzen.
|
|
||||||
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Rechtsklicken Sie auf ein Schaf, um die Wolle braun einzufärben. Rechtsklicken Sie an die Seite eines Dschungelbaumstamms (Dschungelholz), um eine junge Kakaoschote zu pflanzen.
|
|
||||||
Cocoa Beans=Kakaobohnen
|
|
||||||
Grows at the side of jungle trees=Wächst an der Seite von Dschungelbäumen
|
|
||||||
Speeds up plant growth=Beschleunigt Pflanzenwachstum
|
|
||||||
|
|
|
@ -17,9 +17,3 @@ Magenta Dye=Tinte magenta
|
||||||
Pink Dye=Tinte rosado
|
Pink Dye=Tinte rosado
|
||||||
This item is a dye which is used for dyeing and crafting.=Este artículo es un tinte que se utiliza para teñir y elaborar.
|
This item is a dye which is used for dyeing and crafting.=Este artículo es un tinte que se utiliza para teñir y elaborar.
|
||||||
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=Haga clic derecho sobre una oveja para teñir su lana. Otras cosas pueden ser teñidas mediante la elaboración.
|
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=Haga clic derecho sobre una oveja para teñir su lana. Otras cosas pueden ser teñidas mediante la elaboración.
|
||||||
Bone Meal=Harina de hueso
|
|
||||||
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=La harina de hueso es un tinte blanco y también es útil como fertilizante para acelerar el crecimiento de muchas plantas.
|
|
||||||
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=RHaga clic derecho en una oveja para volver su lana blanca. Haga clic derecho en una planta para acelerar su crecimiento. Tenga en cuenta que no todas las plantas pueden ser fertilizadas de esta manera. Cuando haces clic derecho en un bloque de hierba, crecerán hierba alta y flores por todo el lugar.
|
|
||||||
Cocoa beans are a brown dye and can be used to plant cocoas.=Los granos de cacao son un tinte marrón y se pueden usar para plantar cacao.
|
|
||||||
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Haga clic derecho en una oveja para convertir su lana en marrón. Haga clic derecho en el costado del tronco de un árbol de jungla para plantar un cacao joven.
|
|
||||||
Cocoa Beans=Granos de cacao
|
|
||||||
|
|
|
@ -17,11 +17,3 @@ Magenta Dye=Teinture Magenta
|
||||||
Pink Dye=Teinture Rose
|
Pink Dye=Teinture Rose
|
||||||
This item is a dye which is used for dyeing and crafting.=Cet objet est un colorant utilisé pour la teinture et l'artisanat.
|
This item is a dye which is used for dyeing and crafting.=Cet objet est un colorant utilisé pour la teinture et l'artisanat.
|
||||||
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=Clic droit sur un mouton pour teindre sa laine. D'autres choses sont teintes par l'artisanat.
|
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=Clic droit sur un mouton pour teindre sa laine. D'autres choses sont teintes par l'artisanat.
|
||||||
Bone Meal=Farine d'Os
|
|
||||||
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=La farine d'os est une teinture blanche et également utile comme engrais pour accélérer la croissance de nombreuses plantes.
|
|
||||||
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Cliquez avec le bouton droit sur un mouton pour blanchir sa laine. Cliquez avec le bouton droit sur une plante pour accélérer sa croissance. Notez que toutes les plantes ne peuvent pas être fertilisées comme ça. Lorsque vous cliquez avec le bouton droit sur un bloc d'herbe, les hautes herbes et les fleurs poussent partout.
|
|
||||||
Cocoa beans are a brown dye and can be used to plant cocoas.=Les fèves de cacao ont une teinture brune et peuvent être utilisées pour planter du cacao.
|
|
||||||
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Faites un clic droit sur un mouton pour brunir sa laine. Clic droit sur le côté d'un tronc d'arbre de la jungle (Bois Acajou) pour planter un jeune cacao.
|
|
||||||
Cocoa Beans=Fèves de Cacao
|
|
||||||
Grows at the side of jungle trees=Pousse à côté des arbres de la jungle
|
|
||||||
Speeds up plant growth=Accélère la croissance des plantes
|
|
||||||
|
|
|
@ -17,11 +17,3 @@ Magenta Dye=Karmazynowa farba
|
||||||
Pink Dye=Różowa farba
|
Pink Dye=Różowa farba
|
||||||
This item is a dye which is used for dyeing and crafting.=Ten przedmiot to farba wykorzystywana to farbowania i wytwarzania.
|
This item is a dye which is used for dyeing and crafting.=Ten przedmiot to farba wykorzystywana to farbowania i wytwarzania.
|
||||||
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=Kliknij prawym na owcę aby zafarbować jej wełnę. Inne rzeczy mogą być zafarbowane przy wytwarzaniu.
|
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=Kliknij prawym na owcę aby zafarbować jej wełnę. Inne rzeczy mogą być zafarbowane przy wytwarzaniu.
|
||||||
Bone Meal=Mączka kostna
|
|
||||||
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=Mączka kostna to biała farba i przydatny nawóz, który przyspiesza rośnięcie wielu roślin.
|
|
||||||
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Kliknij prawym na owcę, aby wybielić jej wełnę. Kliknij prawym na roślinę aby przyspieszyć jej wzrost. Zważ, że nie na wszystkie rośliny to tak działa. Gdy klikniesz prawym na blok trawy, wysoka trawa wyrośnie wokół.
|
|
||||||
Cocoa beans are a brown dye and can be used to plant cocoas.=Ziarna kakaowe mogą być wykorzystane do sadzenia kakao.
|
|
||||||
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Naciśnij prawym aby zafarbować wełnę owcy na brązowo. Naciśnij prawym na boku tropikalnego pnia (Tropikalne drewno) aby zasadzić młode kakao.
|
|
||||||
Cocoa Beans=Ziarna kakaowe
|
|
||||||
Grows at the side of jungle trees=Rośnie na boku tropikalnych drzew
|
|
||||||
Speeds up plant growth=Przyspiesza wzrost roślin
|
|
||||||
|
|
|
@ -22,6 +22,3 @@ Bone meal is a white dye and also useful as a fertilizer to speed up the growth
|
||||||
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Кликните правой по овце, чтобы сделать её шерсть белой. Кликните правой по растению, чтобы ускорить его рост. Имейте в виду, что не все растения можно удобрять таким способом. Если вы кликнете по травяному блоку, то на этом месте вырастет высокая трава и цветы.
|
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=Кликните правой по овце, чтобы сделать её шерсть белой. Кликните правой по растению, чтобы ускорить его рост. Имейте в виду, что не все растения можно удобрять таким способом. Если вы кликнете по травяному блоку, то на этом месте вырастет высокая трава и цветы.
|
||||||
Cocoa beans are a brown dye and can be used to plant cocoas.=Какао-бобы являются коричневым красителем. Их также можно использовать, чтобы посадить какао.
|
Cocoa beans are a brown dye and can be used to plant cocoas.=Какао-бобы являются коричневым красителем. Их также можно использовать, чтобы посадить какао.
|
||||||
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Кликните правой по овце, чтобы сделать её шерсть коричневой. Кликните правой по боковой части ствола тропического дерева, чтобы посадить молодое какао.
|
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=Кликните правой по овце, чтобы сделать её шерсть коричневой. Кликните правой по боковой части ствола тропического дерева, чтобы посадить молодое какао.
|
||||||
Cocoa Beans=Какао-бобы
|
|
||||||
Grows at the side of jungle trees=Растут на стволах тропических деревьев
|
|
||||||
Speeds up plant growth=Ускоряет рост растений
|
|
||||||
|
|
|
@ -17,9 +17,3 @@ Magenta Dye=洋紅色染料
|
||||||
Pink Dye=粉紅色染料
|
Pink Dye=粉紅色染料
|
||||||
This item is a dye which is used for dyeing and crafting.=這個物品是一種用於染色和合成的染料。
|
This item is a dye which is used for dyeing and crafting.=這個物品是一種用於染色和合成的染料。
|
||||||
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=右鍵單擊綿羊以染它的毛。其他東西是通過合成染色的。
|
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=右鍵單擊綿羊以染它的毛。其他東西是通過合成染色的。
|
||||||
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=骨粉是一種白色染料,也可作為肥料,加速許多植物的生長。
|
|
||||||
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=右鍵點擊一隻羊,使其羊毛變白。右鍵點擊一株植物以加快其生長速度。注意,不是所有的植物都能像這樣施肥。當你右鍵點擊一個草方時,高高的草和花會到處生長。
|
|
||||||
Cocoa beans are a brown dye and can be used to plant cocoas.=可可豆是一種棕色染料,也可用於種植可可。
|
|
||||||
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=右鍵點擊一隻羊,使其羊毛變成褐色。右鍵點擊叢林木的一側,可以種植一個可可。
|
|
||||||
Grows at the side of jungle trees=在叢林木側生長
|
|
||||||
Speeds up plant growth=加速植物生長
|
|
||||||
|
|
|
@ -17,11 +17,3 @@ Magenta Dye=
|
||||||
Pink Dye=
|
Pink Dye=
|
||||||
This item is a dye which is used for dyeing and crafting.=
|
This item is a dye which is used for dyeing and crafting.=
|
||||||
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=
|
Rightclick on a sheep to dye its wool. Other things are dyed by crafting.=
|
||||||
Bone Meal=
|
|
||||||
Bone meal is a white dye and also useful as a fertilizer to speed up the growth of many plants.=
|
|
||||||
Rightclick a sheep to turn its wool white. Rightclick a plant to speed up its growth. Note that not all plants can be fertilized like this. When you rightclick a grass block, tall grass and flowers will grow all over the place.=
|
|
||||||
Cocoa beans are a brown dye and can be used to plant cocoas.=
|
|
||||||
Rightclick a sheep to turn its wool brown. Rightclick on the side of a jungle tree trunk (Jungle Wood) to plant a young cocoa.=
|
|
||||||
Cocoa Beans=
|
|
||||||
Grows at the side of jungle trees=
|
|
||||||
Speeds up plant growth=
|
|
||||||
|
|
|
@ -1,2 +1,3 @@
|
||||||
name = mcl_dye
|
name = mcl_dye
|
||||||
depends = mcl_core, mcl_flowers, mcl_mobitems, mcl_cocoas
|
description = Adds color to your world!
|
||||||
|
depends = mcl_bone_meal, mcl_cocoas
|
||||||
|
|
|
@ -285,7 +285,8 @@ function minetest.calculate_knockback(player, hitter, time_from_last_punch, tool
|
||||||
local wielditem = hitter:get_wielded_item()
|
local wielditem = hitter:get_wielded_item()
|
||||||
--knockback = knockback + 3 * mcl_enchanting.get_enchantment(wielditem, "knockback")
|
--knockback = knockback + 3 * mcl_enchanting.get_enchantment(wielditem, "knockback")
|
||||||
local enchant = mcl_enchanting.get_enchantment(wielditem, "knockback")
|
local enchant = mcl_enchanting.get_enchantment(wielditem, "knockback")
|
||||||
knockback = knockback + 3.22 * enchant
|
local hammer = minetest.get_item_group(wielditem:get_name(), "hammer")
|
||||||
|
knockback = knockback + 3.22 * enchant + 3.22 * hammer
|
||||||
-- add vertical lift to knockback
|
-- add vertical lift to knockback
|
||||||
local v = player:get_velocity()
|
local v = player:get_velocity()
|
||||||
local added_v = 0
|
local added_v = 0
|
||||||
|
|
|
@ -13,8 +13,11 @@ minetest.register_craftitem("mcl_farming:beetroot_seeds", {
|
||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_node("mcl_farming:beetroot_0", {
|
local size = {[0]=-5, -4, -3}
|
||||||
description = S("Premature Beetroot Plant (Stage 1)"),
|
|
||||||
|
for i = 0, 2 do
|
||||||
|
minetest.register_node("mcl_farming:beetroot_".. i, {
|
||||||
|
description = S("Premature Beetroot Plant (Stage ".. i + 1 ..")"),
|
||||||
_doc_items_longdesc = S("Beetroot plants are plants which grow on farmland under sunlight in 4 stages. On hydrated farmland, they grow a bit faster. They can be harvested at any time but will only yield a profit when mature."),
|
_doc_items_longdesc = S("Beetroot plants are plants which grow on farmland under sunlight in 4 stages. On hydrated farmland, they grow a bit faster. They can be harvested at any time but will only yield a profit when mature."),
|
||||||
_doc_items_entry_name = S("Premature Beetroot Plant"),
|
_doc_items_entry_name = S("Premature Beetroot Plant"),
|
||||||
paramtype = "light",
|
paramtype = "light",
|
||||||
|
@ -24,67 +27,30 @@ minetest.register_node("mcl_farming:beetroot_0", {
|
||||||
walkable = false,
|
walkable = false,
|
||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
drop = "mcl_farming:beetroot_seeds",
|
drop = "mcl_farming:beetroot_seeds",
|
||||||
tiles = {"mcl_farming_beetroot_0.png"},
|
tiles = {"mcl_farming_beetroot_".. i ..".png"},
|
||||||
inventory_image = "mcl_farming_beetroot_0.png",
|
inventory_image = "mcl_farming_beetroot_".. i ..".png",
|
||||||
wield_image = "mcl_farming_beetroot_0.png",
|
wield_image = "mcl_farming_beetroot_".. i ..".png",
|
||||||
selection_box = {
|
selection_box = {
|
||||||
type = "fixed",
|
type = "fixed",
|
||||||
fixed = {
|
fixed = { {-0.5, -0.5, -0.5, 0.5, size[i]/16, 0.5} },
|
||||||
{-0.5, -0.5, -0.5, 0.5, -5/16, 0.5}
|
|
||||||
},
|
},
|
||||||
|
groups = {
|
||||||
|
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
|
||||||
},
|
},
|
||||||
groups = {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},
|
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
|
||||||
_mcl_blast_resistance = 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_node("mcl_farming:beetroot_1", {
|
|
||||||
description = S("Premature Beetroot Plant (Stage 2)"),
|
|
||||||
_doc_items_create_entry = false,
|
|
||||||
paramtype = "light",
|
|
||||||
paramtype2 = "meshoptions",
|
|
||||||
sunlight_propagates = true,
|
|
||||||
place_param2 = 3,
|
|
||||||
walkable = false,
|
|
||||||
drawtype = "plantlike",
|
|
||||||
drop = "mcl_farming:beetroot_seeds",
|
|
||||||
tiles = {"mcl_farming_beetroot_1.png"},
|
|
||||||
inventory_image = "mcl_farming_beetroot_1.png",
|
|
||||||
wield_image = "mcl_farming_beetroot_1.png",
|
|
||||||
selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.5, -0.5, -0.5, 0.5, -4/16, 0.5}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
groups = {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},
|
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
|
||||||
_mcl_blast_resistance = 0,
|
|
||||||
})
|
|
||||||
|
|
||||||
minetest.register_node("mcl_farming:beetroot_2", {
|
|
||||||
description = S("Premature Beetroot Plant (Stage 3)"),
|
|
||||||
_doc_items_create_entry = false,
|
|
||||||
paramtype = "light",
|
|
||||||
paramtype2 = "meshoptions",
|
|
||||||
sunlight_propagates = true,
|
|
||||||
place_param2 = 3,
|
|
||||||
walkable = false,
|
|
||||||
drawtype = "plantlike",
|
|
||||||
drop = "mcl_farming:beetroot_seeds",
|
|
||||||
tiles = {"mcl_farming_beetroot_2.png"},
|
|
||||||
inventory_image = "mcl_farming_beetroot_2.png",
|
|
||||||
wield_image = "mcl_farming_beetroot_2.png",
|
|
||||||
selection_box = {
|
|
||||||
type = "fixed",
|
|
||||||
fixed = {
|
|
||||||
{-0.5, -0.5, -0.5, 0.5, -3/16, 0.5}
|
|
||||||
},
|
|
||||||
},
|
|
||||||
groups = {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},
|
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
-- 75% chance to advance to next stage
|
||||||
|
if math.random(1, 100) <= 75 then
|
||||||
|
return mcl_farming:grow_plant("plant_beetroot", pos, n, 1, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
})
|
})
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_node("mcl_farming:beetroot", {
|
minetest.register_node("mcl_farming:beetroot", {
|
||||||
description = S("Mature Beetroot Plant"),
|
description = S("Mature Beetroot Plant"),
|
||||||
|
@ -171,7 +137,8 @@ minetest.register_craft({
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
mcl_farming:add_plant("plant_beetroot", "mcl_farming:beetroot", {"mcl_farming:beetroot_0", "mcl_farming:beetroot_1", "mcl_farming:beetroot_2"}, 68, 3)
|
-- beetroots grow at 2/3rd of the default speed
|
||||||
|
mcl_farming:add_plant("plant_beetroot", "mcl_farming:beetroot", {"mcl_farming:beetroot_0", "mcl_farming:beetroot_1", "mcl_farming:beetroot_2"}, 8.7012, 35)
|
||||||
|
|
||||||
if minetest.get_modpath("doc") then
|
if minetest.get_modpath("doc") then
|
||||||
for i = 1, 2 do
|
for i = 1, 2 do
|
||||||
|
|
|
@ -45,6 +45,12 @@ for i=1, 7 do
|
||||||
groups = {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},
|
groups = {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},
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
local stages = math.random(2, 5)
|
||||||
|
return mcl_farming:grow_plant("plant_carrot", pos, n, stages, true)
|
||||||
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -118,7 +124,7 @@ minetest.register_craft({
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
mcl_farming:add_plant("plant_carrot", "mcl_farming:carrot", {"mcl_farming:carrot_1", "mcl_farming:carrot_2", "mcl_farming:carrot_3", "mcl_farming:carrot_4", "mcl_farming:carrot_5", "mcl_farming:carrot_6", "mcl_farming:carrot_7"}, 25, 20)
|
mcl_farming:add_plant("plant_carrot", "mcl_farming:carrot", {"mcl_farming:carrot_1", "mcl_farming:carrot_2", "mcl_farming:carrot_3", "mcl_farming:carrot_4", "mcl_farming:carrot_5", "mcl_farming:carrot_6", "mcl_farming:carrot_7"}, 5.8013, 35)
|
||||||
|
|
||||||
if minetest.get_modpath("doc") then
|
if minetest.get_modpath("doc") then
|
||||||
for i=2,7 do
|
for i=2,7 do
|
||||||
|
|
|
@ -65,7 +65,7 @@ local hoe_usagehelp = S("Use the hoe on a cultivatable block (by rightclicking i
|
||||||
|
|
||||||
minetest.register_tool("mcl_farming:hoe_wood", {
|
minetest.register_tool("mcl_farming:hoe_wood", {
|
||||||
description = S("Wood Hoe"),
|
description = S("Wood Hoe"),
|
||||||
_tt_help = hoe_tt.."\n"..S("Uses: @1", uses.wood),
|
_tt_help = hoe_tt,
|
||||||
_doc_items_longdesc = hoe_longdesc,
|
_doc_items_longdesc = hoe_longdesc,
|
||||||
_doc_items_usagehelp = hoe_usagehelp,
|
_doc_items_usagehelp = hoe_usagehelp,
|
||||||
_doc_items_hidden = false,
|
_doc_items_hidden = false,
|
||||||
|
@ -109,7 +109,7 @@ minetest.register_craft({
|
||||||
|
|
||||||
minetest.register_tool("mcl_farming:hoe_stone", {
|
minetest.register_tool("mcl_farming:hoe_stone", {
|
||||||
description = S("Stone Hoe"),
|
description = S("Stone Hoe"),
|
||||||
_tt_help = hoe_tt.."\n"..S("Uses: @1", uses.stone),
|
_tt_help = hoe_tt,
|
||||||
_doc_items_longdesc = hoe_longdesc,
|
_doc_items_longdesc = hoe_longdesc,
|
||||||
_doc_items_usagehelp = hoe_usagehelp,
|
_doc_items_usagehelp = hoe_usagehelp,
|
||||||
inventory_image = "farming_tool_stonehoe.png",
|
inventory_image = "farming_tool_stonehoe.png",
|
||||||
|
@ -147,7 +147,7 @@ minetest.register_craft({
|
||||||
|
|
||||||
minetest.register_tool("mcl_farming:hoe_iron", {
|
minetest.register_tool("mcl_farming:hoe_iron", {
|
||||||
description = S("Iron Hoe"),
|
description = S("Iron Hoe"),
|
||||||
_tt_help = hoe_tt.."\n"..S("Uses: @1", uses.iron),
|
_tt_help = hoe_tt,
|
||||||
_doc_items_longdesc = hoe_longdesc,
|
_doc_items_longdesc = hoe_longdesc,
|
||||||
_doc_items_usagehelp = hoe_usagehelp,
|
_doc_items_usagehelp = hoe_usagehelp,
|
||||||
inventory_image = "farming_tool_steelhoe.png",
|
inventory_image = "farming_tool_steelhoe.png",
|
||||||
|
@ -193,7 +193,7 @@ minetest.register_craft({
|
||||||
|
|
||||||
minetest.register_tool("mcl_farming:hoe_gold", {
|
minetest.register_tool("mcl_farming:hoe_gold", {
|
||||||
description = S("Golden Hoe"),
|
description = S("Golden Hoe"),
|
||||||
_tt_help = hoe_tt.."\n"..S("Uses: @1", uses.gold),
|
_tt_help = hoe_tt,
|
||||||
_doc_items_longdesc = hoe_longdesc,
|
_doc_items_longdesc = hoe_longdesc,
|
||||||
_doc_items_usagehelp = hoe_usagehelp,
|
_doc_items_usagehelp = hoe_usagehelp,
|
||||||
inventory_image = "farming_tool_goldhoe.png",
|
inventory_image = "farming_tool_goldhoe.png",
|
||||||
|
@ -240,7 +240,7 @@ minetest.register_craft({
|
||||||
|
|
||||||
minetest.register_tool("mcl_farming:hoe_diamond", {
|
minetest.register_tool("mcl_farming:hoe_diamond", {
|
||||||
description = S("Diamond Hoe"),
|
description = S("Diamond Hoe"),
|
||||||
_tt_help = hoe_tt.."\n"..S("Uses: @1", uses.diamond),
|
_tt_help = hoe_tt,
|
||||||
_doc_items_longdesc = hoe_longdesc,
|
_doc_items_longdesc = hoe_longdesc,
|
||||||
_doc_items_usagehelp = hoe_usagehelp,
|
_doc_items_usagehelp = hoe_usagehelp,
|
||||||
inventory_image = "farming_tool_diamondhoe.png",
|
inventory_image = "farming_tool_diamondhoe.png",
|
||||||
|
@ -280,7 +280,7 @@ minetest.register_craft({
|
||||||
|
|
||||||
minetest.register_tool("mcl_farming:hoe_netherite", {
|
minetest.register_tool("mcl_farming:hoe_netherite", {
|
||||||
description = S("Netherite Hoe"),
|
description = S("Netherite Hoe"),
|
||||||
_tt_help = hoe_tt.."\n"..S("Uses: @1", uses.netherite),
|
_tt_help = hoe_tt,
|
||||||
_doc_items_longdesc = hoe_longdesc,
|
_doc_items_longdesc = hoe_longdesc,
|
||||||
_doc_items_usagehelp = hoe_usagehelp,
|
_doc_items_usagehelp = hoe_usagehelp,
|
||||||
inventory_image = "farming_tool_netheritehoe.png",
|
inventory_image = "farming_tool_netheritehoe.png",
|
||||||
|
|
|
@ -109,6 +109,12 @@ for s=1,7 do
|
||||||
groups = {dig_immediate=3, not_in_creative_inventory=1, plant=1,attached_node=1, dig_by_water=1,destroy_by_lava_flow=1, plant_melon_stem=s},
|
groups = {dig_immediate=3, not_in_creative_inventory=1, plant=1,attached_node=1, dig_by_water=1,destroy_by_lava_flow=1, plant_melon_stem=s},
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
local stages = math.random(2, 5)
|
||||||
|
return mcl_farming:grow_plant("plant_melon_stem", pos, n, stages, true)
|
||||||
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -123,10 +129,10 @@ local stem_def = {
|
||||||
}
|
}
|
||||||
|
|
||||||
-- Register stem growth
|
-- Register stem growth
|
||||||
mcl_farming:add_plant("plant_melon_stem", "mcl_farming:melontige_unconnect", {"mcl_farming:melontige_1", "mcl_farming:melontige_2", "mcl_farming:melontige_3", "mcl_farming:melontige_4", "mcl_farming:melontige_5", "mcl_farming:melontige_6", "mcl_farming:melontige_7"}, 30, 5)
|
mcl_farming:add_plant("plant_melon_stem", "mcl_farming:melontige_unconnect", {"mcl_farming:melontige_1", "mcl_farming:melontige_2", "mcl_farming:melontige_3", "mcl_farming:melontige_4", "mcl_farming:melontige_5", "mcl_farming:melontige_6", "mcl_farming:melontige_7"}, 5.8014, 35)
|
||||||
|
|
||||||
-- Register actual melon, connected stems and stem-to-melon growth
|
-- Register actual melon, connected stems and stem-to-melon growth
|
||||||
mcl_farming:add_gourd("mcl_farming:melontige_unconnect", "mcl_farming:melontige_linked", "mcl_farming:melontige_unconnect", stem_def, stem_drop, "mcl_farming:melon", melon_base_def, 25, 15, "mcl_farming_melon_stem_connected.png^[colorize:#FFA800:127")
|
mcl_farming:add_gourd("mcl_farming:melontige_unconnect", "mcl_farming:melontige_linked", "mcl_farming:melontige_unconnect", stem_def, stem_drop, "mcl_farming:melon", melon_base_def, 5.8015, 35, "mcl_farming_melon_stem_connected.png^[colorize:#FFA800:127")
|
||||||
|
|
||||||
-- Items and crafting
|
-- Items and crafting
|
||||||
minetest.register_craftitem("mcl_farming:melon_item", {
|
minetest.register_craftitem("mcl_farming:melon_item", {
|
||||||
|
|
|
@ -49,6 +49,12 @@ for i=1, 7 do
|
||||||
groups = {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},
|
groups = {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},
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
local stages = math.random(2, 5)
|
||||||
|
return mcl_farming:grow_plant("plant_potato", pos, n, stages, true)
|
||||||
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -135,7 +141,7 @@ minetest.register_craft({
|
||||||
cooktime = 10,
|
cooktime = 10,
|
||||||
})
|
})
|
||||||
|
|
||||||
mcl_farming:add_plant("plant_potato", "mcl_farming:potato", {"mcl_farming:potato_1", "mcl_farming:potato_2", "mcl_farming:potato_3", "mcl_farming:potato_4", "mcl_farming:potato_5", "mcl_farming:potato_6", "mcl_farming:potato_7"}, 19.75, 20)
|
mcl_farming:add_plant("plant_potato", "mcl_farming:potato", {"mcl_farming:potato_1", "mcl_farming:potato_2", "mcl_farming:potato_3", "mcl_farming:potato_4", "mcl_farming:potato_5", "mcl_farming:potato_6", "mcl_farming:potato_7"}, 5.8016, 35)
|
||||||
|
|
||||||
minetest.register_on_item_eat(function (hp_change, replace_with_item, itemstack, user, pointed_thing)
|
minetest.register_on_item_eat(function (hp_change, replace_with_item, itemstack, user, pointed_thing)
|
||||||
|
|
||||||
|
|
|
@ -79,6 +79,12 @@ for s=1,7 do
|
||||||
groups = {dig_immediate=3, not_in_creative_inventory=1, plant=1,attached_node=1, dig_by_water=1,destroy_by_lava_flow=1,},
|
groups = {dig_immediate=3, not_in_creative_inventory=1, plant=1,attached_node=1, dig_by_water=1,destroy_by_lava_flow=1,},
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
local stages = math.random(2, 5)
|
||||||
|
return mcl_farming:grow_plant("plant_pumpkin_stem", pos, n, stages, true)
|
||||||
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -180,10 +186,10 @@ if minetest.get_modpath("mcl_armor") then
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Register stem growth
|
-- Register stem growth
|
||||||
mcl_farming:add_plant("plant_pumpkin_stem", "mcl_farming:pumpkintige_unconnect", {"mcl_farming:pumpkin_1", "mcl_farming:pumpkin_2", "mcl_farming:pumpkin_3", "mcl_farming:pumpkin_4", "mcl_farming:pumpkin_5", "mcl_farming:pumpkin_6", "mcl_farming:pumpkin_7"}, 30, 5)
|
mcl_farming:add_plant("plant_pumpkin_stem", "mcl_farming:pumpkintige_unconnect", {"mcl_farming:pumpkin_1", "mcl_farming:pumpkin_2", "mcl_farming:pumpkin_3", "mcl_farming:pumpkin_4", "mcl_farming:pumpkin_5", "mcl_farming:pumpkin_6", "mcl_farming:pumpkin_7"}, 5.8017, 35)
|
||||||
|
|
||||||
-- Register actual pumpkin, connected stems and stem-to-pumpkin growth
|
-- Register actual pumpkin, connected stems and stem-to-pumpkin growth
|
||||||
mcl_farming:add_gourd("mcl_farming:pumpkintige_unconnect", "mcl_farming:pumpkintige_linked", "mcl_farming:pumpkintige_unconnect", stem_def, stem_drop, "mcl_farming:pumpkin", pumpkin_base_def, 30, 15, "mcl_farming_pumpkin_stem_connected.png^[colorize:#FFA800:127")
|
mcl_farming:add_gourd("mcl_farming:pumpkintige_unconnect", "mcl_farming:pumpkintige_linked", "mcl_farming:pumpkintige_unconnect", stem_def, stem_drop, "mcl_farming:pumpkin", pumpkin_base_def, 5.8018, 35, "mcl_farming_pumpkin_stem_connected.png^[colorize:#FFA800:127")
|
||||||
|
|
||||||
-- Steal function to properly disconnect a carved pumpkin
|
-- Steal function to properly disconnect a carved pumpkin
|
||||||
pumpkin_face_base_def.after_destruct = minetest.registered_nodes["mcl_farming:pumpkin"].after_destruct
|
pumpkin_face_base_def.after_destruct = minetest.registered_nodes["mcl_farming:pumpkin"].after_destruct
|
||||||
|
|
|
@ -5,73 +5,99 @@
|
||||||
--
|
--
|
||||||
local math = math
|
local math = math
|
||||||
local vector = vector
|
local vector = vector
|
||||||
|
local random = math.random
|
||||||
|
local floor = math.floor
|
||||||
|
|
||||||
local plant_lists = {}
|
local plant_lists = {}
|
||||||
mcl_farming.plant_lists = plant_lists -- export
|
mcl_farming.plant_lists = plant_lists -- export
|
||||||
local plant_nodename_to_id_list = {}
|
local plant_nodename_to_id = {} -- map nodes to plants
|
||||||
|
local plant_step_from_name = {} -- map nodes to growth steps
|
||||||
|
|
||||||
local time_speed = tonumber(minetest.settings:get("time_speed")) or 72
|
local growth_factor = tonumber(minetest.settings:get("vl_plant_growth")) or 1.0
|
||||||
local time_multiplier = time_speed > 0 and (86400 / time_speed) or 0
|
|
||||||
|
|
||||||
local function get_intervals_counter(pos, interval, chance)
|
-- wetness of the surroundings
|
||||||
if time_multiplier == 0 then return 0 end
|
-- dry farmland = 1 point
|
||||||
-- "wall clock time", so plants continue to grow while sleeping
|
-- wet farmland = 3 points
|
||||||
local current_game_time = (minetest.get_day_count() + minetest.get_timeofday()) * time_multiplier
|
-- center point gives + 1 point, so 2 resp. 4
|
||||||
local approx_interval = math.max(interval, 1) * math.max(chance, 1)
|
-- neighbors only 25%
|
||||||
|
local function get_moisture_level(pos)
|
||||||
local meta = minetest.get_meta(pos)
|
local n = vector.offset(pos, 0, -1, 0)
|
||||||
local last_game_time = meta:get_float("last_gametime")
|
local totalm = 1
|
||||||
if last_game_time < 1 then
|
for z = -1,1 do
|
||||||
last_game_time = current_game_time - approx_interval * 0.5
|
n.z = pos.z + z
|
||||||
elseif last_game_time == current_game_time then
|
for x = -1,1 do
|
||||||
current_game_time = current_game_time + approx_interval
|
n.x = pos.x + x
|
||||||
|
local ndef = minetest.registered_nodes[minetest.get_node(n).name]
|
||||||
|
local soil = ndef and ndef.groups.soil
|
||||||
|
if soil and soil >= 2 then
|
||||||
|
local m = soil > 2 and 3 or 1
|
||||||
|
-- corners have less weight
|
||||||
|
if x ~= 0 or z ~= 0 then m = m * 0.25 end
|
||||||
|
totalm = totalm + m
|
||||||
end
|
end
|
||||||
meta:set_float("last_gametime", current_game_time)
|
end
|
||||||
return (current_game_time - last_game_time) / approx_interval
|
end
|
||||||
|
return totalm
|
||||||
end
|
end
|
||||||
|
|
||||||
local function get_avg_light_level(pos)
|
-- moisture penalty function:
|
||||||
local meta = minetest.get_meta(pos)
|
-- 0.5 if both on the x axis and the z axis at least one of the same plants grows
|
||||||
-- EWMA would use a single variable:
|
-- 0.5 if at least one diagonal neighbor is the same
|
||||||
-- local avg = meta:get_float("avg_light")
|
-- 1.0 otherwise
|
||||||
-- avg = avg + (node_light - avg) * 0.985
|
-- we cannot use the names directly, because growth is encoded in the names
|
||||||
-- meta.set_float("avg_light", avg)
|
local function get_same_crop_penalty(pos)
|
||||||
local summary = meta:get_int("avg_light_summary")
|
local name = minetest.get_node(pos).name
|
||||||
local counter = meta:get_int("avg_light_count")
|
local plant = plant_nodename_to_id[name]
|
||||||
if counter > 99 then
|
if not plant then return 1 end
|
||||||
summary, counter = math.ceil(summary * 0.5), 50
|
local n = vector.copy(pos)
|
||||||
|
-- check adjacent positions, avoid vector allocations and reduce node accesses
|
||||||
|
n.x = pos.x - 1
|
||||||
|
local dx = plant_nodename_to_id[minetest.get_node(n).name] == plant
|
||||||
|
n.x = pos.x + 1
|
||||||
|
dx = dx or plant_nodename_to_id[minetest.get_node(n).name] == plant
|
||||||
|
if dx then -- no need to check z otherwise
|
||||||
|
n.x = pos.x
|
||||||
|
n.z = pos.z - 1
|
||||||
|
local dz = plant_nodename_to_id[minetest.get_node(n).name] == plant
|
||||||
|
n.z = pos.z + 1
|
||||||
|
dz = dz or plant_nodename_to_id[minetest.get_node(n).name] == plant
|
||||||
|
if dz then return 0.5 end
|
||||||
end
|
end
|
||||||
local node_light = minetest.get_node_light(pos)
|
-- check diagonals, clockwise
|
||||||
if node_light ~= nil then
|
n.x, n.z = pos.x - 1, pos.z - 1
|
||||||
summary, counter = summary + node_light, counter + 1
|
if plant_nodename_to_id[minetest.get_node(n).name] == plant then return 0.5 end
|
||||||
meta:set_int("avg_light_summary", summary)
|
n.x = pos.x + 1
|
||||||
meta:set_int("avg_light_count", counter)
|
if plant_nodename_to_id[minetest.get_node(n).name] == plant then return 0.5 end
|
||||||
end
|
n.z = pos.z + 1
|
||||||
return math.ceil(summary / counter)
|
if plant_nodename_to_id[minetest.get_node(n).name] == plant then return 0.5 end
|
||||||
|
n.x = pos.x - 1
|
||||||
|
if plant_nodename_to_id[minetest.get_node(n).name] == plant then return 0.5 end
|
||||||
|
return 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function mcl_farming:add_plant(identifier, full_grown, names, interval, chance)
|
function mcl_farming:add_plant(identifier, full_grown, names, interval, chance)
|
||||||
|
interval = growth_factor > 0 and (interval / growth_factor) or 0
|
||||||
local plant_info = {}
|
local plant_info = {}
|
||||||
plant_info.full_grown = full_grown
|
plant_info.full_grown = full_grown
|
||||||
plant_info.names = names
|
plant_info.names = names
|
||||||
plant_info.interval = interval
|
plant_info.interval = interval
|
||||||
plant_info.chance = chance
|
plant_info.chance = chance
|
||||||
|
plant_nodename_to_id[full_grown] = identifier
|
||||||
for _, nodename in pairs(names) do
|
for _, nodename in pairs(names) do
|
||||||
plant_nodename_to_id_list[nodename] = identifier
|
plant_nodename_to_id[nodename] = identifier
|
||||||
end
|
end
|
||||||
plant_info.step_from_name = {}
|
|
||||||
for i, name in ipairs(names) do
|
for i, name in ipairs(names) do
|
||||||
plant_info.step_from_name[name] = i
|
plant_step_from_name[name] = i
|
||||||
end
|
end
|
||||||
plant_lists[identifier] = plant_info
|
plant_lists[identifier] = plant_info
|
||||||
|
if interval == 0 then return end -- growth disabled
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
label = string.format("Farming plant growth (%s)", identifier),
|
label = string.format("Farming plant growth (%s)", identifier),
|
||||||
nodenames = names,
|
nodenames = names,
|
||||||
interval = interval,
|
interval = interval,
|
||||||
chance = chance,
|
chance = chance,
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
local low_speed = minetest.get_node(vector.offset(pos, 0, -1, 0)).name ~= "mcl_farming:soil_wet"
|
mcl_farming:grow_plant(identifier, pos, node, 1, false)
|
||||||
mcl_farming:grow_plant(identifier, pos, node, 1, false, low_speed)
|
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
@ -81,40 +107,30 @@ end
|
||||||
-- pos: Position
|
-- pos: Position
|
||||||
-- node: Node table
|
-- node: Node table
|
||||||
-- stages: Number of stages to advance (optional, defaults to 1)
|
-- stages: Number of stages to advance (optional, defaults to 1)
|
||||||
-- ignore_light: if true, ignore light requirements for growing
|
-- ignore_light_water: if true, ignore light and water requirements for growing
|
||||||
-- low_speed: grow more slowly (not wet), default false
|
|
||||||
-- Returns true if plant has been grown by 1 or more stages.
|
-- Returns true if plant has been grown by 1 or more stages.
|
||||||
-- Returns false if nothing changed.
|
-- Returns false if nothing changed.
|
||||||
function mcl_farming:grow_plant(identifier, pos, node, stages, ignore_light, low_speed)
|
function mcl_farming:grow_plant(identifier, pos, node, stages, ignore_light_water)
|
||||||
stages = stages or 1
|
-- number of missed interval ticks, for catch-up in block loading
|
||||||
local plant_info = plant_lists[identifier]
|
local plant_info = plant_lists[identifier]
|
||||||
local intervals_counter = get_intervals_counter(pos, plant_info.interval, plant_info.chance)
|
if not plant_info then return end
|
||||||
if stages > 0 then intervals_counters = intervals_counter - 1 end
|
if not ignore_light_water then
|
||||||
if low_speed then -- 10% speed approximately
|
if (minetest.get_node_light(pos, 0.5) or 0) < 0 then return false end -- day light
|
||||||
if intervals_counter < 1.01 and math.random(0, 9) > 0 then return false end
|
local odds = floor(25 / (get_moisture_level(pos) * get_same_crop_penalty(pos))) + 1
|
||||||
intervals_counter = intervals_counter / 10
|
for i = 1,stages do
|
||||||
end
|
-- compared to info from the MC wiki, our ABM runs a third as often, hence we use triple the chance
|
||||||
if not ignore_light and intervals_counter < 1.5 then
|
if random() * odds >= 3 then stages = stages - 1 end
|
||||||
local light = minetest.get_node_light(pos)
|
|
||||||
if not light or light < 10 then return false end
|
|
||||||
end
|
|
||||||
|
|
||||||
if intervals_counter >= 1.5 then
|
|
||||||
local average_light_level = get_avg_light_level(pos)
|
|
||||||
if average_light_level < 0.1 then return false end
|
|
||||||
if average_light_level < 10 then
|
|
||||||
intervals_counter = intervals_counter * average_light_level / 10
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local step = plant_info.step_from_name[node.name]
|
|
||||||
if step == nil then return false end
|
|
||||||
stages = stages + math.floor(intervals_counter)
|
|
||||||
if stages == 0 then return false end
|
if stages == 0 then return false end
|
||||||
local new_node = { name = plant_info.names[step + stages] or plant_info.full_grown }
|
local step = plant_step_from_name[node.name]
|
||||||
new_node.param = node.param
|
if step == nil then return false end
|
||||||
new_node.param2 = node.param2
|
minetest.set_node(pos, {
|
||||||
minetest.set_node(pos, new_node)
|
name = plant_info.names[step + stages] or plant_info.full_grown,
|
||||||
|
param = node.param,
|
||||||
|
param2 = node.param2,
|
||||||
|
})
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -157,40 +173,13 @@ end
|
||||||
|
|
||||||
|
|
||||||
function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, stem_itemstring, stem_def, stem_drop, gourd_itemstring, gourd_def, grow_interval, grow_chance, connected_stem_texture)
|
function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, stem_itemstring, stem_def, stem_drop, gourd_itemstring, gourd_def, grow_interval, grow_chance, connected_stem_texture)
|
||||||
|
grow_interval = growth_factor > 0 and (grow_interval / growth_factor) or 0
|
||||||
local connected_stem_names = {
|
local connected_stem_names = {
|
||||||
connected_stem_basename .. "_r",
|
connected_stem_basename .. "_r",
|
||||||
connected_stem_basename .. "_l",
|
connected_stem_basename .. "_l",
|
||||||
connected_stem_basename .. "_t",
|
connected_stem_basename .. "_t",
|
||||||
connected_stem_basename .. "_b" }
|
connected_stem_basename .. "_b" }
|
||||||
|
|
||||||
-- Connect the stem at stempos to the first neighboring gourd block.
|
|
||||||
-- No-op if not a stem or no gourd block found
|
|
||||||
local function try_connect_stem(stempos)
|
|
||||||
local stem = minetest.get_node(stempos)
|
|
||||||
if stem.name ~= full_unconnected_stem then return false end
|
|
||||||
-- four directions, but avoid table allocation
|
|
||||||
local neighbor = vector.offset(stempos, 1, 0, 0)
|
|
||||||
if minetest.get_node(neighbor).name == gourd_itemstring then
|
|
||||||
minetest.swap_node(stempos, { name = connected_stem_names[1] })
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
local neighbor = vector.offset(stempos, -1, 0, 0)
|
|
||||||
if minetest.get_node(neighbor).name == gourd_itemstring then
|
|
||||||
minetest.swap_node(stempos, { name = connected_stem_names[2] })
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
local neighbor = vector.offset(stempos, 0, 0, 1)
|
|
||||||
if minetest.get_node(neighbor).name == gourd_itemstring then
|
|
||||||
minetest.swap_node(stempos, { name = connected_stem_names[3] })
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
local neighbor = vector.offset(stempos, 0, 0, -1)
|
|
||||||
if minetest.get_node(neighbor).name == gourd_itemstring then
|
|
||||||
minetest.swap_node(stempos, { name = connected_stem_names[4] })
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Register gourd
|
-- Register gourd
|
||||||
if not gourd_def.after_destruct then
|
if not gourd_def.after_destruct then
|
||||||
gourd_def.after_destruct = function(blockpos, oldnode)
|
gourd_def.after_destruct = function(blockpos, oldnode)
|
||||||
|
@ -200,34 +189,21 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
|
||||||
local stempos = vector.offset(blockpos, -1, 0, 0)
|
local stempos = vector.offset(blockpos, -1, 0, 0)
|
||||||
if minetest.get_node(stempos).name == connected_stem_names[1] then
|
if minetest.get_node(stempos).name == connected_stem_names[1] then
|
||||||
minetest.swap_node(stempos, { name = full_unconnected_stem })
|
minetest.swap_node(stempos, { name = full_unconnected_stem })
|
||||||
try_connect_stem(stempos)
|
|
||||||
end
|
end
|
||||||
local stempos = vector.offset(blockpos, 1, 0, 0)
|
local stempos = vector.offset(blockpos, 1, 0, 0)
|
||||||
if minetest.get_node(stempos).name == connected_stem_names[2] then
|
if minetest.get_node(stempos).name == connected_stem_names[2] then
|
||||||
minetest.swap_node(stempos, { name = full_unconnected_stem })
|
minetest.swap_node(stempos, { name = full_unconnected_stem })
|
||||||
try_connect_stem(stempos)
|
|
||||||
end
|
end
|
||||||
local stempos = vector.offset(blockpos, 0, 0, -1)
|
local stempos = vector.offset(blockpos, 0, 0, -1)
|
||||||
if minetest.get_node(stempos).name == connected_stem_names[3] then
|
if minetest.get_node(stempos).name == connected_stem_names[3] then
|
||||||
minetest.swap_node(stempos, { name = full_unconnected_stem })
|
minetest.swap_node(stempos, { name = full_unconnected_stem })
|
||||||
try_connect_stem(stempos)
|
|
||||||
end
|
end
|
||||||
local stempos = vector.offset(blockpos, 0, 0, 1)
|
local stempos = vector.offset(blockpos, 0, 0, 1)
|
||||||
if minetest.get_node(stempos).name == connected_stem_names[4] then
|
if minetest.get_node(stempos).name == connected_stem_names[4] then
|
||||||
minetest.swap_node(stempos, { name = full_unconnected_stem })
|
minetest.swap_node(stempos, { name = full_unconnected_stem })
|
||||||
try_connect_stem(stempos)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not gourd_def.on_construct then
|
|
||||||
function gourd_def.on_construct(blockpos)
|
|
||||||
-- Connect all unconnected stems at full size
|
|
||||||
try_connect_stem(vector.offset(blockpos, 1, 0, 0))
|
|
||||||
try_connect_stem(vector.offset(blockpos, -1, 0, 0))
|
|
||||||
try_connect_stem(vector.offset(blockpos, 0, 0, 1))
|
|
||||||
try_connect_stem(vector.offset(blockpos, 0, 0, -1))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
minetest.register_node(gourd_itemstring, gourd_def)
|
minetest.register_node(gourd_itemstring, gourd_def)
|
||||||
|
|
||||||
-- Register unconnected stem
|
-- Register unconnected stem
|
||||||
|
@ -243,8 +219,8 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
|
||||||
stem_def.drop = stem_def.drop or stem_drop
|
stem_def.drop = stem_def.drop or stem_drop
|
||||||
stem_def.groups = stem_def.groups or { dig_immediate = 3, not_in_creative_inventory = 1, plant = 1, attached_node = 1, dig_by_water = 1, destroy_by_lava_flow = 1 }
|
stem_def.groups = stem_def.groups or { dig_immediate = 3, not_in_creative_inventory = 1, plant = 1, attached_node = 1, dig_by_water = 1, destroy_by_lava_flow = 1 }
|
||||||
stem_def.sounds = stem_def.sounds or mcl_sounds.node_sound_leaves_defaults()
|
stem_def.sounds = stem_def.sounds or mcl_sounds.node_sound_leaves_defaults()
|
||||||
stem_def.on_construct = stem_def.on_construct or try_connect_stem
|
|
||||||
minetest.register_node(stem_itemstring, stem_def)
|
minetest.register_node(stem_itemstring, stem_def)
|
||||||
|
plant_nodename_to_id[stem_itemstring] = stem_itemstring
|
||||||
|
|
||||||
-- Register connected stems
|
-- Register connected stems
|
||||||
|
|
||||||
|
@ -307,22 +283,14 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
})
|
})
|
||||||
|
plant_nodename_to_id[connected_stem_names[i]] = stem_itemstring
|
||||||
|
|
||||||
if minetest.get_modpath("doc") then
|
if minetest.get_modpath("doc") then
|
||||||
doc.add_entry_alias("nodes", full_unconnected_stem, "nodes", connected_stem_names[i])
|
doc.add_entry_alias("nodes", full_unconnected_stem, "nodes", connected_stem_names[i])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Check for a suitable spot to grow
|
if grow_interval == 0 then return end
|
||||||
local function check_neighbor_soil(blockpos)
|
|
||||||
if minetest.get_node(blockpos).name ~= "air" then return false end
|
|
||||||
local floorpos = vector.offset(blockpos, 0, -1, 0)
|
|
||||||
local floorname = minetest.get_node(floorpos).name
|
|
||||||
if floorname == "mcl_core:dirt" then return true end
|
|
||||||
local floordef = minetest.registered_nodes[floorname]
|
|
||||||
return floordef.groups.grass_block or floordef.groups.dirt or (floordef.groups.soil or 0) >= 2
|
|
||||||
end
|
|
||||||
|
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
label = "Grow gourd stem to gourd (" .. full_unconnected_stem .. " → " .. gourd_itemstring .. ")",
|
label = "Grow gourd stem to gourd (" .. full_unconnected_stem .. " → " .. gourd_itemstring .. ")",
|
||||||
nodenames = { full_unconnected_stem },
|
nodenames = { full_unconnected_stem },
|
||||||
|
@ -330,39 +298,27 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
|
||||||
interval = grow_interval,
|
interval = grow_interval,
|
||||||
chance = grow_chance,
|
chance = grow_chance,
|
||||||
action = function(stempos)
|
action = function(stempos)
|
||||||
local light = minetest.get_node_light(stempos)
|
local light = minetest.get_node_light(stempos, 0.5)
|
||||||
if not light or light <= 10 then return end
|
if not light or light < 9 then return end
|
||||||
-- Check the four neighbors and filter out neighbors where gourds can't grow
|
-- Pick one neighbor and check if it can be used to grow
|
||||||
local neighbor, dir, nchance = nil, -1, 1 -- reservoir sampling
|
local dir = random(1, 4) -- pick direction at random
|
||||||
if nchance == 1 or math.random(1, nchance) == 1 then
|
local neighbor = (dir == 1 and vector.offset(stempos, 1, 0, 0))
|
||||||
local blockpos = vector.offset(stempos, 1, 0, 0)
|
or (dir == 2 and vector.offset(stempos, -1, 0, 0))
|
||||||
if check_neighbor_soil(blockpos) then
|
or (dir == 3 and vector.offset(stempos, 0, 0, 1))
|
||||||
neighbor, dir, nchance = blockpos, 1, nchance + 1
|
or vector.offset(stempos, 0, 0, -1)
|
||||||
end
|
if minetest.get_node(neighbor).name ~= "air" then return end -- occupied
|
||||||
end
|
-- check for suitable floor -- in contrast to MC, we think everything solid is fine
|
||||||
if nchance == 1 or math.random(1, nchance) == 1 then
|
local floorpos = vector.offset(neighbor, 0, -1, 0)
|
||||||
local blockpos = vector.offset(stempos, -1, 0, 0)
|
local floorname = minetest.get_node(floorpos).name
|
||||||
if check_neighbor_soil(blockpos) then
|
local floordef = minetest.registered_nodes[floorname]
|
||||||
neighbor, dir, nchance = blockpos, 2, nchance + 1
|
if not floordef or not floordef.walkable then return end
|
||||||
end
|
|
||||||
end
|
-- check moisture level
|
||||||
if nchance == 1 or math.random(1, nchance) == 1 then
|
local odds = floor(25 / (get_moisture_level(stempos) * get_same_crop_penalty(stempos))) + 1
|
||||||
local blockpos = vector.offset(stempos, 0, 0, 1)
|
-- we triple the odds, and rather call the ABM less often
|
||||||
if check_neighbor_soil(blockpos) then
|
if random() * odds >= 3 then return end
|
||||||
neighbor, dir, nchance = blockpos, 3, nchance + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if nchance == 1 or math.random(1, nchance) == 1 then
|
|
||||||
local blockpos = vector.offset(stempos, 0, 0, -1)
|
|
||||||
if check_neighbor_soil(blockpos) then
|
|
||||||
neighbor, dir, nchance = blockpos, 4, nchance + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Gourd needs at least 1 free neighbor to grow
|
|
||||||
if not neighbor then return end
|
|
||||||
minetest.swap_node(stempos, { name = connected_stem_names[dir] })
|
minetest.swap_node(stempos, { name = connected_stem_names[dir] })
|
||||||
-- Place the gourd
|
|
||||||
if gourd_def.paramtype2 == "facedir" then
|
if gourd_def.paramtype2 == "facedir" then
|
||||||
local p2 = (dir == 1 and 3) or (dir == 2 and 1) or (dir == 3 and 2) or 0
|
local p2 = (dir == 1 and 3) or (dir == 2 and 1) or (dir == 3 and 2) or 0
|
||||||
minetest.add_node(neighbor, { name = gourd_itemstring, param2 = p2 })
|
minetest.add_node(neighbor, { name = gourd_itemstring, param2 = p2 })
|
||||||
|
@ -371,8 +327,7 @@ function mcl_farming:add_gourd(full_unconnected_stem, connected_stem_basename, s
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Reset farmland, etc. to dirt when the gourd grows on top
|
-- Reset farmland, etc. to dirt when the gourd grows on top
|
||||||
local floorpos = vector.offset(neighbor, 0, -1, 0)
|
if (floordef.groups.dirtifies_below_solid or 0) > 0 then
|
||||||
if minetest.get_item_group(minetest.get_node(floorpos).name, "dirtifies_below_solid") == 1 then
|
|
||||||
minetest.set_node(floorpos, { name = "mcl_core:dirt" })
|
minetest.set_node(floorpos, { name = "mcl_core:dirt" })
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
@ -409,10 +364,21 @@ minetest.register_lbm({
|
||||||
nodenames = { "group:plant" },
|
nodenames = { "group:plant" },
|
||||||
run_at_every_load = true,
|
run_at_every_load = true,
|
||||||
action = function(pos, node, dtime_s)
|
action = function(pos, node, dtime_s)
|
||||||
local identifier = plant_nodename_to_id_list[node.name]
|
local identifier = plant_nodename_to_id[node.name]
|
||||||
if not identifier then return end
|
if not identifier then return end
|
||||||
local low_speed = minetest.get_node(vector.offset(pos, 0, -1, 0)).name ~= "mcl_farming:soil_wet"
|
|
||||||
mcl_farming:grow_plant(identifier, pos, node, 0, false, low_speed)
|
local plant_info = plant_lists[identifier]
|
||||||
|
if not plant_info then return end
|
||||||
|
local rolls = floor(dtime_s / plant_info.interval)
|
||||||
|
if rolls <= 0 then return end
|
||||||
|
-- simulate how often the block will be ticked
|
||||||
|
local stages = 0
|
||||||
|
for i = 1,rolls do
|
||||||
|
if random(1, plant_info.chance) == 1 then stages = stages + 1 end
|
||||||
|
end
|
||||||
|
if stages > 0 then
|
||||||
|
mcl_farming:grow_plant(identifier, pos, node, stages, false)
|
||||||
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -15,10 +15,6 @@ minetest.register_node("mcl_farming:soil", {
|
||||||
{-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5},
|
{-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_construct = function(pos)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
meta:set_int("wet", 0)
|
|
||||||
end,
|
|
||||||
groups = {handy=1,shovely=1, dirtifies_below_solid=1, dirtifier=1, soil=2, soil_sapling=1, deco_block=1 },
|
groups = {handy=1,shovely=1, dirtifies_below_solid=1, dirtifier=1, soil=2, soil_sapling=1, deco_block=1 },
|
||||||
sounds = mcl_sounds.node_sound_dirt_defaults(),
|
sounds = mcl_sounds.node_sound_dirt_defaults(),
|
||||||
_mcl_blast_resistance = 0.6,
|
_mcl_blast_resistance = 0.6,
|
||||||
|
@ -38,10 +34,6 @@ minetest.register_node("mcl_farming:soil_wet", {
|
||||||
{-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5},
|
{-0.5, -0.5, -0.5, 0.5, 0.4375, 0.5},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
on_construct = function(pos)
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
meta:set_int("wet", 7)
|
|
||||||
end,
|
|
||||||
groups = {handy=1,shovely=1, not_in_creative_inventory=1, dirtifies_below_solid=1, dirtifier=1, soil=3, soil_sapling=1 },
|
groups = {handy=1,shovely=1, not_in_creative_inventory=1, dirtifies_below_solid=1, dirtifier=1, soil=3, soil_sapling=1 },
|
||||||
sounds = mcl_sounds.node_sound_dirt_defaults(),
|
sounds = mcl_sounds.node_sound_dirt_defaults(),
|
||||||
_mcl_blast_resistance = 0.6,
|
_mcl_blast_resistance = 0.6,
|
||||||
|
@ -51,75 +43,54 @@ minetest.register_node("mcl_farming:soil_wet", {
|
||||||
minetest.register_abm({
|
minetest.register_abm({
|
||||||
label = "Farmland hydration",
|
label = "Farmland hydration",
|
||||||
nodenames = {"mcl_farming:soil", "mcl_farming:soil_wet"},
|
nodenames = {"mcl_farming:soil", "mcl_farming:soil_wet"},
|
||||||
interval = 15,
|
interval = 2.73,
|
||||||
chance = 4,
|
chance = 25,
|
||||||
action = function(pos, node)
|
action = function(pos, node)
|
||||||
-- Get wetness value
|
|
||||||
local meta = minetest.get_meta(pos)
|
|
||||||
local wet = meta:get_int("wet")
|
|
||||||
if not wet then
|
|
||||||
if node.name == "mcl_farming:soil" then
|
|
||||||
wet = 0
|
|
||||||
else
|
|
||||||
wet = 7
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Turn back into dirt when covered by solid node
|
-- Turn back into dirt when covered by solid node
|
||||||
local above_node = minetest.get_node_or_nil({x=pos.x,y=pos.y+1,z=pos.z})
|
local above_node = minetest.get_node_or_nil(vector.offset(pos, 0, 1, 0))
|
||||||
if above_node then
|
if above_node and minetest.get_item_group(above_node.name, "solid") ~= 0 then
|
||||||
if minetest.get_item_group(above_node.name, "solid") ~= 0 then
|
|
||||||
node.name = "mcl_core:dirt"
|
node.name = "mcl_core:dirt"
|
||||||
minetest.set_node(pos, node)
|
minetest.set_node(pos, node)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
-- Check an area of 9×2×9 around the node for nodename (9×9 on same level and 9×9 below)
|
-- in rain, become wet, do not decay
|
||||||
local function check_surroundings(pos, nodename)
|
if mcl_weather and mcl_weather.rain.raining and mcl_weather.is_outdoor(pos) then
|
||||||
local nodes = minetest.find_nodes_in_area({x=pos.x-4,y=pos.y,z=pos.z-4}, {x=pos.x+4,y=pos.y+1,z=pos.z+4}, {nodename})
|
if node.name == "mcl_farming:soil" then
|
||||||
return #nodes > 0
|
|
||||||
end
|
|
||||||
|
|
||||||
if check_surroundings(pos, "group:water") then
|
|
||||||
if node.name ~= "mcl_farming:soil_wet" then
|
|
||||||
-- Make it wet
|
|
||||||
node.name = "mcl_farming:soil_wet"
|
node.name = "mcl_farming:soil_wet"
|
||||||
minetest.set_node(pos, node)
|
minetest.set_node(pos, node)
|
||||||
end
|
end
|
||||||
else -- No water nearby.
|
|
||||||
-- The decay branch (make farmland dry or turn back to dirt)
|
|
||||||
|
|
||||||
-- Don't decay while it's raining
|
|
||||||
if mcl_weather.rain.raining then
|
|
||||||
if mcl_weather.is_outdoor(pos) then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Check an area of 9x2x9 around the node for nodename (9x9 on same level and 9x9 above)
|
||||||
|
-- include "ignore" to detect unloaded blocks
|
||||||
|
local nodes, counts = minetest.find_nodes_in_area(vector.offset(pos, -4, 0, -4), vector.offset(pos, 4, 1, 4), {"group:water", "ignore"})
|
||||||
|
local ignore = counts.ignore or 0
|
||||||
|
local has_water, fully_loaded = #nodes > ignore, ignore == 0
|
||||||
|
|
||||||
|
-- Hydrate by rain or water, do not decay
|
||||||
|
if has_water then
|
||||||
|
if node.name == "mcl_farming:soil" then
|
||||||
|
node.name = "mcl_farming:soil_wet"
|
||||||
|
minetest.set_node(pos, node)
|
||||||
end
|
end
|
||||||
-- No decay near unloaded areas since these might include water.
|
|
||||||
if not check_surroundings(pos, "ignore") then
|
|
||||||
if wet <= 0 then
|
|
||||||
--local n_def = minetest.registered_nodes[node.name] or nil
|
|
||||||
local nn = minetest.get_node_or_nil({x=pos.x,y=pos.y+1,z=pos.z})
|
|
||||||
if not nn or not nn.name then
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local nn_def = minetest.registered_nodes[nn.name] or nil
|
-- No decay near unloaded areas (ignore) since these might include water.
|
||||||
|
if not fully_loaded then return end
|
||||||
|
|
||||||
if nn_def and minetest.get_item_group(nn.name, "plant") == 0 then
|
-- Decay: make wet farmland dry up
|
||||||
node.name = "mcl_core:dirt"
|
if node.name == "mcl_farming:soil_wet" then
|
||||||
|
node.name = "mcl_farming:soil"
|
||||||
minetest.set_node(pos, node)
|
minetest.set_node(pos, node)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
else
|
-- Revert to dirt if wetness is 0, and no plant above
|
||||||
if wet == 7 then
|
local above = minetest.get_node_or_nil(vector.offset(pos, 0, 1, 0))
|
||||||
node.name = "mcl_farming:soil"
|
if minetest.get_item_group(above.name, "plant") == 0 then
|
||||||
minetest.swap_node(pos, node)
|
node.name = "mcl_core:dirt"
|
||||||
end
|
minetest.set_node(pos, node)
|
||||||
-- Slowly count down wetness
|
|
||||||
meta:set_int("wet", wet-1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
})
|
})
|
||||||
|
|
|
@ -12,6 +12,25 @@ for i=0, 3 do
|
||||||
local drop_berries = (i >= 2)
|
local drop_berries = (i >= 2)
|
||||||
local berries_to_drop = drop_berries and {i - 1, i} or nil
|
local berries_to_drop = drop_berries and {i - 1, i} or nil
|
||||||
|
|
||||||
|
local on_bonemealing = nil
|
||||||
|
local function do_berry_drop(pos)
|
||||||
|
for j=1, berries_to_drop[math.random(2)] do
|
||||||
|
minetest.add_item(pos, "mcl_farming:sweet_berry")
|
||||||
|
end
|
||||||
|
minetest.swap_node(pos, {name = "mcl_farming:sweet_berry_bush_1"})
|
||||||
|
end
|
||||||
|
if i ~= 3 then
|
||||||
|
on_bonemealing = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local node = minetest.get_node(pos)
|
||||||
|
return mcl_farming:grow_plant("plant_sweet_berry_bush", pos, node, 0, true)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
on_bonemealing = function(itemstack, placer, pointed_thing)
|
||||||
|
do_berry_drop(pointed_thing.under)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_node(node_name, {
|
minetest.register_node(node_name, {
|
||||||
drawtype = "plantlike",
|
drawtype = "plantlike",
|
||||||
tiles = {texture},
|
tiles = {texture},
|
||||||
|
@ -45,6 +64,7 @@ for i=0, 3 do
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
_mcl_hardness = 0,
|
_mcl_hardness = 0,
|
||||||
|
_on_bone_meal = on_bonemealing,
|
||||||
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
on_rightclick = function(pos, node, clicker, itemstack, pointed_thing)
|
||||||
local pn = clicker:get_player_name()
|
local pn = clicker:get_player_name()
|
||||||
if clicker:is_player() and minetest.is_protected(pos, pn) then
|
if clicker:is_player() and minetest.is_protected(pos, pn) then
|
||||||
|
@ -60,11 +80,13 @@ for i=0, 3 do
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if drop_berries then
|
if i >= 2 then
|
||||||
for j=1, berries_to_drop[math.random(2)] do
|
do_berry_drop(pos)
|
||||||
minetest.add_item(pos, "mcl_farming:sweet_berry")
|
else
|
||||||
|
-- Use bonemeal
|
||||||
|
if mcl_bone_meal and clicker:get_wielded_item():get_name() == "mcl_bone_meal:bone_meal" then
|
||||||
|
return mcl_bone_meal.use_bone_meal(itemstack, clicker, pointed_thing)
|
||||||
end
|
end
|
||||||
minetest.swap_node(pos, {name = "mcl_farming:sweet_berry_bush_1"})
|
|
||||||
end
|
end
|
||||||
return itemstack
|
return itemstack
|
||||||
end,
|
end,
|
||||||
|
@ -99,8 +121,8 @@ minetest.register_craftitem("mcl_farming:sweet_berry", {
|
||||||
})
|
})
|
||||||
minetest.register_alias("mcl_sweet_berry:sweet_berry", "mcl_farming:sweet_berry")
|
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.
|
-- 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, 2/3rd of the default.
|
||||||
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)
|
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"}, 8.7019, 35)
|
||||||
|
|
||||||
local function berry_damage_check(obj)
|
local function berry_damage_check(obj)
|
||||||
local p = obj:get_pos()
|
local p = obj:get_pos()
|
||||||
|
|
|
@ -60,6 +60,12 @@ for i=1,7 do
|
||||||
dig_by_water=1,destroy_by_lava_flow=1, dig_by_piston=1},
|
dig_by_water=1,destroy_by_lava_flow=1, dig_by_piston=1},
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
local stages = math.random(2, 5)
|
||||||
|
return mcl_farming:grow_plant("plant_wheat", pos, n, stages, true)
|
||||||
|
end
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -99,7 +105,7 @@ minetest.register_node("mcl_farming:wheat", {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
mcl_farming:add_plant("plant_wheat", "mcl_farming:wheat", {"mcl_farming:wheat_1", "mcl_farming:wheat_2", "mcl_farming:wheat_3", "mcl_farming:wheat_4", "mcl_farming:wheat_5", "mcl_farming:wheat_6", "mcl_farming:wheat_7"}, 25, 20)
|
mcl_farming:add_plant("plant_wheat", "mcl_farming:wheat", {"mcl_farming:wheat_1", "mcl_farming:wheat_2", "mcl_farming:wheat_3", "mcl_farming:wheat_4", "mcl_farming:wheat_5", "mcl_farming:wheat_6", "mcl_farming:wheat_7"}, 5.8020, 35)
|
||||||
|
|
||||||
minetest.register_craftitem("mcl_farming:wheat_item", {
|
minetest.register_craftitem("mcl_farming:wheat_item", {
|
||||||
description = S("Wheat"),
|
description = S("Wheat"),
|
||||||
|
|
|
@ -0,0 +1,136 @@
|
||||||
|
-- bonemealing grass nodes
|
||||||
|
--
|
||||||
|
-- When bonemealing "mcl_core:dirt_with_grass", it spawns grass and flowers
|
||||||
|
-- over a 7x7 patch of adjacent grassy nodes.
|
||||||
|
--
|
||||||
|
-- Because of potential dependency complications it is not advisable to add
|
||||||
|
-- callbacks to mcl_core that create dependencies on mods that depend on
|
||||||
|
-- mcl_core, such as mcl_flowers.
|
||||||
|
--
|
||||||
|
-- To work around this restriction, the bonemealing callback is defined here
|
||||||
|
-- and the _on_bone_meal callback in "mcl_core:dirt_with_grass" node
|
||||||
|
-- definition is overwritten with it.
|
||||||
|
|
||||||
|
local mg_name = minetest.get_mapgen_setting("mg_name")
|
||||||
|
|
||||||
|
local flowers_table_simple = {
|
||||||
|
"mcl_flowers:dandelion",
|
||||||
|
"mcl_flowers:poppy",
|
||||||
|
}
|
||||||
|
local flowers_table_plains = {
|
||||||
|
"mcl_flowers:dandelion",
|
||||||
|
"mcl_flowers:dandelion",
|
||||||
|
"mcl_flowers:poppy",
|
||||||
|
"mcl_flowers:oxeye_daisy",
|
||||||
|
"mcl_flowers:tulip_orange",
|
||||||
|
"mcl_flowers:tulip_red",
|
||||||
|
"mcl_flowers:tulip_white",
|
||||||
|
"mcl_flowers:tulip_pink",
|
||||||
|
"mcl_flowers:azure_bluet",
|
||||||
|
}
|
||||||
|
local flowers_table_swampland = {
|
||||||
|
"mcl_flowers:blue_orchid",
|
||||||
|
}
|
||||||
|
local flowers_table_flower_forest = {
|
||||||
|
"mcl_flowers:dandelion",
|
||||||
|
"mcl_flowers:poppy",
|
||||||
|
"mcl_flowers:oxeye_daisy",
|
||||||
|
"mcl_flowers:tulip_orange",
|
||||||
|
"mcl_flowers:tulip_red",
|
||||||
|
"mcl_flowers:tulip_white",
|
||||||
|
"mcl_flowers:tulip_pink",
|
||||||
|
"mcl_flowers:azure_bluet",
|
||||||
|
"mcl_flowers:allium",
|
||||||
|
}
|
||||||
|
|
||||||
|
local biome_flowers_tables = {
|
||||||
|
["Plains"] = flowers_table_plains,
|
||||||
|
["Plains_beach"] = flowers_table_plains,
|
||||||
|
["Plains_ocean"] = flowers_table_plains,
|
||||||
|
["Plains_deep_ocean"] = flowers_table_plains,
|
||||||
|
["Plains_underground"] = flowers_table_plains,
|
||||||
|
["SunflowerPlains"] = flowers_table_plains,
|
||||||
|
["SunflowerPlains_ocean"] = flowers_table_plains,
|
||||||
|
["SunflowerPlains_deep_ocean"] = flowers_table_plains,
|
||||||
|
["SunflowerPlains_underground"] = flowers_table_plains,
|
||||||
|
["Swampland"] = flowers_table_swampland,
|
||||||
|
["Swampland_shore"] = flowers_table_swampland,
|
||||||
|
["Swampland_ocean"] = flowers_table_swampland,
|
||||||
|
["Swampland_deep_ocean"] = flowers_table_swampland,
|
||||||
|
["Swampland_underground"] = flowers_table_swampland,
|
||||||
|
["FlowerForest"] = flowers_table_flower_forest,
|
||||||
|
["FlowerForest_beach"] = flowers_table_flower_forest,
|
||||||
|
["FlowerForest_ocean"] = flowers_table_flower_forest,
|
||||||
|
["FlowerForest_deep_ocean"] = flowers_table_flower_forest,
|
||||||
|
["FlowerForest_underground"] = flowers_table_flower_forest,
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Randomly generate flowers, tall grass or nothing
|
||||||
|
-- pos: node to place into
|
||||||
|
-- color: param2 value for tall grass
|
||||||
|
--
|
||||||
|
local function add_random_flower(pos, color)
|
||||||
|
-- 90% tall grass, 10% flower
|
||||||
|
local rnd = math.random(1,100)
|
||||||
|
if rnd <= 60 then
|
||||||
|
minetest.add_node(pos, {name="mcl_flowers:tallgrass", param2=color})
|
||||||
|
elseif rnd <= 80 then
|
||||||
|
-- double tallgrass
|
||||||
|
local toppos = vector.offset(pos, 0, 1, 0)
|
||||||
|
local topnode = minetest.get_node(toppos)
|
||||||
|
if minetest.registered_nodes[topnode.name].buildable_to then
|
||||||
|
minetest.set_node(pos, { name = "mcl_flowers:double_grass", param2 = color })
|
||||||
|
minetest.set_node(toppos, { name = "mcl_flowers:double_grass_top", param2 = color })
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local flowers_table
|
||||||
|
if mg_name == "v6" then
|
||||||
|
flowers_table = flowers_table_plains
|
||||||
|
else
|
||||||
|
local biome = minetest.get_biome_name(minetest.get_biome_data(pos).biome)
|
||||||
|
flowers_table = biome_flowers_tables[biome] or flowers_table_simple
|
||||||
|
end
|
||||||
|
minetest.add_node(pos, {name=flowers_table[math.random(1, #flowers_table)]})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- Generate tall grass and random flowers in a 7x7 area
|
||||||
|
-- Bonemealing callback handler for "mcl_core:dirt_with_grass"
|
||||||
|
--
|
||||||
|
local function bonemeal_grass(pointed_thing, placer)
|
||||||
|
local pos, below, r, color
|
||||||
|
for i = -7, 7 do for j = -7, 7 do for y = -1, 1 do
|
||||||
|
pos = vector.offset(pointed_thing.above, i, y, j)
|
||||||
|
if minetest.get_node(pos).name == "air" then
|
||||||
|
below = minetest.get_node(vector.offset(pos, 0, -1, 0))
|
||||||
|
r = ((math.abs(i) + math.abs(j)) / 2)
|
||||||
|
if (minetest.get_item_group(below.name, "grass_block_no_snow") == 1) and
|
||||||
|
math.random(1, 100) <= 90 / r then
|
||||||
|
color = below.param2
|
||||||
|
add_random_flower(pos, color)
|
||||||
|
if math.random(1,5) == 1 then
|
||||||
|
mcl_bone_meal.add_bone_meal_particle(pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end end end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Override "mcl_core:dirt_with_grass" bonemealing handler.
|
||||||
|
local nodename = "mcl_core:dirt_with_grass"
|
||||||
|
local olddef = minetest.registered_nodes[nodename]
|
||||||
|
if not olddef then
|
||||||
|
minetest.log("warning", "'mcl_core:dirt_with_grass' not registered, cannot add override!")
|
||||||
|
else
|
||||||
|
local oldhandler = olddef._on_bone_meal
|
||||||
|
local newhandler = function(itemstack, placer, pointed_thing)
|
||||||
|
local res = bonemeal_grass(pointed_thing, placer)
|
||||||
|
if oldhandler then
|
||||||
|
res = oldhandler(itemstack, placer, pointed_thing) or res
|
||||||
|
end
|
||||||
|
return res
|
||||||
|
end
|
||||||
|
minetest.override_item(nodename, {_on_bone_meal = newhandler})
|
||||||
|
end
|
|
@ -162,6 +162,18 @@ local def_tallgrass = {
|
||||||
_mcl_fortune_drop = fortune_wheat_seed_drop,
|
_mcl_fortune_drop = fortune_wheat_seed_drop,
|
||||||
node_placement_prediction = "",
|
node_placement_prediction = "",
|
||||||
on_place = on_place_flower,
|
on_place = on_place_flower,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
-- Grow into double tallgrass
|
||||||
|
local toppos = vector.offset(pos, 0, 1, 0)
|
||||||
|
local topnode = minetest.get_node(toppos)
|
||||||
|
if minetest.registered_nodes[topnode.name].buildable_to then
|
||||||
|
minetest.set_node(pos, { name = "mcl_flowers:double_grass", param2 = n.param2 })
|
||||||
|
minetest.set_node(toppos, { name = "mcl_flowers:double_grass_top", param2 = n.param2 })
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end,
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
_mcl_hardness = 0,
|
_mcl_hardness = 0,
|
||||||
}
|
}
|
||||||
|
@ -180,6 +192,18 @@ def_fern.selection_box = {
|
||||||
fixed = { -6/16, -0.5, -6/16, 6/16, 5/16, 6/16 },
|
fixed = { -6/16, -0.5, -6/16, 6/16, 5/16, 6/16 },
|
||||||
}
|
}
|
||||||
def_fern.groups.compostability = 65
|
def_fern.groups.compostability = 65
|
||||||
|
def_fern._on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
local n = minetest.get_node(pos)
|
||||||
|
-- Grow into double fern.
|
||||||
|
local toppos = vector.offset(pos, 0, 1, 0)
|
||||||
|
local topnode = minetest.get_node(toppos)
|
||||||
|
if minetest.registered_nodes[topnode.name].buildable_to then
|
||||||
|
minetest.set_node(pos, { name = "mcl_flowers:double_fern", param2 = n.param2 })
|
||||||
|
minetest.set_node(toppos, { name = "mcl_flowers:double_fern_top", param2 = n.param2 })
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
minetest.register_node("mcl_flowers:fern", def_fern)
|
minetest.register_node("mcl_flowers:fern", def_fern)
|
||||||
|
|
||||||
|
@ -243,10 +267,16 @@ local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_im
|
||||||
if name == "double_grass" then
|
if name == "double_grass" then
|
||||||
bottom_groups.compostability = 50
|
bottom_groups.compostability = 50
|
||||||
end
|
end
|
||||||
|
local on_bonemealing
|
||||||
if is_flower then
|
if is_flower then
|
||||||
bottom_groups.flower = 1
|
bottom_groups.flower = 1
|
||||||
bottom_groups.place_flowerlike = 1
|
bottom_groups.place_flowerlike = 1
|
||||||
bottom_groups.dig_immediate = 3
|
bottom_groups.dig_immediate = 3
|
||||||
|
on_bonemealing = function(itemstack, placer, pointed_thing)
|
||||||
|
local pos = pointed_thing.under
|
||||||
|
minetest.add_item(pos, "mcl_flowers:"..name)
|
||||||
|
return true
|
||||||
|
end
|
||||||
else
|
else
|
||||||
bottom_groups.place_flowerlike = 2
|
bottom_groups.place_flowerlike = 2
|
||||||
bottom_groups.handy = 1
|
bottom_groups.handy = 1
|
||||||
|
@ -381,6 +411,7 @@ local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_im
|
||||||
minetest.remove_node(top)
|
minetest.remove_node(top)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
_on_bone_meal = on_bonemealing,
|
||||||
groups = bottom_groups,
|
groups = bottom_groups,
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
mesh = mesh
|
mesh = mesh
|
||||||
|
@ -419,6 +450,7 @@ local function add_large_plant(name, desc, longdesc, bottom_img, top_img, inv_im
|
||||||
minetest.remove_node(bottom)
|
minetest.remove_node(bottom)
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
|
_on_bone_meal = on_bonemealing,
|
||||||
groups = top_groups,
|
groups = top_groups,
|
||||||
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
sounds = mcl_sounds.node_sound_leaves_defaults(),
|
||||||
})
|
})
|
||||||
|
@ -572,3 +604,6 @@ if mod_mcimport and mg_name == "singlenode" and fix_doubleplants == true then
|
||||||
end
|
end
|
||||||
|
|
||||||
dofile(modpath.."/register.lua")
|
dofile(modpath.."/register.lua")
|
||||||
|
|
||||||
|
-- Bonemealing handler and override for "mcl_core:dirt_with_grass":
|
||||||
|
dofile(modpath.."/bonemealing.lua")
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
name=mcl_flowers
|
name=mcl_flowers
|
||||||
depends=mcl_core, mcl_util, mcl_sounds
|
depends=mcl_core, mcl_util, mcl_sounds, mcl_bone_meal
|
||||||
optional_depends=screwdriver, doc, mcl_flowerpots
|
optional_depends=screwdriver, doc, mcl_flowerpots
|
|
@ -1,5 +1,8 @@
|
||||||
local S = minetest.get_translator(minetest.get_current_modname())
|
local S = minetest.get_translator(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
local schempath = modpath .. "/schematics/"
|
||||||
|
|
||||||
local on_place = mcl_util.generate_on_place_plant_function(function(place_pos, place_node)
|
local on_place = mcl_util.generate_on_place_plant_function(function(place_pos, place_node)
|
||||||
local soil_node = minetest.get_node_or_nil({x=place_pos.x, y=place_pos.y-1, z=place_pos.z})
|
local soil_node = minetest.get_node_or_nil({x=place_pos.x, y=place_pos.y-1, z=place_pos.z})
|
||||||
if not soil_node then return false end
|
if not soil_node then return false end
|
||||||
|
@ -16,6 +19,40 @@ local on_place = mcl_util.generate_on_place_plant_function(function(place_pos, p
|
||||||
return ((snn == "mcl_core:podzol" or snn == "mcl_core:podzol_snow" or snn == "mcl_core:mycelium" or snn == "mcl_core:mycelium_snow") or (light_ok and minetest.get_item_group(snn, "solid") == 1 and minetest.get_item_group(snn, "opaque") == 1))
|
return ((snn == "mcl_core:podzol" or snn == "mcl_core:podzol_snow" or snn == "mcl_core:mycelium" or snn == "mcl_core:mycelium_snow") or (light_ok and minetest.get_item_group(snn, "solid") == 1 and minetest.get_item_group(snn, "opaque") == 1))
|
||||||
end)
|
end)
|
||||||
|
|
||||||
|
-- Try to grow huge mushroom
|
||||||
|
local function apply_bonemeal(pos, schematic, offset)
|
||||||
|
-- Must be on a dirt-type block
|
||||||
|
local below = minetest.get_node(vector.offset(pos, 0, -1, 0))
|
||||||
|
if minetest.get_item_group(below.name, "grass_block") ~= 1
|
||||||
|
and below.name ~= "mcl_core:mycelium"
|
||||||
|
and below.name ~= "mcl_core:dirt"
|
||||||
|
and below.name ~= "mcl_core:coarse_dirt"
|
||||||
|
and below.name ~= "mcl_core:podzol" then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
-- 40% chance
|
||||||
|
if math.random(1, 100) <= 40 then
|
||||||
|
-- Check space requirements
|
||||||
|
for i= 1, 3 do
|
||||||
|
local cpos = vector.offset(pos, 0, i, 0)
|
||||||
|
if minetest.get_node(cpos).name ~= "air" then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local minp = vector.offset(pos, -3, 3, -3)
|
||||||
|
local maxp = vector.offset(pos, 3, 8, 3)
|
||||||
|
local diff = maxp - minp
|
||||||
|
local goodnodes = minetest.find_nodes_in_area(minp, maxp, {"air", "group:leaves"})
|
||||||
|
if #goodnodes < (diff.x + 1) * (diff.y + 1) * (diff.z + 1) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
-- Place the huge mushroom
|
||||||
|
minetest.remove_node(pos)
|
||||||
|
return minetest.place_schematic(pos + offset, schematic, 0, nil, false)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
local longdesc_intro_brown = S("Brown mushrooms are fungi which grow and spread in darkness, but are sensitive to light. They are inedible as such, but they can be used to craft food items.")
|
local longdesc_intro_brown = S("Brown mushrooms are fungi which grow and spread in darkness, but are sensitive to light. They are inedible as such, but they can be used to craft food items.")
|
||||||
local longdesc_intro_red = S("Red mushrooms are fungi which grow and spread in darkness, but are sensitive to light. They are inedible as such, but they can be used to craft food items.")
|
local longdesc_intro_red = S("Red mushrooms are fungi which grow and spread in darkness, but are sensitive to light. They are inedible as such, but they can be used to craft food items.")
|
||||||
|
|
||||||
|
@ -51,6 +88,11 @@ minetest.register_node("mcl_mushrooms:mushroom_brown", {
|
||||||
},
|
},
|
||||||
node_placement_prediction = "",
|
node_placement_prediction = "",
|
||||||
on_place = on_place,
|
on_place = on_place,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local schematic = schempath .. "mcl_mushrooms_huge_brown.mts"
|
||||||
|
local offset = vector.new(-3, -1, -3)
|
||||||
|
return apply_bonemeal(pointed_thing.under, schematic, offset)
|
||||||
|
end,
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -78,6 +120,11 @@ minetest.register_node("mcl_mushrooms:mushroom_red", {
|
||||||
},
|
},
|
||||||
node_placement_prediction = "",
|
node_placement_prediction = "",
|
||||||
on_place = on_place,
|
on_place = on_place,
|
||||||
|
_on_bone_meal = function(itemstack, placer, pointed_thing)
|
||||||
|
local schematic = schempath .. "mcl_mushrooms_huge_red.mts"
|
||||||
|
local offset = vector.new(-2, -1, -2)
|
||||||
|
return apply_bonemeal(pointed_thing.under, schematic, offset)
|
||||||
|
end,
|
||||||
_mcl_blast_resistance = 0,
|
_mcl_blast_resistance = 0,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -211,16 +211,37 @@ local function set_interact(player, interact)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
local meta = player:get_meta()
|
local meta = player:get_meta()
|
||||||
if meta:get_int("mcl_privs:interact_revoked") ~= 1 then
|
|
||||||
privs.interact = interact
|
if interact and meta:get_int("mcl_shields:interact_revoked") ~= 0 then
|
||||||
|
meta:set_int("mcl_shields:interact_revoked", 0)
|
||||||
|
privs.interact = true
|
||||||
|
elseif not interact then
|
||||||
|
meta:set_int("mcl_shields:interact_revoked", privs.interact and 1 or 0)
|
||||||
|
privs.interact = nil
|
||||||
|
end
|
||||||
|
|
||||||
minetest.set_player_privs(player_name, privs)
|
minetest.set_player_privs(player_name, privs)
|
||||||
meta:set_int("mcl_privs:interact_revoked",0)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Prevent player from being able to circumvent interact privilage removal by
|
||||||
|
-- using shield.
|
||||||
|
minetest.register_on_priv_revoke(function(name, revoker, priv)
|
||||||
|
if priv == "interact" and revoker then
|
||||||
|
local player = minetest.get_player_by_name(name)
|
||||||
|
if not player then
|
||||||
|
return
|
||||||
end
|
end
|
||||||
|
local meta = player:get_meta()
|
||||||
|
meta:set_int("mcl_shields:interact_revoked", 0)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
local shield_hud = {}
|
local shield_hud = {}
|
||||||
|
|
||||||
local function remove_shield_hud(player)
|
local function remove_shield_hud(player)
|
||||||
|
set_interact(player, true)
|
||||||
|
playerphysics.remove_physics_factor(player, "speed", "shield_speed")
|
||||||
|
|
||||||
if not shield_hud[player] then return end --this function takes a long time. only run it when necessary
|
if not shield_hud[player] then return end --this function takes a long time. only run it when necessary
|
||||||
player:hud_remove(shield_hud[player])
|
player:hud_remove(shield_hud[player])
|
||||||
shield_hud[player] = nil
|
shield_hud[player] = nil
|
||||||
|
@ -231,9 +252,6 @@ local function remove_shield_hud(player)
|
||||||
if not hf.wielditem then
|
if not hf.wielditem then
|
||||||
player:hud_set_flags({wielditem = true})
|
player:hud_set_flags({wielditem = true})
|
||||||
end
|
end
|
||||||
|
|
||||||
playerphysics.remove_physics_factor(player, "speed", "shield_speed")
|
|
||||||
set_interact(player, true)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function add_shield_entity(player, i)
|
local function add_shield_entity(player, i)
|
||||||
|
@ -251,6 +269,11 @@ local function remove_shield_entity(player, i)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function is_rmb_conflicting_node(nodename)
|
||||||
|
local nodedef = minetest.registered_nodes[nodename] or {}
|
||||||
|
return nodedef.on_rightclick
|
||||||
|
end
|
||||||
|
|
||||||
local function handle_blocking(player)
|
local function handle_blocking(player)
|
||||||
local player_shield = mcl_shields.players[player]
|
local player_shield = mcl_shields.players[player]
|
||||||
local rmb = player:get_player_control().RMB
|
local rmb = player:get_player_control().RMB
|
||||||
|
@ -259,14 +282,25 @@ local function handle_blocking(player)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local pointed_thing = mcl_util.get_pointed_thing(player, true)
|
||||||
|
local wielded_stack = player:get_wielded_item()
|
||||||
|
|
||||||
local shield_in_offhand = mcl_shields.wielding_shield(player, 1)
|
local shield_in_offhand = mcl_shields.wielding_shield(player, 1)
|
||||||
local shield_in_hand = mcl_shields.wielding_shield(player)
|
local shield_in_hand = mcl_shields.wielding_shield(player)
|
||||||
local not_blocking = player_shield.blocking == 0
|
local not_blocking = player_shield.blocking == 0
|
||||||
|
|
||||||
local pos = player:get_pos()
|
if pointed_thing and pointed_thing.type == "node" then
|
||||||
|
local pointed_node = minetest.get_node(pointed_thing.under)
|
||||||
|
if minetest.get_item_group(pointed_node.name, "container") > 1
|
||||||
|
or is_rmb_conflicting_node(pointed_node.name)
|
||||||
|
or wielded_stack:get_definition().type == "node" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if shield_in_hand then
|
if shield_in_hand then
|
||||||
if not_blocking then
|
if not_blocking then
|
||||||
minetest.after(0.25, function()
|
minetest.after(0.05, function()
|
||||||
if (not_blocking or not shield_in_offhand) and shield_in_hand and rmb then
|
if (not_blocking or not shield_in_offhand) and shield_in_hand and rmb then
|
||||||
player_shield.blocking = 2
|
player_shield.blocking = 2
|
||||||
set_shield(player, true, 2)
|
set_shield(player, true, 2)
|
||||||
|
@ -276,22 +310,15 @@ local function handle_blocking(player)
|
||||||
player_shield.blocking = 2
|
player_shield.blocking = 2
|
||||||
end
|
end
|
||||||
elseif shield_in_offhand then
|
elseif shield_in_offhand then
|
||||||
local pointed_thing = mcl_util.get_pointed_thing(player, true)
|
local offhand_can_block = minetest.get_item_group(wielded_item(player), "cannot_block") ~= 1
|
||||||
local offhand_can_block = (wielded_item(player) == "" or not pointed_thing)
|
|
||||||
and (minetest.get_item_group(wielded_item(player), "bow") ~= 1 and minetest.get_item_group(wielded_item(player), "crossbow") ~= 1)
|
|
||||||
|
|
||||||
if pointed_thing and pointed_thing.type == "node" then
|
|
||||||
if minetest.get_item_group(minetest.get_node(pointed_thing.under).name, "container") > 1 then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not offhand_can_block then
|
if not offhand_can_block then
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
if not_blocking then
|
if not_blocking then
|
||||||
minetest.after(0.25, function()
|
minetest.after(0.05, function()
|
||||||
if (not_blocking or not shield_in_hand) and shield_in_offhand and rmb and offhand_can_block then
|
if (not_blocking or not shield_in_hand) and shield_in_offhand
|
||||||
|
and rmb and offhand_can_block then
|
||||||
player_shield.blocking = 1
|
player_shield.blocking = 1
|
||||||
set_shield(player, true, 1)
|
set_shield(player, true, 1)
|
||||||
end
|
end
|
||||||
|
@ -344,7 +371,7 @@ local function add_shield_hud(shieldstack, player, blocking)
|
||||||
z_index = -200,
|
z_index = -200,
|
||||||
})
|
})
|
||||||
playerphysics.add_physics_factor(player, "speed", "shield_speed", 0.5)
|
playerphysics.add_physics_factor(player, "speed", "shield_speed", 0.5)
|
||||||
set_interact(player, nil)
|
set_interact(player, false)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function update_shield_hud(player, blocking, shieldstack)
|
local function update_shield_hud(player, blocking, shieldstack)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
name = mcl_signs
|
name = mcl_signs
|
||||||
description = New and Improved signs - can be colored and made to glow.
|
description = New and Improved signs - can be colored and made to glow.
|
||||||
depends = mcl_core, mcl_sounds, mcl_dye, mcl_colors, mcl_util
|
depends = mcl_core, mcl_sounds, mcl_dye, mcl_colors, mcl_util, mesecons_mvps
|
||||||
optional_depends = doc
|
optional_depends = doc
|
||||||
|
|
|
@ -167,6 +167,12 @@ minetest.register_node("mcl_smithing_table:table", {
|
||||||
end,
|
end,
|
||||||
|
|
||||||
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
allow_metadata_inventory_put = function(pos, listname, index, stack, player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
if minetest.is_protected(pos, name) then
|
||||||
|
minetest.record_protection_violation(pos, name)
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
local stackname = stack:get_name()
|
local stackname = stack:get_name()
|
||||||
local def = stack:get_definition()
|
local def = stack:get_definition()
|
||||||
if
|
if
|
||||||
|
@ -187,6 +193,16 @@ minetest.register_node("mcl_smithing_table:table", {
|
||||||
return 0
|
return 0
|
||||||
end,
|
end,
|
||||||
|
|
||||||
|
allow_metadata_inventory_take = function(pos, listname, index, stack, player)
|
||||||
|
local name = player:get_player_name()
|
||||||
|
if minetest.is_protected(pos, name) then
|
||||||
|
minetest.record_protection_violation(pos, name)
|
||||||
|
return 0
|
||||||
|
else
|
||||||
|
return stack:get_count()
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
|
||||||
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
allow_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player)
|
||||||
return 0
|
return 0
|
||||||
end,
|
end,
|
||||||
|
|
|
@ -6,6 +6,7 @@ minetest.register_tool("mcl_spyglass:spyglass",{
|
||||||
inventory_image = "mcl_spyglass.png",
|
inventory_image = "mcl_spyglass.png",
|
||||||
stack_max = 1,
|
stack_max = 1,
|
||||||
_mcl_toollike_wield = true,
|
_mcl_toollike_wield = true,
|
||||||
|
touch_interaction = "short_dig_long_place",
|
||||||
})
|
})
|
||||||
|
|
||||||
minetest.register_craft({
|
minetest.register_craft({
|
||||||
|
|
|
@ -22,9 +22,13 @@ dig_speed_class group:
|
||||||
-- Help texts
|
-- Help texts
|
||||||
local pickaxe_longdesc = S("Pickaxes are mining tools to mine hard blocks, such as stone. A pickaxe can also be used as weapon, but it is rather inefficient.")
|
local pickaxe_longdesc = S("Pickaxes are mining tools to mine hard blocks, such as stone. A pickaxe can also be used as weapon, but it is rather inefficient.")
|
||||||
local axe_longdesc = S("An axe is your tool of choice to cut down trees, wood-based blocks and other blocks. Axes deal a lot of damage as well, but they are rather slow.")
|
local axe_longdesc = S("An axe is your tool of choice to cut down trees, wood-based blocks and other blocks. Axes deal a lot of damage as well, but they are rather slow.")
|
||||||
|
|
||||||
local sword_longdesc = S("Swords are great in melee combat, as they are fast, deal high damage and can endure countless battles. Swords can also be used to cut down a few particular blocks, such as cobwebs.")
|
local sword_longdesc = S("Swords are great in melee combat, as they are fast, deal high damage and can endure countless battles. Swords can also be used to cut down a few particular blocks, such as cobwebs.")
|
||||||
|
local sword_use = S("To slash multiple enemies, hold the sword in your hand, then use (rightclick) an enemy.")
|
||||||
|
|
||||||
local shovel_longdesc = S("Shovels are tools for digging coarse blocks, such as dirt, sand and gravel. They can also be used to turn grass blocks to grass paths. Shovels can be used as weapons, but they are very weak.")
|
local shovel_longdesc = S("Shovels are tools for digging coarse blocks, such as dirt, sand and gravel. They can also be used to turn grass blocks to grass paths. Shovels can be used as weapons, but they are very weak.")
|
||||||
local shovel_use = S("To turn a grass block into a grass path, hold the shovel in your hand, then use (rightclick) the top or side of a grass block. This only works when there's air above the grass block.")
|
local shovel_use = S("To turn a grass block into a grass path, hold the shovel in your hand, then use (rightclick) the top or side of a grass block. This only works when there's air above the grass block.")
|
||||||
|
|
||||||
local shears_longdesc = S("Shears are tools to shear sheep and to mine a few block types. Shears are a special mining tool and can be used to obtain the original item from grass, leaves and similar blocks that require cutting.")
|
local shears_longdesc = S("Shears are tools to shear sheep and to mine a few block types. Shears are a special mining tool and can be used to obtain the original item from grass, leaves and similar blocks that require cutting.")
|
||||||
local shears_use = S("To shear sheep or carve faceless pumpkins, use the “place” key on them. Faces can only be carved at the side of faceless pumpkins. Mining works as usual, but the drops are different for a few blocks.")
|
local shears_use = S("To shear sheep or carve faceless pumpkins, use the “place” key on them. Faces can only be carved at the side of faceless pumpkins. Mining works as usual, but the drops are different for a few blocks.")
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,799 @@
|
||||||
|
local modname = minetest.get_current_modname()
|
||||||
|
local modpath = minetest.get_modpath(modname)
|
||||||
|
local S = minetest.get_translator(modname)
|
||||||
|
|
||||||
|
|
||||||
|
local hammer_tt = S("Can crush blocks") .. "\n" .. S("Increased knockback")
|
||||||
|
local hammer_longdesc = S("Hammers are great in melee combat, as they deal high damage with increased knockback and can endure countless battles. Hammers can also be used to crush things.")
|
||||||
|
local hammer_use = S("To crush a block, dig the block with the hammer. This only works with some blocks.")
|
||||||
|
|
||||||
|
local spear_tt = S("Reaches farther") .. "\n" .. S("Can be thrown")
|
||||||
|
local spear_longdesc = S("Spears are great in melee combat, as they have an increased reach. They can also be thrown.")
|
||||||
|
local spear_use = S("To throw a spear, hold it in your hand, then hold use (rightclick) in the air.")
|
||||||
|
|
||||||
|
local wield_scale = mcl_vars.tool_wield_scale
|
||||||
|
|
||||||
|
local GRAVITY = 9.81
|
||||||
|
local YAW_OFFSET = -math.pi/2
|
||||||
|
local function dir_to_pitch(dir)
|
||||||
|
--local dir2 = vector.normalize(dir)
|
||||||
|
local xz = math.abs(dir.x) + math.abs(dir.z)
|
||||||
|
return -math.atan2(-dir.y, xz)
|
||||||
|
end
|
||||||
|
-- Time after which stuck spear is rechecked for being stuck
|
||||||
|
local STUCK_RECHECK_TIME = 5
|
||||||
|
-- Time in seconds after which a stuck spear is deleted
|
||||||
|
local SPEAR_TIMEOUT = 180
|
||||||
|
local SPEAR_ENTITY={
|
||||||
|
physical = true,
|
||||||
|
pointable = false,
|
||||||
|
visual = "item",
|
||||||
|
visual_size = {x=-0.5, y=-0.5},
|
||||||
|
textures = {"vl_weaponry:spear_wood"},
|
||||||
|
collisionbox = {-0.19, -0.125, -0.19, 0.19, 0.125, 0.19},
|
||||||
|
collide_with_objects = false,
|
||||||
|
_fire_damage_resistant = true,
|
||||||
|
|
||||||
|
_lastpos={},
|
||||||
|
_startpos=nil,
|
||||||
|
_damage=1, -- Damage on impact
|
||||||
|
_is_critical=false, -- Whether this spear would deal critical damage
|
||||||
|
_stuck=false, -- Whether spear is stuck
|
||||||
|
_stucktimer=nil,-- Amount of time (in seconds) the spear has been stuck so far
|
||||||
|
_stuckrechecktimer=nil,-- An additional timer for periodically re-checking the stuck status of an spear
|
||||||
|
_stuckin=nil, --Position of node in which spear is stuck.
|
||||||
|
_shooter=nil, -- ObjectRef of player or mob who threw it
|
||||||
|
_is_arrow = true,
|
||||||
|
_in_player = false,
|
||||||
|
_blocked = false,
|
||||||
|
_viscosity = 0, -- Viscosity of node the spear is currently in
|
||||||
|
_deflection_cooloff = 0, -- Cooloff timer after an spear deflection, to prevent many deflections in quick succession
|
||||||
|
_itemstack = nil, -- ItemStack of the original object
|
||||||
|
}
|
||||||
|
|
||||||
|
-- Destroy spear entity self at pos and drops it as an item
|
||||||
|
local function spawn_item(self, pos)
|
||||||
|
if not minetest.is_creative_enabled("") then
|
||||||
|
local item = minetest.add_item(pos, self._itemstack)
|
||||||
|
item:set_velocity(vector.new(0, 0, 0))
|
||||||
|
item:set_yaw(self.object:get_yaw())
|
||||||
|
end
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
|
||||||
|
local function damage_particles(pos, is_critical)
|
||||||
|
if is_critical then
|
||||||
|
minetest.add_particlespawner({
|
||||||
|
amount = 15,
|
||||||
|
time = 0.1,
|
||||||
|
minpos = vector.offset(pos, -0.5, -0.5, -0.5),
|
||||||
|
maxpos = vector.offset(pos, 0.5, 0.5, 0.5),
|
||||||
|
minvel = vector.new(-0.1, -0.1, -0.1),
|
||||||
|
maxvel = vector.new(0.1, 0.1, 0.1),
|
||||||
|
minexptime = 1,
|
||||||
|
maxexptime = 2,
|
||||||
|
minsize = 1.5,
|
||||||
|
maxsize = 1.5,
|
||||||
|
collisiondetection = false,
|
||||||
|
vertical = false,
|
||||||
|
texture = "mcl_particles_crit.png^[colorize:#bc7a57:127",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SPEAR_ENTITY.on_step(self, dtime)
|
||||||
|
mcl_burning.tick(self.object, dtime, self)
|
||||||
|
-- mcl_burning.tick may remove object immediately
|
||||||
|
if not self.object:get_pos() then return end
|
||||||
|
|
||||||
|
self._time_in_air = self._time_in_air + .001
|
||||||
|
|
||||||
|
local pos = self.object:get_pos()
|
||||||
|
local dpos = vector.round(vector.new(pos)) -- digital pos
|
||||||
|
local node = minetest.get_node(dpos)
|
||||||
|
|
||||||
|
if self._stuck then
|
||||||
|
self._stucktimer = self._stucktimer + dtime
|
||||||
|
self._stuckrechecktimer = self._stuckrechecktimer + dtime
|
||||||
|
if self._stucktimer > SPEAR_TIMEOUT then
|
||||||
|
spawn_item(self, pos)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
-- Drop spear as item when it is no longer stuck
|
||||||
|
if self._stuckrechecktimer > STUCK_RECHECK_TIME then
|
||||||
|
local stuckin_def
|
||||||
|
if self._stuckin then
|
||||||
|
stuckin_def = minetest.registered_nodes[minetest.get_node(self._stuckin).name]
|
||||||
|
end
|
||||||
|
-- TODO: fall down without turning into an item?
|
||||||
|
if stuckin_def and stuckin_def.walkable == false then
|
||||||
|
spawn_item(self, pos)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
self._stuckrechecktimer = 0
|
||||||
|
end
|
||||||
|
-- Pickup spear if player is nearby (not in Creative Mode)
|
||||||
|
local objects = minetest.get_objects_inside_radius(pos, 1)
|
||||||
|
for _,obj in ipairs(objects) do
|
||||||
|
if obj:is_player() then
|
||||||
|
if self._collectable and not minetest.is_creative_enabled(obj:get_player_name()) then
|
||||||
|
if obj:get_inventory():room_for_item("main", self._itemstack) then
|
||||||
|
obj:get_inventory():add_item("main", self._itemstack)
|
||||||
|
minetest.sound_play("item_drop_pickup", {
|
||||||
|
pos = pos,
|
||||||
|
max_hear_distance = 16,
|
||||||
|
gain = 1.0,
|
||||||
|
}, true)
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
|
self.object:remove()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
spawn_item(self, pos)
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check for object "collision". Done every tick (hopefully this is not too stressing)
|
||||||
|
else
|
||||||
|
|
||||||
|
if self._damage >= 9 and self._in_player == false then
|
||||||
|
minetest.add_particlespawner({
|
||||||
|
amount = 20,
|
||||||
|
time = .2,
|
||||||
|
minpos = vector.new(0,0,0),
|
||||||
|
maxpos = vector.new(0,0,0),
|
||||||
|
minvel = vector.new(-0.1,-0.1,-0.1),
|
||||||
|
maxvel = vector.new(0.1,0.1,0.1),
|
||||||
|
minexptime = 0.5,
|
||||||
|
maxexptime = 0.5,
|
||||||
|
minsize = 2,
|
||||||
|
maxsize = 2,
|
||||||
|
attached = self.object,
|
||||||
|
collisiondetection = false,
|
||||||
|
vertical = false,
|
||||||
|
texture = "mobs_mc_arrow_particle.png",
|
||||||
|
glow = 1,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local closest_object
|
||||||
|
local closest_distance
|
||||||
|
|
||||||
|
if self._deflection_cooloff > 0 then
|
||||||
|
self._deflection_cooloff = self._deflection_cooloff - dtime
|
||||||
|
end
|
||||||
|
|
||||||
|
local spear_dir = self.object:get_velocity()
|
||||||
|
--create a raycast from the spear based on the velocity of the spear to deal with lag
|
||||||
|
local raycast = minetest.raycast(pos, vector.add(pos, vector.multiply(spear_dir, 0.1)), true, false)
|
||||||
|
for hitpoint in raycast do
|
||||||
|
if hitpoint.type == "object" then
|
||||||
|
-- find the closest object that is in the way of the spear
|
||||||
|
local ok = false
|
||||||
|
if hitpoint.ref:is_player() and enable_pvp then
|
||||||
|
ok = true
|
||||||
|
elseif not hitpoint.ref:is_player() and hitpoint.ref:get_luaentity() then
|
||||||
|
if (hitpoint.ref:get_luaentity().is_mob or hitpoint.ref:get_luaentity()._hittable_by_projectile) then
|
||||||
|
ok = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ok then
|
||||||
|
local dist = vector.distance(hitpoint.ref:get_pos(), pos)
|
||||||
|
if not closest_object or not closest_distance then
|
||||||
|
closest_object = hitpoint.ref
|
||||||
|
closest_distance = dist
|
||||||
|
elseif dist < closest_distance then
|
||||||
|
closest_object = hitpoint.ref
|
||||||
|
closest_distance = dist
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if closest_object then
|
||||||
|
local obj = closest_object
|
||||||
|
local is_player = obj:is_player()
|
||||||
|
local lua = obj:get_luaentity()
|
||||||
|
if obj == self._shooter and self._time_in_air > 1.02 or obj ~= self._shooter and (is_player or (lua and (lua.is_mob or lua._hittable_by_projectile))) then
|
||||||
|
if obj:get_hp() > 0 then
|
||||||
|
-- Check if there is no solid node between spear and object
|
||||||
|
local ray = minetest.raycast(self.object:get_pos(), obj:get_pos(), true)
|
||||||
|
for pointed_thing in ray do
|
||||||
|
if pointed_thing.type == "object" and pointed_thing.ref == closest_object then
|
||||||
|
-- Target reached! We can proceed now.
|
||||||
|
break
|
||||||
|
elseif pointed_thing.type == "node" then
|
||||||
|
local nn = minetest.get_node(minetest.get_pointed_thing_position(pointed_thing)).name
|
||||||
|
local def = minetest.registered_nodes[nn]
|
||||||
|
if (not def) or def.walkable then
|
||||||
|
-- There's a node in the way. Delete spear without damage
|
||||||
|
spawn_item(self, pos)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Punch target object but avoid hurting enderman.
|
||||||
|
if not lua or lua.name ~= "mobs_mc:enderman" then
|
||||||
|
if not self._in_player then
|
||||||
|
damage_particles(vector.add(pos, vector.multiply(self.object:get_velocity(), 0.1)), self._is_critical)
|
||||||
|
end
|
||||||
|
if mcl_burning.is_burning(self.object) then
|
||||||
|
mcl_burning.set_on_fire(obj, 5)
|
||||||
|
end
|
||||||
|
if not self._in_player and not self._blocked then
|
||||||
|
obj:punch(self.object, 1.0, {
|
||||||
|
full_punch_interval=1.0,
|
||||||
|
damage_groups={fleshy=self._damage},
|
||||||
|
}, self.object:get_velocity())
|
||||||
|
if obj:is_player() then
|
||||||
|
if not mcl_shields.is_blocking(obj) then
|
||||||
|
spawn_item(self, pos)
|
||||||
|
else
|
||||||
|
self._blocked = true
|
||||||
|
self.object:set_velocity(vector.multiply(self.object:get_velocity(), -0.25))
|
||||||
|
end
|
||||||
|
minetest.after(150, function()
|
||||||
|
spawn_item(self, pos)
|
||||||
|
end)
|
||||||
|
else
|
||||||
|
spawn_item(self, pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
if is_player then
|
||||||
|
if self._shooter and self._shooter:is_player() and not self._in_player and not self._blocked then
|
||||||
|
-- “Ding” sound for hitting another player
|
||||||
|
minetest.sound_play({name="mcl_bows_hit_player", gain=0.1}, {to_player=self._shooter:get_player_name()}, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if not self._in_player and not self._blocked then
|
||||||
|
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not obj:is_player() then
|
||||||
|
mcl_burning.extinguish(self.object)
|
||||||
|
if self._piercing == 0 then
|
||||||
|
spawn_item(self, pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Check for node collision
|
||||||
|
if self._lastpos.x~=nil and not self._stuck then
|
||||||
|
local def = minetest.registered_nodes[node.name]
|
||||||
|
local vel = self.object:get_velocity()
|
||||||
|
-- Spear has stopped in one axis, so it probably hit something.
|
||||||
|
-- This detection is a bit clunky, but sadly, MT does not offer a direct collision detection for us. :-(
|
||||||
|
if (math.abs(vel.x) < 0.0001) or (math.abs(vel.z) < 0.0001) or (math.abs(vel.y) < 0.00001) then
|
||||||
|
-- Check for the node to which the spear is pointing
|
||||||
|
local dir
|
||||||
|
if math.abs(vel.y) < 0.00001 then
|
||||||
|
if self._lastpos.y < pos.y then
|
||||||
|
dir = vector.new(0, 1, 0)
|
||||||
|
else
|
||||||
|
dir = vector.new(0, -1, 0)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
dir = minetest.facedir_to_dir(minetest.dir_to_facedir(minetest.yaw_to_dir(self.object:get_yaw()-YAW_OFFSET)))
|
||||||
|
end
|
||||||
|
self._stuckin = vector.add(dpos, dir)
|
||||||
|
local snode = minetest.get_node(self._stuckin)
|
||||||
|
local sdef = minetest.registered_nodes[snode.name]
|
||||||
|
|
||||||
|
-- If node is non-walkable, unknown or ignore, don't make spear stuck.
|
||||||
|
-- This causes a deflection in the engine.
|
||||||
|
if not sdef or sdef.walkable == false or snode.name == "ignore" then
|
||||||
|
self._stuckin = nil
|
||||||
|
if self._deflection_cooloff <= 0 then
|
||||||
|
-- Lose 1/3 of velocity on deflection
|
||||||
|
local newvel = vector.multiply(vel, 0.6667)
|
||||||
|
|
||||||
|
self.object:set_velocity(newvel)
|
||||||
|
-- Reset deflection cooloff timer to prevent many deflections happening in quick succession
|
||||||
|
self._deflection_cooloff = 1.0
|
||||||
|
end
|
||||||
|
else
|
||||||
|
|
||||||
|
-- Node was walkable, make spear stuck
|
||||||
|
self._stuck = true
|
||||||
|
self._stucktimer = 0
|
||||||
|
self._stuckrechecktimer = 0
|
||||||
|
|
||||||
|
self.object:set_velocity(vector.new(0, 0, 0))
|
||||||
|
self.object:set_acceleration(vector.new(0, 0, 0))
|
||||||
|
|
||||||
|
minetest.sound_play({name="mcl_bows_hit_other", gain=0.3}, {pos=self.object:get_pos(), max_hear_distance=16}, true)
|
||||||
|
|
||||||
|
if mcl_burning.is_burning(self.object) and snode.name == "mcl_tnt:tnt" then
|
||||||
|
tnt.ignite(self._stuckin)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Ignite Campfires
|
||||||
|
if mod_campfire and mcl_burning.is_burning(self.object) and minetest.get_item_group(snode.name, "campfire") ~= 0 then
|
||||||
|
mcl_campfires.light_campfire(self._stuckin)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Activate target
|
||||||
|
if mod_target and snode.name == "mcl_target:target_off" then
|
||||||
|
mcl_target.hit(self._stuckin, 1) --10 redstone ticks
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Push the button! Push, push, push the button!
|
||||||
|
if mod_button and minetest.get_item_group(node.name, "button") > 0 and minetest.get_item_group(node.name, "button_push_by_arrow") == 1 then
|
||||||
|
local bdir = minetest.wallmounted_to_dir(node.param2)
|
||||||
|
-- Check the button orientation
|
||||||
|
if vector.equals(vector.add(dpos, bdir), self._stuckin) then
|
||||||
|
mesecon.push_button(dpos, node)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif (def and def.liquidtype ~= "none") then
|
||||||
|
-- Slow down spear in liquids
|
||||||
|
local v = def.liquid_viscosity
|
||||||
|
if not v then
|
||||||
|
v = 0
|
||||||
|
end
|
||||||
|
--local old_v = self._viscosity
|
||||||
|
self._viscosity = v
|
||||||
|
local vpenalty = math.max(0.1, 0.98 - 0.1 * v)
|
||||||
|
if math.abs(vel.x) > 0.001 then
|
||||||
|
vel.x = vel.x * vpenalty
|
||||||
|
end
|
||||||
|
if math.abs(vel.z) > 0.001 then
|
||||||
|
vel.z = vel.z * vpenalty
|
||||||
|
end
|
||||||
|
self.object:set_velocity(vel)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update yaw
|
||||||
|
if not self._stuck then
|
||||||
|
local vel = self.object:get_velocity()
|
||||||
|
local yaw = minetest.dir_to_yaw(vel)+YAW_OFFSET
|
||||||
|
local pitch = dir_to_pitch(vel)
|
||||||
|
self.object:set_rotation({ x = 0, y = yaw, z = pitch })
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Update internal variable
|
||||||
|
self._lastpos = pos
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Force recheck of stuck spears when punched.
|
||||||
|
-- Otherwise, punching has no effect.
|
||||||
|
function SPEAR_ENTITY.on_punch(self)
|
||||||
|
if self._stuck then
|
||||||
|
self._stuckrechecktimer = STUCK_RECHECK_TIME
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SPEAR_ENTITY.get_staticdata(self)
|
||||||
|
local out = {
|
||||||
|
lastpos = self._lastpos,
|
||||||
|
startpos = self._startpos,
|
||||||
|
damage = self._damage,
|
||||||
|
is_critical = self._is_critical,
|
||||||
|
stuck = self._stuck,
|
||||||
|
stuckin = self._stuckin,
|
||||||
|
stuckin_player = self._in_player,
|
||||||
|
}
|
||||||
|
if self._stuck then
|
||||||
|
-- If _stucktimer is missing for some reason, assume the maximum
|
||||||
|
if not self._stucktimer then
|
||||||
|
self._stucktimer = SPEAR_TIMEOUT
|
||||||
|
end
|
||||||
|
out.stuckstarttime = minetest.get_gametime() - self._stucktimer
|
||||||
|
end
|
||||||
|
if self._shooter and self._shooter:is_player() then
|
||||||
|
out.shootername = self._shooter:get_player_name()
|
||||||
|
end
|
||||||
|
return minetest.serialize(out)
|
||||||
|
end
|
||||||
|
|
||||||
|
function SPEAR_ENTITY.on_activate(self, staticdata, dtime_s)
|
||||||
|
self._time_in_air = 1.0
|
||||||
|
local data = minetest.deserialize(staticdata)
|
||||||
|
if data then
|
||||||
|
self._stuck = data.stuck
|
||||||
|
if data.stuck then
|
||||||
|
if data.stuckstarttime then
|
||||||
|
-- First, check if the stuck spear is aleady past its life timer.
|
||||||
|
-- If yes, delete it.
|
||||||
|
self._stucktimer = minetest.get_gametime() - data.stuckstarttime
|
||||||
|
if self._stucktimer > SPEAR_TIMEOUT then
|
||||||
|
spawn_item(self, pos)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Perform a stuck recheck on the next step.
|
||||||
|
self._stuckrechecktimer = STUCK_RECHECK_TIME
|
||||||
|
|
||||||
|
self._stuckin = data.stuckin
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Get the remaining spear state
|
||||||
|
self._lastpos = data.lastpos
|
||||||
|
self._startpos = data.startpos
|
||||||
|
self._damage = data.damage
|
||||||
|
self._is_critical = data.is_critical
|
||||||
|
if data.shootername then
|
||||||
|
local shooter = minetest.get_player_by_name(data.shootername)
|
||||||
|
if shooter and shooter:is_player() then
|
||||||
|
self._shooter = shooter
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if data.stuckin_player then
|
||||||
|
spawn_item(self, pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.object:set_armor_groups({ immortal = 1 })
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_entity("vl_weaponry:spear_entity", SPEAR_ENTITY)
|
||||||
|
|
||||||
|
local spear_throw_power = 25
|
||||||
|
|
||||||
|
local spear_on_place = function(wear_divisor)
|
||||||
|
return function(itemstack, user, pointed_thing)
|
||||||
|
if pointed_thing.type == "node" then
|
||||||
|
-- Call on_rightclick if the pointed node defines it
|
||||||
|
local node = minetest.get_node(pointed_thing.under)
|
||||||
|
if user and not user:get_player_control().sneak then
|
||||||
|
if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
|
||||||
|
return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if minetest.is_protected(pointed_thing.under, user:get_player_name()) then
|
||||||
|
minetest.record_protection_violation(pointed_thing.under, user:get_player_name())
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local pos = user:get_pos()
|
||||||
|
pos.y = pos.y + 1.5
|
||||||
|
local dir = user:get_look_dir()
|
||||||
|
local yaw = user:get_look_horizontal()
|
||||||
|
local obj = minetest.add_entity({x=pos.x,y=pos.y,z=pos.z}, "vl_weaponry:spear_entity")
|
||||||
|
obj:set_velocity({x=dir.x*spear_throw_power, y=dir.y*spear_throw_power, z=dir.z*spear_throw_power})
|
||||||
|
obj:set_acceleration({x=0, y=-GRAVITY, z=0})
|
||||||
|
obj:set_yaw(yaw-math.pi/2)
|
||||||
|
obj:set_properties({textures = {itemstack:get_name()}})
|
||||||
|
local le = obj:get_luaentity()
|
||||||
|
le._shooter = user
|
||||||
|
le._source_object = user
|
||||||
|
le._damage = itemstack:get_definition()._mcl_spear_thrown_damage
|
||||||
|
le._is_critical = false
|
||||||
|
le._startpos = pos
|
||||||
|
le._collectable = true
|
||||||
|
le._itemstack = itemstack
|
||||||
|
minetest.sound_play("mcl_bows_bow_shoot", {pos=pos, max_hear_distance=16}, true)
|
||||||
|
if user and user:is_player() then
|
||||||
|
if obj:get_luaentity().player == "" then
|
||||||
|
obj:get_luaentity().player = user
|
||||||
|
end
|
||||||
|
-- obj:get_luaentity().node = shooter:get_inventory():get_stack("main", 1):get_name()
|
||||||
|
end
|
||||||
|
|
||||||
|
return ItemStack()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local uses = {
|
||||||
|
wood = 60,
|
||||||
|
stone = 132,
|
||||||
|
iron = 251,
|
||||||
|
gold = 33,
|
||||||
|
diamond = 1562,
|
||||||
|
netherite = 2031,
|
||||||
|
}
|
||||||
|
|
||||||
|
local SPEAR_RANGE = 4.5
|
||||||
|
|
||||||
|
--Hammers
|
||||||
|
minetest.register_tool("vl_weaponry:hammer_wood", {
|
||||||
|
description = S("Wooden Hammer"),
|
||||||
|
_tt_help = hammer_tt,
|
||||||
|
_doc_items_longdesc = hammer_longdesc,
|
||||||
|
_doc_items_usagehelp = hammer_use,
|
||||||
|
_doc_items_hidden = false,
|
||||||
|
inventory_image = "vl_tool_woodhammer.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
groups = { weapon=1, hammer=1, dig_speed_class=2, enchantability=15 },
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 1.2,
|
||||||
|
max_drop_level=1,
|
||||||
|
damage_groups = {fleshy=4},
|
||||||
|
punch_attack_uses = 60,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "group:wood",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
pickaxey = { speed = 1, level = 1, uses = 60 },
|
||||||
|
shovely = { speed = 1, level = 2, uses = 60 }
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:hammer_stone", {
|
||||||
|
description = S("Stone Hammer"),
|
||||||
|
_tt_help = hammer_tt,
|
||||||
|
_doc_items_longdesc = hammer_longdesc,
|
||||||
|
_doc_items_usagehelp = hammer_use,
|
||||||
|
inventory_image = "vl_tool_stonehammer.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
groups = { weapon=1, hammer=1, dig_speed_class=2, enchantability=5 },
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 1.3,
|
||||||
|
max_drop_level=3,
|
||||||
|
damage_groups = {fleshy=5},
|
||||||
|
punch_attack_uses = 132,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "group:cobble",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
pickaxey = { speed = 2, level = 3, uses = 132 },
|
||||||
|
shovely = { speed = 2, level = 3, uses = 132 }
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:hammer_iron", {
|
||||||
|
description = S("Iron Hammer"),
|
||||||
|
_tt_help = hammer_tt,
|
||||||
|
_doc_items_longdesc = hammer_longdesc,
|
||||||
|
_doc_items_usagehelp = hammer_use,
|
||||||
|
inventory_image = "vl_tool_steelhammer.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
groups = { weapon=1, hammer=1, dig_speed_class=2, enchantability=14 },
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 1.2,
|
||||||
|
max_drop_level=4,
|
||||||
|
damage_groups = {fleshy=6},
|
||||||
|
punch_attack_uses = 251,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "mcl_core:iron_ingot",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
pickaxey = { speed = 3, level = 4, uses = 251 },
|
||||||
|
shovely = { speed = 3, level = 4, uses = 251 }
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:hammer_gold", {
|
||||||
|
description = S("Golden Hammer"),
|
||||||
|
_tt_help = hammer_tt,
|
||||||
|
_doc_items_longdesc = hammer_longdesc,
|
||||||
|
_doc_items_usagehelp = hammer_use,
|
||||||
|
inventory_image = "vl_tool_goldhammer.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
groups = { weapon=1, hammer=1, dig_speed_class=2, enchantability=22 },
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 1.0,
|
||||||
|
max_drop_level=2,
|
||||||
|
damage_groups = {fleshy=5},
|
||||||
|
punch_attack_uses = 33,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "mcl_core:gold_ingot",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
pickaxey = { speed = 8, level = 4, uses = 33 },
|
||||||
|
shovely = { speed = 8, level = 4, uses = 33 }
|
||||||
|
},
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:hammer_diamond", {
|
||||||
|
description = S("Diamond Hammer"),
|
||||||
|
_tt_help = hammer_tt,
|
||||||
|
_doc_items_longdesc = hammer_longdesc,
|
||||||
|
_doc_items_usagehelp = hammer_use,
|
||||||
|
inventory_image = "vl_tool_diamondhammer.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
groups = { weapon=1, hammer=1, dig_speed_class=2, enchantability=10 },
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 1.0,
|
||||||
|
max_drop_level=5,
|
||||||
|
damage_groups = {fleshy=7},
|
||||||
|
punch_attack_uses = 1562,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "mcl_core:diamond",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
pickaxey = { speed = 4, level = 5, uses = 1562 },
|
||||||
|
pickaxey = { speed = 4, level = 5, uses = 1562 }
|
||||||
|
},
|
||||||
|
_mcl_upgradable = true,
|
||||||
|
_mcl_upgrade_item = "vl_weaponry:hammer_netherite"
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:hammer_netherite", {
|
||||||
|
description = S("Netherite Hammer"),
|
||||||
|
_tt_help = hammer_tt,
|
||||||
|
_doc_items_longdesc = hammer_longdesc,
|
||||||
|
_doc_items_usagehelp = hammer_use,
|
||||||
|
inventory_image = "vl_tool_netheritehammer.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
groups = { weapon=1, hammer=1, dig_speed_class=2, enchantability=10, fire_immune=1 },
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 1.0,
|
||||||
|
max_drop_level=5,
|
||||||
|
damage_groups = {fleshy=9},
|
||||||
|
punch_attack_uses = 2031,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "mcl_nether:netherite_ingot",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
pickaxey = { speed = 6, level = 6, uses = 2031 },
|
||||||
|
shovely = { speed = 6, level = 6, uses = 2031 }
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
--Spears
|
||||||
|
minetest.register_tool("vl_weaponry:spear_wood", {
|
||||||
|
description = S("Wooden Spear"),
|
||||||
|
_tt_help = spear_tt,
|
||||||
|
_doc_items_longdesc = spear_longdesc,
|
||||||
|
_doc_items_usagehelp = spear_use,
|
||||||
|
_doc_items_hidden = false,
|
||||||
|
inventory_image = "vl_tool_woodspear.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
on_place = spear_on_place(uses.wood),
|
||||||
|
on_secondary_use = spear_on_place(uses.wood),
|
||||||
|
groups = { weapon=1, spear=1, dig_speed_class=2, enchantability=15 },
|
||||||
|
range = SPEAR_RANGE,
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 0.75,
|
||||||
|
max_drop_level=1,
|
||||||
|
damage_groups = {fleshy=3},
|
||||||
|
punch_attack_uses = 60,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "group:wood",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
swordy = { speed = 2, level = 1, uses = 60 },
|
||||||
|
swordy_cobweb = { speed = 2, level = 1, uses = 60 }
|
||||||
|
},
|
||||||
|
_mcl_spear_thrown_damage = 5,
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:spear_stone", {
|
||||||
|
description = S("Stone Spear"),
|
||||||
|
_tt_help = spear_tt,
|
||||||
|
_doc_items_longdesc = spear_longdesc,
|
||||||
|
_doc_items_usagehelp = spear_use,
|
||||||
|
inventory_image = "vl_tool_stonespear.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
on_place = spear_on_place(uses.stone),
|
||||||
|
on_secondary_use = spear_on_place(uses.stone),
|
||||||
|
groups = { weapon=1, spear=1, dig_speed_class=2, enchantability=5 },
|
||||||
|
range = SPEAR_RANGE,
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 0.75,
|
||||||
|
max_drop_level=3,
|
||||||
|
damage_groups = {fleshy=4},
|
||||||
|
punch_attack_uses = 132,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "group:cobble",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
swordy = { speed = 2, level = 1, uses = 132 },
|
||||||
|
swordy_cobweb = { speed = 2, level = 1, uses = 132 }
|
||||||
|
},
|
||||||
|
_mcl_spear_thrown_damage = 6,
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:spear_iron", {
|
||||||
|
description = S("Iron Spear"),
|
||||||
|
_tt_help = spear_tt,
|
||||||
|
_doc_items_longdesc = spear_longdesc,
|
||||||
|
_doc_items_usagehelp = spear_use,
|
||||||
|
inventory_image = "vl_tool_steelspear.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
on_place = spear_on_place(uses.iron),
|
||||||
|
on_secondary_use = spear_on_place(uses.iron),
|
||||||
|
groups = { weapon=1, spear=1, dig_speed_class=2, enchantability=14 },
|
||||||
|
range = SPEAR_RANGE,
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 0.75,
|
||||||
|
max_drop_level=4,
|
||||||
|
damage_groups = {fleshy=5},
|
||||||
|
punch_attack_uses = 251,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "mcl_core:iron_ingot",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
swordy = { speed = 2, level = 1, uses = 251 },
|
||||||
|
swordy_cobweb = { speed = 2, level = 1, uses = 251 }
|
||||||
|
},
|
||||||
|
_mcl_spear_thrown_damage = 7,
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:spear_gold", {
|
||||||
|
description = S("Golden Spear"),
|
||||||
|
_tt_help = spear_tt,
|
||||||
|
_doc_items_longdesc = spear_longdesc,
|
||||||
|
_doc_items_usagehelp = spear_use,
|
||||||
|
inventory_image = "vl_tool_goldspear.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
on_place = spear_on_place(uses.gold),
|
||||||
|
on_secondary_use = spear_on_place(uses.gold),
|
||||||
|
groups = { weapon=1, spear=1, dig_speed_class=2, enchantability=22 },
|
||||||
|
range = SPEAR_RANGE,
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 0.75,
|
||||||
|
max_drop_level=2,
|
||||||
|
damage_groups = {fleshy=3},
|
||||||
|
punch_attack_uses = 33,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "mcl_core:gold_ingot",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
swordy = { speed = 2, level = 1, uses = 33 },
|
||||||
|
swordy_cobweb = { speed = 2, level = 1, uses = 33 }
|
||||||
|
},
|
||||||
|
_mcl_spear_thrown_damage = 5,
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:spear_diamond", {
|
||||||
|
description = S("Diamond Spear"),
|
||||||
|
_tt_help = spear_tt,
|
||||||
|
_doc_items_longdesc = spear_longdesc,
|
||||||
|
_doc_items_usagehelp = spear_use,
|
||||||
|
inventory_image = "vl_tool_diamondspear.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
on_place = spear_on_place(uses.diamond),
|
||||||
|
on_secondary_use = spear_on_place(uses.diamond),
|
||||||
|
groups = { weapon=1, spear=1, dig_speed_class=2, enchantability=10 },
|
||||||
|
range = SPEAR_RANGE,
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 0.75,
|
||||||
|
max_drop_level=5,
|
||||||
|
damage_groups = {fleshy=6},
|
||||||
|
punch_attack_uses = 1562,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "mcl_core:diamond",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
swordy = { speed = 2, level = 1, uses = 1562 },
|
||||||
|
swordy_cobweb = { speed = 2, level = 1, uses = 1562 }
|
||||||
|
},
|
||||||
|
_mcl_spear_thrown_damage = 8,
|
||||||
|
_mcl_upgradable = true,
|
||||||
|
_mcl_upgrade_item = "vl_weaponry:spear_netherite"
|
||||||
|
})
|
||||||
|
minetest.register_tool("vl_weaponry:spear_netherite", {
|
||||||
|
description = S("Netherite Spear"),
|
||||||
|
_tt_help = spear_tt,
|
||||||
|
_doc_items_longdesc = spear_longdesc,
|
||||||
|
_doc_items_usagehelp = spear_use,
|
||||||
|
inventory_image = "vl_tool_netheritespear.png",
|
||||||
|
wield_scale = wield_scale,
|
||||||
|
on_place = spear_on_place(uses.netherite),
|
||||||
|
on_secondary_use = spear_on_place(uses.netherite),
|
||||||
|
groups = { weapon=1, spear=1, dig_speed_class=2, enchantability=10, fire_immune=1 },
|
||||||
|
range = SPEAR_RANGE,
|
||||||
|
tool_capabilities = {
|
||||||
|
full_punch_interval = 0.75,
|
||||||
|
max_drop_level=5,
|
||||||
|
damage_groups = {fleshy=8},
|
||||||
|
punch_attack_uses = 2031,
|
||||||
|
},
|
||||||
|
sound = { breaks = "default_tool_breaks" },
|
||||||
|
_repair_material = "mcl_nether:netherite_ingot",
|
||||||
|
_mcl_toollike_wield = true,
|
||||||
|
_mcl_diggroups = {
|
||||||
|
swordy = { speed = 2, level = 1, uses = 2031 },
|
||||||
|
swordy_cobweb = { speed = 2, level = 1, uses = 2031 }
|
||||||
|
},
|
||||||
|
_mcl_spear_thrown_damage = 12,
|
||||||
|
})
|
|
@ -0,0 +1,3 @@
|
||||||
|
name = vl_weaponry
|
||||||
|
author = Herowl
|
||||||
|
depends = mcl_sounds, mcl_init, mcl_bows
|
|
@ -36,7 +36,11 @@ else
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
tsm_railcorridors.carts = { "mcl_minecarts:chest_minecart" }
|
tsm_railcorridors.carts = {
|
||||||
|
"mcl_minecarts:minecart", "mcl_minecarts:minecart",
|
||||||
|
"mcl_minecarts:chest_minecart", "mcl_minecarts:chest_minecart",
|
||||||
|
"mcl_minecarts:tnt_minecart"
|
||||||
|
}
|
||||||
|
|
||||||
-- This is called after a spawner has been placed by the game.
|
-- This is called after a spawner has been placed by the game.
|
||||||
-- Use this to properly set up the metadata and stuff.
|
-- Use this to properly set up the metadata and stuff.
|
||||||
|
@ -54,10 +58,12 @@ end
|
||||||
function tsm_railcorridors.on_construct_cart(_, cart, pr_carts)
|
function tsm_railcorridors.on_construct_cart(_, cart, pr_carts)
|
||||||
local l = cart:get_luaentity()
|
local l = cart:get_luaentity()
|
||||||
local inv = mcl_entity_invs.load_inv(l,27)
|
local inv = mcl_entity_invs.load_inv(l,27)
|
||||||
|
if inv then -- otherwise probably not a chest minecart
|
||||||
local items = tsm_railcorridors.get_treasures(pr_carts)
|
local items = tsm_railcorridors.get_treasures(pr_carts)
|
||||||
mcl_loot.fill_inventory(inv, "main", items, pr_carts)
|
mcl_loot.fill_inventory(inv, "main", items, pr_carts)
|
||||||
mcl_entity_invs.save_inv(l)
|
mcl_entity_invs.save_inv(l)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Fallback function. Returns a random treasure. This function is called for chests
|
-- Fallback function. Returns a random treasure. This function is called for chests
|
||||||
-- only if the Treasurer mod is not found.
|
-- only if the Treasurer mod is not found.
|
||||||
|
|
|
@ -397,7 +397,9 @@ end
|
||||||
-- This is a workaround thanks to the fact that minetest.add_entity is unreliable as fuck
|
-- This is a workaround thanks to the fact that minetest.add_entity is unreliable as fuck
|
||||||
-- See: https://github.com/minetest/minetest/issues/4759
|
-- See: https://github.com/minetest/minetest/issues/4759
|
||||||
-- FIXME: Kill this horrible hack with fire as soon you can.
|
-- FIXME: Kill this horrible hack with fire as soon you can.
|
||||||
local function RecheckCartHack(params)
|
local RecheckCartHack = nil
|
||||||
|
if not minetest.features.random_state_restore then -- proxy for minetest > 5.9.0, this feature will not be removed
|
||||||
|
RecheckCartHack = function(params)
|
||||||
local pos = params[1]
|
local pos = params[1]
|
||||||
local cart_id = params[2]
|
local cart_id = params[2]
|
||||||
-- Find cart
|
-- Find cart
|
||||||
|
@ -412,6 +414,7 @@ local function RecheckCartHack(params)
|
||||||
end
|
end
|
||||||
minetest.log("info", "[tsm_railcorridors] Cart spawn FAILED: "..minetest.pos_to_string(pos))
|
minetest.log("info", "[tsm_railcorridors] Cart spawn FAILED: "..minetest.pos_to_string(pos))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- Try to place a cobweb.
|
-- Try to place a cobweb.
|
||||||
-- pos: Position of cobweb
|
-- pos: Position of cobweb
|
||||||
|
@ -935,13 +938,17 @@ local function spawn_carts()
|
||||||
-- See <https://github.com/minetest/minetest/issues/4759>
|
-- See <https://github.com/minetest/minetest/issues/4759>
|
||||||
local cart_id = tsm_railcorridors.carts[cart_type]
|
local cart_id = tsm_railcorridors.carts[cart_type]
|
||||||
minetest.log("info", "[tsm_railcorridors] Cart spawn attempt: "..minetest.pos_to_string(cpos))
|
minetest.log("info", "[tsm_railcorridors] Cart spawn attempt: "..minetest.pos_to_string(cpos))
|
||||||
minetest.add_entity(cpos, cart_id)
|
local obj = minetest.add_entity(cpos, cart_id)
|
||||||
|
|
||||||
-- This checks if the cart is actually spawned, it's a giant hack!
|
-- This checks if the cart is actually spawned, it's a giant hack!
|
||||||
-- Note that the callback function is also called there.
|
-- Note that the callback function is also called there.
|
||||||
-- TODO: Move callback function to this position when the
|
-- TODO: Move callback function to this position when the
|
||||||
-- minetest.add_entity bug has been fixed (supposedly in 5.9.0?)
|
-- minetest.add_entity bug has been fixed (supposedly in 5.9.0?)
|
||||||
|
if RecheckCartHack then
|
||||||
minetest.after(3, RecheckCartHack, {cpos, cart_id})
|
minetest.after(3, RecheckCartHack, {cpos, cart_id})
|
||||||
|
else
|
||||||
|
tsm_railcorridors.on_construct_cart(cpos, obj, pr_carts)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
carts_table = {}
|
carts_table = {}
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
bonemeal = {
|
||||||
|
item_list = {
|
||||||
|
bucket_water = "mcl_buckets:bucket_water",
|
||||||
|
bucket_empty = "mcl_buckets:bucket_empty",
|
||||||
|
dirt = "mcl_core:dirt",
|
||||||
|
torch = "mcl_torches:torch",
|
||||||
|
coral = "mcl_ocean:dead_horn_coral_block"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function bonemeal:on_use(pos, strength, node)
|
||||||
|
-- Fake itemstack for bone meal
|
||||||
|
local itemstack = ItemStack("mcl_bone_meal:bone_meal")
|
||||||
|
|
||||||
|
local pointed_thing = {
|
||||||
|
above = pos,
|
||||||
|
under = vector.offset(pos, 0, -1, 0)
|
||||||
|
}
|
||||||
|
mcl_bone_meal.use_bone_meal(itemstack, nil, pointed_thing)
|
||||||
|
end
|
||||||
|
|
||||||
|
function bonemeal:is_creative(player_name)
|
||||||
|
return minetest.is_creative_enabled(player_name)
|
||||||
|
end
|
||||||
|
|
||||||
|
function bonemeal:add_deco(list)
|
||||||
|
minetest.log("TODO: implement bonemeal:add_deco("..dump(list).."..)")
|
||||||
|
for i = 1,#list do
|
||||||
|
local item = list[i]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_alias("bonemeal:bone", "mcl_mobitems:bone")
|
|
@ -0,0 +1,4 @@
|
||||||
|
name = bonemeal
|
||||||
|
author = teknomunk
|
||||||
|
description = Compatibility shim for WorldEdit-Additions bonemeal support
|
||||||
|
depends = mcl_bone_meal, mcl_mobitems, mcl_flowers
|
|
@ -30,17 +30,5 @@ for _, action in pairs({"grant", "revoke"}) do
|
||||||
if priv == "fly" then
|
if priv == "fly" then
|
||||||
meta:set_int("mcl_privs:fly_changed", 1)
|
meta:set_int("mcl_privs:fly_changed", 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
--[[
|
|
||||||
so e.g. hackers who have been revoked of the interact privilege
|
|
||||||
will not automatically get the interact privilege through the mcl shields code back
|
|
||||||
]]
|
|
||||||
if priv == "interact" then
|
|
||||||
if action == "revoke" then
|
|
||||||
meta:set_int("mcl_privs:interact_revoked", 1)
|
|
||||||
else
|
|
||||||
meta:set_int("mcl_privs:interact_revoked", 0)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
end)
|
||||||
end
|
end
|
|
@ -752,9 +752,10 @@ end, -200)
|
||||||
minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
|
minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage)
|
||||||
-- attack reach limit
|
-- attack reach limit
|
||||||
if hitter and hitter:is_player() then
|
if hitter and hitter:is_player() then
|
||||||
|
local weapon = hitter:get_wielded_item()
|
||||||
local player_pos = player:get_pos()
|
local player_pos = player:get_pos()
|
||||||
local hitter_pos = hitter:get_pos()
|
local hitter_pos = hitter:get_pos()
|
||||||
if vector.distance(player_pos, hitter_pos) > 3 then
|
if vector.distance(player_pos, hitter_pos) > (weapon:get_definition().range or 3) then
|
||||||
damage = 0
|
damage = 0
|
||||||
return damage
|
return damage
|
||||||
end
|
end
|
||||||
|
|
|
@ -45,6 +45,9 @@ mcl_disabled_structures (Disabled structures) string
|
||||||
# Comma separated list of disabled event names
|
# Comma separated list of disabled event names
|
||||||
mcl_disabled_events (Disabled events) string
|
mcl_disabled_events (Disabled events) string
|
||||||
|
|
||||||
|
# Control the relative plant growth speed (default: 1)
|
||||||
|
vl_plant_growth (Plant growth factor) float 1.0 0 100
|
||||||
|
|
||||||
[Players]
|
[Players]
|
||||||
# If enabled, players respawn at the bed they last lay on instead of normal
|
# If enabled, players respawn at the bed they last lay on instead of normal
|
||||||
# spawn.
|
# spawn.
|
||||||
|
|
Before Width: | Height: | Size: 244 B After Width: | Height: | Size: 244 B |
After Width: | Height: | Size: 189 B |
After Width: | Height: | Size: 183 B |
After Width: | Height: | Size: 213 B |
After Width: | Height: | Size: 157 B |
After Width: | Height: | Size: 255 B |
After Width: | Height: | Size: 201 B |
After Width: | Height: | Size: 210 B |
After Width: | Height: | Size: 171 B |
After Width: | Height: | Size: 228 B |
After Width: | Height: | Size: 144 B |
After Width: | Height: | Size: 215 B |
After Width: | Height: | Size: 156 B |