2018-01-23 00:57:32 +00:00
-- Chorus plants
2018-01-23 00:53:43 +00:00
-- This includes chorus flowers, chorus plant stem nodes and chorus fruit
2021-05-29 14:12:33 +00:00
local S = minetest.get_translator ( minetest.get_current_modname ( ) )
local math = math
local table = table
2018-01-23 00:57:32 +00:00
--- Plant parts ---
local MAX_FLOWER_AGE = 5 -- Maximum age of chorus flower before it dies
2018-01-23 00:53:43 +00:00
local chorus_flower_box = {
type = " fixed " ,
fixed = {
{ - 0.5 , - 0.375 , - 0.375 , 0.5 , 0.375 , 0.375 } ,
{ - 0.375 , - 0.375 , 0.375 , 0.375 , 0.375 , 0.5 } ,
{ - 0.375 , - 0.375 , - 0.5 , 0.375 , 0.375 , - 0.375 } ,
{ - 0.375 , 0.375 , - 0.375 , 0.375 , 0.5 , 0.375 } ,
{ - 0.375 , - 0.5 , - 0.375 , 0.375 , - 0.375 , 0.375 } ,
}
}
2019-02-19 02:42:50 +00:00
-- Helper function
local function round ( num , idp )
local mult = 10 ^ ( idp or 0 )
return math.floor ( num * mult + 0.5 ) / mult
end
2019-12-09 19:44:55 +00:00
-- This is a list of nodes that SHOULD NOT call their detach function
local no_detach = { }
2019-03-10 01:58:53 +00:00
-- This detaches all chorus plants that are/were attached
-- at start_pos.
2021-05-22 21:56:52 +00:00
function mcl_end . detach_chorus_plant ( start_pos , digger )
2019-12-09 19:44:55 +00:00
-- This node should not call a detach function, do NOTHING
local hash = minetest.hash_node_position ( start_pos )
2021-05-29 14:12:33 +00:00
if no_detach [ hash ] then
2019-12-09 19:44:55 +00:00
return
end
-- This node SHOULD be detached, make sure no others are
no_detach = { }
2019-03-10 01:58:53 +00:00
local neighbors = {
{ x = 0 , y = 1 , z = 0 } ,
{ x = 0 , y = 0 , z = 1 } ,
{ x =- 1 , y = 0 , z = 0 } ,
{ x = 0 , y = 0 , z =- 1 } ,
{ x = 1 , y = 0 , z = 0 } ,
{ x = 0 , y =- 1 , z = 0 } ,
}
table.insert ( neighbors , { x = 0 , y =- 1 , z = 0 } )
local tree_start_posses = { }
for i = 1 , # neighbors do
table.insert ( tree_start_posses , vector.add ( start_pos , neighbors [ i ] ) )
end
-- From the start_pos, we look at the 6 possible directions. Each of these can
-- have a full independent chorus plant ("tree") that might be detached.
for t = 1 , # tree_start_posses do
-- For each "tree", we do a depth-first search to traverse all
-- chorus plant nodes.
local touched_nodes_hashes = { minetest.hash_node_position ( start_pos ) }
local check_posses = { tree_start_posses [ t ] }
local chorus_nodes = { }
local break_tree = true
while # check_posses > 0 do
local pos = check_posses [ 1 ]
2019-12-09 19:44:55 +00:00
-- Don't just count neighbors as being touched, count THIS NODE as well
-- This will prevent it from getting stuck in an endless loop
if not touched_nodes_hashes [ minetest.hash_node_position ( pos ) ] then
local node = minetest.get_node ( pos )
touched_nodes_hashes [ minetest.hash_node_position ( pos ) ] = true
if node.name == " mcl_end:end_stone " then
-- End stone found, the algorithm ends here (haha!)
-- without destroying any nodes, because chorus plants
-- attach to end stone.
break_tree = false
break
elseif minetest.get_item_group ( node.name , " chorus_plant " ) == 1 then
table.insert ( chorus_nodes , pos )
for i = 1 , # neighbors do
local newpos = vector.add ( pos , neighbors [ i ] )
if not touched_nodes_hashes [ minetest.hash_node_position ( newpos ) ] then
table.insert ( check_posses , vector.add ( pos , neighbors [ i ] ) )
end
2019-03-10 01:58:53 +00:00
end
end
end
2019-12-09 19:44:55 +00:00
2019-03-10 01:58:53 +00:00
table.remove ( check_posses , 1 )
end
if break_tree then
-- If we traversed the entire chorus plant and it was not attached to end stone:
-- Drop ALL the chorus nodes we found.
for c = 1 , # chorus_nodes do
2019-12-09 19:44:55 +00:00
no_detach [ minetest.hash_node_position ( chorus_nodes [ c ] ) ] = true
2019-12-09 20:06:17 +00:00
if digger then
minetest.node_dig ( chorus_nodes [ c ] , { name = " mcl_end:chorus_plant " } , digger )
else
minetest.remove_node ( chorus_nodes [ c ] )
end
2019-03-10 01:58:53 +00:00
end
end
end
2019-12-09 19:44:55 +00:00
no_detach = { }
2019-03-10 01:58:53 +00:00
end
2021-05-22 21:56:52 +00:00
function mcl_end . check_detach_chorus_plant ( pos , oldnode , oldmetadata , digger )
2019-05-04 10:59:53 +00:00
mcl_end.detach_chorus_plant ( pos , digger )
2019-03-10 01:58:53 +00:00
end
2021-05-22 21:56:52 +00:00
function mcl_end . check_blast_chorus_plant ( pos )
2020-07-27 17:44:55 +00:00
minetest.remove_node ( pos )
2019-12-09 20:06:17 +00:00
mcl_end.detach_chorus_plant ( pos )
end
2018-01-23 00:53:43 +00:00
minetest.register_node ( " mcl_end:chorus_flower " , {
2019-03-07 23:00:09 +00:00
description = S ( " Chorus Flower " ) ,
2020-02-19 03:54:17 +00:00
_tt_help = S ( " Grows on end stone " ) ,
2019-03-07 23:00:09 +00:00
_doc_items_longdesc = S ( " A chorus flower is the living part of a chorus plant. It can grow into a tall chorus plant, step by step. When it grows, it may die on old age eventually. It also dies when it is unable to grow. " ) ,
2019-03-10 02:22:35 +00:00
_doc_items_usagehelp = S ( " Place it and wait for it to grow. It can only be placed on top of end stone, on top of a chorus plant stem, or at the side of exactly one chorus plant stem. " ) ,
2018-01-23 00:53:43 +00:00
tiles = {
" mcl_end_chorus_flower.png " ,
" mcl_end_chorus_flower.png " ,
" mcl_end_chorus_flower.png " ,
" mcl_end_chorus_flower.png " ,
" mcl_end_chorus_flower.png " ,
" mcl_end_chorus_flower.png " ,
} ,
drawtype = " nodebox " ,
paramtype = " light " ,
sunlight_propagates = true ,
node_box = chorus_flower_box ,
selection_box = { type = " regular " } ,
sounds = mcl_sounds.node_sound_wood_defaults ( ) ,
2020-08-05 18:40:34 +00:00
groups = { handy = 1 , axey = 1 , deco_block = 1 , dig_by_piston = 1 , destroy_by_lava_flow = 1 , chorus_plant = 1 } ,
2018-01-23 00:53:43 +00:00
node_placement_prediction = " " ,
on_place = function ( itemstack , placer , pointed_thing )
local node_under = minetest.get_node ( pointed_thing.under )
2021-05-22 21:56:52 +00:00
--local node_above = minetest.get_node(pointed_thing.above)
2018-01-23 00:53:43 +00:00
if placer and not placer : get_player_control ( ) . sneak then
-- Use pointed node's on_rightclick function first, if present
if minetest.registered_nodes [ node_under.name ] and minetest.registered_nodes [ node_under.name ] . on_rightclick then
return minetest.registered_nodes [ node_under.name ] . on_rightclick ( pointed_thing.under , node_under , placer , itemstack ) or itemstack
end
end
2019-05-04 11:33:37 +00:00
--[[ Part 1: Check placement rules. Placement is legal if one of the following
2018-01-23 00:53:43 +00:00
conditions is met :
1 ) On top of end stone or chorus plant
2 ) On top of air and horizontally adjacent to exactly 1 chorus plant ] ]
local pos
if minetest.registered_nodes [ node_under.name ] . buildable_to then
pos = pointed_thing.under
else
pos = pointed_thing.above
end
local below = { x = pos.x , y = pos.y - 1 , z = pos.z }
local node_below = minetest.get_node ( below )
local plant_ok = false
-- Condition 1
if node_below.name == " mcl_end:chorus_plant " or node_below.name == " mcl_end:end_stone " then
plant_ok = true
-- Condition 2
elseif node_below.name == " air " then
local around = {
{ x = 1 , y = 0 , z = 0 } ,
{ x =- 1 , y = 0 , z = 0 } ,
{ x = 0 , y = 0 , z = 1 } ,
{ x = 0 , y = 0 , z =- 1 } ,
}
local around_count = 0
for a = 1 , # around do
local pos_side = vector.add ( pos , around [ a ] )
local node_side = minetest.get_node ( pos_side )
if node_side.name == " mcl_end:chorus_plant " then
around_count = around_count + 1
if around_count > 1 then
break
end
end
end
if around_count == 1 then
plant_ok = true
end
end
if plant_ok then
-- Placement OK! Proceed normally
2019-05-04 11:33:37 +00:00
local it , suc = minetest.item_place_node ( itemstack , placer , pointed_thing )
if suc then
2020-04-06 22:55:45 +00:00
minetest.sound_play ( mcl_sounds.node_sound_wood_defaults ( ) . place , { pos = pos } , true )
2019-05-04 11:33:37 +00:00
end
return it
2018-01-23 00:53:43 +00:00
else
return itemstack
end
end ,
2019-03-10 01:58:53 +00:00
after_dig_node = mcl_end.check_detach_chorus_plant ,
2019-12-09 20:06:17 +00:00
on_blast = mcl_end.check_blast_chorus_plant ,
2020-04-17 19:40:13 +00:00
_mcl_blast_resistance = 0.4 ,
2018-01-23 00:53:43 +00:00
_mcl_hardness = 0.4 ,
} )
2018-01-23 00:57:32 +00:00
minetest.register_node ( " mcl_end:chorus_flower_dead " , {
2019-03-07 23:00:09 +00:00
description = S ( " Dead Chorus Flower " ) ,
_doc_items_longdesc = S ( " This is a part of a chorus plant. It doesn't grow. Chorus flowers die of old age or when they are unable to grow. A dead chorus flower can be harvested to obtain a fresh chorus flower which is able to grow again. " ) ,
2018-01-23 00:57:32 +00:00
tiles = {
" mcl_end_chorus_flower_dead.png " ,
" mcl_end_chorus_flower_dead.png " ,
" mcl_end_chorus_flower_dead.png " ,
" mcl_end_chorus_flower_dead.png " ,
" mcl_end_chorus_flower_dead.png " ,
" mcl_end_chorus_flower_dead.png " ,
} ,
drawtype = " nodebox " ,
paramtype = " light " ,
sunlight_propagates = true ,
node_box = chorus_flower_box ,
selection_box = { type = " regular " } ,
sounds = mcl_sounds.node_sound_wood_defaults ( ) ,
drop = " mcl_end:chorus_flower " ,
2020-08-05 19:00:30 +00:00
groups = { handy = 1 , axey = 1 , deco_block = 1 , dig_by_piston = 1 , destroy_by_lava_flow = 1 , chorus_plant = 1 , not_in_creative_inventory = 1 } ,
2019-03-10 01:58:53 +00:00
after_dig_node = mcl_end.check_detach_chorus_plant ,
2019-12-09 20:06:17 +00:00
on_blast = mcl_end.check_blast_chorus_plant ,
2018-01-23 00:57:32 +00:00
_mcl_blast_resistance = 2 ,
_mcl_hardness = 0.4 ,
} )
minetest.register_node ( " mcl_end:chorus_plant " , {
2019-03-07 23:00:09 +00:00
description = S ( " Chorus Plant Stem " ) ,
_doc_items_longdesc = S ( " A chorus plant stem is the part of a chorus plant which holds the whole plant together. It needs end stone as its soil. Stems are grown from chorus flowers. " ) ,
2019-05-04 11:39:11 +00:00
_doc_items_usagehelp = S ( " The stem attaches itself to end stone and other chorus blocks. " ) ,
2018-01-23 00:57:32 +00:00
tiles = {
" mcl_end_chorus_plant.png " ,
" mcl_end_chorus_plant.png " ,
" mcl_end_chorus_plant.png " ,
" mcl_end_chorus_plant.png " ,
" mcl_end_chorus_plant.png " ,
" mcl_end_chorus_plant.png " ,
} ,
drawtype = " nodebox " ,
paramtype = " light " ,
sunlight_propagates = true ,
node_box = {
type = " connected " ,
fixed = { - 0.25 , - 0.25 , - 0.25 , 0.25 , 0.25 , 0.25 } , -- Core
connect_top = { - 0.1875 , 0.25 , - 0.1875 , 0.1875 , 0.5 , 0.1875 } ,
connect_left = { - 0.5 , - 0.1875 , - 0.1875 , - 0.25 , 0.1875 , 0.1875 } ,
connect_right = { 0.25 , - 0.1875 , - 0.1875 , 0.5 , 0.1875 , 0.1875 } ,
connect_bottom = { - 0.1875 , - 0.5 , - 0.25 , 0.1875 , - 0.25 , 0.25 } ,
connect_front = { - 0.1875 , - 0.1875 , - 0.5 , 0.1875 , 0.1875 , - 0.25 } ,
connect_back = { - 0.1875 , - 0.1875 , 0.25 , 0.1875 , 0.1875 , 0.5 } ,
} ,
connect_sides = { " top " , " bottom " , " front " , " back " , " left " , " right " } ,
2019-05-04 11:33:37 +00:00
connects_to = { " group:chorus_plant " , " mcl_end:end_stone " } ,
2018-01-23 00:57:32 +00:00
sounds = mcl_sounds.node_sound_wood_defaults ( ) ,
drop = {
items = {
{ items = { " mcl_end:chorus_fruit " } , rarity = 2 } ,
}
} ,
2019-06-13 18:44:04 +00:00
groups = { handy = 1 , axey = 1 , deco_block = 1 , dig_by_piston = 1 , destroy_by_lava_flow = 1 , chorus_plant = 1 } ,
2019-05-04 11:33:37 +00:00
node_placement_prediction = " " ,
on_place = function ( itemstack , placer , pointed_thing )
local node_under = minetest.get_node ( pointed_thing.under )
local node_above = minetest.get_node ( pointed_thing.above )
if placer and not placer : get_player_control ( ) . sneak then
-- Use pointed node's on_rightclick function first, if present
if minetest.registered_nodes [ node_under.name ] and minetest.registered_nodes [ node_under.name ] . on_rightclick then
return minetest.registered_nodes [ node_under.name ] . on_rightclick ( pointed_thing.under , node_under , placer , itemstack ) or itemstack
end
end
--[[ Part 1: Check placement rules. Placement is legal if this
condition is met :
- placed on end stone or any chorus node ] ]
local pos_place , node_check
if minetest.registered_nodes [ node_under.name ] . buildable_to then
pos_place = pointed_thing.under
node_check = node_above
else
pos_place = pointed_thing.above
node_check = node_under
end
local plant_ok = false
if node_check.name == " mcl_end:end_stone " or minetest.get_item_group ( node_check.name , " chorus_plant " ) > 0 then
plant_ok = true
end
if plant_ok then
-- Placement OK! Proceed normally
local it , suc = minetest.item_place_node ( itemstack , placer , pointed_thing )
if suc then
2020-04-06 22:55:45 +00:00
minetest.sound_play ( mcl_sounds.node_sound_wood_defaults ( ) . place , { pos = pos_place } , true )
2019-05-04 11:33:37 +00:00
end
return it
else
return itemstack
end
end ,
2019-03-10 01:58:53 +00:00
after_dig_node = mcl_end.check_detach_chorus_plant ,
2019-12-09 20:06:17 +00:00
on_blast = mcl_end.check_blast_chorus_plant ,
2018-01-23 00:57:32 +00:00
_mcl_blast_resistance = 2 ,
_mcl_hardness = 0.4 ,
} )
2019-03-09 20:02:40 +00:00
-- Grow a complete chorus plant at pos
2021-05-22 21:56:52 +00:00
function mcl_end . grow_chorus_plant ( pos , node , pr )
2019-03-09 20:02:40 +00:00
local flowers = { pos }
-- Plant initial flower (if it isn't there already)
if not node then
node = minetest.get_node ( pos )
end
if node.name ~= " mcl_end:chorus_flower " then
minetest.set_node ( pos , { name = " mcl_end:chorus_flower " } )
end
while true do
local new_flowers_list = { }
for f = 1 , # flowers do
2021-05-09 22:24:38 +00:00
local new_flowers = mcl_end.grow_chorus_plant_step ( flowers [ f ] , minetest.get_node ( flowers [ f ] ) , pr )
2019-03-09 20:02:40 +00:00
if # new_flowers > 0 then
table.insert ( new_flowers_list , new_flowers )
2018-01-23 00:53:43 +00:00
end
end
2019-03-09 20:02:40 +00:00
if # new_flowers_list == 0 then
return
end
flowers = { }
for l = 1 , # new_flowers_list do
for f = 1 , # new_flowers_list [ l ] do
table.insert ( flowers , new_flowers_list [ l ] [ f ] )
end
end
end
end
-- Grow a single step of a chorus plant at pos.
-- Pos must be a chorus flower.
2021-05-22 21:56:52 +00:00
function mcl_end . grow_chorus_plant_step ( pos , node , pr )
2019-03-09 20:02:40 +00:00
local new_flower_buds = { }
local above = { x = pos.x , y = pos.y + 1 , z = pos.z }
local node_above = minetest.get_node ( above )
local around = {
{ x =- 1 , y = 0 , z = 0 } ,
{ x = 1 , y = 0 , z = 0 } ,
{ x = 0 , y = 0 , z =- 1 } ,
{ x = 0 , y = 0 , z = 1 } ,
}
local air_around = true
for a = 1 , # around do
if minetest.get_node ( vector.add ( above , around [ a ] ) ) . name ~= " air " then
air_around = false
break
end
end
local grown = false
if node_above.name == " air " and air_around then
local branching = false
local h = 0
for y = 1 , 4 do
local checkpos = { x = pos.x , y = pos.y - y , z = pos.z }
local node = minetest.get_node ( checkpos )
if node.name == " mcl_end:chorus_plant " then
h = y
if not branching then
for a = 1 , # around do
local node_side = minetest.get_node ( vector.add ( checkpos , around [ a ] ) )
if node_side.name == " mcl_end:chorus_plant " then
branching = true
2018-01-23 00:53:43 +00:00
end
end
end
2019-03-09 20:02:40 +00:00
else
break
2018-01-23 00:53:43 +00:00
end
2019-03-09 20:02:40 +00:00
end
2018-01-23 00:53:43 +00:00
2019-03-09 20:02:40 +00:00
local grow_chance
if h <= 1 then
grow_chance = 100
elseif h == 2 and branching == false then
grow_chance = 60
elseif h == 2 and branching == true then
grow_chance = 50
elseif h == 3 and branching == false then
grow_chance = 40
elseif h == 3 and branching == true then
grow_chance = 25
elseif h == 4 and branching == false then
grow_chance = 20
end
2018-01-23 00:53:43 +00:00
2019-03-09 20:02:40 +00:00
if grow_chance then
local new_flowers = { }
2021-05-09 22:24:38 +00:00
local r = pr : next ( 1 , 100 )
2019-03-09 20:02:40 +00:00
local age = node.param2
if r <= grow_chance then
table.insert ( new_flowers , above )
else
age = age + 1
local branches
if branching == false then
2021-05-09 22:24:38 +00:00
branches = pr : next ( 1 , 4 )
2019-03-09 20:02:40 +00:00
elseif branching == true then
2021-05-09 22:24:38 +00:00
branches = pr : next ( 0 , 3 )
2018-01-23 00:53:43 +00:00
end
2019-03-09 20:02:40 +00:00
for b = 1 , branches do
2021-05-09 22:24:38 +00:00
local next_branch = pr : next ( 1 , # around )
2019-03-09 20:02:40 +00:00
local branch = vector.add ( pos , around [ next_branch ] )
local below_branch = vector.add ( branch , { x = 0 , y =- 1 , z = 0 } )
if minetest.get_node ( below_branch ) . name == " air " then
table.insert ( new_flowers , branch )
2018-01-23 00:53:43 +00:00
end
end
2019-03-09 20:02:40 +00:00
end
2021-03-16 16:39:06 +00:00
for _ , f in pairs ( new_flowers ) do
2019-03-09 20:02:40 +00:00
if age >= MAX_FLOWER_AGE then
2019-03-09 22:19:14 +00:00
local nn = minetest.get_node ( f ) . name
if nn ~= " mcl_end:chorus_flower " and nn ~= " mcl_end:chorus_flower_dead " then
minetest.set_node ( f , { name = " mcl_end:chorus_flower_dead " } )
grown = true
end
2019-03-09 20:02:40 +00:00
else
2019-03-09 22:19:14 +00:00
local nn = minetest.get_node ( f ) . name
if nn ~= " mcl_end:chorus_flower " and nn ~= " mcl_end:chorus_flower_dead " then
minetest.set_node ( f , { name = " mcl_end:chorus_flower " , param2 = age } )
table.insert ( new_flower_buds , f )
grown = true
end
2018-01-23 00:53:43 +00:00
end
end
2019-03-09 20:02:40 +00:00
if # new_flowers >= 1 then
minetest.set_node ( pos , { name = " mcl_end:chorus_plant " } )
grown = true
end
2018-01-23 00:54:59 +00:00
end
2019-03-09 20:02:40 +00:00
end
if not grown then
2019-03-10 00:05:06 +00:00
-- FIXME: In the End, chorus plant fails to generate thru mapchunk borders.
-- So the chorus plants are capped at a fixed height.
-- The mapgen needs to be taught somehow how to deal with this.
2019-03-09 20:02:40 +00:00
minetest.set_node ( pos , { name = " mcl_end:chorus_flower_dead " } )
end
return new_flower_buds
end
--- ABM ---
2021-05-25 06:40:21 +00:00
local seed = minetest.get_mapgen_params ( ) . seed
local pr = PseudoRandom ( seed )
2019-03-09 20:02:40 +00:00
minetest.register_abm ( {
label = " Chorus plant growth " ,
nodenames = { " mcl_end:chorus_flower " } ,
interval = 35.0 ,
chance = 4.0 ,
action = function ( pos , node , active_object_count , active_object_count_wider )
2021-05-09 22:24:38 +00:00
mcl_end.grow_chorus_plant_step ( pos , node , pr )
2018-01-23 00:53:43 +00:00
end ,
} )
2018-01-23 02:58:08 +00:00
--- Chorus fruit ---
-- Attempt to randomly teleport the player within a 8× 8× 8 box around. Rules:
-- * Not in solid blocks.
-- * Not in liquids.
-- * Always on top of a solid block
-- * Maximum attempts: 16
--
-- Returns true on success.
2021-05-29 14:12:33 +00:00
local function random_teleport ( player )
2018-01-23 02:58:08 +00:00
local pos = player : get_pos ( )
-- 16 attempts to find a suitable position
for a = 1 , 16 do
-- Teleportation box
local x , y , z
2019-02-19 02:42:50 +00:00
x = math.random ( round ( pos.x ) - 8 , round ( pos.x ) + 8 )
2018-01-23 02:58:08 +00:00
y = math.random ( math.ceil ( pos.y ) - 8 , math.ceil ( pos.y ) + 8 )
2019-02-19 02:42:50 +00:00
z = math.random ( round ( pos.z ) - 8 , round ( pos.z ) + 8 )
2018-01-23 02:58:08 +00:00
local node_cache = { }
local ground_level = false
-- Scan nodes from selected position until we hit ground
for t = 0 , 16 do
local tpos = { x = x , y = y - t , z = z }
local tnode = minetest.get_node ( tpos )
2019-02-19 02:42:50 +00:00
if tnode.name == " mcl_core:void " or tnode.name == " ignore " then
2018-01-23 02:58:08 +00:00
break
end
local tdef = minetest.registered_nodes [ tnode.name ]
table.insert ( node_cache , { pos = tpos , node = tnode } )
if tdef.walkable then
ground_level = true
break
end
end
-- Ground found? Then let's check if the player has enough room
if ground_level and # node_cache >= 1 then
local streak = 0
2019-02-19 02:42:50 +00:00
local last_was_walkable = true
2018-01-23 02:58:08 +00:00
for c =# node_cache , 1 , - 1 do
local tpos = node_cache [ c ] . pos
local tnode = node_cache [ c ] . node
local tdef = minetest.registered_nodes [ tnode.name ]
2019-02-19 02:42:50 +00:00
-- Player needs a space of 2 safe non-liquid nodes on top of a walkable node
if not tdef.walkable and tdef.liquidtype == " none " and tdef.damage_per_second <= 0 then
if ( streak == 0 and last_was_walkable ) or ( streak > 0 ) then
streak = streak + 1
end
2018-01-23 02:58:08 +00:00
else
streak = 0
end
2019-02-19 02:42:50 +00:00
last_was_walkable = tdef.walkable
2018-01-23 02:58:08 +00:00
if streak >= 2 then
-- JACKPOT! Now we can teleport.
2018-01-23 03:18:19 +00:00
local goal = { x = tpos.x , y = tpos.y - 1.5 , z = tpos.z }
player : set_pos ( goal )
2020-04-06 22:55:45 +00:00
minetest.sound_play ( { name = " mcl_end_teleport " , gain = 0.8 } , { pos = goal , max_hear_distance = 16 } , true )
2018-01-23 02:58:08 +00:00
return true
end
end
end
end
return false
end
-- Randomly teleport player and update hunger
local eat_chorus_fruit = function ( itemstack , player , pointed_thing )
if player and pointed_thing and pointed_thing.type == " node " and not player : get_player_control ( ) . sneak then
local node_under = minetest.get_node ( pointed_thing.under )
-- Use pointed node's on_rightclick function first, if present
if minetest.registered_nodes [ node_under.name ] and minetest.registered_nodes [ node_under.name ] . on_rightclick then
2019-02-05 21:05:56 +00:00
return minetest.registered_nodes [ node_under.name ] . on_rightclick ( pointed_thing.under , node_under , player , itemstack ) or itemstack
2018-01-23 02:58:08 +00:00
end
end
2018-01-23 03:24:05 +00:00
local count = itemstack : get_count ( )
2019-12-09 07:24:38 +00:00
local new_itemstack = minetest.do_item_eat ( 4 , nil , itemstack , player , pointed_thing )
2018-01-23 03:24:05 +00:00
local new_count = new_itemstack : get_count ( )
2020-07-10 14:08:40 +00:00
if count ~= new_count or new_itemstack : get_name ( ) ~= " mcl_end:chorus_fruit " or ( minetest.is_creative_enabled ( player : get_player_name ( ) ) == true ) then
2018-01-23 03:24:05 +00:00
random_teleport ( player )
end
return new_itemstack
2018-01-23 02:58:08 +00:00
end
2018-01-23 00:53:43 +00:00
minetest.register_craftitem ( " mcl_end:chorus_fruit " , {
2019-03-07 23:00:09 +00:00
description = S ( " Chorus Fruit " ) ,
2020-02-19 03:54:17 +00:00
_tt_help = S ( " Randomly teleports you when eaten " ) ,
2019-03-07 23:00:09 +00:00
_doc_items_longdesc = S ( " A chorus fruit is an edible fruit from the chorus plant which is home to the End. Eating it teleports you to the top of a random solid block nearby, provided you won't end up inside a liquid, solid or harmful blocks. Teleportation might fail if there are very few or no places to teleport to. " ) ,
2018-01-23 00:53:43 +00:00
wield_image = " mcl_end_chorus_fruit.png " ,
inventory_image = " mcl_end_chorus_fruit.png " ,
2018-01-23 02:58:08 +00:00
on_place = eat_chorus_fruit ,
on_secondary_use = eat_chorus_fruit ,
2019-02-06 11:04:58 +00:00
groups = { food = 2 , transport = 1 , eatable = 4 , can_eat_when_full = 1 } ,
2018-01-23 00:53:43 +00:00
_mcl_saturation = 2.4 ,
stack_max = 64 ,
} )
minetest.register_craftitem ( " mcl_end:chorus_fruit_popped " , {
2019-03-07 23:00:09 +00:00
description = S ( " Popped Chorus Fruit " ) ,
2018-01-23 00:53:43 +00:00
_doc_items_longdesc = doc.sub . items.temp . craftitem ,
wield_image = " mcl_end_chorus_fruit_popped.png " ,
inventory_image = " mcl_end_chorus_fruit_popped.png " ,
groups = { craftitem = 1 } ,
stack_max = 64 ,
} )
2018-01-23 00:57:32 +00:00
--- Crafting ---
2018-01-23 00:53:43 +00:00
minetest.register_craft ( {
type = " cooking " ,
output = " mcl_end:chorus_fruit_popped " ,
recipe = " mcl_end:chorus_fruit " ,
cooktime = 10 ,
} )