2 -- This includes chorus flowers, chorus plant stem nodes and chorus fruit
7 local MAX_FLOWER_AGE
= 5 -- Maximum age of chorus flower before it dies
9 local chorus_flower_box
= {
12 {-0.5, -0.375, -0.375, 0.5, 0.375, 0.375},
13 {-0.375, -0.375, 0.375, 0.375, 0.375, 0.5},
14 {-0.375, -0.375, -0.5, 0.375, 0.375, -0.375},
15 {-0.375, 0.375, -0.375, 0.375, 0.5, 0.375},
16 {-0.375, -0.5, -0.375, 0.375, -0.375, 0.375},
20 minetest
.register_node("mcl_end:chorus_flower", {
21 description
= "Chorus Flower",
22 _doc_items_longdesc
= "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.",
23 _doc_items_usagehelp
= "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 a chorus plant stem.",
25 "mcl_end_chorus_flower.png",
26 "mcl_end_chorus_flower.png",
27 "mcl_end_chorus_flower.png",
28 "mcl_end_chorus_flower.png",
29 "mcl_end_chorus_flower.png",
30 "mcl_end_chorus_flower.png",
34 sunlight_propagates
= true,
35 node_box
= chorus_flower_box
,
36 selection_box
= { type = "regular" },
37 sounds
= mcl_sounds
.node_sound_wood_defaults(),
38 groups
= {handy
=1,axey
=1, deco_block
= 1, dig_by_piston
= 1, destroy_by_lava_flow
= 1,},
40 node_placement_prediction
= "",
41 on_place
= function(itemstack
, placer
, pointed_thing
)
42 local node_under
= minetest
.get_node(pointed_thing
.under
)
43 local node_above
= minetest
.get_node(pointed_thing
.above
)
44 if placer
and not placer
:get_player_control().sneak
then
45 -- Use pointed node's on_rightclick function first, if present
46 if minetest
.registered_nodes
[node_under
.name
] and minetest
.registered_nodes
[node_under
.name
].on_rightclick
then
47 return minetest
.registered_nodes
[node_under
.name
].on_rightclick(pointed_thing
.under
, node_under
, placer
, itemstack
) or itemstack
51 --[[ Part 1: Check placement rules. Placement is legal is one of the following
53 1) On top of end stone or chorus plant
54 2) On top of air and horizontally adjacent to exactly 1 chorus plant ]]
56 if minetest
.registered_nodes
[node_under
.name
].buildable_to
then
57 pos
= pointed_thing
.under
59 pos
= pointed_thing
.above
63 local below
= {x
=pos
.x
, y
=pos
.y
-1, z
=pos
.z
}
64 local node_below
= minetest
.get_node(below
)
65 local plant_ok
= false
67 if node_below
.name
== "mcl_end:chorus_plant" or node_below
.name
== "mcl_end:end_stone" then
70 elseif node_below
.name
== "air" then
77 local around_count
= 0
79 local pos_side
= vector
.add(pos
, around
[a
])
80 local node_side
= minetest
.get_node(pos_side
)
81 if node_side
.name
== "mcl_end:chorus_plant" then
82 around_count
= around_count
+ 1
83 if around_count
> 1 then
88 if around_count
== 1 then
93 -- Placement OK! Proceed normally
94 minetest
.sound_play(mcl_sounds
.node_sound_wood_defaults().place
, {pos
= pos
})
95 return minetest
.item_place_node(itemstack
, placer
, pointed_thing
)
100 _mcl_blast_resistance
= 2,
104 minetest
.register_node("mcl_end:chorus_flower_dead", {
105 description
= "Dead Chorus Flower",
106 _doc_items_longdesc
= "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.",
108 "mcl_end_chorus_flower_dead.png",
109 "mcl_end_chorus_flower_dead.png",
110 "mcl_end_chorus_flower_dead.png",
111 "mcl_end_chorus_flower_dead.png",
112 "mcl_end_chorus_flower_dead.png",
113 "mcl_end_chorus_flower_dead.png",
115 drawtype
= "nodebox",
117 sunlight_propagates
= true,
118 node_box
= chorus_flower_box
,
119 selection_box
= { type = "regular" },
120 sounds
= mcl_sounds
.node_sound_wood_defaults(),
121 drop
= "mcl_end:chorus_flower",
122 groups
= {handy
=1,axey
=1, deco_block
= 1, dig_by_piston
= 1, destroy_by_lava_flow
= 1,},
123 _mcl_blast_resistance
= 2,
127 minetest
.register_node("mcl_end:chorus_plant", {
128 description
= "Chorus Plant Stem",
129 _doc_items_longdesc
= "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.",
131 "mcl_end_chorus_plant.png",
132 "mcl_end_chorus_plant.png",
133 "mcl_end_chorus_plant.png",
134 "mcl_end_chorus_plant.png",
135 "mcl_end_chorus_plant.png",
136 "mcl_end_chorus_plant.png",
138 drawtype
= "nodebox",
140 sunlight_propagates
= true,
143 fixed
= { -0.25, -0.25, -0.25, 0.25, 0.25, 0.25 }, -- Core
144 connect_top
= { -0.1875, 0.25, -0.1875, 0.1875, 0.5, 0.1875 },
145 connect_left
= { -0.5, -0.1875, -0.1875, -0.25, 0.1875, 0.1875 },
146 connect_right
= { 0.25, -0.1875, -0.1875, 0.5, 0.1875, 0.1875 },
147 connect_bottom
= { -0.1875, -0.5, -0.25, 0.1875, -0.25, 0.25 },
148 connect_front
= { -0.1875, -0.1875, -0.5, 0.1875, 0.1875, -0.25 },
149 connect_back
= { -0.1875, -0.1875, 0.25, 0.1875, 0.1875, 0.5 },
151 connect_sides
= { "top", "bottom", "front", "back", "left", "right" },
152 connects_to
= {"mcl_end:chorus_plant", "mcl_end:chorus_flower", "mcl_end:chorus_flower_dead", "mcl_end:end_stone"},
153 sounds
= mcl_sounds
.node_sound_wood_defaults(),
156 { items
= { "mcl_end:chorus_fruit"}, rarity
= 2 },
159 groups
= {handy
=1,axey
=1, not_in_creative_inventory
= 1, dig_by_piston
= 1, destroy_by_lava_flow
= 1 },
160 _mcl_blast_resistance
= 2,
166 minetest
.register_abm({
167 label
= "Chorus plant growth",
168 nodenames
= { "mcl_end:chorus_flower" },
171 action
= function(pos
, node
, active_object_count
, active_object_count_wider
)
172 local above
= { x
= pos
.x
, y
= pos
.y
+ 1, z
= pos
.z
}
173 local node_above
= minetest
.get_node(above
)
180 local air_around
= true
182 if minetest
.get_node(vector
.add(above
, around
[a
])).name
~= "air" then
188 if node_above
.name
== "air" and air_around
then
189 local branching
= false
192 local checkpos
= {x
=pos
.x
, y
=pos
.y
-y
, z
=pos
.z
}
193 local node
= minetest
.get_node(checkpos
)
194 if node
.name
== "mcl_end:chorus_plant" then
196 if not branching
then
198 local node_side
= minetest
.get_node(vector
.add(checkpos
, around
[a
]))
199 if node_side
.name
== "mcl_end:chorus_plant" then
212 elseif h
== 2 and branching
== false then
214 elseif h
== 2 and branching
== true then
216 elseif h
== 3 and branching
== false then
218 elseif h
== 3 and branching
== true then
220 elseif h
== 4 and branching
== false then
225 local new_flowers
= {}
226 local r
= math
.random(1, 100)
227 local age
= node
.param2
228 if r
<= grow_chance
then
229 table.insert(new_flowers
, above
)
233 if branching
== false then
234 branches
= math
.random(1, 4)
235 elseif branching
== true then
236 branches
= math
.random(0, 3)
238 local branch_grown
= false
240 local next_branch
= math
.random(1, #around
)
241 local branch
= vector
.add(pos
, around
[next_branch
])
242 local below_branch
= vector
.add(branch
, {x
=0,y
=-1,z
=0})
243 if minetest
.get_node(below_branch
).name
== "air" then
244 table.insert(new_flowers
, branch
)
249 for _
, f
in ipairs(new_flowers
) do
250 if age
>= MAX_FLOWER_AGE
then
251 minetest
.set_node(f
, {name
="mcl_end:chorus_flower_dead"})
254 minetest
.set_node(f
, {name
="mcl_end:chorus_flower", param2
= age
})
258 if #new_flowers
>= 1 then
259 minetest
.set_node(pos
, {name
="mcl_end:chorus_plant"})
265 minetest
.set_node(pos
, {name
= "mcl_end:chorus_flower_dead"})
272 -- Attempt to randomly teleport the player within a 8×8×8 box around. Rules:
273 -- * Not in solid blocks.
275 -- * Always on top of a solid block
276 -- * Maximum attempts: 16
278 -- Returns true on success.
279 local random_teleport
= function(player
)
280 local pos
= player
:get_pos()
281 -- 16 attempts to find a suitable position
285 x
= math
.random(pos
.x
-8, pos
.x
+8)
286 y
= math
.random(math
.ceil(pos
.y
)-8, math
.ceil(pos
.y
)+8)
287 z
= math
.random(pos
.z
-8, pos
.z
+8)
288 local node_cache
= {}
289 local ground_level
= false
290 -- Scan nodes from selected position until we hit ground
292 local tpos
= {x
=x
, y
=y
-t
, z
=z
}
293 local tnode
= minetest
.get_node(tpos
)
294 if tnode
.name
== "mcl_core:void" then
297 local tdef
= minetest
.registered_nodes
[tnode
.name
]
298 table.insert(node_cache
, {pos
=tpos
, node
=tnode
})
299 if tdef
.walkable
then
304 -- Ground found? Then let's check if the player has enough room
305 if ground_level
and #node_cache
>= 1 then
307 for c
=#node_cache
, 1, -1 do
308 local tpos
= node_cache
[c
].pos
309 local tnode
= node_cache
[c
].node
310 local tdef
= minetest
.registered_nodes
[tnode
.name
]
311 -- Player needs a space of 2 nodes on top of each other
312 if not tdef
.walkable
and tdef
.liquidtype
== "none" then
318 -- JACKPOT! Now we can teleport.
319 local goal
= {x
=tpos
.x
, y
=tpos
.y
-1.5, z
=tpos
.z
}
321 minetest
.sound_play({name
="mcl_end_teleport", gain
=0.8}, {pos
=goal
, max_hear_distance
=16})
330 -- Randomly teleport player and update hunger
331 local eat_chorus_fruit
= function(itemstack
, player
, pointed_thing
)
332 if player
and pointed_thing
and pointed_thing
.type == "node" and not player
:get_player_control().sneak
then
333 local node_under
= minetest
.get_node(pointed_thing
.under
)
334 -- Use pointed node's on_rightclick function first, if present
335 if minetest
.registered_nodes
[node_under
.name
] and minetest
.registered_nodes
[node_under
.name
].on_rightclick
then
336 return minetest
.registered_nodes
[node_under
.name
].on_rightclick(pointed_thing
.under
, node_under
, placer
, itemstack
) or itemstack
339 local count
= itemstack
:get_count()
340 local new_itemstack
= minetest
.do_item_eat(0, nil, itemstack
, player
, pointed_thing
)
341 local new_count
= new_itemstack
:get_count()
342 if count
~= new_count
or new_itemstack
:get_name() ~= "mcl_end:chorus_fruit" then
343 random_teleport(player
)
348 minetest
.register_craftitem("mcl_end:chorus_fruit", {
349 description
= "Chorus Fruit",
350 _doc_items_longdesc
= "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 or some solid blocks. Teleportation might fail if there are very few or no places to teleport to.",
351 wield_image
= "mcl_end_chorus_fruit.png",
352 inventory_image
= "mcl_end_chorus_fruit.png",
353 on_place
= eat_chorus_fruit
,
354 on_secondary_use
= eat_chorus_fruit
,
355 groups
= { food
= 2, eatable
= 4, can_eat_when_full
= 1 },
356 _mcl_saturation
= 2.4,
360 minetest
.register_craftitem("mcl_end:chorus_fruit_popped", {
361 description
= "Popped Chorus Fruit",
362 _doc_items_longdesc
= doc
.sub
.items
.temp
.craftitem
,
363 wield_image
= "mcl_end_chorus_fruit_popped.png",
364 inventory_image
= "mcl_end_chorus_fruit_popped.png",
365 groups
= { craftitem
= 1 },
370 minetest
.register_craft({
372 output
= "mcl_end:chorus_fruit_popped",
373 recipe
= "mcl_end:chorus_fruit",