Add vine growth

This commit is contained in:
Wuzzy 2023-02-19 00:47:39 +01:00
parent 185711d248
commit 063677a511
6 changed files with 741 additions and 2 deletions

View File

@ -312,9 +312,13 @@ for _, npc_type_table in pairs(npc_types) do
elseif iname == "rp_farming:cotton_1" then elseif iname == "rp_farming:cotton_1" then
if npc_type == "farmer" then if npc_type == "farmer" then
say(S("Did you know cotton seed not only grow on dirt, but also on sand? But it still needs water."), name) say(S("Did you know cotton seed not only grow on dirt, but also on sand? But it still needs water."), name)
elseif npc_type == "carpenter" then
say(S("If you have grown a cotton plant, try using scissors to perform a precise cut."), name)
else else
say(S("Every kid knows seeds need soil, water and sunlight."), name) say(S("Every kid knows seeds need soil, water and sunlight."), name)
end end
elseif iname == "rp_farming:cotton" then
say(S("This can be used to make cotton bales.", name))
elseif iname == "rp_default:book" then elseif iname == "rp_default:book" then
say(S("A truly epic story!"), name) say(S("A truly epic story!"), name)
elseif iname == "rp_default:pearl" then elseif iname == "rp_default:pearl" then
@ -421,6 +425,14 @@ for _, npc_type_table in pairs(npc_types) do
else else
say(S("Algae grow underwater in different heights."), name) say(S("Algae grow underwater in different heights."), name)
end end
elseif iname == "rp_default:vine" then
if npc_type == "farmer" then
say(S("Place it at the ceiling and watch it grow."), name)
elseif npc_type == "carpenter" then
say(S("If you want the vine to stops growing, make a precise cut using scissors."), name)
else
say(S("It's climbing time!"), name)
end
elseif iname == "rp_default:dirt" then elseif iname == "rp_default:dirt" then
if npc_type == "farmer" then if npc_type == "farmer" then
say(S("Many wild plants as well as wheat and cotton grow on dirt, but they grow better when it's fertilized."), name) say(S("Many wild plants as well as wheat and cotton grow on dirt, but they grow better when it's fertilized."), name)

View File

@ -0,0 +1,635 @@
local S = minetest.get_translator("rp_boats")
local STATE_INIT = 0 -- initial state (after spawning)
local STATE_FALLING = 1 -- free fall
local STATE_SINKING = 2 -- inside a liquid and sinking
local STATE_FLOATING = 3 -- floating on liquid, stable
local STATE_FLOATING_UP = 4 -- floating on liquid, correcting upwards
local STATE_FLOATING_DOWN = 5 -- floating on liquid, correcting downwards
local STATE_STUCK = 6 -- disable movement
local GRAVITY = tonumber(minetest.settings:get("movement_gravity")) or 9.81 --gravity
local LIQUID_SINK_SPEED = 1 -- how fast the boat will sink inside a liquid
local FLOAT_UP_SPEED = 0.5 -- how fast the boat will move upwards if slightly below liquid surface
local FLOAT_DOWN_SPEED = -0.5 -- how fast the boat will move downwards if slightly above liquid surface
local DRAG_FACTOR = 0.1 -- How fast the boat will slow down
local DRAG_FACTOR_HIGH = 1 -- Higher slow down rate when not swimming/floating
local DRAG_CONSTANT = 0.01
local DRAG_CONSTANT_HIGH = 0.1
local CHECK_NODES_AFTER_LANDING = 10 -- number of water nodes to check above boat if it has gotten deep
-- below the water surface after falling fast
local SNEAK_DETACHES = true -- if true, sneak key will detach player
local BOOST_TIME = 1.25
local is_water = function(nodename)
local def = minetest.registered_nodes[nodename]
if not def then
return false
end
if def.liquidtype ~= "none" and minetest.get_item_group(nodename, "water") ~= 0 then
return true, def.liquidtype
end
return false
end
local set_driver = function(self, driver, orig_collisionbox)
self._driver = driver
local colbox = table.copy(orig_collisionbox)
-- Add player height to boat collisionbox top Y
-- so the player will also collide.
local dcolbox = driver:get_properties().collisionbox
colbox[5] = colbox[5] + (dcolbox[5] - dcolbox[2])
local props = self.object:get_properties()
props.collisionbox = colbox
self.object:set_properties(props)
end
local unset_driver = function(self, orig_collisionbox)
self._driver = nil
local colbox = table.copy(orig_collisionbox)
local props = self.object:get_properties()
props.collisionbox = colbox
self.object:set_properties(props)
end
-- Returns false if not enough space to mount boat at pos
local check_space = function(pos, player, side, top)
local tiny = 0.01
local side = side - tiny
local bottom = -tiny
local top = top + tiny
local offsets = {
-- Format: { Xmin, Ymin, Zmin, Xmax, Ymax, Zmax }
-- middle vertical ray
{ 0, bottom, 0, 0, top, 0 },
-- for testing the 4 vertical edges of the collisionbox
{ -side, bottom, -side, -side, top, -side },
{ -side, bottom, side, -side, top, side },
{ side, bottom, -side, side, top, -side },
{ side, bottom, side, side, top, side },
}
-- Finally check the rays
for i=1, #offsets do
local off_start = vector.new(offsets[i][1], offsets[i][2], offsets[i][3])
local off_end = vector.new(offsets[i][4], offsets[i][5], offsets[i][6])
local ray_start = vector.add(pos, off_start)
local ray_end = vector.add(pos, off_end)
local ray = minetest.raycast(ray_start, ray_end, false, false)
local on_ground_only = true
local collide = false
while true do
local thing = ray:next()
if not thing then
break
end
if thing.type == "node" then
local node = minetest.get_node(thing.under)
local def = minetest.registered_nodes[node.name]
if def and def.walkable then
return false
end
end
end
end
return true
end
-- detaches driver of boat 'self'.
-- assumes that the boat has an active driver
local detach_driver = function(self, detach_offset_y)
local driver = self._driver
driver:set_detach()
-- Put driver slightly above the boat
local dpos = vector.add(vector.new(0, detach_offset_y, 0), self.object:get_pos())
minetest.after(0.1, function(param)
if not param.driver or not param.driver:is_player() then
return
end
param.driver:set_pos(param.pos)
end, {driver=driver, pos=dpos})
end
local register_boat = function(name, def)
local itemstring = "rp_boats:"..name
if not def.attach_offset then
def.attach_offset = {x=0, y=0, z=0}
end
if not def.float_offset then
def.float_offset = 0
end
minetest.register_entity(itemstring, {
physical = true,
collide_with_objects = true,
visual = "mesh",
collisionbox = def.collisionbox,
selectionbox = def.selectionbox,
textures = def.textures,
mesh = def.mesh,
hp_max = def.hp_max or 4,
_state = STATE_INIT,
_driver = nil,
_speed = 0,
_boost_timer = BOOST_TIME,
on_activate = function(self, staticdata, dtime_s)
local data = minetest.deserialize(staticdata)
if data then
self._state = data._state or STATE_FALLING
self._speed = data._speed or 0
end
end,
get_staticdata = function(self)
local data = {
_state = self._state,
_speed = self._speed,
}
return minetest.serialize(data)
end,
on_step = function(self, dtime, moveresult)
local mypos_precise = self.object:get_pos()
local mypos = table.copy(mypos_precise)
mypos.y = math.floor(mypos.y)
local mynode = minetest.get_node(mypos)
local mydef = minetest.registered_nodes[mynode.name]
local mypos_below = vector.add(mypos, {x=0,y=-1,z=0})
local mynode_below = minetest.get_node(mypos_below)
local mydef_below = minetest.registered_nodes[mynode_below.name]
local mypos_above = vector.add(mypos, {x=0,y=1,z=0})
local mynode_above = minetest.get_node(mypos_above)
local mydef_above = minetest.registered_nodes[mynode_above.name]
local mypos_above2 = vector.add(mypos, {x=0,y=2,z=0})
local mynode_above2 = minetest.get_node(mypos_above2)
local mydef_above2 = minetest.registered_nodes[mynode_above2.name]
local curvel = self.object:get_velocity()
local v = curvel * math.sign(self._speed)
self._speed = math.sqrt(v.x ^ 2 + v.z ^ 2)
if self._boost_timer > 0 then
self._boost_timer = self._boost_timer - dtime
end
-- Update boat state (for Y movement)
if mydef and mydef_below and mydef_above then
local above2_water, a2lt = is_water(mynode_above2.name)
local above_water, alt = is_water(mynode_above.name)
local here_water, hlt = is_water(mynode.name)
local below_water, blt = is_water(mynode_below.name)
if here_water or below_water then
local water_y -- y of water surface
local tlt
if above2_water then
water_y = mypos_above2.y
tlt = a2lt
elseif above_water then
water_y = mypos_above.y
tlt = alt
elseif here_water then
water_y = mypos.y
tlt = hlt
elseif below_water then
water_y = mypos_below.y
tlt = blt
end
if tlt == "flowing" then
water_y = water_y - 0.5
end
local ydiff = mypos_precise.y - (water_y + 1) -- y difference between boat and water surface
local yvel = 0
local TOL = 0.01 -- tolerance
--[[ Special check for when boat got into water after
falling. Checks for a water surface
above and teleport the node back to surface if it exists.
This is because if the boat fell on the water at a high
speed, it might have "passed" the water surface so
the chance of sinking is pretty high.
This code should (mostly) ensure that boats will
land on the surface of the water rather than sinking if falling
into at high speed.
If the boat was ULTRA fast, the boat might *not* teleport
to surface because it was too deep below the surface and we only
check for a limited number of nodes. This is acceptable tho.
Params:
* self: Boat object
* pos: Boat pos
Returns:
* true if was teleported to water surface, false otherwise ]]
local function land_on_water(self, pos)
-- Boat must've been in falling state before
-- for the check to matter at all.
if self._state == STATE_FALLING then
-- Boat was falling, this implies we might "land" on water
local check_pos = table.copy(pos)
local float = false
local offset = 0
-- Check for nodes above the boat
for k=1,CHECK_NODES_AFTER_LANDING do
offset = k
check_pos.y = check_pos.y + 1
local cnode = minetest.get_node(check_pos)
if not is_water(cnode.name) then
-- Non-water node found! We will teleport
float = true
break
end
end
if float then
-- Teleport boat to surface
local newpos = self.object:get_pos()
newpos.y = newpos.y + offset
self.object:set_pos(newpos)
-- Note: The caller still needs to update boat state manually
return true
end
end
return false
end
-- Update boat state
if above_water and (alt == "source" or above2_water) then
-- Sink if in water, float if boat has landed on water
if land_on_water(self, mypos) then
self._STATE = STATE_FLOATING
else
self._state = STATE_SINKING
end
-- Adjust boat Y position up/down when close to the water surface
elseif ydiff < def.float_max and ydiff > def.float_offset + TOL then
self._state = STATE_FLOATING_DOWN
elseif ydiff > def.float_min and ydiff < def.float_offset - TOL then
self._state = STATE_FLOATING_UP
-- Boat is at water surface, no Y adjustment needed (this is the "normal" floating state)
elseif ydiff > def.float_offset - TOL and ydiff < def.float_offset + TOL then
self._state = STATE_FLOATING
elseif ydiff < def.float_min then
-- Sink if in water, float if boat has landed on water
if land_on_water(self, mypos) then
self._state = STATE_FLOATING
else
self._state = STATE_SINKING
end
else
self._state = STATE_FALLING
end
else
self._state = STATE_FALLING
end
else
-- Should only happen if boat is inside unknown nodes
self._state = STATE_STUCK
end
-- Boat controls
local horvel = {x=0, y=0, z=0}
local vertvel = {x=0, y=0, z=0}
local vertacc = {x=0, y=0, z=0}
local yaw = self.object:get_yaw()
local v = self._speed
local moved = false
if self._driver then
if not self._driver:is_player() then
unset_driver(self, def.collisionbox)
else
-- Read player controls
local ctrl = self._driver:get_player_control()
-- Sneak = detach
if SNEAK_DETACHES and ctrl.sneak then
detach_driver(self, def.detach_offset_y)
end
-- Left/right = Rotate left/right
if ctrl.left and not ctrl.right then
yaw = yaw + def.yaw_change_rate * dtime
self.object:set_yaw(yaw)
elseif ctrl.right and not ctrl.left then
yaw = yaw - def.yaw_change_rate * dtime
self.object:set_yaw(yaw)
end
local floating = self._state == STATE_FLOATING or self._state == STATE_FLOATING_UP or self._state == STATE_FLOATING_DOWN
do
-- Up = speed up
if ctrl.up and not ctrl.down then
if floating then
v = math.min(def.max_speed, v + def.speed_change_rate * dtime)
moved = true
elseif self._boost_timer <= 0 then
v = def.max_speed
moved = true
end
-- Down = slow down
elseif ctrl.down and not ctrl.up then
v = math.max(-def.max_speed, v - def.speed_change_rate * dtime)
moved = true
end
end
end
end
-- Slow down boat if not moved by driver
if moved then
self._boost_timer = BOOST_TIME
else
local f, c
if self._state ~= STATE_FLOATING and self._state ~= STATE_FLOATING_UP and self._state ~= STATE_FLOATING_DOWN then
-- Higher slow down rate when not floating on liquid
f = DRAG_FACTOR_HIGH
c = DRAG_CONSTANT_HIGH
else
f = DRAG_FACTOR
c = DRAG_CONSTANT
end
local drag = dtime * math.sign(v) * (c + f * v * v)
if math.abs(v) <= math.abs(drag) then
v = 0
else
v = v - drag
end
end
if math.abs(v) < 0.001 then
v = 0
end
self._speed = v
local get_horvel = function(v, yaw)
local x = -math.sin(yaw) * v
local z = math.cos(yaw) * v
return {x=x, y=0, z=z}
end
horvel = get_horvel(v, yaw)
do
if self._state == STATE_FALLING then
vertacc = {x=0, y=-GRAVITY, z=0}
vertvel = {x=0, y=curvel.y, z=0}
elseif self._state == STATE_SINKING then
vertacc = {x=0, y=0, z=0}
vertvel = {x=0, y=-LIQUID_SINK_SPEED, z=0}
elseif self._state == STATE_STUCK then
vertacc = {x=0, y=0, z=0}
vertvel = {x=0, y=0, z=0}
elseif self._state == STATE_FLOATING then
vertacc = {x=0, y=0, z=0}
vertvel = {x=0, y=0, z=0}
elseif self._state == STATE_FLOATING_UP then
vertacc = {x=0, y=0, z=0}
vertvel = {x=0, y=FLOAT_UP_SPEED, z=0}
elseif self._state == STATE_FLOATING_DOWN then
vertacc = {x=0, y=0, z=0}
vertvel = {x=0, y=FLOAT_DOWN_SPEED, z=0}
end
end
self.object:set_acceleration(vertacc)
self.object:set_velocity(vector.add(horvel, vertvel))
end,
on_rightclick = function(self, clicker)
if clicker and clicker:is_player() then
local cname = clicker:get_player_name()
if self._driver then
if self._driver == clicker then
-- Detach driver
detach_driver(self, def.detach_offset_y)
end
else
if clicker:get_attach() == nil then
local pos = self.object:get_pos()
if not check_space(pos, clicker, 0.49, 2) then
minetest.chat_send_player(
clicker:get_player_name(),
minetest.colorize("#FFFF00", S("Not enough space to enter!")))
return
end
minetest.log("action", "[rp_boats] "..cname.." attaches to boat at "..minetest.pos_to_string(self.object:get_pos(),1))
set_driver(self, clicker, def.collisionbox)
rp_player.player_attached[cname] = true
self._driver:set_attach(self.object, "", def.attach_offset, {x=0,y=0,z=0}, true)
end
end
end
end,
on_detach_child = function(self, child)
if child and child == self._driver then
local cname = child:get_player_name()
minetest.log("action", "[rp_boats] "..cname.." detaches from boat at "..minetest.pos_to_string(self.object:get_pos(),1))
rp_player.player_attached[cname] = false
unset_driver(self, def.collisionbox)
end
end,
on_death = function(self, killer)
minetest.log("action", "[rp_boats] Boat dies at "..minetest.pos_to_string(self.object:get_pos(),1))
-- Drop boat item (except in Creative Mode)
if killer and killer:is_player() and minetest.is_creative_enabled(killer:get_player_name()) then
return
end
minetest.add_item(self.object:get_pos(), itemstring)
end,
on_punch = function(self, puncher, time_from_last_punch, tool_capabilities, dir, damage)
if damage >= 1 then
-- TODO: Add custom sound
minetest.sound_play({name = "default_dig_hard"}, {pos=self.object:get_pos()}, true)
end
end,
})
minetest.register_craftitem(itemstring, {
description = def.description,
_tt_help = def._tt_help,
liquids_pointable = true,
groups = { boat = 1 },
inventory_image = def.inventory_image,
wield_image = def.wield_image,
on_place = function(itemstack, placer, pointed_thing)
-- Boilerplace to handle pointed node's rightclick handler
if not placer or not placer:is_player() then
return itemstack
end
if pointed_thing.type ~= "node" then
return itemstack
end
local pos1 = pointed_thing.above
local node1 = minetest.get_node(pos1)
local ndef1 = minetest.registered_nodes[node1.name]
local pos2 = pointed_thing.under
local node2 = minetest.get_node(pos2)
local ndef2 = minetest.registered_nodes[node2.name]
if ndef2 and ndef2.on_rightclick and
((not placer) or (placer and not placer:get_player_control().sneak)) then
return ndef2.on_rightclick(pointed_thing.under, node2, placer, itemstack,
pointed_thing) or itemstack
end
-- Get place position
local place_pos = table.copy(pos1)
-- Offset when placed sideways
local spo = def.sideways_place_offset
if spo then
if pointed_thing.under.x > pointed_thing.above.x then
place_pos.x = place_pos.x - spo
elseif pointed_thing.under.x < pointed_thing.above.x then
place_pos.x = place_pos.x + spo
end
if pointed_thing.under.z > pointed_thing.above.z then
place_pos.z = place_pos.z - spo
elseif pointed_thing.under.z < pointed_thing.above.z then
place_pos.z = place_pos.z + spo
end
end
local on_liquid = false
if pos1.x == pos2.x and pos1.z == pos2.z and ndef2 and ndef2.liquidtype ~= "none" and minetest.get_item_group(node2.name, "fake_liquid") == 0 then
place_pos = vector.add(place_pos, {x=0, y=def.float_offset, z=0})
on_liquid = true
end
if ndef1 and not ndef1.walkable then
-- Optional function to check for available space for boat
if def.check_boat_space then
local res = def.check_boat_space(place_pos, on_liquid) -- returns true if enough space, false otherwise
if not res then
return itemstack
end
end
-- Place boat
local ent = minetest.add_entity(place_pos, itemstring)
if ent then
-- TODO: Add custom sound
minetest.sound_play({name = "default_place_node_hard"}, {pos=place_pos}, true)
ent:set_yaw(placer:get_look_horizontal())
minetest.log("action", "[rp_boats] "..placer:get_player_name().." spawns rp_boats:"..name.." at "..minetest.pos_to_string(place_pos, 1))
if not minetest.is_creative_enabled(placer:get_player_name()) then
itemstack:take_item()
end
end
end
return itemstack
end,
})
end
-- Register boats
local log_boats = {
{ "wood", S("Wooden Log Boat"), "rp_default:tree" },
{ "birch", S("Birch Log Boat"), "rp_default:tree_birch" },
{ "oak", S("Oak Log Boat"), "rp_default:tree_oak" },
}
for l=1, #log_boats do
local id = log_boats[l][1]
register_boat("log_boat_"..id, {
description = log_boats[l][2],
_tt_help = S("Water vehicle"),
collisionbox = { -0.49, -0.49, -0.49, 0.49, 0.49, 0.49 },
selectionbox = { -0.6, -0.501, -0.6, 0.6, 0.501, 0.6 },
inventory_image = "rp_boats_boat_log_"..id.."_item.png",
wield_image = "rp_boats_boat_log_"..id.."_item.png",
textures = {
"rp_boats_boat_log_"..id.."_side.png",
"rp_boats_boat_log_"..id.."_end.png",
"rp_boats_boat_log_"..id.."_inner_side.png",
"rp_boats_boat_log_"..id.."_inner_end.png",
"rp_boats_boat_log_"..id.."_inner.png",
"rp_boats_boat_log_"..id.."_side.png",
},
mesh = "rp_boats_log_boat.obj",
hp_max = 4,
float_max = 0.0,
float_offset = -0.3,
float_min = -0.85,
attach_offset = { x=0, y=0, z=0 },
max_speed = 3.8,
speed_change_rate = 1.5,
yaw_change_rate = 0.6,
detach_offset_y = 0.8,
})
crafting.register_craft({
output = "rp_boats:log_boat_"..id,
items = {
log_boats[l][3] .. " 2",
},
})
end
local rafts = {
{ "wood", S("Wooden Raft"), "rp_default:planks" },
{ "birch", S("Birch Raft"), "rp_default:planks_birch" },
{ "oak", S("Oak Raft"), "rp_default:planks_oak" },
}
for r=1, #rafts do
local id = rafts[r][1]
register_boat("raft_"..id, {
description = rafts[r][2],
_tt_help = S("Water vehicle"),
collisionbox = { -0.74, -0.3, -0.74, 0.74, 0.1, 0.74 },
selectionbox = { -0.85, -0.301, -0.85, 0.85, 0.101, 0.85 },
inventory_image = "rp_boats_boat_raft_"..id.."_item.png",
wield_image = "rp_boats_boat_raft_"..id.."_item.png",
textures = {
"rp_boats_boat_raft_"..id..".png",
"rp_boats_boat_raft_"..id..".png",
"rp_boats_boat_raft_"..id.."_side.png",
"rp_boats_boat_raft_"..id.."_mini.png",
"rp_boats_boat_raft_"..id.."_front.png",
"rp_boats_boat_raft_"..id.."_back.png",
},
mesh = "rp_boats_raft.obj",
hp_max = 4,
float_max = -0.201,
float_offset = -0.401,
float_min = -1.001,
attach_offset = { x=0, y=1, z=0 },
max_speed = 6,
speed_change_rate = 1.5,
yaw_change_rate = 0.3,
detach_offset_y = 0.2,
check_boat_space = function(place_pos, on_liquid)
local ymin = 0
if on_liquid then
ymin = -1
end
for x=-1,1 do
for y=ymin,0 do
for z=-1,1 do
local pnode = minetest.get_node(vector.add({x=x, y=y, z=z}, place_pos))
local pdef = minetest.registered_nodes[pnode.name]
if pdef and pdef.walkable then
return false
end
end
end
end
return true
end,
sideways_place_offset = 1.0,
})
crafting.register_craft({
output = "rp_boats:raft_"..id,
items = {
rafts[r][3] .. " 8",
"rp_default:fiber 10",
"rp_default:stick 5",
},
})
end
minetest.register_craft({
type = "fuel",
recipe = "group:boat",
burntime = 30,
})

View File

@ -971,6 +971,30 @@ minetest.register_abm({
end, end,
}) })
-- Grow vine
minetest.register_abm(
{
label = "Grow vines",
name = "rp_default:grow_vines",
nodenames = {"rp_default:vine"},
interval = 21,
chance = 120,
action = function(pos, node)
local meta = minetest.get_meta(pos)
local age = node.param2
if node.param2 == 0 or node.param2 >= default.VINE_MAX_AGE then
return
end
local below = {x=pos.x, y=pos.y-1, z=pos.z}
local nbelow = minetest.get_node(below)
if nbelow.name == "air" then
age = math.min(default.VINE_MAX_AGE, age + 1)
minetest.set_node(below, {name="rp_default:vine", param2 = age})
end
end,
}
)
-- Grow algae -- Grow algae
minetest.register_abm( minetest.register_abm(
{ {

View File

@ -18,6 +18,9 @@ default.WEAK_TORCH_MAX_TIMER = 360
-- is reduced by 100s*0.1 = 10s. -- is reduced by 100s*0.1 = 10s.
default.SAPLING_FERTILIZER_TIME_BONUS_FACTOR = 0.1 default.SAPLING_FERTILIZER_TIME_BONUS_FACTOR = 0.1
-- Maximum 'age' of a vine (determines how long it'll grow)
default.VINE_MAX_AGE = 20
minetest.nodedef_default.stack_max = 60 minetest.nodedef_default.stack_max = 60
minetest.craftitemdef_default.stack_max = 60 minetest.craftitemdef_default.stack_max = 60

View File

@ -113,13 +113,37 @@ minetest.register_node(
groups = {_attached_node_top = 1, snappy = 3, plant = 1, vine = 1}, groups = {_attached_node_top = 1, snappy = 3, plant = 1, vine = 1},
sounds = rp_sounds.node_sound_leaves_defaults(), sounds = rp_sounds.node_sound_leaves_defaults(),
after_dig_node = function(pos, node, metadata, digger) after_dig_node = function(pos, node, metadata, digger)
-- Set random age of vine above, it it exists
local above = {x=pos.x, y=pos.y+1, z=pos.z}
local aboven = minetest.get_node(above)
if aboven.name == "rp_default:vine" then
minetest.set_node(above, {name="rp_default:vine", param2 = math.random(1, default.VINE_MAX_AGE)})
end
-- Detach vines below
util.dig_down(pos, node, digger) util.dig_down(pos, node, digger)
end, end,
on_flood = function(pos, oldnode, newnode) on_flood = function(pos, oldnode, newnode)
-- Set random age of vine above, it it exists
local above = {x=pos.x, y=pos.y+1, z=pos.z}
local aboven = minetest.get_node(above)
if aboven.name == "rp_default:vine" then
minetest.set_node(above, {name="rp_default:vine", param2 = math.random(1, default.VINE_MAX_AGE)})
end
-- Drop vine as item and detach vines below
minetest.add_item(pos, "rp_default:vine") minetest.add_item(pos, "rp_default:vine")
util.dig_down(pos, oldnode, nil, "rp_default:vine") util.dig_down(pos, oldnode, nil, "rp_default:vine")
end, end,
on_blast = function(pos) on_blast = function(pos)
-- Set random age of vine above, it it exists
local above = {x=pos.x, y=pos.y+1, z=pos.z}
local aboven = minetest.get_node(above)
if aboven.name == "rp_default:vine" then
minetest.set_node(above, {name="rp_default:vine", param2 = math.random(1, default.VINE_MAX_AGE)})
end
-- Destroy the blasted node and detach vines below
local oldnode = minetest.get_node(pos) local oldnode = minetest.get_node(pos)
minetest.remove_node(pos) minetest.remove_node(pos)
util.dig_down(pos, oldnode) util.dig_down(pos, oldnode)
@ -150,8 +174,24 @@ minetest.register_node(
return itemstack return itemstack
end end
local age = ceilingnode.param2
-- Update age
if ceilingnode.name == "rp_default:vine" then
-- Vine extended: Increase age by 1 or set random age
local meta_c = minetest.get_meta(place_floor)
if age > 0 then
local meta_new = minetest.get_meta(place_in)
age = math.min(default.VINE_MAX_AGE, age + 1)
else
age = math.random(1, default.VINE_MAX_AGE)
end
else
-- New vine: Set random age
age = math.random(1, default.VINE_MAX_AGE)
end
-- Place vine -- Place vine
minetest.set_node(place_in, {name = itemstack:get_name()}) minetest.set_node(place_in, {name = itemstack:get_name(), param2 = age})
-- Reduce item count -- Reduce item count
if not minetest.is_creative_enabled(placer:get_player_name()) then if not minetest.is_creative_enabled(placer:get_player_name()) then
@ -160,6 +200,31 @@ minetest.register_node(
return itemstack return itemstack
end, end,
_on_trim = function(pos, node, player, itemstack)
-- Cut the vine, set age of a remaining vine to 0 to stop growth
-- Dig vine
minetest.remove_node(pos)
local is_creative = minetest.is_creative_enabled(player:get_player_name())
if not is_creative then
item_drop.drop_item(pos, "rp_default:vine")
end
util.dig_down(pos, node)
minetest.sound_play({name = "default_shears_cut", gain = 0.5}, {pos = player:get_pos(), max_hear_distance = 8}, true)
-- Reset age of vine above, if present
local above = {x=pos.x, y=pos.y+1, z=pos.z}
local aboven = minetest.get_node(above)
if aboven.name == "rp_default:vine" then
minetest.set_node(above, {name="rp_default:vine", param2=0})
end
-- Add tool wear
if not is_creative then
local def = itemstack:get_definition()
itemstack:add_wear_by_uses(def.tool_capabilities.groupcaps.snappy.uses)
end
return itemstack
end,
}) })
-- Fern -- Fern

View File

@ -248,7 +248,7 @@ local tt_pick = S("Digs hard, cracky blocks")
local tt_shovel = S("Digs soft, crumbly blocks") local tt_shovel = S("Digs soft, crumbly blocks")
local tt_axe = S("Chops wood") local tt_axe = S("Chops wood")
local tt_spear = S("Melee weapon") local tt_spear = S("Melee weapon")
local tt_shears = S("Cuts leaves and plants and shears sheep") local tt_shears = S("Cuts leaves and plants and shears sheep").."\n"..S("“Place” key: Precise cut")
-- Pickaxes -- Pickaxes