Cake+cauldron+endportalfr. put signal 4 comparator
[MineClone/MineClone2.git] / mods / ITEMS / mcl_portals / portal_end.lua
bloba83b42b2e9ac9be1448242dbfc77a6eef5af07fa
1 -- Parameters
2 local SPAWN_MIN = mcl_vars.mg_end_min+70
3 local SPAWN_MAX = mcl_vars.mg_end_min+98
5 local mg_name = minetest.get_mapgen_setting("mg_name")
7 -- End portal
8 minetest.register_node("mcl_portals:portal_end", {
9 description = "End Portal",
10 _doc_items_longdesc = "An End portal teleports creatures and objects to the mysterious End dimension (and back!).",
11 _doc_items_usagehelp = "Hop into the portal to teleport. Entering an End portal in the Overworld teleports you to a fixed position in the End dimension and creates a 5×5 obsidian platform at your destination. End portals in the End will lead back to your spawn point in the Overworld.",
12 tiles = {
14 name = "mcl_portals_end_portal.png",
15 animation = {
16 type = "vertical_frames",
17 aspect_w = 16,
18 aspect_h = 16,
19 length = 1.0,
22 "blank.png",
23 "blank.png",
24 "blank.png",
25 "blank.png",
26 "blank.png",
28 drawtype = "nodebox",
29 paramtype = "light",
30 sunlight_propagates = true,
31 use_texture_alpha = true,
32 walkable = false,
33 diggable = false,
34 pointable = false,
35 buildable_to = false,
36 is_ground_content = false,
37 drop = "",
38 -- This is 15 in MC.
39 light_source = 14,
40 post_effect_color = {a = 192, r = 0, g = 0, b = 0},
41 alpha = 192,
42 node_box = {
43 type = "fixed",
44 fixed = {
45 {-0.5, -0.5, -0.5, 0.5, 4/16, 0.5},
48 groups = {not_in_creative_inventory = 1},
50 _mcl_hardness = -1,
51 _mcl_blast_resistance = 18000000,
54 -- Obsidian platform at the End portal destination in the End
55 local function build_end_portal_destination(pos)
56 local p1 = {x = pos.x - 2, y = pos.y, z = pos.z-2}
57 local p2 = {x = pos.x + 2, y = pos.y+2, z = pos.z+2}
59 for x = p1.x, p2.x do
60 for y = p1.y, p2.y do
61 for z = p1.z, p2.z do
62 local newp = {x=x,y=y,z=z}
63 -- Build obsidian platform
64 if minetest.registered_nodes[minetest.get_node(newp).name].is_ground_content then
65 if y == p1.y then
66 minetest.set_node(newp, {name="mcl_core:obsidian"})
67 else
68 minetest.remove_node(newp)
69 end
70 end
71 end
72 end
73 end
74 end
77 -- Check if pos is part of a valid end portal frame, filled with eyes of ender.
78 local function check_end_portal_frame(pos)
79 -- Check if pos has an end portal frame with eye of ender
80 local eframe = function(pos, param2)
81 local node = minetest.get_node(pos)
82 if node.name == "mcl_portals:end_portal_frame_eye" then
83 if param2 == nil or node.param2 == param2 then
84 return true, node
85 end
86 end
87 return false
88 end
90 -- Step 1: Find a row of 3 end portal frames with eyes, all facing the same direction
91 local streak = 0
92 local streak_start, streak_end, streak_start_node, streak_end_node
93 local last_param2
94 local axes = { "x", "z" }
95 for a=1, #axes do
96 local axis = axes[a]
97 for b=pos[axis]-2, pos[axis]+2 do
98 local cpos = table.copy(pos)
99 cpos[axis] = b
100 local e, node = eframe(cpos, last_param2)
101 if e then
102 last_param2 = node.param2
103 streak = streak + 1
104 if streak == 1 then
105 streak_start = table.copy(pos)
106 streak_start[axis] = b
107 streak_start_node = node
108 elseif streak == 3 then
109 streak_end = table.copy(pos)
110 streak_end[axis] = b
111 streak_end_node = node
112 break
114 else
115 streak = 0
116 last_param2 = nil
119 if streak_end then
120 break
122 streak = 0
123 last_param2 = nil
125 -- Has a row been found?
126 if streak_end then
127 -- Step 2: Using the known facedir, check the remaining spots in which we expect
128 -- “eyed” end portal frames.
129 local dir = minetest.facedir_to_dir(streak_start_node.param2)
130 if dir.x ~= 0 then
131 for i=1, 3 do
132 if not eframe({x=streak_start.x + i*dir.x, y=streak_start.y, z=streak_start.z - 1}) then
133 return false
135 if not eframe({x=streak_start.x + i*dir.x, y=streak_start.y, z=streak_end.z + 1}) then
136 return false
138 if not eframe({x=streak_start.x + 4*dir.x, y=streak_start.y, z=streak_start.z + i-1}) then
139 return false
142 -- All checks survived! We have a valid portal!
143 local k
144 if dir.x > 0 then
145 k = 1
146 else
147 k = -3
149 return true, { x = streak_start.x + k, y = streak_start.y, z = streak_start.z }
150 elseif dir.z ~= 0 then
151 for i=1, 3 do
152 if not eframe({x=streak_start.x - 1, y=streak_start.y, z=streak_start.z + i*dir.z}) then
153 return false
155 if not eframe({x=streak_end.x + 1, y=streak_start.y, z=streak_start.z + i*dir.z}) then
156 return false
158 if not eframe({x=streak_start.x + i-1, y=streak_start.y, z=streak_start.z + 4*dir.z}) then
159 return false
162 local k
163 if dir.z > 0 then
164 k = 1
165 else
166 k = -3
168 -- All checks survived! We have a valid portal!
169 return true, { x = streak_start.x, y = streak_start.y, z = streak_start.z + k }
172 return false
175 -- Generate or destroy a 3×3 end portal beginning at pos. To be used to fill an end portal framea.
176 -- If destroy == true, the 3×3 area is removed instead.
177 local function end_portal_area(pos, destroy)
178 local SIZE = 3
179 local name
180 if destroy then
181 name = "air"
182 else
183 name = "mcl_portals:portal_end"
185 for x=pos.x, pos.x+SIZE-1 do
186 for z=pos.z, pos.z+SIZE-1 do
187 minetest.set_node({x=x,y=pos.y,z=z}, {name=name})
192 minetest.register_abm({
193 label = "End portal teleportation",
194 nodenames = {"mcl_portals:portal_end"},
195 interval = 1,
196 chance = 1,
197 action = function(pos, node)
198 -- Destroy legacy end portals created with quartz block frame
199 -- by turning them into cobwebs.
200 -- We can tell if a end portal is legacy if it has portal_target as metadata.
201 -- FIXME: Remove this after some time.
202 local meta = minetest.get_meta(pos)
203 local legacy_portal_target = meta:get_string("portal_frame1")
204 if legacy_portal_target and legacy_portal_target ~= "" then
205 minetest.set_node(pos, {name="mcl_core:cobweb"})
206 return
209 for _,obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
210 local lua_entity = obj:get_luaentity() --maikerumine added for objects to travel
211 if obj:is_player() or lua_entity then
212 local dim = mcl_worlds.pos_to_dimension(pos)
214 local objpos = obj:getpos()
215 if objpos == nil then
216 return
219 -- Check if object is actually in portal.
220 objpos.y = math.ceil(objpos.y)
221 if minetest.get_node(objpos).name ~= "mcl_portals:portal_end" then
222 return
225 local target
226 if dim == "end" then
227 -- End portal in the End:
228 -- Teleport back to the player's spawn in the Overworld.
230 target = mcl_spawn.get_spawn_pos(obj)
231 else
232 -- End portal in any other dimension:
233 -- Teleport to the End at a fixed position and generate a
234 -- 5×5 obsidian platform below.
236 local platform_pos = mcl_vars.mg_end_platform_pos
237 -- force emerge of target1 area
238 minetest.get_voxel_manip():read_from_map(platform_pos, platform_pos)
239 if not minetest.get_node_or_nil(platform_pos) then
240 minetest.emerge_area(vector.subtract(platform_pos, 3), vector.add(platform_pos, 3))
243 -- Build destination
244 local function check_and_build_end_portal_destination(pos)
245 local n = minetest.get_node_or_nil(pos)
246 if n and n.name ~= "mcl_core:obsidian" then
247 build_end_portal_destination(pos)
248 minetest.after(2, check_and_build_end_portal_destination, pos)
249 elseif not n then
250 minetest.after(1, check_and_build_end_portal_destination, pos)
254 local platform
255 build_end_portal_destination(platform_pos)
256 check_and_build_end_portal_destination(platform_pos)
258 target = table.copy(platform_pos)
259 target.y = target.y + 1
262 -- Teleport
263 obj:set_pos(target)
264 if obj:is_player() then
265 -- Look towards the main End island
266 if dim ~= "end" then
267 obj:set_look_horizontal(math.pi/2)
269 mcl_worlds.dimension_change(obj, mcl_worlds.pos_to_dimension(target))
270 minetest.sound_play("mcl_portals_teleport", {pos=target, gain=0.5, max_hear_distance = 16})
274 end,
277 local rotate_frame, rotate_frame_eye
279 if minetest.get_modpath("screwdriver") then
280 -- Intentionally not rotatable
281 rotate_frame = false
282 rotate_frame_eye = false
285 minetest.register_node("mcl_portals:end_portal_frame", {
286 description = "End Portal Frame",
287 _doc_items_longdesc = "End portal frames are used in the construction of End portals. Each block has a socket for an eye of ender." .. "\n" .. "NOTE: The End dimension is currently incomplete and boring.",
288 _doc_items_usagehelp = "To create an End portal, you need 12 end portal frames and 12 eyes of ender. The end portal frames have to be arranged around a horizontal 3×3 area with each block facing inward. Any other arrangement will fail." .. "\n" .. "Place an eye of ender into each block. The end portal appears in the middle after placing the final eye." .. "\n" .. "Once placed, an eye of ender can not be taken back.",
289 groups = { creative_breakable = 1, deco_block = 1 },
290 tiles = { "mcl_portals_endframe_top.png", "mcl_portals_endframe_bottom.png", "mcl_portals_endframe_side.png" },
291 paramtype2 = "facedir",
292 drawtype = "nodebox",
293 node_box = {
294 type = "fixed",
295 fixed = { -0.5, -0.5, -0.5, 0.5, 5/16, 0.5 },
297 is_ground_content = false,
298 sounds = mcl_sounds.node_sound_stone_defaults(),
299 paramtype = "light",
300 sunlight_propagates = false,
301 light_source = 1,
303 on_rotate = rotate_frame,
305 _mcl_blast_resistance = 18000000,
306 _mcl_hardness = -1,
309 minetest.register_node("mcl_portals:end_portal_frame_eye", {
310 description = "End Portal Frame with Eye of Ender",
311 _doc_items_create_entry = false,
312 groups = { creative_breakable = 1, not_in_creative_inventory = 1, comparator_signal = 15 },
313 tiles = { "mcl_portals_endframe_top.png^[lowpart:75:mcl_portals_endframe_eye.png", "mcl_portals_endframe_bottom.png", "mcl_portals_endframe_eye.png^mcl_portals_endframe_side.png" },
314 paramtype2 = "facedir",
315 drawtype = "nodebox",
316 node_box = {
317 type = "fixed",
318 fixed = {
319 { -0.5, -0.5, -0.5, 0.5, 5/16, 0.5 }, -- Frame
320 { -4/16, 5/16, -4/16, 4/16, 0.5, 4/16 }, -- Eye
323 is_ground_content = false,
324 sounds = mcl_sounds.node_sound_stone_defaults(),
325 paramtype = "light",
326 sunlight_propagates = false,
327 light_source = 1,
328 on_destruct = function(pos)
329 local ok, ppos = check_end_portal_frame(pos)
330 if ok then
331 end_portal_area(ppos, true)
333 end,
335 on_rotate = rotate_frame_eye,
337 _mcl_blast_resistance = 18000000,
338 _mcl_hardness = -1,
341 if minetest.get_modpath("doc") then
342 doc.add_entry_alias("nodes", "mcl_portals:end_portal_frame", "nodes", "mcl_portals:end_portal_frame_eye")
346 --[[ ITEM OVERRIDES ]]
348 -- Portal opener
349 minetest.override_item("mcl_end:ender_eye", {
350 on_place = function(itemstack, user, pointed_thing)
351 -- Use pointed node's on_rightclick function first, if present
352 local node = minetest.get_node(pointed_thing.under)
353 if user and not user:get_player_control().sneak then
354 if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
355 return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, user, itemstack) or itemstack
359 -- Place eye of ender into end portal frame
360 if pointed_thing.under and node.name == "mcl_portals:end_portal_frame" then
361 minetest.swap_node(pointed_thing.under, { name = "mcl_portals:end_portal_frame_eye", param2 = node.param2 })
363 if minetest.get_modpath("doc") then
364 doc.mark_entry_as_revealed(user:get_player_name(), "nodes", "mcl_portals:end_portal_frame")
366 minetest.sound_play(
367 "default_place_node_hard",
368 {pos = pointed_thing.under, gain = 0.5, max_hear_distance = 16})
369 if not minetest.settings:get_bool("creative_mode") then
370 itemstack:take_item() -- 1 use
373 local ok, ppos = check_end_portal_frame(pointed_thing.under)
374 if ok then
375 end_portal_area(ppos)
376 if minetest.get_modpath("doc") then
377 doc.mark_entry_as_revealed(user:get_player_name(), "nodes", "mcl_portals:portal_end")
381 return itemstack
382 end,