Refactor mcl_end

This commit is contained in:
Wuzzy 2018-01-23 01:53:43 +01:00
parent bdaaf912ab
commit 5e47bce74e
4 changed files with 637 additions and 627 deletions

@ -0,0 +1,192 @@
-- Building blocks and decorative nodes
minetest.register_node("mcl_end:end_stone", {
description = "End Stone",
_doc_items_longdesc = doc.sub.items.temp.build,
tiles = {"mcl_end_end_stone.png"},
stack_max = 64,
groups = {pickaxey=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 45,
_mcl_hardness = 3,
})
minetest.register_node("mcl_end:end_bricks", {
description = "End Stone Bricks",
_doc_items_longdesc = doc.sub.items.temp.build,
tiles = {"mcl_end_end_bricks.png"},
is_ground_content = false,
stack_max = 64,
groups = {pickaxey=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 4,
_mcl_hardness = 0.8,
})
minetest.register_node("mcl_end:purpur_block", {
description = "Purpur Block",
_doc_items_longdesc = doc.sub.items.temp.build,
tiles = {"mcl_end_purpur_block.png"},
is_ground_content = false,
stack_max = 64,
groups = {pickaxey=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 30,
_mcl_hardness = 1.5,
})
minetest.register_node("mcl_end:purpur_pillar", {
description = "Purpur Pillar",
_doc_items_longdesc = doc.sub.items.temp.build,
stack_max = 64,
paramtype2 = "facedir",
is_ground_content = false,
on_place = mcl_util.rotate_axis,
tiles = {"mcl_end_purpur_pillar_top.png", "mcl_end_purpur_pillar_top.png", "mcl_end_purpur_pillar.png"},
groups = {pickaxey=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 30,
_mcl_hardness = 1.5,
})
minetest.register_node("mcl_end:end_rod", {
description = "End Rod",
_doc_items_longdesc = "End rods are decorational light sources.",
tiles = {
"mcl_end_end_rod_top.png",
"mcl_end_end_rod_bottom.png",
"mcl_end_end_rod_side.png",
"mcl_end_end_rod_side.png",
"mcl_end_end_rod_side.png",
"mcl_end_end_rod_side.png",
},
drawtype = "nodebox",
is_ground_content = false,
paramtype = "light",
paramtype2 = "facedir",
light_source = 14,
sunlight_propagates = true,
groups = { dig_immediate=3, deco_block=1, destroy_by_lava_flow=1, },
node_box = {
type = "fixed",
fixed = {
{-0.125, -0.5, -0.125, 0.125, -0.4375, 0.125}, -- Base
{-0.0625, -0.4375, -0.0625, 0.0625, 0.5, 0.0625}, -- Rod
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.125, -0.5, -0.125, 0.125, 0.5, 0.125}, -- Base
},
},
collision_box = {
type = "fixed",
fixed = {
{-0.125, -0.5, -0.125, 0.125, 0.5, 0.125}, -- Base
},
},
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local p0 = pointed_thing.under
local p1 = pointed_thing.above
local param2 = 0
local placer_pos = placer:getpos()
if placer_pos then
local dir = {
x = p1.x - placer_pos.x,
y = p1.y - placer_pos.y,
z = p1.z - placer_pos.z
}
param2 = minetest.dir_to_facedir(dir)
end
if p0.y - 1 == p1.y then
param2 = 20
elseif p0.x - 1 == p1.x then
param2 = 16
elseif p0.x + 1 == p1.x then
param2 = 12
elseif p0.z - 1 == p1.z then
param2 = 8
elseif p0.z + 1 == p1.z then
param2 = 4
end
return minetest.item_place(itemstack, placer, pointed_thing, param2)
end,
sounds = mcl_sounds.node_sound_glass_defaults(),
_mcl_blast_resistance = 0,
})
minetest.register_node("mcl_end:dragon_egg", {
description = "Dragon Egg",
_doc_items_longdesc = "A dragon egg is a decorational item which can be placed.",
tiles = {
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
},
drawtype = "nodebox",
is_ground_content = false,
paramtype = "light",
light_source = 1,
node_box = {
type = "fixed",
fixed = {
{-0.375, -0.5, -0.375, 0.375, -0.4375, 0.375},
{-0.5, -0.4375, -0.5, 0.5, -0.1875, 0.5},
{-0.4375, -0.1875, -0.4375, 0.4375, 0, 0.4375},
{-0.375, 0, -0.375, 0.375, 0.125, 0.375},
{-0.3125, 0.125, -0.3125, 0.3125, 0.25, 0.3125},
{-0.25, 0.25, -0.25, 0.25, 0.3125, 0.25},
{-0.1875, 0.3125, -0.1875, 0.1875, 0.375, 0.1875},
{-0.125, 0.375, -0.125, 0.125, 0.4375, 0.125},
{-0.0625, 0.4375, -0.0625, 0.0625, 0.5, 0.0625},
}
},
selection_box = {
type = "regular",
},
groups = {handy=1, falling_node = 1, deco_block = 1, not_in_creative_inventory = 1, dig_by_piston = 1 },
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 45,
_mcl_hardness = 3,
-- TODO: Make dragon egg teleport on punching
})
-- Crafting recipes
minetest.register_craft({
output = "mcl_end:end_bricks 4",
recipe = {
{"mcl_end:end_stone", "mcl_end:end_stone"},
{"mcl_end:end_stone", "mcl_end:end_stone"},
}
})
minetest.register_craft({
output = "mcl_end:purpur_block 4",
recipe = {
{"mcl_end:chorus_fruit_popped", "mcl_end:chorus_fruit_popped",},
{"mcl_end:chorus_fruit_popped", "mcl_end:chorus_fruit_popped",},
}
})
minetest.register_craft({
output = "mcl_end:end_rod 4",
recipe = {
{"mcl_mobitems:blaze_rod"},
{"mcl_end:chorus_fruit_popped"},
},
})

@ -0,0 +1,288 @@
-- Chorus plants.
-- This includes chorus flowers, chorus plant stem nodes and chorus fruit
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},
}
}
minetest.register_node("mcl_end:chorus_flower", {
description = "Chorus Flower",
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(),
groups = {handy=1,axey=1, deco_block = 1, dig_by_piston = 1, destroy_by_lava_flow = 1,},
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 is one of the following
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
return minetest.item_place(itemstack, placer, pointed_thing)
else
return itemstack
end
end,
_mcl_blast_resistance = 2,
_mcl_hardness = 0.4,
})
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)
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
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
end
end
end
else
break
end
end
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
local grown = false
if grow_chance then
local new_flowers = {}
local r = math.random(1, 100)
local age = node.param2
if r <= grow_chance then
table.insert(new_flowers, above)
else
age = age + 1
local branches
if branching == false then
branches = math.random(1, 4)
elseif branching == true then
branches = math.random(0, 3)
end
local branch_grown = false
for b=1, branches do
local next_branch = math.random(1, #around)
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)
end
end
end
for _, f in ipairs(new_flowers) do
if age >= 5 then
minetest.set_node(f, {name="mcl_end:chorus_flower_dead"})
grown = true
else
minetest.set_node(f, {name="mcl_end:chorus_flower", param2 = age})
grown = true
end
end
if #new_flowers >= 1 then
minetest.set_node(pos, {name="mcl_end:chorus_plant"})
grown = true
end
end
if not grown then
minetest.set_node(pos, {name = "mcl_end:chorus_flower_dead"})
end
end
end,
})
minetest.register_node("mcl_end:chorus_flower_dead", {
description = "Dead Chorus Flower",
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",
groups = {handy=1,axey=1, deco_block = 1, dig_by_piston = 1, destroy_by_lava_flow = 1,},
_mcl_blast_resistance = 2,
_mcl_hardness = 0.4,
})
minetest.register_node("mcl_end:chorus_plant", {
description = "Chorus Plant Stem",
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,
-- TODO: Maybe improve nodebox a bit to look more “natural”
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" },
connects_to = {"mcl_end:chorus_plant", "mcl_end:chorus_flower", "mcl_end:chorus_flower_dead", "mcl_end:end_stone"},
sounds = mcl_sounds.node_sound_wood_defaults(),
drop = {
items = {
{ items = { "mcl_end:chorus_fruit"}, rarity = 2 },
}
},
groups = {handy=1,axey=1, not_in_creative_inventory = 1, dig_by_piston = 1, destroy_by_lava_flow = 1 },
_mcl_blast_resistance = 2,
_mcl_hardness = 0.4,
})
-- Craftitems
minetest.register_craftitem("mcl_end:chorus_fruit", {
description = "Chorus Fruit",
_doc_items_longdesc = "Chorus fruits are the fruits of the chorus plant which is home to the End. They can be eaten to restore a few hunger points.",
wield_image = "mcl_end_chorus_fruit.png",
inventory_image = "mcl_end_chorus_fruit.png",
-- TODO: Teleport player
on_place = minetest.item_eat(4),
on_secondary_use = minetest.item_eat(4),
groups = { food = 2, eatable = 4, can_eat_when_full = 1 },
_mcl_saturation = 2.4,
stack_max = 64,
})
minetest.register_craftitem("mcl_end:chorus_fruit_popped", {
description = "Popped Chorus Fruit",
_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,
})
minetest.register_craft({
type = "cooking",
output = "mcl_end:chorus_fruit_popped",
recipe = "mcl_end:chorus_fruit",
cooktime = 10,
})

@ -0,0 +1,153 @@
-- Eye of Ender
minetest.register_entity("mcl_end:ender_eye", {
physical = false,
textures = {"mcl_end_ender_eye.png"},
visual_size = {x=1.5, y=1.5},
collisionbox = {0,0,0,0,0,0},
-- Save and restore age
get_staticdata = function(self)
return tostring(self._age)
end,
on_activate = function(self, staticdata, dtime_s)
local age = tonumber(staticdata)
if type(age) == "number" then
self._age = age
if self._age >= 2 then
self._phase = 1
else
self._phase = 0
end
end
end,
on_step = function(self, dtime)
self._age = self._age + dtime
if self._age >= 3 then
-- End of life
local r = math.random(1,5)
if r == 1 or minetest.settings:get_bool("creative_mode") then
-- 20% chance to get destroyed completely.
-- 100% if in Creative Mode
self.object:remove()
return
else
-- 80% to drop as an item
local pos = self.object:get_pos()
local v = self.object:getvelocity()
self.object:remove()
local item = minetest.add_item(pos, "mcl_end:ender_eye")
item:setvelocity(v)
return
end
elseif self._age >= 2 then
if self._phase == 0 then
self._phase = 1
-- Stop the eye and wait for another second.
-- The vertical speed changes are just eye candy.
self.object:setacceleration({x=0, y=-3, z=0})
self.object:setvelocity({x=0, y=self.object:getvelocity().y*0.2, z=0})
end
else
-- Fly normally and generate particles
local pos = self.object:get_pos()
pos.x = pos.x + math.random(-1, 1)*0.5
pos.y = pos.y + math.random(-1, 0)*0.5
pos.z = pos.z + math.random(-1, 1)*0.5
minetest.add_particle({
pos = pos,
texture = "mcl_particles_teleport.png",
expirationtime = 1,
velocity = {x=math.random(-1, 1)*0.1, y=math.random(-30, 0)*0.1, z=math.random(-1, 1)*0.1},
acceleration = {x=0, y=0, z=0},
size = 2.5,
})
end
end,
_age = 0, -- age in seconds
_phase = 0, -- phase 0: flying. phase 1: idling in mid air, about to drop or shatter
})
minetest.register_craftitem("mcl_end:ender_eye", {
description = "Eye of Ender",
_doc_items_longdesc = "This item is used to locate End portal shrines in the Overworld and to activate End portals." .. "\n" .. "NOTE: The End dimension is currently incomplete and boring.",
_doc_items_usagehelp = "Use the attack key to release the eye of ender. It will rise and fly in the horizontal direction of the closest end portal shrine. If you're very close, the eye of ender will take the direct path to the End portal shrine instead. After a few seconds, it stops. It may drop as an item, but there's a 20% chance it shatters." .. "\n" .. "To activate an End portal, eyes of ender need to be placed into each block of an intact End portal frame.",
wield_image = "mcl_end_ender_eye.png",
inventory_image = "mcl_end_ender_eye.png",
stack_max = 64,
-- Throw eye of ender to make it fly to the closest stronghold
on_use = function(itemstack, user, pointed_thing)
if user == nil then
return
end
local origin = user:get_pos()
origin.y = origin.y + 1.5
local strongholds = mcl_structures.get_registered_structures("stronghold")
local dim = mcl_worlds.pos_to_dimension(origin)
local is_creative = minetest.settings:get_bool("creative_mode")
-- Just drop the eye of ender if there are no strongholds
if #strongholds <= 0 or dim ~= "overworld" then
if not is_creative then
minetest.item_drop(ItemStack("mcl_end:ender_eye"), user, user:get_pos())
itemstack:take_item()
end
return itemstack
end
-- Find closest stronghold.
-- Note: Only the horizontal axes are taken into account.
local closest_stronghold
local lowest_dist
for s=1, #strongholds do
local h_pos = table.copy(strongholds[s].pos)
local h_origin = table.copy(origin)
h_pos.y = 0
h_origin.y = 0
local dist = vector.distance(h_origin, h_pos)
if not closest_stronghold then
closest_stronghold = strongholds[s]
lowest_dist = dist
else
if dist < lowest_dist then
closest_stronghold = strongholds[s]
lowest_dist = dist
end
end
end
-- Throw it!
local obj = minetest.add_entity(origin, "mcl_end:ender_eye")
local dir
if lowest_dist <= 25 then
local velocity = 4
-- Stronghold is close: Fly directly to stronghold and take Y into account.
dir = vector.normalize(vector.direction(origin, closest_stronghold.pos))
obj:setvelocity({x=dir.x*velocity, y=dir.y*velocity, z=dir.z*velocity})
else
local velocity = 12
-- Don't care about Y if stronghold is still far away.
-- Fly to direction of X/Z, and always upwards so it can be seen easily.
local o = {x=origin.x, y=0, z=origin.z}
local s = {x=closest_stronghold.pos.x, y=0, z=closest_stronghold.pos.z}
dir = vector.normalize(vector.direction(o, s))
obj:setacceleration({x=dir.x*-3, y=4, z=dir.z*-3})
obj:setvelocity({x=dir.x*velocity, y=3, z=dir.z*velocity})
end
if not is_creative then
itemstack:take_item()
end
return itemstack
end,
})
minetest.register_craft({
type = "shapeless",
output = "mcl_end:ender_eye",
recipe = {"mcl_mobitems:blaze_powder", "mcl_throwing:ender_pearl"},
})

@ -1,627 +1,4 @@
-- Nodes local basepath = minetest.get_modpath(minetest.get_current_modname())
minetest.register_node("mcl_end:end_stone", { dofile(basepath.."/building.lua")
description = "End Stone", dofile(basepath.."/chorus_plant.lua")
_doc_items_longdesc = doc.sub.items.temp.build, dofile(basepath.."/eye_of_ender.lua")
tiles = {"mcl_end_end_stone.png"},
stack_max = 64,
groups = {pickaxey=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 45,
_mcl_hardness = 3,
})
minetest.register_node("mcl_end:end_bricks", {
description = "End Stone Bricks",
_doc_items_longdesc = doc.sub.items.temp.build,
tiles = {"mcl_end_end_bricks.png"},
is_ground_content = false,
stack_max = 64,
groups = {pickaxey=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 4,
_mcl_hardness = 0.8,
})
minetest.register_node("mcl_end:purpur_block", {
description = "Purpur Block",
_doc_items_longdesc = doc.sub.items.temp.build,
tiles = {"mcl_end_purpur_block.png"},
is_ground_content = false,
stack_max = 64,
groups = {pickaxey=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 30,
_mcl_hardness = 1.5,
})
minetest.register_node("mcl_end:purpur_pillar", {
description = "Purpur Pillar",
_doc_items_longdesc = doc.sub.items.temp.build,
stack_max = 64,
paramtype2 = "facedir",
is_ground_content = false,
on_place = mcl_util.rotate_axis,
tiles = {"mcl_end_purpur_pillar_top.png", "mcl_end_purpur_pillar_top.png", "mcl_end_purpur_pillar.png"},
groups = {pickaxey=1, building_block=1, material_stone=1},
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 30,
_mcl_hardness = 1.5,
})
minetest.register_node("mcl_end:end_rod", {
description = "End Rod",
_doc_items_longdesc = "End rods are decorational light sources.",
tiles = {
"mcl_end_end_rod_top.png",
"mcl_end_end_rod_bottom.png",
"mcl_end_end_rod_side.png",
"mcl_end_end_rod_side.png",
"mcl_end_end_rod_side.png",
"mcl_end_end_rod_side.png",
},
drawtype = "nodebox",
is_ground_content = false,
paramtype = "light",
paramtype2 = "facedir",
light_source = 14,
sunlight_propagates = true,
groups = { dig_immediate=3, deco_block=1, destroy_by_lava_flow=1, },
node_box = {
type = "fixed",
fixed = {
{-0.125, -0.5, -0.125, 0.125, -0.4375, 0.125}, -- Base
{-0.0625, -0.4375, -0.0625, 0.0625, 0.5, 0.0625}, -- Rod
},
},
selection_box = {
type = "fixed",
fixed = {
{-0.125, -0.5, -0.125, 0.125, 0.5, 0.125}, -- Base
},
},
collision_box = {
type = "fixed",
fixed = {
{-0.125, -0.5, -0.125, 0.125, 0.5, 0.125}, -- Base
},
},
on_place = function(itemstack, placer, pointed_thing)
if pointed_thing.type ~= "node" then
return itemstack
end
local p0 = pointed_thing.under
local p1 = pointed_thing.above
local param2 = 0
local placer_pos = placer:getpos()
if placer_pos then
local dir = {
x = p1.x - placer_pos.x,
y = p1.y - placer_pos.y,
z = p1.z - placer_pos.z
}
param2 = minetest.dir_to_facedir(dir)
end
if p0.y - 1 == p1.y then
param2 = 20
elseif p0.x - 1 == p1.x then
param2 = 16
elseif p0.x + 1 == p1.x then
param2 = 12
elseif p0.z - 1 == p1.z then
param2 = 8
elseif p0.z + 1 == p1.z then
param2 = 4
end
return minetest.item_place(itemstack, placer, pointed_thing, param2)
end,
sounds = mcl_sounds.node_sound_glass_defaults(),
_mcl_blast_resistance = 0,
})
minetest.register_node("mcl_end:dragon_egg", {
description = "Dragon Egg",
_doc_items_longdesc = "A dragon egg is a decorational item which can be placed.",
tiles = {
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
"mcl_end_dragon_egg.png",
},
drawtype = "nodebox",
is_ground_content = false,
paramtype = "light",
light_source = 1,
node_box = {
type = "fixed",
fixed = {
{-0.375, -0.5, -0.375, 0.375, -0.4375, 0.375},
{-0.5, -0.4375, -0.5, 0.5, -0.1875, 0.5},
{-0.4375, -0.1875, -0.4375, 0.4375, 0, 0.4375},
{-0.375, 0, -0.375, 0.375, 0.125, 0.375},
{-0.3125, 0.125, -0.3125, 0.3125, 0.25, 0.3125},
{-0.25, 0.25, -0.25, 0.25, 0.3125, 0.25},
{-0.1875, 0.3125, -0.1875, 0.1875, 0.375, 0.1875},
{-0.125, 0.375, -0.125, 0.125, 0.4375, 0.125},
{-0.0625, 0.4375, -0.0625, 0.0625, 0.5, 0.0625},
}
},
selection_box = {
type = "regular",
},
groups = {handy=1, falling_node = 1, deco_block = 1, not_in_creative_inventory = 1, dig_by_piston = 1 },
sounds = mcl_sounds.node_sound_stone_defaults(),
_mcl_blast_resistance = 45,
_mcl_hardness = 3,
-- TODO: Make dragon egg teleport on punching
})
-- Eye of ender
minetest.register_entity("mcl_end:ender_eye", {
physical = false,
textures = {"mcl_end_ender_eye.png"},
visual_size = {x=1.5, y=1.5},
collisionbox = {0,0,0,0,0,0},
-- Save and restore age
get_staticdata = function(self)
return tostring(self._age)
end,
on_activate = function(self, staticdata, dtime_s)
local age = tonumber(staticdata)
if type(age) == "number" then
self._age = age
if self._age >= 2 then
self._phase = 1
else
self._phase = 0
end
end
end,
on_step = function(self, dtime)
self._age = self._age + dtime
if self._age >= 3 then
-- End of life
local r = math.random(1,5)
if r == 1 or minetest.settings:get_bool("creative_mode") then
-- 20% chance to get destroyed completely.
-- 100% if in Creative Mode
self.object:remove()
return
else
-- 80% to drop as an item
local pos = self.object:get_pos()
local v = self.object:getvelocity()
self.object:remove()
local item = minetest.add_item(pos, "mcl_end:ender_eye")
item:setvelocity(v)
return
end
elseif self._age >= 2 then
if self._phase == 0 then
self._phase = 1
-- Stop the eye and wait for another second.
-- The vertical speed changes are just eye candy.
self.object:setacceleration({x=0, y=-3, z=0})
self.object:setvelocity({x=0, y=self.object:getvelocity().y*0.2, z=0})
end
else
-- Fly normally and generate particles
local pos = self.object:get_pos()
pos.x = pos.x + math.random(-1, 1)*0.5
pos.y = pos.y + math.random(-1, 0)*0.5
pos.z = pos.z + math.random(-1, 1)*0.5
minetest.add_particle({
pos = pos,
texture = "mcl_particles_teleport.png",
expirationtime = 1,
velocity = {x=math.random(-1, 1)*0.1, y=math.random(-30, 0)*0.1, z=math.random(-1, 1)*0.1},
acceleration = {x=0, y=0, z=0},
size = 2.5,
})
end
end,
_age = 0, -- age in seconds
_phase = 0, -- phase 0: flying. phase 1: idling in mid air, about to drop or shatter
})
minetest.register_craftitem("mcl_end:ender_eye", {
description = "Eye of Ender",
_doc_items_longdesc = "This item is used to locate End portal shrines in the Overworld and to activate End portals." .. "\n" .. "NOTE: The End dimension is currently incomplete and boring.",
_doc_items_usagehelp = "Use the attack key to release the eye of ender. It will rise and fly in the horizontal direction of the closest end portal shrine. If you're very close, the eye of ender will take the direct path to the End portal shrine instead. After a few seconds, it stops. It may drop as an item, but there's a 20% chance it shatters." .. "\n" .. "To activate an End portal, eyes of ender need to be placed into each block of an intact End portal frame.",
wield_image = "mcl_end_ender_eye.png",
inventory_image = "mcl_end_ender_eye.png",
stack_max = 64,
-- Throw eye of ender to make it fly to the closest stronghold
on_use = function(itemstack, user, pointed_thing)
if user == nil then
return
end
local origin = user:get_pos()
origin.y = origin.y + 1.5
local strongholds = mcl_structures.get_registered_structures("stronghold")
local dim = mcl_worlds.pos_to_dimension(origin)
local is_creative = minetest.settings:get_bool("creative_mode")
-- Just drop the eye of ender if there are no strongholds
if #strongholds <= 0 or dim ~= "overworld" then
if not is_creative then
minetest.item_drop(ItemStack("mcl_end:ender_eye"), user, user:get_pos())
itemstack:take_item()
end
return itemstack
end
-- Find closest stronghold.
-- Note: Only the horizontal axes are taken into account.
local closest_stronghold
local lowest_dist
for s=1, #strongholds do
local h_pos = table.copy(strongholds[s].pos)
local h_origin = table.copy(origin)
h_pos.y = 0
h_origin.y = 0
local dist = vector.distance(h_origin, h_pos)
if not closest_stronghold then
closest_stronghold = strongholds[s]
lowest_dist = dist
else
if dist < lowest_dist then
closest_stronghold = strongholds[s]
lowest_dist = dist
end
end
end
-- Throw it!
local obj = minetest.add_entity(origin, "mcl_end:ender_eye")
local dir
if lowest_dist <= 25 then
local velocity = 4
-- Stronghold is close: Fly directly to stronghold and take Y into account.
dir = vector.normalize(vector.direction(origin, closest_stronghold.pos))
obj:setvelocity({x=dir.x*velocity, y=dir.y*velocity, z=dir.z*velocity})
else
local velocity = 12
-- Don't care about Y if stronghold is still far away.
-- Fly to direction of X/Z, and always upwards so it can be seen easily.
local o = {x=origin.x, y=0, z=origin.z}
local s = {x=closest_stronghold.pos.x, y=0, z=closest_stronghold.pos.z}
dir = vector.normalize(vector.direction(o, s))
obj:setacceleration({x=dir.x*-3, y=4, z=dir.z*-3})
obj:setvelocity({x=dir.x*velocity, y=3, z=dir.z*velocity})
end
if not is_creative then
itemstack:take_item()
end
return itemstack
end,
})
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},
}
}
minetest.register_node("mcl_end:chorus_flower", {
description = "Chorus Flower",
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(),
groups = {handy=1,axey=1, deco_block = 1, dig_by_piston = 1, destroy_by_lava_flow = 1,},
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 is one of the following
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
return minetest.item_place(itemstack, placer, pointed_thing)
else
return itemstack
end
end,
_mcl_blast_resistance = 2,
_mcl_hardness = 0.4,
})
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)
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
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
end
end
end
else
break
end
end
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
local grown = false
if grow_chance then
local new_flowers = {}
local r = math.random(1, 100)
local age = node.param2
if r <= grow_chance then
table.insert(new_flowers, above)
else
age = age + 1
local branches
if branching == false then
branches = math.random(1, 4)
elseif branching == true then
branches = math.random(0, 3)
end
local branch_grown = false
for b=1, branches do
local next_branch = math.random(1, #around)
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)
end
end
end
for _, f in ipairs(new_flowers) do
if age >= 5 then
minetest.set_node(f, {name="mcl_end:chorus_flower_dead"})
grown = true
else
minetest.set_node(f, {name="mcl_end:chorus_flower", param2 = age})
grown = true
end
end
if #new_flowers >= 1 then
minetest.set_node(pos, {name="mcl_end:chorus_plant"})
grown = true
end
end
if not grown then
minetest.set_node(pos, {name = "mcl_end:chorus_flower_dead"})
end
end
end,
})
minetest.register_node("mcl_end:chorus_flower_dead", {
description = "Dead Chorus Flower",
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",
groups = {handy=1,axey=1, deco_block = 1, dig_by_piston = 1, destroy_by_lava_flow = 1,},
_mcl_blast_resistance = 2,
_mcl_hardness = 0.4,
})
minetest.register_node("mcl_end:chorus_plant", {
description = "Chorus Plant",
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,
-- TODO: Maybe improve nodebox a bit to look more “natural”
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" },
connects_to = {"mcl_end:chorus_plant", "mcl_end:chorus_flower", "mcl_end:chorus_flower_dead", "mcl_end:end_stone"},
sounds = mcl_sounds.node_sound_wood_defaults(),
drop = {
items = {
{ items = { "mcl_end:chorus_fruit"}, rarity = 2 },
}
},
groups = {handy=1,axey=1, not_in_creative_inventory = 1, dig_by_piston = 1, destroy_by_lava_flow = 1 },
_mcl_blast_resistance = 2,
_mcl_hardness = 0.4,
})
-- Craftitems
minetest.register_craftitem("mcl_end:chorus_fruit", {
description = "Chorus Fruit",
_doc_items_longdesc = "Chorus fruits are the fruits of the chorus plant which is home to the End. They can be eaten to restore a few hunger points.",
wield_image = "mcl_end_chorus_fruit.png",
inventory_image = "mcl_end_chorus_fruit.png",
-- TODO: Teleport player
on_place = minetest.item_eat(4),
on_secondary_use = minetest.item_eat(4),
groups = { food = 2, eatable = 4, can_eat_when_full = 1 },
_mcl_saturation = 2.4,
stack_max = 64,
})
minetest.register_craftitem("mcl_end:chorus_fruit_popped", {
description = "Popped Chorus Fruit",
_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,
})
-- Crafting recipes
minetest.register_craft({
output = "mcl_end:end_bricks 4",
recipe = {
{"mcl_end:end_stone", "mcl_end:end_stone"},
{"mcl_end:end_stone", "mcl_end:end_stone"},
}
})
minetest.register_craft({
output = "mcl_end:purpur_block 4",
recipe = {
{"mcl_end:chorus_fruit_popped", "mcl_end:chorus_fruit_popped",},
{"mcl_end:chorus_fruit_popped", "mcl_end:chorus_fruit_popped",},
}
})
minetest.register_craft({
output = "mcl_end:end_rod 4",
recipe = {
{"mcl_mobitems:blaze_rod"},
{"mcl_end:chorus_fruit_popped"},
},
})
minetest.register_craft({
type = "shapeless",
output = "mcl_end:ender_eye",
recipe = {"mcl_mobitems:blaze_powder", "mcl_throwing:ender_pearl"},
})
minetest.register_craft({
type = "cooking",
output = "mcl_end:chorus_fruit_popped",
recipe = "mcl_end:chorus_fruit",
cooktime = 10,
})