From f5f85a2148238baad3f7005e78dadc501525c3bf Mon Sep 17 00:00:00 2001 From: iliekprogrammar Date: Fri, 19 Mar 2021 23:28:33 +0800 Subject: [PATCH 01/58] Slightly lift your right arm when holding an item. --- mods/PLAYER/wieldview/init.lua | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/mods/PLAYER/wieldview/init.lua b/mods/PLAYER/wieldview/init.lua index 6c0f08569..a5e04ced6 100644 --- a/mods/PLAYER/wieldview/init.lua +++ b/mods/PLAYER/wieldview/init.lua @@ -106,14 +106,25 @@ minetest.register_entity("wieldview:wieldnode", { if player then local wielded = player:get_wielded_item() local itemstring = wielded:get_name() + if self.itemstring ~= itemstring then + minetest.chat_send_all(dump2(itemstring, "itemstring")) local def = minetest.registered_items[itemstring] self.object:set_properties({glow = def and def.light_source or 0}) + + -- wield item as cubic if armor.textures[self.wielder].wielditem == "blank.png" then self.object:set_properties({textures = {itemstring}}) - else + else -- displayed item as flat self.object:set_properties({textures = {""}}) end + + if itemstring == "" then -- holding item + player:set_bone_position("Arm_Right", vector.new(0, 0, 0), vector.new(0, 0, 0)) + else -- empty hands + player:set_bone_position("Arm_Right", vector.new(0, 0, 0), vector.new(20, 0, 0)) + end + self.itemstring = itemstring end else From 249b5cfd1efdbca9973873ee3dd1994a885e79be Mon Sep 17 00:00:00 2001 From: iliekprogrammar Date: Sat, 20 Mar 2021 00:11:12 +0800 Subject: [PATCH 02/58] Remove debug information --- mods/PLAYER/wieldview/init.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/PLAYER/wieldview/init.lua b/mods/PLAYER/wieldview/init.lua index a5e04ced6..4db711622 100644 --- a/mods/PLAYER/wieldview/init.lua +++ b/mods/PLAYER/wieldview/init.lua @@ -108,7 +108,6 @@ minetest.register_entity("wieldview:wieldnode", { local itemstring = wielded:get_name() if self.itemstring ~= itemstring then - minetest.chat_send_all(dump2(itemstring, "itemstring")) local def = minetest.registered_items[itemstring] self.object:set_properties({glow = def and def.light_source or 0}) From df8fdda2c5562bf16107566c94c32c094dfcec55 Mon Sep 17 00:00:00 2001 From: Nicu Date: Fri, 19 Mar 2021 17:25:40 +0000 Subject: [PATCH 03/58] Fix #1346 Fixes crash trying to place cocoa --- mods/ITEMS/mcl_cocoas/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_cocoas/init.lua b/mods/ITEMS/mcl_cocoas/init.lua index d0d96b300..f19f85154 100644 --- a/mods/ITEMS/mcl_cocoas/init.lua +++ b/mods/ITEMS/mcl_cocoas/init.lua @@ -19,7 +19,7 @@ function mcl_cocoas.place(itemstack, placer, pt, plantname) -- Am I right-clicking on something that has a custom on_rightclick set? if placer and not placer:get_player_control().sneak then if minetest.registered_nodes[under.name] and minetest.registered_nodes[under.name].on_rightclick then - return minetest.registered_nodes[under.name].on_rightclick(pointed_thing.under, under, placer, itemstack) or itemstack + return minetest.registered_nodes[under.name].on_rightclick(pt.under, under, placer, itemstack) or itemstack end end From a40e1c4737ba0b76a6fa60f56401a6093b06701a Mon Sep 17 00:00:00 2001 From: Nicu Date: Fri, 19 Mar 2021 17:41:37 +0000 Subject: [PATCH 04/58] Reduce the size of the pumpkin texture 2732 -> 303 bytes * We need smaller file sizes for better game startup time, especially for multiplayer and mobile gaming. --- .../textures/mcl_farming_pumpkin_face.png | Bin 2732 -> 303 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/mods/ITEMS/mcl_farming/textures/mcl_farming_pumpkin_face.png b/mods/ITEMS/mcl_farming/textures/mcl_farming_pumpkin_face.png index 0fb980b40ff9c12ab8d0a3a7083e8d72de28d10b..095b90cc6725a2e25c84b0b7f05232890683696b 100644 GIT binary patch delta 41 xcmZ1@x}Ir*G6#cJfKP}kgW=?2P7T4myL?j_7#J8!g8YIR9G=}soBWXTGywFc4MP9` delta 2486 zcmV;n2}$;^0<0B~BYy|1dQ@0+Qek%>aB^>EX>4U6ba`-PAZ2)IW&i+q+U=KHlH@iH zMgO@9FF|~QTnKv+~4sk_xJrNuSeW}84v00L1HL#&d;srYk$5nUO!%V+au1e-rM=QJ_qPakl(Jtx6$u^5d5UC z8Tp%7wpWa}_d|QTz zlaS~8wZl3k{DhSp)%pC{yn$Hrm#t&}g8|Tct%K1s5 z7{p!+5F+-j7!xxHTrK7rTf8JCiIF&V08%VZxugjKvDRc5nM%$r1xY>m-n=96o||fF z$%oM9w~mz4y^|q><6UI@*xY#~7+9C>tqjDf5+)nP#44*4d`aKF8DreO6g@wI!>svDA`f zLnf@5Shr!iW7sIgF1zlwW%oU{9=LY$DW{%x>7!rs0kyhV-qYoVnA4SO!dTf>^_kD zDcnNsKZRTRE98Ph_bZSKK=(avKS0gA&aE4 zlg)i16g6GP92G|@TiCkiCZW#@d?W6M=)0hmdu!^T4Ad?IPE%FmspX5zh^&*oG#Y zwn*B1WbAnsS*JQKymGXJKxa&-8h^8GM8loqP6M!%rq%Lg7V9a^oZ4V~{3=so+L$DUQO?WJ({2%auxKK zr2lDQ5@y5-Tqi-f=?}W37(Nz8Gl_RRFNn@7|8@J64BK1Z^frcbEJWS)34eW_OAo3# zD_LF)i&am{(3yB-P=@VVqm0W5MSf27fk=S92vTcLR+fX2u8goGgB}0=7McK3Me_O;Q3Xb39`?7YXN+bKNl z+8s4&LEfv(0gXmWO!T%6lz-vsgPV}k=pw0rBBB{ow;jcyW`Z_B#A*-}EU_Bfri|LP zT%;c!nmb8o)UavC*eMK~PB1s*bx`0G`N|WRoR~2XpvdGpW-*4z)`yC>zu04he=@}v zH}y5eS$fqc&yb##=A~%%gV8lna0=Tb+QuH_cY%YEK%6YVr|>(YQ-5qvy51U@cj`zu znBouc7s$?Ayg{c-4;!^siW!T!YP=X^O_yo&buj2IEVnN&-Lw;~voK>@d=CkkH+@2s z9lfqk|6!@Ldw*(k_-muTv-xDTSSl%Ai!7z@@6VbAJf|7kur?@n6XLZVt&Ffx-e1ismYwNQ? zp|GjxCy_RN)#-~+2ad&wiM#3}cbjf2-h`C?LC8s?mzT>nntvGs3>ostWZJ5l%BEL@ zDU%gjn-m}FgvsMQ&}tz_>1`N0{O;V+vC)h}n z(MIhKT6sV#UUG8qK7@|4(YYb%WPJ7)t5-?SwBekdHu&Aw@E*z~hfbZ}?mh0_0YbCNRI_IsP&La)Clg{ew<-o+;YS!D z#1NC2sn1DL3ZCQZ9zMR_#d((Zxj#oJUoaWq6NzV;Zdk+{#M7IW&Uv3W!pd@<_?&pm zpbHW|a(`WM`HgeQVS#5xj7)l-I6^Fzx>)IARyI`PDdK2e)hJ)cx}4{{#aXS^S^J*+ zg~5Whvdndw!$@KgOOPN!K^+xTVIfYdMv93v?I%3^Lylh}mqM-z7&#VDg9_R4ga5(r zZq4H4gqsvh0KG4^{V@Urc7ayIw!e>UyLAHipJIV4t>dpXftgRz8yzir1Pp8g7uOw4 z*#j zL;#2d9Y_EG010qNS#tmY3ljhU3ljkVnw%H_000McNliru@tyL%ReE# A>Hq)$ From 34dbddb40ac7756714ac49cdebce092259e9b2d2 Mon Sep 17 00:00:00 2001 From: iliekprogrammar Date: Sat, 20 Mar 2021 08:42:48 +0800 Subject: [PATCH 05/58] Move holding code into mcl_playerplus --- mods/PLAYER/mcl_playerplus/init.lua | 14 ++++++++++++-- mods/PLAYER/wieldview/init.lua | 8 +------- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index 1f66b344f..2759ebc30 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -96,6 +96,8 @@ minetest.register_globalstep(function(dtime) local player_velocity = player:get_velocity() or player:get_player_velocity() + local wielded = player:get_wielded_item() + -- controls head bone local pitch = - degrees(player:get_look_vertical()) local yaw = degrees(player:get_look_horizontal()) @@ -107,13 +109,21 @@ minetest.register_globalstep(function(dtime) player_vel_yaw = limit_vel_yaw(player_vel_yaw, yaw) player_vel_yaws[name] = player_vel_yaw - -- controls right and left arms pitch when shooting a bow or punching - if string.find(player:get_wielded_item():get_name(), "mcl_bows:bow") and controls.RMB and not controls.LMB and not controls.up and not controls.down and not controls.left and not controls.right then + -- controls right and left arms pitch when shooting a bow + if string.find(wielded:get_name(), "mcl_bows:bow") and controls.RMB and not controls.LMB and not controls.up and not controls.down and not controls.left and not controls.right then + minetest.chat_send_all("entered 1") player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) + -- when punching elseif controls.LMB and player:get_attach() == nil then + minetest.chat_send_all("entered 2") player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0)) player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) + -- when holding an item. + elseif wielded:get_name() ~= "" then + player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(20,0,0)) + player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) + -- resets arms pitch else player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0)) diff --git a/mods/PLAYER/wieldview/init.lua b/mods/PLAYER/wieldview/init.lua index 4db711622..48f3f99bd 100644 --- a/mods/PLAYER/wieldview/init.lua +++ b/mods/PLAYER/wieldview/init.lua @@ -114,16 +114,10 @@ minetest.register_entity("wieldview:wieldnode", { -- wield item as cubic if armor.textures[self.wielder].wielditem == "blank.png" then self.object:set_properties({textures = {itemstring}}) - else -- displayed item as flat + else -- wield item as flat self.object:set_properties({textures = {""}}) end - if itemstring == "" then -- holding item - player:set_bone_position("Arm_Right", vector.new(0, 0, 0), vector.new(0, 0, 0)) - else -- empty hands - player:set_bone_position("Arm_Right", vector.new(0, 0, 0), vector.new(20, 0, 0)) - end - self.itemstring = itemstring end else From 03be45b9839cb3661973c88995e99404db004c9e Mon Sep 17 00:00:00 2001 From: iliekprogrammar Date: Sat, 20 Mar 2021 09:17:43 +0800 Subject: [PATCH 06/58] Fix indentation from iliekprogrammar's previous PRs --- mods/ITEMS/mcl_fire/init.lua | 106 +++++++++++++++++------------------ 1 file changed, 53 insertions(+), 53 deletions(-) diff --git a/mods/ITEMS/mcl_fire/init.lua b/mods/ITEMS/mcl_fire/init.lua index f11c683a6..95d76c45d 100644 --- a/mods/ITEMS/mcl_fire/init.lua +++ b/mods/ITEMS/mcl_fire/init.lua @@ -50,69 +50,69 @@ local alldirs= -- 3 exptime variants because the animation is not tied to particle expiration time. -- 3 colorized variants to imitate minecraft's local smoke_pdef_base = { - amount = 0.001, - time = 0, - -- minpos = vector.add(pos, { x = -0.45, y = -0.45, z = -0.45 }), - -- maxpos = vector.add(pos, { x = 0.45, y = 0.45, z = 0.45 }), - minvel = { x = -0.1, y = 0.3, z = -0.1 }, - maxvel = { x = 0.1, y = 1.6, z = 0.1 }, - -- minexptime = 3 exptime variants, - -- maxexptime = 3 exptime variants - minsize = 4.0, - maxsize = 4.5, - -- texture = "mcl_particles_smoke_anim.png^[colorize:#000000:(3 colourize variants)", - animation = { - type = "vertical_frames", - aspect_w = 8, - aspect_h = 8, - -- length = 3 exptime variants - }, - collisiondetection = true, + amount = 0.001, + time = 0, + -- minpos = vector.add(pos, { x = -0.45, y = -0.45, z = -0.45 }), + -- maxpos = vector.add(pos, { x = 0.45, y = 0.45, z = 0.45 }), + minvel = { x = -0.1, y = 0.3, z = -0.1 }, + maxvel = { x = 0.1, y = 1.6, z = 0.1 }, + -- minexptime = 3 exptime variants, + -- maxexptime = 3 exptime variants + minsize = 4.0, + maxsize = 4.5, + -- texture = "mcl_particles_smoke_anim.png^[colorize:#000000:(3 colourize variants)", + animation = { + type = "vertical_frames", + aspect_w = 8, + aspect_h = 8, + -- length = 3 exptime variants + }, + collisiondetection = true, } local smoke_pdef_cached = {} local spawn_smoke = function(pos) - local min = math.min - local new_minpos = vector.add(pos, { x = -0.45, y = -0.45, z = -0.45 }) - local new_maxpos = vector.add(pos, { x = 0.45, y = 0.45, z = 0.45 }) + local min = math.min + local new_minpos = vector.add(pos, { x = -0.45, y = -0.45, z = -0.45 }) + local new_maxpos = vector.add(pos, { x = 0.45, y = 0.45, z = 0.45 }) - -- populate the cache - if not next(smoke_pdef_cached) then - -- the last frame plays for 1/8 * N seconds, so we can take advantage of it - -- to have varying exptime for each variant. - local exptimes = { 0.75, 1.5, 4.0 } - local colorizes = { "199", "209", "243" } -- round(78%, 82%, 90% of 256) - 1 + -- populate the cache + if not next(smoke_pdef_cached) then + -- the last frame plays for 1/8 * N seconds, so we can take advantage of it + -- to have varying exptime for each variant. + local exptimes = { 0.75, 1.5, 4.0 } + local colorizes = { "199", "209", "243" } -- round(78%, 82%, 90% of 256) - 1 - local id = 1 - for _,exptime in ipairs(exptimes) do - for _,colorize in ipairs(colorizes) do - smoke_pdef_base.minpos = new_minpos - smoke_pdef_base.maxpos = new_maxpos - smoke_pdef_base.maxexptime = exptime - smoke_pdef_base.animation.length = exptime + 0.1 - -- minexptime must be set such that the last frame is actully rendered, - -- even if its very short. Larger exptime -> larger range - smoke_pdef_base.minexptime = min(exptime, (7.0/8.0 * (exptime + 0.1) + 0.1)) - smoke_pdef_base.texture = "mcl_particles_smoke_anim.png^[colorize:#000000:" ..colorize + local id = 1 + for _,exptime in ipairs(exptimes) do + for _,colorize in ipairs(colorizes) do + smoke_pdef_base.minpos = new_minpos + smoke_pdef_base.maxpos = new_maxpos + smoke_pdef_base.maxexptime = exptime + smoke_pdef_base.animation.length = exptime + 0.1 + -- minexptime must be set such that the last frame is actully rendered, + -- even if its very short. Larger exptime -> larger range + smoke_pdef_base.minexptime = min(exptime, (7.0/8.0 * (exptime + 0.1) + 0.1)) + smoke_pdef_base.texture = "mcl_particles_smoke_anim.png^[colorize:#000000:" ..colorize - smoke_pdef_cached[id] = table.copy(smoke_pdef_base) + smoke_pdef_cached[id] = table.copy(smoke_pdef_base) - mcl_particles.add_node_particlespawner(pos, smoke_pdef_cached[id], "high") + mcl_particles.add_node_particlespawner(pos, smoke_pdef_cached[id], "high") - id = id + 1 - end - end + id = id + 1 + end + end - -- cache already populated - else - for i, smoke_pdef in ipairs(smoke_pdef_cached) do - smoke_pdef.minpos = new_minpos - smoke_pdef.maxpos = new_maxpos - mcl_particles.add_node_particlespawner(pos, smoke_pdef, "high") - end - end + -- cache already populated + else + for i, smoke_pdef in ipairs(smoke_pdef_cached) do + smoke_pdef.minpos = new_minpos + smoke_pdef.maxpos = new_maxpos + mcl_particles.add_node_particlespawner(pos, smoke_pdef, "high") + end + end --[[ Old smoke pdef - local spawn_smoke = function(pos) + local spawn_smoke = function(pos) mcl_particles.add_node_particlespawner(pos, { amount = 0.1, time = 0, @@ -132,7 +132,7 @@ local spawn_smoke = function(pos) length = 2.1, }, }, "high") - -- ]] + -- ]] end From 12745bd450d0f3d0b8f39d473eaff56d2e938678 Mon Sep 17 00:00:00 2001 From: iliekprogrammar Date: Sat, 20 Mar 2021 10:13:48 +0800 Subject: [PATCH 07/58] Remove debug information... again :/ --- mods/PLAYER/mcl_playerplus/init.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index 2759ebc30..7122cc894 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -111,12 +111,10 @@ minetest.register_globalstep(function(dtime) -- controls right and left arms pitch when shooting a bow if string.find(wielded:get_name(), "mcl_bows:bow") and controls.RMB and not controls.LMB and not controls.up and not controls.down and not controls.left and not controls.right then - minetest.chat_send_all("entered 1") player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) -- when punching elseif controls.LMB and player:get_attach() == nil then - minetest.chat_send_all("entered 2") player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0)) player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) -- when holding an item. From 10154d57781ede8ffa1b65a72fe8673a3743879b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Sat, 20 Mar 2021 11:02:16 +0100 Subject: [PATCH 08/58] Fix #1348 --- mods/CORE/_mcl_autogroup/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/CORE/_mcl_autogroup/init.lua b/mods/CORE/_mcl_autogroup/init.lua index 345bfd302..f4b015484 100644 --- a/mods/CORE/_mcl_autogroup/init.lua +++ b/mods/CORE/_mcl_autogroup/init.lua @@ -209,7 +209,7 @@ function mcl_autogroup.can_harvest(nodename, toolname) -- Check if it can be dug by tool local tdef = minetest.registered_tools[toolname] - if tdef then + if tdef and tdef._mcl_diggroups then for g, gdef in pairs(tdef._mcl_diggroups) do if ndef.groups[g] then if ndef.groups[g] <= gdef.level then From 1873080046009465faf3d4bf3dba0fc63e9315b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Sat, 20 Mar 2021 14:21:50 +0100 Subject: [PATCH 09/58] Remove unnecessary code in mcl_item_entity --- mods/ENTITIES/mcl_item_entity/init.lua | 4 ---- 1 file changed, 4 deletions(-) diff --git a/mods/ENTITIES/mcl_item_entity/init.lua b/mods/ENTITIES/mcl_item_entity/init.lua index 7cea5a91c..d1d337a9c 100644 --- a/mods/ENTITIES/mcl_item_entity/init.lua +++ b/mods/ENTITIES/mcl_item_entity/init.lua @@ -165,10 +165,6 @@ minetest.register_globalstep(function(dtime) end end) -local minigroups = { "shearsy", "swordy", "shearsy_wool", "swordy_cobweb" } -local basegroups = { "pickaxey", "axey", "shovely" } -local materials = { "wood", "gold", "stone", "iron", "diamond" } - -- Stupid workaround to get drops from a drop table: -- Create a temporary table in minetest.registered_nodes that contains the proper drops, -- because unfortunately minetest.get_node_drops needs the drop table to be inside a registered node definition From 1621c2330872c69b50b59e1bc9c963253e6c4512 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Sat, 20 Mar 2021 19:25:47 +0100 Subject: [PATCH 10/58] Rename "tool_multiplier" to "speed" for tools --- mods/CORE/_mcl_autogroup/init.lua | 23 +++++----- mods/ITEMS/mcl_tools/init.lua | 74 +++++++++++++++---------------- 2 files changed, 48 insertions(+), 49 deletions(-) diff --git a/mods/CORE/_mcl_autogroup/init.lua b/mods/CORE/_mcl_autogroup/init.lua index f4b015484..766641ad1 100644 --- a/mods/CORE/_mcl_autogroup/init.lua +++ b/mods/CORE/_mcl_autogroup/init.lua @@ -6,7 +6,7 @@ block has a hardness and the actual Minecraft digging time is determined by this: 1) The block's hardness -2) The tool being used (the tool_multiplier and its efficiency level) +2) The tool being used (the tool speed and its efficiency level) 3) Whether the tool is considered as "eligible" for the block (e.g. only diamond pick eligible for obsidian) @@ -43,13 +43,13 @@ this field is a table which defines which groups the tool can dig and how efficiently. _mcl_diggroups = { - handy = { tool_multiplier = 1, level = 1, uses = 0 }, - pickaxey = { tool_multiplier = 1, level = 0, uses = 0 }, + handy = { speed = 1, level = 1, uses = 0 }, + pickaxey = { speed = 1, level = 0, uses = 0 }, } The "uses" field indicate how many uses (0 for infinite) a tool has when used on -the specified digging group. The "tool_multiplier" field is a multiplier to the -dig speed on that digging group. +the specified digging group. The "speed" field is a multiplier to the dig speed +on that digging group. The "level" field indicates which levels of the group the tool can harvest. A level of 0 means that the tool cannot harvest blocks of that node. A level of 1 @@ -135,19 +135,18 @@ end -- Parameters: -- group - the group which it is digging -- can_harvest - if the tool can harvest the block --- tool_multiplier - dig speed multiplier for tool (default 1) +-- speed - dig speed multiplier for tool (default 1) -- efficiency - efficiency level for the tool if applicable -local function get_digtimes(group, can_harvest, tool_multiplier, efficiency) - tool_multiplier = tool_multiplier or 1 - local speed_multiplier = tool_multiplier +local function get_digtimes(group, can_harvest, speed, efficiency) + local speed = speed or 1 if efficiency then - speed_multiplier = speed_multiplier + efficiency * efficiency + 1 + speed = speed + efficiency * efficiency + 1 end local digtimes = {} for index, hardness in pairs(hardness_values[group]) do - local digtime = (hardness or 0) / speed_multiplier + local digtime = (hardness or 0) / speed if can_harvest then digtime = digtime * 1.5 else @@ -178,7 +177,7 @@ end -- tool. local function add_groupcaps(toolname, groupcaps, groupcaps_def, efficiency) for g, capsdef in pairs(groupcaps_def) do - local mult = capsdef.tool_multiplier or 1 + local mult = capsdef.speed or 1 local uses = capsdef.uses local def = mcl_autogroup.registered_diggroups[g] local max_level = def.levels and #def.levels or 1 diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index 3004a8305..4dc9af01f 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -48,15 +48,15 @@ minetest.register_tool(":", { }, groups = hand_groups, _mcl_diggroups = { - handy = { tool_multiplier = 1, level = 1, uses = 0 }, - axey = { tool_multiplier = 1, level = 1, uses = 0 }, - shovely = { tool_multiplier = 1, level = 1, uses = 0 }, - pickaxey = { tool_multiplier = 1, level = 0, uses = 0 }, - swordy = { tool_multiplier = 1, level = 0, uses = 0 }, - swordy_cobweb = { tool_multiplier = 1, level = 0, uses = 0 }, - shearsy = { tool_multiplier = 1, level = 0, uses = 0 }, - shearsy_wool = { tool_multiplier = 1, level = 0, uses = 0 }, - shearsy_cobweb = { tool_multiplier = 1, level = 0, uses = 0 }, + handy = { speed = 1, level = 1, uses = 0 }, + axey = { speed = 1, level = 1, uses = 0 }, + shovely = { speed = 1, level = 1, uses = 0 }, + pickaxey = { speed = 1, level = 0, uses = 0 }, + swordy = { speed = 1, level = 0, uses = 0 }, + swordy_cobweb = { speed = 1, level = 0, uses = 0 }, + shearsy = { speed = 1, level = 0, uses = 0 }, + shearsy_wool = { speed = 1, level = 0, uses = 0 }, + shearsy_cobweb = { speed = 1, level = 0, uses = 0 }, } }) @@ -90,7 +90,7 @@ minetest.register_tool("mcl_tools:pick_wood", { _repair_material = "group:wood", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 2, level = 1, uses = 60 } + pickaxey = { speed = 2, level = 1, uses = 60 } }, }) minetest.register_tool("mcl_tools:pick_stone", { @@ -110,7 +110,7 @@ minetest.register_tool("mcl_tools:pick_stone", { _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 4, level = 3, uses = 132 } + pickaxey = { speed = 4, level = 3, uses = 132 } }, }) minetest.register_tool("mcl_tools:pick_iron", { @@ -130,7 +130,7 @@ minetest.register_tool("mcl_tools:pick_iron", { _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 6, level = 4, uses = 251 } + pickaxey = { speed = 6, level = 4, uses = 251 } }, }) minetest.register_tool("mcl_tools:pick_gold", { @@ -150,7 +150,7 @@ minetest.register_tool("mcl_tools:pick_gold", { _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 12, level = 2, uses = 33 } + pickaxey = { speed = 12, level = 2, uses = 33 } }, }) minetest.register_tool("mcl_tools:pick_diamond", { @@ -170,7 +170,7 @@ minetest.register_tool("mcl_tools:pick_diamond", { _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, _mcl_diggroups = { - pickaxey = { tool_multiplier = 8, level = 5, uses = 1562 } + pickaxey = { speed = 8, level = 5, uses = 1562 } }, }) @@ -262,7 +262,7 @@ minetest.register_tool("mcl_tools:shovel_wood", { _repair_material = "group:wood", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 2, level = 1, uses = 60 } + shovely = { speed = 2, level = 1, uses = 60 } }, }) minetest.register_tool("mcl_tools:shovel_stone", { @@ -283,7 +283,7 @@ minetest.register_tool("mcl_tools:shovel_stone", { _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 4, level = 3, uses = 132 } + shovely = { speed = 4, level = 3, uses = 132 } }, }) minetest.register_tool("mcl_tools:shovel_iron", { @@ -304,7 +304,7 @@ minetest.register_tool("mcl_tools:shovel_iron", { _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 6, level = 4, uses = 251 } + shovely = { speed = 6, level = 4, uses = 251 } }, }) minetest.register_tool("mcl_tools:shovel_gold", { @@ -325,7 +325,7 @@ minetest.register_tool("mcl_tools:shovel_gold", { _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 12, level = 2, uses = 33 } + shovely = { speed = 12, level = 2, uses = 33 } }, }) minetest.register_tool("mcl_tools:shovel_diamond", { @@ -346,7 +346,7 @@ minetest.register_tool("mcl_tools:shovel_diamond", { _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, _mcl_diggroups = { - shovely = { tool_multiplier = 8, level = 5, uses = 1562 } + shovely = { speed = 8, level = 5, uses = 1562 } }, }) @@ -368,7 +368,7 @@ minetest.register_tool("mcl_tools:axe_wood", { _repair_material = "group:wood", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 2, level = 1, uses = 60 } + axey = { speed = 2, level = 1, uses = 60 } }, }) minetest.register_tool("mcl_tools:axe_stone", { @@ -387,7 +387,7 @@ minetest.register_tool("mcl_tools:axe_stone", { _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 4, level = 3, uses = 132 } + axey = { speed = 4, level = 3, uses = 132 } }, }) minetest.register_tool("mcl_tools:axe_iron", { @@ -407,7 +407,7 @@ minetest.register_tool("mcl_tools:axe_iron", { _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 6, level = 4, uses = 251 } + axey = { speed = 6, level = 4, uses = 251 } }, }) minetest.register_tool("mcl_tools:axe_gold", { @@ -426,7 +426,7 @@ minetest.register_tool("mcl_tools:axe_gold", { _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 12, level = 2, uses = 33 } + axey = { speed = 12, level = 2, uses = 33 } }, }) minetest.register_tool("mcl_tools:axe_diamond", { @@ -445,7 +445,7 @@ minetest.register_tool("mcl_tools:axe_diamond", { _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, _mcl_diggroups = { - axey = { tool_multiplier = 8, level = 5, uses = 1562 } + axey = { speed = 8, level = 5, uses = 1562 } }, }) @@ -467,8 +467,8 @@ minetest.register_tool("mcl_tools:sword_wood", { _repair_material = "group:wood", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 2, level = 1, uses = 60 }, - swordy_cobweb = { tool_multiplier = 2, level = 1, uses = 60 } + swordy = { speed = 2, level = 1, uses = 60 }, + swordy_cobweb = { speed = 2, level = 1, uses = 60 } }, }) minetest.register_tool("mcl_tools:sword_stone", { @@ -487,8 +487,8 @@ minetest.register_tool("mcl_tools:sword_stone", { _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 4, level = 3, uses = 132 }, - swordy_cobweb = { tool_multiplier = 4, level = 3, uses = 132 } + swordy = { speed = 4, level = 3, uses = 132 }, + swordy_cobweb = { speed = 4, level = 3, uses = 132 } }, }) minetest.register_tool("mcl_tools:sword_iron", { @@ -507,8 +507,8 @@ minetest.register_tool("mcl_tools:sword_iron", { _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 6, level = 4, uses = 251 }, - swordy_cobweb = { tool_multiplier = 6, level = 4, uses = 251 } + swordy = { speed = 6, level = 4, uses = 251 }, + swordy_cobweb = { speed = 6, level = 4, uses = 251 } }, }) minetest.register_tool("mcl_tools:sword_gold", { @@ -527,8 +527,8 @@ minetest.register_tool("mcl_tools:sword_gold", { _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 12, level = 2, uses = 33 }, - swordy_cobweb = { tool_multiplier = 12, level = 2, uses = 33 } + swordy = { speed = 12, level = 2, uses = 33 }, + swordy_cobweb = { speed = 12, level = 2, uses = 33 } }, }) minetest.register_tool("mcl_tools:sword_diamond", { @@ -547,8 +547,8 @@ minetest.register_tool("mcl_tools:sword_diamond", { _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, _mcl_diggroups = { - swordy = { tool_multiplier = 8, level = 5, uses = 1562 }, - swordy_cobweb = { tool_multiplier = 8, level = 5, uses = 1562 } + swordy = { speed = 8, level = 5, uses = 1562 }, + swordy_cobweb = { speed = 8, level = 5, uses = 1562 } }, }) @@ -569,9 +569,9 @@ minetest.register_tool("mcl_tools:shears", { sound = { breaks = "default_tool_breaks" }, _mcl_toollike_wield = true, _mcl_diggroups = { - shearsy = { tool_multiplier = 1.5, level = 1, uses = 238 }, - shearsy_wool = { tool_multiplier = 5, level = 1, uses = 238 }, - shearsy_cobweb = { tool_multiplier = 15, level = 1, uses = 238 } + shearsy = { speed = 1.5, level = 1, uses = 238 }, + shearsy_wool = { speed = 5, level = 1, uses = 238 }, + shearsy_cobweb = { speed = 15, level = 1, uses = 238 } }, }) From 0996a83ba03ebcac22dd08f5ed23f22b447fb943 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Sat, 20 Mar 2021 19:32:04 +0100 Subject: [PATCH 11/58] Assert that both parts of mcl_autogroup exist --- mods/CORE/_mcl_autogroup/init.lua | 2 ++ mods/CORE/mcl_autogroup/init.lua | 2 ++ 2 files changed, 4 insertions(+) diff --git a/mods/CORE/_mcl_autogroup/init.lua b/mods/CORE/_mcl_autogroup/init.lua index 766641ad1..75ed4ce2b 100644 --- a/mods/CORE/_mcl_autogroup/init.lua +++ b/mods/CORE/_mcl_autogroup/init.lua @@ -69,6 +69,8 @@ This also means that it is very important that no mod adds _mcl_autogroup as a dependency. --]] +assert(minetest.get_modpath("mcl_autogroup"), "This mod requires the mod mcl_autogroup to function") + -- Returns a table containing the unique "_mcl_hardness" for nodes belonging to -- each diggroup. local function get_hardness_values_for_groups() diff --git a/mods/CORE/mcl_autogroup/init.lua b/mods/CORE/mcl_autogroup/init.lua index 09894dd84..16dd831c0 100644 --- a/mods/CORE/mcl_autogroup/init.lua +++ b/mods/CORE/mcl_autogroup/init.lua @@ -12,6 +12,8 @@ as possible. Minetest loads mods in reverse alphabetical order. mcl_autogroup = {} mcl_autogroup.registered_diggroups = {} +assert(minetest.get_modpath("_mcl_autogroup"), "This mod requires the mod _mcl_autogroup to function") + -- Register a group as a digging group. -- -- Parameters: From b0c7941b3a80f9294f258ee5d8013428254a03e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Sun, 21 Mar 2021 12:18:24 +0100 Subject: [PATCH 12/58] Fix #1358 --- mods/ITEMS/mcl_enchanting/groupcaps.lua | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/mods/ITEMS/mcl_enchanting/groupcaps.lua b/mods/ITEMS/mcl_enchanting/groupcaps.lua index 3060000db..216457d05 100644 --- a/mods/ITEMS/mcl_enchanting/groupcaps.lua +++ b/mods/ITEMS/mcl_enchanting/groupcaps.lua @@ -45,6 +45,10 @@ end -- To make it more efficient it will first check a hash value to determine if -- the tool needs to be updated. function mcl_enchanting.update_groupcaps(itemstack) + if not itemstack:get_tool_capabilities() then + return + end + local name = itemstack:get_name() local level = mcl_enchanting.get_enchantment(itemstack, "efficiency") local groupcaps = get_efficiency_groupcaps(name, level) From dac3c21628595159718c6a2f6e63cf8876f9f624 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Sun, 21 Mar 2021 12:26:34 +0100 Subject: [PATCH 13/58] Do not register "creative_breakable" as a diggroup --- mods/ITEMS/mcl_core/init.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/ITEMS/mcl_core/init.lua b/mods/ITEMS/mcl_core/init.lua index aae6abe9a..b1b2b9d35 100644 --- a/mods/ITEMS/mcl_core/init.lua +++ b/mods/ITEMS/mcl_core/init.lua @@ -14,7 +14,6 @@ mcl_autogroup.register_diggroup("shearsy_wool") mcl_autogroup.register_diggroup("shearsy_cobweb") mcl_autogroup.register_diggroup("swordy") mcl_autogroup.register_diggroup("swordy_cobweb") -mcl_autogroup.register_diggroup("creative_breakable") -- Load files local modpath = minetest.get_modpath("mcl_core") From c1e295de5fbe09c2fa6973f14b48dd73b2405eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Sun, 21 Mar 2021 12:36:33 +0100 Subject: [PATCH 14/58] Make hoe dig some blocks faster - Sponges - Hay and kelp blocks - Nether wart - Leaves --- mods/ITEMS/mcl_core/init.lua | 1 + mods/ITEMS/mcl_core/nodes_trees.lua | 14 +++++++++++++- mods/ITEMS/mcl_farming/hoes.lua | 15 +++++++++++++++ mods/ITEMS/mcl_farming/wheat.lua | 2 +- mods/ITEMS/mcl_nether/init.lua | 2 +- mods/ITEMS/mcl_ocean/kelp.lua | 2 +- mods/ITEMS/mcl_sponges/init.lua | 4 ++-- 7 files changed, 34 insertions(+), 6 deletions(-) diff --git a/mods/ITEMS/mcl_core/init.lua b/mods/ITEMS/mcl_core/init.lua index b1b2b9d35..897382e01 100644 --- a/mods/ITEMS/mcl_core/init.lua +++ b/mods/ITEMS/mcl_core/init.lua @@ -14,6 +14,7 @@ mcl_autogroup.register_diggroup("shearsy_wool") mcl_autogroup.register_diggroup("shearsy_cobweb") mcl_autogroup.register_diggroup("swordy") mcl_autogroup.register_diggroup("swordy_cobweb") +mcl_autogroup.register_diggroup("hoey") -- Load files local modpath = minetest.get_modpath("mcl_core") diff --git a/mods/ITEMS/mcl_core/nodes_trees.lua b/mods/ITEMS/mcl_core/nodes_trees.lua index 3a8aef8d0..197846ebc 100644 --- a/mods/ITEMS/mcl_core/nodes_trees.lua +++ b/mods/ITEMS/mcl_core/nodes_trees.lua @@ -108,7 +108,19 @@ local register_leaves = function(subname, description, longdesc, tiles, sapling, tiles = tiles, paramtype = "light", stack_max = 64, - groups = {handy=1,shearsy=1,swordy=1, leafdecay=leafdecay_distance, flammable=2, leaves=1, deco_block=1, dig_by_piston=1, fire_encouragement=30, fire_flammability=60}, + groups = { + handy=1, + hoey=1, + shearsy=1, + swordy=1, + leafdecay=leafdecay_distance, + flammable=2, + leaves=1, + deco_block=1, + dig_by_piston=1, + fire_encouragement=30, + fire_flammability=60 + }, drop = get_drops(0), _mcl_shears_drop = true, sounds = mcl_sounds.node_sound_leaves_defaults(), diff --git a/mods/ITEMS/mcl_farming/hoes.lua b/mods/ITEMS/mcl_farming/hoes.lua index 5a383d78a..a45b382ed 100644 --- a/mods/ITEMS/mcl_farming/hoes.lua +++ b/mods/ITEMS/mcl_farming/hoes.lua @@ -78,6 +78,9 @@ minetest.register_tool("mcl_farming:hoe_wood", { }, _repair_material = "group:wood", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 2, level = 1, uses = 60 } + }, }) minetest.register_craft({ @@ -118,6 +121,9 @@ minetest.register_tool("mcl_farming:hoe_stone", { }, _repair_material = "mcl_core:cobble", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 4, level = 3, uses = 132 } + }, }) minetest.register_craft({ @@ -154,6 +160,9 @@ minetest.register_tool("mcl_farming:hoe_iron", { }, _repair_material = "mcl_core:iron_ingot", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 6, level = 4, uses = 251 } + }, }) minetest.register_craft({ @@ -196,6 +205,9 @@ minetest.register_tool("mcl_farming:hoe_gold", { }, _repair_material = "mcl_core:gold_ingot", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 12, level = 2, uses = 33 } + }, }) minetest.register_craft({ @@ -240,6 +252,9 @@ minetest.register_tool("mcl_farming:hoe_diamond", { }, _repair_material = "mcl_core:diamond", _mcl_toollike_wield = true, + _mcl_diggroups = { + hoey = { speed = 8, level = 5, uses = 1562 } + }, }) minetest.register_craft({ diff --git a/mods/ITEMS/mcl_farming/wheat.lua b/mods/ITEMS/mcl_farming/wheat.lua index 9a8a9f65e..e3ee79ead 100644 --- a/mods/ITEMS/mcl_farming/wheat.lua +++ b/mods/ITEMS/mcl_farming/wheat.lua @@ -146,7 +146,7 @@ minetest.register_node("mcl_farming:hay_block", { paramtype2 = "facedir", is_ground_content = false, on_place = mcl_util.rotate_axis, - groups = {handy=1, flammable=2, fire_encouragement=60, fire_flammability=20, building_block=1, fall_damage_add_percent=-80}, + groups = {handy=1, hoey=1, flammable=2, fire_encouragement=60, fire_flammability=20, building_block=1, fall_damage_add_percent=-80}, sounds = mcl_sounds.node_sound_leaves_defaults(), on_rotate = on_rotate, _mcl_blast_resistance = 0.5, diff --git a/mods/ITEMS/mcl_nether/init.lua b/mods/ITEMS/mcl_nether/init.lua index 7c8dd56a5..30fc17148 100644 --- a/mods/ITEMS/mcl_nether/init.lua +++ b/mods/ITEMS/mcl_nether/init.lua @@ -176,7 +176,7 @@ minetest.register_node("mcl_nether:nether_wart_block", { stack_max = 64, tiles = {"mcl_nether_nether_wart_block.png"}, is_ground_content = false, - groups = {handy=1, building_block=1}, + groups = {handy=1, hoey=1, building_block=1}, sounds = mcl_sounds.node_sound_leaves_defaults( { footstep={name="default_dirt_footstep", gain=0.7}, diff --git a/mods/ITEMS/mcl_ocean/kelp.lua b/mods/ITEMS/mcl_ocean/kelp.lua index 2e0dfe1a5..3c6e32422 100644 --- a/mods/ITEMS/mcl_ocean/kelp.lua +++ b/mods/ITEMS/mcl_ocean/kelp.lua @@ -275,7 +275,7 @@ minetest.register_node("mcl_ocean:dried_kelp_block", { description = S("Dried Kelp Block"), _doc_items_longdesc = S("A decorative block that serves as a great furnace fuel."), tiles = { "mcl_ocean_dried_kelp_top.png", "mcl_ocean_dried_kelp_bottom.png", "mcl_ocean_dried_kelp_side.png" }, - groups = { handy = 1, building_block = 1, flammable = 2, fire_encouragement = 30, fire_flammability = 60 }, + groups = { handy = 1, hoey = 1, building_block = 1, flammable = 2, fire_encouragement = 30, fire_flammability = 60 }, sounds = mcl_sounds.node_sound_leaves_defaults(), paramtype2 = "facedir", on_place = mcl_util.rotate_axis, diff --git a/mods/ITEMS/mcl_sponges/init.lua b/mods/ITEMS/mcl_sponges/init.lua index 4a2107f88..b832c01c6 100644 --- a/mods/ITEMS/mcl_sponges/init.lua +++ b/mods/ITEMS/mcl_sponges/init.lua @@ -48,7 +48,7 @@ minetest.register_node("mcl_sponges:sponge", { buildable_to = false, stack_max = 64, sounds = mcl_sounds.node_sound_dirt_defaults(), - groups = {handy=1, building_block=1}, + groups = {handy=1, hoey=1, building_block=1}, on_place = function(itemstack, placer, pointed_thing) local pn = placer:get_player_name() if pointed_thing.type ~= "node" then @@ -107,7 +107,7 @@ minetest.register_node("mcl_sponges:sponge_wet", { buildable_to = false, stack_max = 64, sounds = mcl_sounds.node_sound_dirt_defaults(), - groups = {handy=1, building_block=1}, + groups = {handy=1, hoey=1, building_block=1}, _mcl_blast_resistance = 0.6, _mcl_hardness = 0.6, }) From 7f56e5efa4db8a0d1593735dfdb47c5dbbacfeec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Sun, 21 Mar 2021 12:43:47 +0100 Subject: [PATCH 15/58] Add hoey digging group to hand --- mods/ITEMS/mcl_tools/init.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/ITEMS/mcl_tools/init.lua b/mods/ITEMS/mcl_tools/init.lua index 4dc9af01f..bc6bed09f 100644 --- a/mods/ITEMS/mcl_tools/init.lua +++ b/mods/ITEMS/mcl_tools/init.lua @@ -51,6 +51,7 @@ minetest.register_tool(":", { handy = { speed = 1, level = 1, uses = 0 }, axey = { speed = 1, level = 1, uses = 0 }, shovely = { speed = 1, level = 1, uses = 0 }, + hoey = { speed = 1, level = 1, uses = 0 }, pickaxey = { speed = 1, level = 0, uses = 0 }, swordy = { speed = 1, level = 0, uses = 0 }, swordy_cobweb = { speed = 1, level = 0, uses = 0 }, From 1fa2bd34776807faa82e887ca669911d20378a13 Mon Sep 17 00:00:00 2001 From: ArTee3 Date: Sun, 21 Mar 2021 16:43:12 +0100 Subject: [PATCH 16/58] Give xp if items are moved between furnace slots, unlock smelting achievements if furnace is inactive --- mods/ITEMS/mcl_furnaces/init.lua | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/mcl_furnaces/init.lua b/mods/ITEMS/mcl_furnaces/init.lua index d3877d90b..63b4bbc7b 100644 --- a/mods/ITEMS/mcl_furnaces/init.lua +++ b/mods/ITEMS/mcl_furnaces/init.lua @@ -161,6 +161,12 @@ local function on_metadata_inventory_take(pos, listname, index, stack, player) end end +local function on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) + if from_list == "dst" then + give_xp(pos, player) + end +end + local function spawn_flames(pos, param2) local minrelpos, maxrelpos local dir = minetest.facedir_to_dir(param2) @@ -477,10 +483,12 @@ minetest.register_node("mcl_furnaces:furnace", { give_xp(pos) end, - on_metadata_inventory_move = function(pos) + on_metadata_inventory_move = function(pos, from_list, from_index, to_list, to_index, count, player) -- Reset accumulated game time when player works with furnace: furnace_reset_delta_time(pos) minetest.get_node_timer(pos):start(1.0) + + on_metadata_inventory_move(pos, from_list, from_index, to_list, to_index, count, player) end, on_metadata_inventory_put = function(pos) -- Reset accumulated game time when player works with furnace: @@ -494,9 +502,7 @@ minetest.register_node("mcl_furnaces:furnace", { -- start timer function, it will helpful if player clears dst slot minetest.get_node_timer(pos):start(1.0) - if listname == "dst" then - give_xp(pos, player) - end + on_metadata_inventory_take(pos, listname, index, stack, player) end, allow_metadata_inventory_put = allow_metadata_inventory_put, @@ -552,6 +558,7 @@ minetest.register_node("mcl_furnaces:furnace_active", { allow_metadata_inventory_put = allow_metadata_inventory_put, allow_metadata_inventory_move = allow_metadata_inventory_move, allow_metadata_inventory_take = allow_metadata_inventory_take, + on_metadata_inventory_move = on_metadata_inventory_move, on_metadata_inventory_take = on_metadata_inventory_take, on_receive_fields = receive_fields, _mcl_blast_resistance = 3.5, From f0c2a0a1e97f31708568a4ae6b5361f89738de8b Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 21 Mar 2021 19:45:33 +0100 Subject: [PATCH 17/58] Fix arrows crashing the server --- mods/ITEMS/mcl_bows/arrow.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_bows/arrow.lua b/mods/ITEMS/mcl_bows/arrow.lua index 1b7d63c13..aefb92cca 100644 --- a/mods/ITEMS/mcl_bows/arrow.lua +++ b/mods/ITEMS/mcl_bows/arrow.lua @@ -17,7 +17,7 @@ end local random_arrow_positions = function(positions, placement) local min = 0 - local max = 0 + local max = 1 if positions == 'x' then min = -4 max = 4 From 2d1ac1c7fa4b3ad473e9ca752a663452ed79d37b Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 21 Mar 2021 19:47:13 +0100 Subject: [PATCH 18/58] Properly fix arrows crashing the server --- mods/ITEMS/mcl_bows/arrow.lua | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/mods/ITEMS/mcl_bows/arrow.lua b/mods/ITEMS/mcl_bows/arrow.lua index aefb92cca..36034cc96 100644 --- a/mods/ITEMS/mcl_bows/arrow.lua +++ b/mods/ITEMS/mcl_bows/arrow.lua @@ -16,23 +16,17 @@ local dir_to_pitch = function(dir) end local random_arrow_positions = function(positions, placement) - local min = 0 - local max = 1 if positions == 'x' then - min = -4 - max = 4 + return math.random(-4, 4) elseif positions == 'y' then - min = 0 - max = 10 + return math.random(0, 10) end if placement == 'front' and positions == 'z' then - min = 3 - max = 3 + return 3 elseif placement == 'back' and positions == 'z' then - min = -3 - max = -3 + return -3 end - return math.random(max, min) + return 0 end local mod_awards = minetest.get_modpath("awards") and minetest.get_modpath("mcl_achievements") From 9a4d26c2ae2fffea258936fe2310518974c2ae5f Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Sun, 21 Mar 2021 19:52:27 +0100 Subject: [PATCH 19/58] Fix all invalid usages of math.random in mcl_bows --- mods/ITEMS/mcl_bows/arrow.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/mcl_bows/arrow.lua b/mods/ITEMS/mcl_bows/arrow.lua index 36034cc96..cddae0869 100644 --- a/mods/ITEMS/mcl_bows/arrow.lua +++ b/mods/ITEMS/mcl_bows/arrow.lua @@ -298,8 +298,8 @@ ARROW_ENTITY.on_step = function(self, dtime) else self._attach_parent = 'Body' end - self._z_rotation = math.random(30, -30) - self._y_rotation = math.random(30, -30) + self._z_rotation = math.random(-30, 30) + self._y_rotation = math.random( -30, 30) self.object:set_attach(obj, self._attach_parent, {x=self._x_position,y=self._y_position,z=random_arrow_positions('z', placement)}, {x=0,y=self._rotation_station + self._y_rotation,z=self._z_rotation}) minetest.after(150, function() self.object:remove() From 03feb3655883999219c70232999999da059f31fe Mon Sep 17 00:00:00 2001 From: kay27 Date: Sun, 21 Mar 2021 23:14:33 +0000 Subject: [PATCH 20/58] Improve Nether Portals (#1315) (as a squash) Remove Nether portal caches, https://git.minetest.land/MineClone2/MineClone2/issues/1210 Store all exits from Nether portals in quick-access table Implement proper Nether portal search, using the table, https://git.minetest.land/MineClone2/MineClone2/issues/1055 Store Nether portal exits table in mod storage Remove exits from table on Nether portal destruction Align destination area to [map chunks 5x5x5](https://git.minetest.land/MineClone2/MineClone2/wiki/World-structure%3A-positions%2C-boundaries%2C-blocks%2C-chunks%2C-dimensions%2C-barriers-and-the-void) to avoid lots of ```emerge_area()``` calls Support Nether roof, https://git.minetest.land/MineClone2/MineClone2/issues/1267 Implement better suitable place search, https://git.minetest.land/MineClone2/MineClone2/issues/1126 Implement object queue not to trigger the same search again Avoid lava lakes, https://git.minetest.land/MineClone2/MineClone2/issues/1126 Add ```/spawnstruct nether_portal``` chat command Co-Authored-By: kay27 Co-Committed-By: kay27 --- mods/CORE/mcl_init/init.lua | 17 +- mods/CORE/mcl_worlds/init.lua | 10 +- mods/ENTITIES/mcl_mobs/api.lua | 2 +- mods/ITEMS/mcl_portals/mod.conf | 2 +- mods/ITEMS/mcl_portals/portal_nether.lua | 1087 +++++++++++----------- mods/MAPGEN/mcl_mapgen_core/init.lua | 45 +- mods/MAPGEN/mcl_structures/init.lua | 4 +- 7 files changed, 598 insertions(+), 569 deletions(-) diff --git a/mods/CORE/mcl_init/init.lua b/mods/CORE/mcl_init/init.lua index 884ebfae1..ca510b74f 100644 --- a/mods/CORE/mcl_init/init.lua +++ b/mods/CORE/mcl_init/init.lua @@ -33,25 +33,26 @@ mcl_vars.MAP_BLOCKSIZE = math.max(1, core.MAP_BLOCKSIZE or 16) mcl_vars.mapgen_limit = math.max(1, tonumber(minetest.get_mapgen_setting("mapgen_limit")) or 31000) mcl_vars.MAX_MAP_GENERATION_LIMIT = math.max(1, core.MAX_MAP_GENERATION_LIMIT or 31000) local central_chunk_offset = -math.floor(mcl_vars.chunksize / 2) -local chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE +mcl_vars.central_chunk_offset_in_nodes = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE +mcl_vars.chunk_size_in_nodes = mcl_vars.chunksize * mcl_vars.MAP_BLOCKSIZE local central_chunk_min_pos = central_chunk_offset * mcl_vars.MAP_BLOCKSIZE -local central_chunk_max_pos = central_chunk_min_pos + chunk_size_in_nodes - 1 +local central_chunk_max_pos = central_chunk_min_pos + mcl_vars.chunk_size_in_nodes - 1 local ccfmin = central_chunk_min_pos - mcl_vars.MAP_BLOCKSIZE -- Fullminp/fullmaxp of central chunk, in nodes local ccfmax = central_chunk_max_pos + mcl_vars.MAP_BLOCKSIZE local mapgen_limit_b = math.floor(math.min(mcl_vars.mapgen_limit, mcl_vars.MAX_MAP_GENERATION_LIMIT) / mcl_vars.MAP_BLOCKSIZE) local mapgen_limit_min = -mapgen_limit_b * mcl_vars.MAP_BLOCKSIZE local mapgen_limit_max = (mapgen_limit_b + 1) * mcl_vars.MAP_BLOCKSIZE - 1 -local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk -local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits. -mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * chunk_size_in_nodes -mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * chunk_size_in_nodes +local numcmin = math.max(math.floor((ccfmin - mapgen_limit_min) / mcl_vars.chunk_size_in_nodes), 0) -- Number of complete chunks from central chunk +local numcmax = math.max(math.floor((mapgen_limit_max - ccfmax) / mcl_vars.chunk_size_in_nodes), 0) -- fullminp/fullmaxp to effective mapgen limits. +mcl_vars.mapgen_edge_min = central_chunk_min_pos - numcmin * mcl_vars.chunk_size_in_nodes +mcl_vars.mapgen_edge_max = central_chunk_max_pos + numcmax * mcl_vars.chunk_size_in_nodes local function coordinate_to_block(x) return math.floor(x / mcl_vars.MAP_BLOCKSIZE) end local function coordinate_to_chunk(x) - return math.floor((coordinate_to_block(x) + central_chunk_offset) / mcl_vars.chunksize) + return math.floor((coordinate_to_block(x) - central_chunk_offset) / mcl_vars.chunksize) end function mcl_vars.pos_to_block(pos) @@ -70,7 +71,7 @@ function mcl_vars.pos_to_chunk(pos) } end -local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / chunk_size_in_nodes) +local k_positive = math.ceil(mcl_vars.MAX_MAP_GENERATION_LIMIT / mcl_vars.chunk_size_in_nodes) local k_positive_z = k_positive * 2 local k_positive_y = k_positive_z * k_positive_z diff --git a/mods/CORE/mcl_worlds/init.lua b/mods/CORE/mcl_worlds/init.lua index 35549ffad..6cdeaab7e 100644 --- a/mods/CORE/mcl_worlds/init.lua +++ b/mods/CORE/mcl_worlds/init.lua @@ -6,7 +6,7 @@ mcl_worlds = {} function mcl_worlds.is_in_void(pos) local void = not ((pos.y < mcl_vars.mg_overworld_max and pos.y > mcl_vars.mg_overworld_min) or - (pos.y < mcl_vars.mg_nether_max and pos.y > mcl_vars.mg_nether_min) or + (pos.y < mcl_vars.mg_nether_max+128 and pos.y > mcl_vars.mg_nether_min) or (pos.y < mcl_vars.mg_end_max and pos.y > mcl_vars.mg_end_min)) local void_deadly = false @@ -15,11 +15,11 @@ function mcl_worlds.is_in_void(pos) -- Overworld → Void → End → Void → Nether → Void if pos.y < mcl_vars.mg_overworld_min and pos.y > mcl_vars.mg_end_max then void_deadly = pos.y < mcl_vars.mg_overworld_min - deadly_tolerance - elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max then + elseif pos.y < mcl_vars.mg_end_min and pos.y > mcl_vars.mg_nether_max+128 then -- The void between End and Nether. Like usual, but here, the void -- *above* the Nether also has a small tolerance area, so player -- can fly above the Nether without getting hurt instantly. - void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max + deadly_tolerance) + void_deadly = (pos.y < mcl_vars.mg_end_min - deadly_tolerance) and (pos.y > mcl_vars.mg_nether_max+128 + deadly_tolerance) elseif pos.y < mcl_vars.mg_nether_min then void_deadly = pos.y < mcl_vars.mg_nether_min - deadly_tolerance end @@ -35,7 +35,7 @@ end function mcl_worlds.y_to_layer(y) if y >= mcl_vars.mg_overworld_min then return y - mcl_vars.mg_overworld_min, "overworld" - elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max then + elseif y >= mcl_vars.mg_nether_min and y <= mcl_vars.mg_nether_max+128 then return y - mcl_vars.mg_nether_min, "nether" elseif y >= mcl_vars.mg_end_min and y <= mcl_vars.mg_end_max then return y - mcl_vars.mg_end_min, "end" @@ -73,7 +73,7 @@ end -- Takes a position and returns true if this position can have Nether dust function mcl_worlds.has_dust(pos) -- Weather in the Overworld and the high part of the void below - return pos.y <= mcl_vars.mg_nether_max + 64 and pos.y >= mcl_vars.mg_nether_min - 64 + return pos.y <= mcl_vars.mg_nether_max + 138 and pos.y >= mcl_vars.mg_nether_min - 10 end -- Takes a position (pos) and returns true if compasses are working here diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 3b929a119..93b7bc146 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -2826,7 +2826,7 @@ local falling = function(self, pos) end if mcl_portals ~= nil then - if mcl_portals.nether_portal_cooloff[self.object] then + if mcl_portals.nether_portal_cooloff(self.object) then return false -- mob has teleported through Nether portal - it's 99% not falling end end diff --git a/mods/ITEMS/mcl_portals/mod.conf b/mods/ITEMS/mcl_portals/mod.conf index b25ab391f..d99344a76 100644 --- a/mods/ITEMS/mcl_portals/mod.conf +++ b/mods/ITEMS/mcl_portals/mod.conf @@ -1,4 +1,4 @@ name = mcl_portals description = Adds buildable portals to the Nether and End dimensions. -depends = mcl_init, mcl_worlds, mcl_core, mcl_nether, mcl_end, mcl_particles, mcl_spawn +depends = mcl_nether, mcl_end, mcl_particles, mcl_spawn optional_depends = awards, doc diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index ff9df2b4d..c63c78384 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -1,83 +1,213 @@ local S = minetest.get_translator("mcl_portals") --- Parameters +-- Localize functions for better performance +local abs = math.abs +local ceil = math.ceil +local floor = math.floor +local max = math.max +local min = math.min +local random = math.random +local dist = vector.distance +local add = vector.add +local mul = vector.multiply +local sub = vector.subtract -local OVERWORLD_TO_NETHER_SCALE = 8 -local LIMIT = math.min(math.abs(mcl_vars.mapgen_edge_min), math.abs(mcl_vars.mapgen_edge_max)) +-- Setup +local W_MIN, W_MAX = 4, 23 +local H_MIN, H_MAX = 5, 23 +local N_MIN, N_MAX = 6, (W_MAX-2) * (H_MAX-2) +local TRAVEL_X, TRAVEL_Y, TRAVEL_Z = 8, 1, 8 +local LIM_MIN, LIM_MAX = mcl_vars.mapgen_edge_min, mcl_vars.mapgen_edge_max +local PLAYER_COOLOFF, MOB_COOLOFF = 3, 14 -- for this many seconds they won't teleported again +local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds +local CHATTER_US = TOUCH_CHATTER_TIME * 1000000 +local DELAY = 3 -- seconds before teleporting in Nether portal in Survival mode (4 minus ABM interval time) +local DISTANCE_MAX = 128 +local PORTAL = "mcl_portals:portal" +local OBSIDIAN = "mcl_core:obsidian" +local O_Y_MIN, O_Y_MAX = max(mcl_vars.mg_overworld_min, -31), min(mcl_vars.mg_overworld_max_official, 2048) +local N_Y_MIN, N_Y_MAX = mcl_vars.mg_bedrock_nether_bottom_min, mcl_vars.mg_bedrock_nether_top_max +local O_DY, N_DY = O_Y_MAX - O_Y_MIN + 1, N_Y_MAX - N_Y_MIN + 1 --- Portal frame sizes -local FRAME_SIZE_X_MIN = 4 -local FRAME_SIZE_Y_MIN = 5 -local FRAME_SIZE_X_MAX = 23 -local FRAME_SIZE_Y_MAX = 23 - -local PORTAL_NODES_MIN = 5 -local PORTAL_NODES_MAX = (FRAME_SIZE_X_MAX - 2) * (FRAME_SIZE_Y_MAX - 2) - -local TELEPORT_COOLOFF = 3 -- after player was teleported, for this many seconds they won't teleported again -local MOB_TELEPORT_COOLOFF = 14 -- after mob was teleported, for this many seconds they won't teleported again -local TOUCH_CHATTER_TIME = 1 -- prevent multiple teleportation attempts caused by multiple portal touches, for this number of seconds -local TOUCH_CHATTER_TIME_US = TOUCH_CHATTER_TIME * 1000000 -local TELEPORT_DELAY = 3 -- seconds before teleporting in Nether portal (4 minus ABM interval time) -local DESTINATION_EXPIRES = 60 * 1000000 -- cached destination expires after this number of microseconds have passed without using the same origin portal - -local PORTAL_SEARCH_HALF_CHUNK = 40 -- greater values may slow down the teleportation -local PORTAL_SEARCH_ALTITUDE = 128 - -local PORTAL_ALPHA = 192 -if minetest.features.use_texture_alpha_string_modes then - PORTAL_ALPHA = nil -end +-- Alpha and particles +local ALPHA = minetest.features.use_texture_alpha_string_modes and 192 +local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none" +local node_particles_levels = { none=0, low=1, medium=2, high=3 } +local PARTICLES = node_particles_levels[node_particles_allowed] -- Table of objects (including players) which recently teleported by a -- Nether portal. Those objects have a brief cooloff period before they -- can teleport again. This prevents annoying back-and-forth teleportation. -mcl_portals.nether_portal_cooloff = {} -local touch_chatter_prevention = {} +local cooloff = {} +function mcl_portals.nether_portal_cooloff(object) + return cooloff[object] +end -local overworld_ymin = math.max(mcl_vars.mg_overworld_min, -31) -local overworld_ymax = math.min(mcl_vars.mg_overworld_max_official, 63) -local nether_ymin = mcl_vars.mg_bedrock_nether_bottom_min -local nether_ymax = mcl_vars.mg_bedrock_nether_top_max -local overworld_dy = overworld_ymax - overworld_ymin + 1 -local nether_dy = nether_ymax - nether_ymin + 1 +local chatter = {} -local node_particles_allowed = minetest.settings:get("mcl_node_particles") or "none" -local node_particles_levels = { - high = 3, - medium = 2, - low = 1, - none = 0, +local queue = {} +local chunks = {} + +local storage = minetest.get_mod_storage() +local exits = {} +local keys = minetest.deserialize(storage:get_string("nether_exits_keys") or "return {}") or {} +for _, key in pairs(keys) do + local n = tonumber(key) + if n then + exits[key] = minetest.deserialize(storage:get_string("nether_exits_"..key) or "return {}") or {} + end +end +minetest.register_on_shutdown(function() + local keys={} + for key, data in pairs(exits) do + storage:set_string("nether_exits_"..tostring(key), minetest.serialize(data)) + keys[#keys+1] = key + end + storage:set_string("nether_exits_keys", minetest.serialize(keys)) +end) + +mcl_portals.get_node = function(pos) + if mcl_mapgen_core and mcl_mapgen_core.get_node then + mcl_portals.get_node = mcl_mapgen_core.get_node + end + return minetest.get_node(pos) +end +local set_node = minetest.set_node +local registered_nodes = minetest.registered_nodes +local is_protected = minetest.is_protected +local find_nodes_in_area = minetest.find_nodes_in_area +local find_nodes_in_area_under_air = minetest.find_nodes_in_area_under_air +local log = minetest.log +local pos_to_string = minetest.pos_to_string +local is_area_protected = minetest.is_area_protected +local get_us_time = minetest.get_us_time + +local limits = { + nether = { + pmin = {x=LIM_MIN, y = N_Y_MIN, z = LIM_MIN}, + pmax = {x=LIM_MAX, y = N_Y_MAX, z = LIM_MAX}, + }, + overworld = { + pmin = {x=LIM_MIN, y = O_Y_MIN, z = LIM_MIN}, + pmax = {x=LIM_MAX, y = O_Y_MAX, z = LIM_MAX}, + }, } -local node_particles_allowed_level = node_particles_levels[node_particles_allowed] + +-- This function registers exits from Nether portals. +-- Incoming verification performed: two nodes must be portal nodes, and an obsidian below them. +-- If the verification passes - position adds to the table and saves to mod storage on exit. +local function add_exit(p) + local get_node = mcl_portals.get_node + if not p or not p.y or not p.z or not p.x then return end + local x, y, z = floor(p.x), floor(p.y), floor(p.z) + local p = {x = x, y = y, z = z} + if get_node({x=x,y=y-1,z=z}).name ~= OBSIDIAN or get_node(p).name ~= PORTAL or get_node({x=x,y=y+1,z=z}).name ~= PORTAL then return end + local k = floor(z/256) * 256 + floor(x/256) + if not exits[k] then + exits[k]={} + end + local e = exits[k] + for i = 1, #e do + local t = e[i] + if t.x == p.x and t.y == p.y and t.z == p.z then + return + end + end + e[#e+1] = p + log("action", "[mcl_portals] Exit added at " .. pos_to_string(p)) +end + +-- This function removes Nether portals exits. +local function remove_exit(p) + if not p or not p.y or not p.z or not p.x then return end + local x, y, z = floor(p.x), floor(p.y), floor(p.z) + local k = floor(z/256) * 256 + floor(x/256) + if not exits[k] then return end + local p = {x = x, y = y, z = z} + local e = exits[k] + if e then + for i, t in pairs(e) do + if t and t.x == x and t.y == y and t.z == z then + e[i] = nil + log("action", "[mcl_portals] Nether portal removed from " .. pos_to_string(p)) + return + end + end + end +end + +-- This functon searches Nether portal nodes whitin distance specified +local function find_exit(p, dx, dy, dz) + if not p or not p.y or not p.z or not p.x then return end + local dx, dy, dz = dx or DISTANCE_MAX, dy or DISTANCE_MAX, dz or DISTANCE_MAX + if dx < 1 or dy < 1 or dz < 1 then return false end + local x, y, z = floor(p.x), floor(p.y), floor(p.z) + local x1, y1, z1, x2, y2, z2 = x-dx+1, y-dy+1, z-dz+1, x+dx-1, y+dy-1, z+dz-1 + local k1x, k2x = floor(x1/256), floor(x2/256) + local k1z, k2z = floor(z1/256), floor(z2/256) + + local t, d + for kx = k1x, k2x do for kz = k1z, k2z do + local k = kz*256 + kx + local e = exits[k] + if e then + for _, t0 in pairs(e) do + local d0 = dist(p, t0) + if not d or d>d0 then + d = d0 + t = t0 + if d==0 then return t end + end + end + end + end end + + if t and abs(t.x-p.x) <= dx and abs(t.y-p.y) <= dy and abs(t.z-p.z) <= dz then + return t + end +end --- Functions +-- Ping-Pong the coordinate for Fast Travelling, https://git.minetest.land/Wuzzy/MineClone2/issues/795#issuecomment-11058 +local function ping_pong(x, m, l1, l2) + if x < 0 then + return l1 + abs(((x*m+l1) % (l1*4)) - (l1*2)), floor(x*m/l1/2) + ((ceil(x*m/l1)+1)%2) * ((x*m)%l1)/l1 + end + return l2 - abs(((x*m+l2) % (l2*4)) - (l2*2)), floor(x*m/l2/2) + (floor(x*m/l2)%2) * ((x*m)%l2)/l2 +end --- Ping-Pong fast travel, https://git.minetest.land/Wuzzy/MineClone2/issues/795#issuecomment-11058 -local function nether_to_overworld(x) - return LIMIT - math.abs(((x * OVERWORLD_TO_NETHER_SCALE + LIMIT) % (LIMIT*4)) - (LIMIT*2)) +local function get_target(p) + if p and p.y and p.x and p.z then + local x, z = p.x, p.z + local y, d = mcl_worlds.y_to_layer(p.y) + local o1, o2 -- y offset + if y then + if d=="nether" then + x, o1 = ping_pong(x, TRAVEL_X, LIM_MIN, LIM_MAX) + z, o2 = ping_pong(z, TRAVEL_Z, LIM_MIN, LIM_MAX) + y = floor(y * TRAVEL_Y + (o1+o2) / 16 * LIM_MAX) + y = min(max(y + mcl_vars.mg_overworld_min, mcl_vars.mg_overworld_min), mcl_vars.mg_overworld_max) + elseif d=="overworld" then + x, y, z = floor(x / TRAVEL_X + 0.5), floor(y / TRAVEL_Y + 0.5), floor(z / TRAVEL_Z + 0.5) + y = min(max(y + mcl_vars.mg_nether_min, mcl_vars.mg_nether_min), mcl_vars.mg_nether_max) + end + return {x=x, y=y, z=z}, d + end + end end -- Destroy portal if pos (portal frame or portal node) got destroyed -local function destroy_nether_portal(pos) - local meta = minetest.get_meta(pos) - local node = minetest.get_node(pos) +local function destroy_nether_portal(pos, node) + if not node then return end local nn, orientation = node.name, node.param2 - local obsidian = nn == "mcl_core:obsidian" + local obsidian = nn == OBSIDIAN - local has_meta = minetest.string_to_pos(meta:get_string("portal_frame1")) - if has_meta then - meta:set_string("portal_frame1", "") - meta:set_string("portal_frame2", "") - meta:set_string("portal_target", "") - meta:set_string("portal_time", "") - end + local get_node = mcl_portals.get_node local check_remove = function(pos, orientation) - local node = minetest.get_node(pos) - if node and (node.name == "mcl_portals:portal" and (orientation == nil or (node.param2 == orientation))) then - minetest.log("action", "[mcl_portal] Destroying Nether portal at " .. minetest.pos_to_string(pos)) - return minetest.remove_node(pos) + local node = get_node(pos) + if node and (node.name == PORTAL and (orientation == nil or (node.param2 == orientation))) then + minetest.remove_node(pos) + remove_exit(pos) end end if obsidian then -- check each of 6 sides of it and destroy every portal: @@ -89,9 +219,6 @@ local function destroy_nether_portal(pos) check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) return end - if not has_meta then -- no meta means repeated call: function calls on every node destruction - return - end if orientation == 0 then check_remove({x = pos.x - 1, y = pos.y, z = pos.z}, 0) check_remove({x = pos.x + 1, y = pos.y, z = pos.z}, 0) @@ -103,7 +230,7 @@ local function destroy_nether_portal(pos) check_remove({x = pos.x, y = pos.y + 1, z = pos.z}) end -minetest.register_node("mcl_portals:portal", { +minetest.register_node(PORTAL, { description = S("Nether Portal"), _doc_items_longdesc = S("A Nether portal teleports creatures and objects to the hot and dangerous Nether dimension (and back!). Enter at your own risk!"), _doc_items_usagehelp = S("Stand in the portal for a moment to activate the teleportation. Entering a Nether portal for the first time will also create a new portal in the other dimension. If a Nether portal has been built in the Nether, it will lead to the Overworld. A Nether portal is destroyed if the any of the obsidian which surrounds it is destroyed, or if it was caught in an explosion."), @@ -143,7 +270,7 @@ minetest.register_node("mcl_portals:portal", { drop = "", light_source = 11, post_effect_color = {a = 180, r = 51, g = 7, b = 89}, - alpha = PORTAL_ALPHA, + alpha = ALPHA, node_box = { type = "fixed", fixed = { @@ -152,398 +279,368 @@ minetest.register_node("mcl_portals:portal", { }, groups = { creative_breakable = 1, portal = 1, not_in_creative_inventory = 1 }, sounds = mcl_sounds.node_sound_glass_defaults(), - on_destruct = destroy_nether_portal, + after_destruct = destroy_nether_portal, _mcl_hardness = -1, _mcl_blast_resistance = 0, }) -local function find_target_y(x, y, z, y_min, y_max) - local y_org = math.max(math.min(y, y_max), y_min) - local node = minetest.get_node_or_nil({x = x, y = y, z = z}) - if node == nil then - return y_org +local function light_frame(x1, y1, z1, x2, y2, z2, name) + local orientation = 0 + if x1 == x2 then + orientation = 1 end - while node.name ~= "air" and y < y_max do - y = y + 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - if node == nil then - break - end - end - if node then - if node.name ~= "air" then - y = y_org - end - end - while node == nil and y > y_min do - y = y - 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - end - if y == y_max and node ~= nil then -- try reverse direction who knows what they built there... - while node.name ~= "air" and y > y_min do - y = y - 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - if node == nil then - break - end - end - end - if node == nil then - return y_org - end - while node.name == "air" and y > y_min do - y = y - 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - while node == nil and y > y_min do - y = y - 1 - node = minetest.get_node_or_nil({x = x, y = y, z = z}) - end - if node == nil then - return y_org - end - end - if y == y_min then - return y_org - end - return math.max(math.min(y, y_max), y_min) -end - -local function find_nether_target_y(x, y, z) - local target_y = find_target_y(x, y, z, nether_ymin + 4, nether_ymax - 25) + 1 - minetest.log("verbose", "[mcl_portal] Found Nether target altitude: " .. tostring(target_y) .. " for pos. " .. minetest.pos_to_string({x = x, y = y, z = z})) - return target_y -end - -local function find_overworld_target_y(x, y, z) - local target_y = find_target_y(x, y, z, overworld_ymin + 4, overworld_ymax - 25) + 1 - local node = minetest.get_node({x = x, y = target_y - 1, z = z}) - if not node then - return target_y - end - local nn = node.name - if nn ~= "air" and minetest.get_item_group(nn, "water") == 0 then - target_y = target_y + 1 - end - minetest.log("verbose", "[mcl_portal] Found Overworld target altitude: " .. tostring(target_y) .. " for pos. " .. minetest.pos_to_string({x = x, y = y, z = z})) - return target_y -end - - -local function update_target(pos, target, time_str) - local stack = {{x = pos.x, y = pos.y, z = pos.z}} - while #stack > 0 do - local i = #stack - local meta = minetest.get_meta(stack[i]) - if meta:get_string("portal_time") == time_str then - stack[i] = nil -- Already updated, skip it - else - local node = minetest.get_node(stack[i]) - local portal = node.name == "mcl_portals:portal" - if not portal then - stack[i] = nil - else - local x, y, z = stack[i].x, stack[i].y, stack[i].z - meta:set_string("portal_time", time_str) - meta:set_string("portal_target", target) - stack[i].y = y - 1 - stack[i + 1] = {x = x, y = y + 1, z = z} - if node.param2 == 0 then - stack[i + 2] = {x = x - 1, y = y, z = z} - stack[i + 3] = {x = x + 1, y = y, z = z} + local pos = {} + for x = x1 - 1 + orientation, x2 + 1 - orientation do + pos.x = x + for z = z1 - orientation, z2 + orientation do + pos.z = z + for y = y1 - 1, y2 + 1 do + pos.y = y + local frame = (x < x1) or (x > x2) or (y < y1) or (y > y2) or (z < z1) or (z > z2) + if frame then + set_node(pos, {name = OBSIDIAN}) else - stack[i + 2] = {x = x, y = y, z = z - 1} - stack[i + 3] = {x = x, y = y, z = z + 1} + set_node(pos, {name = PORTAL, param2 = orientation}) + add_exit({x=pos.x, y=pos.y-1, z=pos.z}) end end end end end -local function ecb_setup_target_portal(blockpos, action, calls_remaining, param) - -- param.: srcx, srcy, srcz, dstx, dsty, dstz, srcdim, ax1, ay1, az1, ax2, ay2, az2 +--Build arrival portal +function build_nether_portal(pos, width, height, orientation, name) + local width, height, orientation = width or W_MIN - 2, height or H_MIN - 2, orientation or random(0, 1) - local portal_search = function(target, p1, p2) - local portal_nodes = minetest.find_nodes_in_area(p1, p2, "mcl_portals:portal") - local portal_pos = false - if portal_nodes and #portal_nodes > 0 then - -- Found some portal(s), use nearest: - portal_pos = {x = portal_nodes[1].x, y = portal_nodes[1].y, z = portal_nodes[1].z} - local nearest_distance = vector.distance(target, portal_pos) - for n = 2, #portal_nodes do - local distance = vector.distance(target, portal_nodes[n]) - if distance < nearest_distance then - portal_pos = {x = portal_nodes[n].x, y = portal_nodes[n].y, z = portal_nodes[n].z} - nearest_distance = distance - end - end - end -- here we have the best portal_pos - return portal_pos - end + light_frame(pos.x, pos.y, pos.z, pos.x + (1 - orientation) * (width - 1), pos.y + height - 1, pos.z + orientation * (width - 1)) - if calls_remaining <= 0 then - minetest.log("action", "[mcl_portal] Area for destination Nether portal emerged!") - local src_pos = {x = param.srcx, y = param.srcy, z = param.srcz} - local dst_pos = {x = param.dstx, y = param.dsty, z = param.dstz} - local meta = minetest.get_meta(src_pos) - local portal_pos = portal_search(dst_pos, {x = param.ax1, y = param.ay1, z = param.az1}, {x = param.ax2, y = param.ay2, z = param.az2}) + local get_node = mcl_portals.get_node - if portal_pos == false then - minetest.log("verbose", "[mcl_portal] No portal in area " .. minetest.pos_to_string({x = param.ax1, y = param.ay1, z = param.az1}) .. "-" .. minetest.pos_to_string({x = param.ax2, y = param.ay2, z = param.az2})) - -- Need to build arrival portal: - local org_dst_y = dst_pos.y - if param.srcdim == "overworld" then - dst_pos.y = find_nether_target_y(dst_pos.x, dst_pos.y, dst_pos.z) - else - dst_pos.y = find_overworld_target_y(dst_pos.x, dst_pos.y, dst_pos.z) - end - if math.abs(org_dst_y - dst_pos.y) >= PORTAL_SEARCH_ALTITUDE / 2 then - portal_pos = portal_search(dst_pos, - {x = dst_pos.x - PORTAL_SEARCH_HALF_CHUNK, y = math.floor(dst_pos.y - PORTAL_SEARCH_ALTITUDE / 2), z = dst_pos.z - PORTAL_SEARCH_HALF_CHUNK}, - {x = dst_pos.x + PORTAL_SEARCH_HALF_CHUNK, y = math.ceil(dst_pos.y + PORTAL_SEARCH_ALTITUDE / 2), z = dst_pos.z + PORTAL_SEARCH_HALF_CHUNK} - ) - end - if portal_pos == false then - minetest.log("verbose", "[mcl_portal] 2nd attempt: No portal in area " .. minetest.pos_to_string({x = dst_pos.x - PORTAL_SEARCH_HALF_CHUNK, y = math.floor(dst_pos.y - PORTAL_SEARCH_ALTITUDE / 2), z = dst_pos.z - PORTAL_SEARCH_HALF_CHUNK}) .. "-" .. minetest.pos_to_string({x = dst_pos.x + PORTAL_SEARCH_HALF_CHUNK, y = math.ceil(dst_pos.y + PORTAL_SEARCH_ALTITUDE / 2), z = dst_pos.z + PORTAL_SEARCH_HALF_CHUNK})) - local width, height = 2, 3 - portal_pos = mcl_portals.build_nether_portal(dst_pos, width, height) + -- Build obsidian platform: + for x = pos.x - orientation, pos.x + orientation + (width - 1) * (1 - orientation), 1 + orientation do + for z = pos.z - 1 + orientation, pos.z + 1 - orientation + (width - 1) * orientation, 2 - orientation do + local pp = {x = x, y = pos.y - 1, z = z} + local pp_1 = {x = x, y = pos.y - 2, z = z} + local nn = get_node(pp).name + local nn_1 = get_node(pp_1).name + log("warning", "[mcl_portals] pos=" .. pos_to_string(pp) .. " nn=" .. nn .. " name=" .. name .. " width=" .. tostring(width) .. " height=" .. tostring(height).." orientation=" ..tostring(orientation).." gc="..tostring(registered_nodes[nn].is_ground_content) .." for obsidian platform:") + if ((nn=="air" and nn_1 == "air") or not registered_nodes[nn].is_ground_content) and not is_protected(pp, name) then + set_node(pp, {name = OBSIDIAN}) + minetest.log("warning", "set!") end end + end - local target_meta = minetest.get_meta(portal_pos) - local p3 = minetest.string_to_pos(target_meta:get_string("portal_frame1")) - local p4 = minetest.string_to_pos(target_meta:get_string("portal_frame2")) - if p3 and p4 then - portal_pos = vector.divide(vector.add(p3, p4), 2.0) - portal_pos.y = math.min(p3.y, p4.y) - portal_pos = vector.round(portal_pos) - local node = minetest.get_node(portal_pos) - if node and node.name ~= "mcl_portals:portal" then - portal_pos = {x = p3.x, y = p3.y, z = p3.z} - if minetest.get_node(portal_pos).name == "mcl_core:obsidian" then - -- Old-version portal: - if p4.z == p3.z then - portal_pos = {x = p3.x + 1, y = p3.y + 1, z = p3.z} - else - portal_pos = {x = p3.x, y = p3.y + 1, z = p3.z + 1} + log("action", "[mcl_portals] Destination Nether portal generated at "..pos_to_string(pos).."!") + + return pos +end + +function mcl_portals.spawn_nether_portal(pos, rot, pr, name) + if not pos then return end + local o = 0 + if rot then + if rot == "270" or rot=="90" then + o = 1 + elseif rot == "random" then + o = random(0,1) + end + end + build_nether_portal(pos, nil, nil, o, name) +end + +-- Teleportation cooloff for some seconds, to prevent back-and-forth teleportation +local function stop_teleport_cooloff(o) + cooloff[o] = nil + chatter[o] = nil +end + +local function teleport_cooloff(obj) + cooloff[obj] = true + if obj:is_player() then + minetest.after(PLAYER_COOLOFF, stop_teleport_cooloff, obj) + else + minetest.after(MOB_COOLOFF, stop_teleport_cooloff, obj) + end +end + +local function finalize_teleport(obj, exit) + if not obj or not exit or not exit.x or not exit.y or not exit.z then return end + + local objpos = obj:get_pos() + if not objpos then return end + + local is_player = obj:is_player() + local name + if is_player then + name = obj:get_player_name() + end + local y, dim = mcl_worlds.y_to_layer(exit.y) + + + -- If player stands, player is at ca. something+0.5 which might cause precision problems, so we used ceil for objpos.y + objpos = {x = floor(objpos.x+0.5), y = ceil(objpos.y), z = floor(objpos.z+0.5)} + if mcl_portals.get_node(objpos).name ~= PORTAL then return end + + -- Enable teleportation cooloff for some seconds, to prevent back-and-forth teleportation + teleport_cooloff(obj) + + -- Teleport + obj:set_pos(exit) + + if is_player then + mcl_worlds.dimension_change(obj, dim) + minetest.sound_play("mcl_portals_teleport", {pos=exit, gain=0.5, max_hear_distance = 16}, true) + log("action", "[mcl_portals] player "..name.." teleported to Nether portal at "..pos_to_string(exit)..".") + else + log("action", "[mcl_portals] entity teleported to Nether portal at "..pos_to_string(exit)..".") + end +end + +local function create_portal_2(pos1, name, obj) + local orientation = 0 + local pos2 = {x = pos1.x + 3, y = pos1.y + 3, z = pos1.z + 3} + local nodes = find_nodes_in_area(pos1, pos2, {"air"}) + if #nodes == 64 then + orientation = random(0,1) + else + pos2.x = pos2.x - 1 + nodes = find_nodes_in_area(pos1, pos2, {"air"}) + if #nodes == 48 then + orientation = 1 + end + end + local exit = build_nether_portal(pos1, W_MIN-2, H_MIN-2, orientation, name) + finalize_teleport(obj, exit) + local cn = mcl_vars.get_chunk_number(pos1) + chunks[cn] = nil + if queue[cn] then + for next_obj, _ in pairs(queue[cn]) do + if next_obj ~= obj then + finalize_teleport(next_obj, exit) + end + end + queue[cn] = nil + end +end + +local function get_lava_level(pos, pos1, pos2) + if pos.y > -1000 then + return max(min(mcl_vars.mg_lava_overworld_max, pos2.y-1), pos1.y+1) + end + return max(min(mcl_vars.mg_lava_nether_max, pos2.y-1), pos1.y+1) +end + +local function ecb_scan_area(blockpos, action, calls_remaining, param) + if calls_remaining and calls_remaining > 0 then return end + local pos, pos1, pos2, name, obj = param.pos, param.pos1, param.pos2, param.name or "", param.obj + local lava = get_lava_level(pos, pos1, pos2) + + local ttt1 = minetest.get_us_time() -- !!debug + -- loop in a spiral around pos + local cs, x, z, dx, dz, p0x, p0z, p1x, p1y, p1z, p2x, p2y, p2z = mcl_vars.chunk_size_in_nodes, 0, 0, 0, -1, pos.x, pos.z, pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z + + local i_max = (cs*2-1) * (cs*2-1) + log("action", "[mcl_portals] Area for destination Nether portal emerged! We about to iterate " .. tostring(i_max) .. " positions of spiral around "..pos_to_string(pos)) + + local backup_pos, bnc = nil, 0 -- 'better than nothing' + + local p1 = {x=0, y=p1y, z=0} + local p2 = {x=0, y=p2y, z=0} + for i = 1, i_max do + local px, pz = p0x + x, p0z + z + if ((i%100) == 1) then + log("action", "[mcl_portals] i=" ..tostring(i) .." px=" .. tostring(px) .." pz=" .. tostring(pz) .. " x:"..tostring(p1x) .."-"..tostring(p2x) .. " z:"..tostring(p1z) .."-"..tostring(p2z)) + end + if px >= p1x and pz >= p1z and px <= p2x and pz <= p2z then + p1.x, p2.x, p1.z, p2.z = px, px, pz, pz + local nodes = find_nodes_in_area_under_air(p1, p2, {"group:building_block"}) + log("action", "[mcl_portals] check " .. pos_to_string(p1) .. "-" .. pos_to_string(p2) .. ": " .. tostring(nodes and #nodes)) + if nodes and #nodes > 0 then + for j = 1, #nodes do + local node = nodes[j] + if not is_protected(node, name) then + node.y = node.y + 2 + local node2 = {x = node.x, y = node.y + 2, z = node.z} + if not is_protected(node2, name) then + local nodes_j = find_nodes_in_area(node, node2, {"air"}) + local nc = #nodes_j + if nc >= 3 then + node2.x = node2.x + 2 + node2.z = node2.z + 2 + nodes_j = find_nodes_in_area(node, node2, {"air"}) + if #nodes_j == 36 then + local msg1 = "DEBUG message: space found using algorithm 1, elapsed time: " .. tostring(minetest.get_us_time()-ttt1) .." us" -- !!debug + log("warning", "[mcl_portals] " .. msg1) -- !!debug + minetest.chat_send_all(msg1) -- !!debug + log("action", "[mcl_portals] found space at pos "..pos_to_string(node).." - creating a portal") + create_portal_2({x=node.x, y=node.y+1, z=node.z}, name, obj) + return + end + elseif nc > bnc or ((nc > max(bnc-2,0)) and backup_pos.y lava) then + bnc = nc + backup_pos = {x = node2.x, y = node2.y, z = node2.z} + log("action", "[mcl_portals] set backup pos "..pos_to_string(backup_pos).." with "..tostring(nc).." air node(s)") + end + end end end end end - local time_str = tostring(minetest.get_us_time()) - local target = minetest.pos_to_string(portal_pos) - - update_target(src_pos, target, time_str) + if x == z or (x < 0 and x == -z) or (x > 0 and x == 1-z) then + dx, dz = -dz, dx + end + x, z = x+dx, z+dz + px, pz = p0x + x, p0z + z end -end - -local function nether_portal_get_target_position(src_pos) - local _, current_dimension = mcl_worlds.y_to_layer(src_pos.y) - local x, y, z, y_min, y_max = 0, 0, 0, 0, 0 - if current_dimension == "nether" then - x = math.floor(nether_to_overworld(src_pos.x) + 0.5) - z = math.floor(nether_to_overworld(src_pos.z) + 0.5) - y = math.floor((math.min(math.max(src_pos.y, nether_ymin), nether_ymax) - nether_ymin) / nether_dy * overworld_dy + overworld_ymin + 0.5) - y_min = overworld_ymin - y_max = overworld_ymax - else -- overworld: - x = math.floor(src_pos.x / OVERWORLD_TO_NETHER_SCALE + 0.5) - z = math.floor(src_pos.z / OVERWORLD_TO_NETHER_SCALE + 0.5) - y = math.floor((math.min(math.max(src_pos.y, overworld_ymin), overworld_ymax) - overworld_ymin) / overworld_dy * nether_dy + nether_ymin + 0.5) - y_min = nether_ymin - y_max = nether_ymax + if backup_pos then -- several nodes of air might be better than lava lake, right? + local msg1 = "DEBUG message: space partially found using algorithm 1, elapsed time: " .. tostring(minetest.get_us_time()-ttt1) .." us" -- !!debug + log("warning", "[mcl_portals] " .. msg1) -- !!debug + minetest.chat_send_all(msg1) -- !!debug + log("action", "[mcl_portals] using backup pos "..pos_to_string(backup_pos).." to create a portal") + create_portal_2(backup_pos, name, obj) + return end - return x, y, z, current_dimension, y_min, y_max -end - -local function find_or_create_portal(src_pos) - local x, y, z, cdim, y_min, y_max = nether_portal_get_target_position(src_pos) - local pos1 = {x = x - PORTAL_SEARCH_HALF_CHUNK, y = math.max(y_min, math.floor(y - PORTAL_SEARCH_ALTITUDE / 2)), z = z - PORTAL_SEARCH_HALF_CHUNK} - local pos2 = {x = x + PORTAL_SEARCH_HALF_CHUNK, y = math.min(y_max, math.ceil(y + PORTAL_SEARCH_ALTITUDE / 2)), z = z + PORTAL_SEARCH_HALF_CHUNK} - if pos1.y == y_min then - pos2.y = math.min(y_max, pos1.y + PORTAL_SEARCH_ALTITUDE) + local msg1 = "DEBUG message: space not found using algorithm 1, elapsed time: " .. tostring(minetest.get_us_time()-ttt1) .." us" -- !!debug + log("warning", "[mcl_portals] " .. msg1) -- !!debug + minetest.chat_send_all(msg1) -- !!debug + log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") + if pos.y < lava then + pos.y = lava + 1 else - if pos2.y == y_max then - pos1.y = math.max(y_min, pos2.y - PORTAL_SEARCH_ALTITUDE) + pos.y = pos.y + 1 + end + create_portal_2(pos, name, obj) +end + +local function ecb_scan_area_2(blockpos, action, calls_remaining, param) + if calls_remaining and calls_remaining > 0 then return end + local pos, pos1, pos2, name, obj = param.pos, param.pos1, param.pos2, param.name or "", param.obj + local pos0, distance + local lava = get_lava_level(pos, pos1, pos2) + + local ttt2 = minetest.get_us_time() -- !!debug + + local nodes = find_nodes_in_area_under_air(pos1, pos2, {"group:building_block"}) + if nodes then + local nc = #nodes + if nc > 0 then + log("action", "[mcl_portals] Area for destination Nether portal emerged! Found " .. tostring(nc) .. " nodes under the air around "..pos_to_string(pos)) + for i=1,nc do + local node = nodes[i] + local node1 = {x=node.x, y=node.y+1, z=node.z } + local node2 = {x=node.x+2, y=node.y+3, z=node.z+2} + local nodes2 = find_nodes_in_area(node1, node2, {"air"}) + if nodes2 then + local nc2 = #nodes2 + log("action", "[mcl_portals] nc2=" .. tostring(nc2)) + if nc2 == 27 and not is_area_protected(node, node2, name) then + local distance0 = dist(pos, node) + if distance0 < 2 then + local msg1 = "DEBUG message: space found using algorithm 2, elapsed time: " .. tostring(minetest.get_us_time()-ttt2) .." us" -- !!debug + log("warning", "[mcl_portals] " .. msg1) -- !!debug + minetest.chat_send_all(msg1) -- !!debug + log("action", "[mcl_portals] found space at pos "..pos_to_string(node).." - creating a portal") + create_portal_2(node1, name, obj) + return + end + if not distance or (distance0 < distance) or (distance0 < distance-1 and node.y > lava and pos0.y < lava) then + log("action", "[mcl_portals] found distance "..tostring(distance0).." at pos "..pos_to_string(node)) + distance = distance0 + pos0 = {x=node1.x, y=node1.y, z=node1.z} + end + end + end + end end end - minetest.emerge_area(pos1, pos2, ecb_setup_target_portal, {srcx=src_pos.x, srcy=src_pos.y, srcz=src_pos.z, dstx=x, dsty=y, dstz=z, srcdim=cdim, ax1=pos1.x, ay1=pos1.y, az1=pos1.z, ax2=pos2.x, ay2=pos2.y, az2=pos2.z}) + if distance then -- several nodes of air might be better than lava lake, right? + local msg1 = "DEBUG message: space partially found using algorithm 2, elapsed time: " .. tostring(minetest.get_us_time()-ttt2) .." us" -- !!debug + log("warning", "[mcl_portals] " .. msg1) -- !!debug + minetest.chat_send_all(msg1) -- !!debug + log("action", "[mcl_portals] using backup pos "..pos_to_string(pos0).." to create a portal") + create_portal_2(pos0, name, obj) + return + end + local msg1 = "DEBUG message: space not found using algorithm 2, elapsed time: " .. tostring(minetest.get_us_time()-ttt2) .." us" -- !!debug + log("warning", "[mcl_portals] " .. msg1) -- !!debug + minetest.chat_send_all(msg1) -- !!debug + log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") + if pos.y < lava then + pos.y = lava + 1 + else + pos.y = pos.y + 1 + end + create_portal_2(pos, name, obj) end -local function emerge_target_area(src_pos) - local x, y, z, cdim, y_min, y_max = nether_portal_get_target_position(src_pos) - local pos1 = {x = x - PORTAL_SEARCH_HALF_CHUNK, y = math.max(y_min + 2, math.floor(y - PORTAL_SEARCH_ALTITUDE / 2)), z = z - PORTAL_SEARCH_HALF_CHUNK} - local pos2 = {x = x + PORTAL_SEARCH_HALF_CHUNK, y = math.min(y_max - 2, math.ceil(y + PORTAL_SEARCH_ALTITUDE / 2)), z = z + PORTAL_SEARCH_HALF_CHUNK} - minetest.emerge_area(pos1, pos2) - pos1 = {x = x - 1, y = y_min, z = z - 1} - pos2 = {x = x + 1, y = y_max, z = z + 1} - minetest.emerge_area(pos1, pos2) +local function create_portal(pos, limit1, limit2, name, obj) + local cn = mcl_vars.get_chunk_number(pos) + if chunks[cn] then + local q = queue[cn] or {} + q[obj] = true + queue[cn] = q + return + end + chunks[cn] = true + + -- we need to emerge the area here, but currently (mt5.4/mcl20.71) map generation is slow + -- so we'll emerge single chunk only: 5x5x5 blocks, 80x80x80 nodes maximum + + local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes) + local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1) + + if limit1 and limit1.x and limit1.y and limit1.z then + pos1 = {x = max(min(limit1.x, pos.x), pos1.x), y = max(min(limit1.y, pos.y), pos1.y), z = max(min(limit1.z, pos.z), pos1.z)} + end + if limit2 and limit2.x and limit2.y and limit2.z then + pos2 = {x = min(max(limit2.x, pos.x), pos2.x), y = min(max(limit2.y, pos.y), pos2.y), z = min(max(limit2.z, pos.z), pos2.z)} + end + + if random(1,2) == 2 then + minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj}) + else + minetest.emerge_area(pos1, pos2, ecb_scan_area, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj}) + end end local function available_for_nether_portal(p) - local nn = minetest.get_node(p).name - local obsidian = nn == "mcl_core:obsidian" + local nn = mcl_portals.get_node(p).name + local obsidian = nn == OBSIDIAN if nn ~= "air" and minetest.get_item_group(nn, "fire") ~= 1 then return false, obsidian end return true, obsidian end -local function light_frame(x1, y1, z1, x2, y2, z2, build_frame) - local build_frame = build_frame or false - local orientation = 0 - if x1 == x2 then - orientation = 1 - end - local disperse = 50 - local pass = 1 - while true do - local protection = false - - for x = x1 - 1 + orientation, x2 + 1 - orientation do - for z = z1 - orientation, z2 + orientation do - for y = y1 - 1, y2 + 1 do - local frame = (x < x1) or (x > x2) or (y < y1) or (y > y2) or (z < z1) or (z > z2) - if frame then - if build_frame then - if pass == 1 then - if minetest.is_protected({x = x, y = y, z = z}, "") then - protection = true - local offset_x = math.random(-disperse, disperse) - local offset_z = math.random(-disperse, disperse) - disperse = disperse + math.random(25, 177) - if disperse > 5000 then - return nil - end - x1, z1 = x1 + offset_x, z1 + offset_z - x2, z2 = x2 + offset_x, z2 + offset_z - local _, dimension = mcl_worlds.y_to_layer(y1) - local height = math.abs(y2 - y1) - y1 = (y1 + y2) / 2 - if dimension == "nether" then - y1 = find_nether_target_y(math.min(x1, x2), y1, math.min(z1, z2)) - else - y1 = find_overworld_target_y(math.min(x1, x2), y1, math.min(z1, z2)) - end - y2 = y1 + height - break - end - else - minetest.set_node({x = x, y = y, z = z}, {name = "mcl_core:obsidian"}) - end - end - else - if not build_frame or pass == 2 then - local node = minetest.get_node({x = x, y = y, z = z}) - minetest.set_node({x = x, y = y, z = z}, {name = "mcl_portals:portal", param2 = orientation}) - end - end - if not frame and pass == 2 then - local meta = minetest.get_meta({x = x, y = y, z = z}) - -- Portal frame corners - meta:set_string("portal_frame1", minetest.pos_to_string({x = x1, y = y1, z = z1})) - meta:set_string("portal_frame2", minetest.pos_to_string({x = x2, y = y2, z = z2})) - -- Portal target coordinates - meta:set_string("portal_target", "") - -- Portal last teleportation time - meta:set_string("portal_time", tostring(0)) - end - end - if protection then - break - end - end - if protection then - break - end - end - if build_frame == false or pass == 2 then - break - end - if build_frame and not protection and pass == 1 then - pass = 2 - end - end - emerge_target_area({x = x1, y = y1, z = z1}) - return {x = x1, y = y1, z = z1} -end - ---Build arrival portal -function mcl_portals.build_nether_portal(pos, width, height, orientation) - local height = height or FRAME_SIZE_Y_MIN - 2 - local width = width or FRAME_SIZE_X_MIN - 2 - local orientation = orientation or math.random(0, 1) - - if orientation == 0 then - minetest.load_area({x = pos.x - 3, y = pos.y - 1, z = pos.z - width * 2}, {x = pos.x + width + 2, y = pos.y + height + 2, z = pos.z + width * 2}) - else - minetest.load_area({x = pos.x - width * 2, y = pos.y - 1, z = pos.z - 3}, {x = pos.x + width * 2, y = pos.y + height + 2, z = pos.z + width + 2}) - end - - pos = light_frame(pos.x, pos.y, pos.z, pos.x + (1 - orientation) * (width - 1), pos.y + height - 1, pos.z + orientation * (width - 1), true) - - -- Clear some space around: - for x = pos.x - math.random(2 + (width-2)*( orientation), 5 + (2*width-5)*( orientation)), pos.x + width*(1-orientation) + math.random(2+(width-2)*( orientation), 4 + (2*width-4)*( orientation)) do - for z = pos.z - math.random(2 + (width-2)*(1-orientation), 5 + (2*width-5)*(1-orientation)), pos.z + width*( orientation) + math.random(2+(width-2)*(1-orientation), 4 + (2*width-4)*(1-orientation)) do - for y = pos.y - 1, pos.y + height + math.random(1,6) do - local nn = minetest.get_node({x = x, y = y, z = z}).name - if nn ~= "mcl_core:obsidian" and nn ~= "mcl_portals:portal" and minetest.registered_nodes[nn].is_ground_content and not minetest.is_protected({x = x, y = y, z = z}, "") then - minetest.remove_node({x = x, y = y, z = z}) - end - end - end - end - - -- Build obsidian platform: - for x = pos.x - orientation, pos.x + orientation + (width - 1) * (1 - orientation), 1 + orientation do - for z = pos.z - 1 + orientation, pos.z + 1 - orientation + (width - 1) * orientation, 2 - orientation do - local pp = {x = x, y = pos.y - 1, z = z} - local nn = minetest.get_node(pp).name - if not minetest.registered_nodes[nn].is_ground_content and not minetest.is_protected(pp, "") then - minetest.set_node(pp, {name = "mcl_core:obsidian"}) - end - end - end - - minetest.log("action", "[mcl_portal] Destination Nether portal generated at "..minetest.pos_to_string(pos).."!") - - return pos -end - local function check_and_light_shape(pos, orientation) local stack = {{x = pos.x, y = pos.y, z = pos.z}} local node_list = {} + local index_list = {} local node_counter = 0 -- Search most low node from the left (pos1) and most right node from the top (pos2) local pos1 = {x = pos.x, y = pos.y, z = pos.z} local pos2 = {x = pos.x, y = pos.y, z = pos.z} - local wrong_portal_nodes_clean_up = function(node_list) - for i = 1, #node_list do - local meta = minetest.get_meta(node_list[i]) - meta:set_string("portal_time", "") - end - return false - end - + local kx, ky, kz = pos.x - 1999, pos.y - 1999, pos.z - 1999 while #stack > 0 do local i = #stack - local meta = minetest.get_meta(stack[i]) - local target = meta:get_string("portal_time") - if target and target == "-2" then + local x, y, z = stack[i].x, stack[i].y, stack[i].z + local k = (x-kx)*16000000 + (y-ky)*4000 + z-kz + if index_list[k] then stack[i] = nil -- Already checked, skip it else local good, obsidian = available_for_nether_portal(stack[i]) if obsidian then stack[i] = nil else - if (not good) or (node_counter >= PORTAL_NODES_MAX) then - return wrong_portal_nodes_clean_up(node_list) + if (not good) or (node_counter >= N_MAX) then + return false end - local x, y, z = stack[i].x, stack[i].y, stack[i].z - meta:set_string("portal_time", "-2") node_counter = node_counter + 1 node_list[node_counter] = {x = x, y = y, z = z} + index_list[k] = true stack[i].y = y - 1 stack[i + 1] = {x = x, y = y + 1, z = z} if orientation == 0 then @@ -563,24 +660,19 @@ local function check_and_light_shape(pos, orientation) end end - if node_counter < PORTAL_NODES_MIN then - return wrong_portal_nodes_clean_up(node_list) + if node_counter < N_MIN then + return false end -- Limit rectangles width and height - if math.abs(pos2.x - pos1.x + pos2.z - pos1.z) + 3 > FRAME_SIZE_X_MAX or math.abs(pos2.y - pos1.y) + 3 > FRAME_SIZE_Y_MAX then - return wrong_portal_nodes_clean_up(node_list) + if abs(pos2.x - pos1.x + pos2.z - pos1.z) + 3 > W_MAX or abs(pos2.y - pos1.y) + 3 > H_MAX then + return false end for i = 1, node_counter do local node_pos = node_list[i] - local node = minetest.get_node(node_pos) - minetest.set_node(node_pos, {name = "mcl_portals:portal", param2 = orientation}) - local meta = minetest.get_meta(node_pos) - meta:set_string("portal_frame1", minetest.pos_to_string(pos1)) - meta:set_string("portal_frame2", minetest.pos_to_string(pos2)) - meta:set_string("portal_time", tostring(0)) - meta:set_string("portal_target", "") + minetest.set_node(node_pos, {name = PORTAL, param2 = orientation}) + add_exit(node_pos) end return true end @@ -596,7 +688,7 @@ function mcl_portals.light_nether_portal(pos) if dim ~= "overworld" and dim ~= "nether" then return false end - local orientation = math.random(0, 1) + local orientation = random(0, 1) for orientation_iteration = 1, 2 do if check_and_light_shape(pos, orientation) then return true @@ -606,126 +698,50 @@ function mcl_portals.light_nether_portal(pos) return false end -local function update_portal_time(pos, time_str) - local stack = {{x = pos.x, y = pos.y, z = pos.z}} - while #stack > 0 do - local i = #stack - local meta = minetest.get_meta(stack[i]) - if meta:get_string("portal_time") == time_str then - stack[i] = nil -- Already updated, skip it - else - local node = minetest.get_node(stack[i]) - local portal = node.name == "mcl_portals:portal" - if not portal then - stack[i] = nil - else - local x, y, z = stack[i].x, stack[i].y, stack[i].z - meta:set_string("portal_time", time_str) - stack[i].y = y - 1 - stack[i + 1] = {x = x, y = y + 1, z = z} - if node.param2 == 0 then - stack[i + 2] = {x = x - 1, y = y, z = z} - stack[i + 3] = {x = x + 1, y = y, z = z} - else - stack[i + 2] = {x = x, y = y, z = z - 1} - stack[i + 3] = {x = x, y = y, z = z + 1} - end - end - end - end -end - -local function prepare_target(pos) - local meta, us_time = minetest.get_meta(pos), minetest.get_us_time() - local portal_time = tonumber(meta:get_string("portal_time")) or 0 - local delta_time_us = us_time - portal_time - local pos1, pos2 = minetest.string_to_pos(meta:get_string("portal_frame1")), minetest.string_to_pos(meta:get_string("portal_frame2")) - if delta_time_us <= DESTINATION_EXPIRES then - -- Destination point must be still cached according to https://minecraft.gamepedia.com/Nether_portal - return update_portal_time(pos, tostring(us_time)) - end - -- No cached destination point - find_or_create_portal(pos) -end - --- Teleportation cooloff for some seconds, to prevent back-and-forth teleportation -local function stop_teleport_cooloff(o) - mcl_portals.nether_portal_cooloff[o] = false - touch_chatter_prevention[o] = nil -end - -local function teleport_cooloff(obj) - if obj:is_player() then - minetest.after(TELEPORT_COOLOFF, stop_teleport_cooloff, obj) - else - minetest.after(MOB_TELEPORT_COOLOFF, stop_teleport_cooloff, obj) - end -end - -- Teleport function local function teleport_no_delay(obj, pos) local is_player = obj:is_player() - if (not obj:get_luaentity()) and (not is_player) then - return - end + if (not is_player and not obj:get_luaentity()) or cooloff[obj] then return end local objpos = obj:get_pos() - if objpos == nil then - return - end + if not objpos then return end - if mcl_portals.nether_portal_cooloff[obj] then - return - end - -- If player stands, player is at ca. something+0.5 - -- which might cause precision problems, so we used ceil. - objpos.y = math.ceil(objpos.y) + -- If player stands, player is at ca. something+0.5 which might cause precision problems, so we used ceil for objpos.y + objpos = {x = floor(objpos.x+0.5), y = ceil(objpos.y), z = floor(objpos.z+0.5)} + if mcl_portals.get_node(objpos).name ~= PORTAL then return end - if minetest.get_node(objpos).name ~= "mcl_portals:portal" then - return - end - - local meta = minetest.get_meta(pos) - local delta_time = minetest.get_us_time() - (tonumber(meta:get_string("portal_time")) or 0) - local target = minetest.string_to_pos(meta:get_string("portal_target")) - if delta_time > DESTINATION_EXPIRES or target == nil then - -- Area not ready yet - retry after a second - return minetest.after(1, teleport_no_delay, obj, pos) - end - - -- Enable teleportation cooloff for some seconds, to prevent back-and-forth teleportation - teleport_cooloff(obj) - mcl_portals.nether_portal_cooloff[obj] = true - - -- Teleport - obj:set_pos(target) + local target, dim = get_target(objpos) + if not target then return end + local name if is_player then - mcl_worlds.dimension_change(obj, mcl_worlds.pos_to_dimension(target)) - minetest.sound_play("mcl_portals_teleport", {pos=target, gain=0.5, max_hear_distance = 16}, true) - local name = obj:get_player_name() - minetest.log("action", "[mcl_portal] "..name.." teleported to Nether portal at "..minetest.pos_to_string(target)..".") + name = obj:get_player_name() + end + + local exit = find_exit(target) + if exit then + finalize_teleport(obj, exit) + else + -- need to create arrival portal + create_portal(target, limits[dim].pmin, limits[dim].pmax, name, obj) end end local function prevent_portal_chatter(obj) - local time_us = minetest.get_us_time() - local chatter = touch_chatter_prevention[obj] or 0 - touch_chatter_prevention[obj] = time_us + local time_us = get_us_time() + local ch = chatter[obj] or 0 + chatter[obj] = time_us minetest.after(TOUCH_CHATTER_TIME, function(o) - if not o or not touch_chatter_prevention[o] then - return - end - if minetest.get_us_time() - touch_chatter_prevention[o] >= TOUCH_CHATTER_TIME_US then - touch_chatter_prevention[o] = nil + if o and chatter[o] and get_us_time() - chatter[o] >= CHATTER_US then + chatter[o] = nil end end, obj) - return time_us - chatter > TOUCH_CHATTER_TIME_US + return time_us - ch > CHATTER_US end local function animation(player, playername) - local chatter = touch_chatter_prevention[player] or 0 - if mcl_portals.nether_portal_cooloff[player] or minetest.get_us_time() - chatter < TOUCH_CHATTER_TIME_US then + local ch = chatter[player] or 0 + if cooloff[player] or get_us_time() - ch < CHATTER_US then local pos = player:get_pos() if not pos then return @@ -756,36 +772,35 @@ local function teleport(obj, portal_pos) name = obj:get_player_name() animation(obj, name) end - -- Call prepare_target() first because it might take a long - prepare_target(portal_pos) - -- Prevent quick back-and-forth teleportation - if not mcl_portals.nether_portal_cooloff[obj] then - local creative_enabled = minetest.is_creative_enabled(name) - if creative_enabled then - return teleport_no_delay(obj, portal_pos) - end - minetest.after(TELEPORT_DELAY, teleport_no_delay, obj, portal_pos) + + if cooloff[obj] then return end + + if minetest.is_creative_enabled(name) then + teleport_no_delay(obj, portal_pos) + return end + + minetest.after(DELAY, teleport_no_delay, obj, portal_pos) end minetest.register_abm({ label = "Nether portal teleportation and particles", - nodenames = {"mcl_portals:portal"}, + nodenames = {PORTAL}, interval = 1, chance = 1, action = function(pos, node) local o = node.param2 -- orientation - local d = math.random(0, 1) -- direction - local time = math.random() * 1.9 + 0.5 + local d = random(0, 1) -- direction + local time = random() * 1.9 + 0.5 local velocity, acceleration if o == 1 then - velocity = {x = math.random() * 0.7 + 0.3, y = math.random() - 0.5, z = math.random() - 0.5} - acceleration = {x = math.random() * 1.1 + 0.3, y = math.random() - 0.5, z = math.random() - 0.5} + velocity = {x = random() * 0.7 + 0.3, y = random() - 0.5, z = random() - 0.5} + acceleration = {x = random() * 1.1 + 0.3, y = random() - 0.5, z = random() - 0.5} else - velocity = {x = math.random() - 0.5, y = math.random() - 0.5, z = math.random() * 0.7 + 0.3} - acceleration = {x = math.random() - 0.5, y = math.random() - 0.5, z = math.random() * 1.1 + 0.3} + velocity = {x = random() - 0.5, y = random() - 0.5, z = random() * 0.7 + 0.3} + acceleration = {x = random() - 0.5, y = random() - 0.5, z = random() * 1.1 + 0.3} end - local distance = vector.add(vector.multiply(velocity, time), vector.multiply(acceleration, time * time / 2)) + local distance = add(mul(velocity, time), mul(acceleration, time * time / 2)) if d == 1 then if o == 1 then distance.x = -distance.x @@ -797,11 +812,11 @@ minetest.register_abm({ acceleration.z = -acceleration.z end end - distance = vector.subtract(pos, distance) + distance = sub(pos, distance) for _, obj in pairs(minetest.get_objects_inside_radius(pos, 15)) do if obj:is_player() then minetest.add_particlespawner({ - amount = node_particles_allowed_level + 1, + amount = PARTICLES + 1, minpos = distance, maxpos = distance, minvel = velocity, @@ -830,14 +845,14 @@ minetest.register_abm({ --[[ ITEM OVERRIDES ]] -local longdesc = minetest.registered_nodes["mcl_core:obsidian"]._doc_items_longdesc +local longdesc = registered_nodes[OBSIDIAN]._doc_items_longdesc longdesc = longdesc .. "\n" .. S("Obsidian is also used as the frame of Nether portals.") local usagehelp = S("To open a Nether portal, place an upright frame of obsidian with a width of at least 4 blocks and a height of 5 blocks, leaving only air in the center. After placing this frame, light a fire in the obsidian frame. Nether portals only work in the Overworld and the Nether.") -minetest.override_item("mcl_core:obsidian", { +minetest.override_item(OBSIDIAN, { _doc_items_longdesc = longdesc, _doc_items_usagehelp = usagehelp, - on_destruct = destroy_nether_portal, + after_destruct = destroy_nether_portal, _on_ignite = function(user, pointed_thing) local x, y, z = pointed_thing.under.x, pointed_thing.under.y, pointed_thing.under.z -- Check empty spaces around obsidian and light all frames found: @@ -846,9 +861,9 @@ minetest.override_item("mcl_core:obsidian", { mcl_portals.light_nether_portal({x = x, y = y - 1, z = z}) or mcl_portals.light_nether_portal({x = x, y = y + 1, z = z}) or mcl_portals.light_nether_portal({x = x, y = y, z = z - 1}) or mcl_portals.light_nether_portal({x = x, y = y, z = z + 1}) if portals_placed then - minetest.log("action", "[mcl_portal] Nether portal activated at "..minetest.pos_to_string({x=x,y=y,z=z})..".") + log("action", "[mcl_portals] Nether portal activated at "..pos_to_string({x=x,y=y,z=z})..".") if minetest.get_modpath("doc") then - doc.mark_entry_as_revealed(user:get_player_name(), "nodes", "mcl_portals:portal") + doc.mark_entry_as_revealed(user:get_player_name(), "nodes", PORTAL) -- Achievement for finishing a Nether portal TO the Nether local dim = mcl_worlds.pos_to_dimension({x=x, y=y, z=z}) diff --git a/mods/MAPGEN/mcl_mapgen_core/init.lua b/mods/MAPGEN/mcl_mapgen_core/init.lua index 2986664f6..496b2e222 100644 --- a/mods/MAPGEN/mcl_mapgen_core/init.lua +++ b/mods/MAPGEN/mcl_mapgen_core/init.lua @@ -29,7 +29,7 @@ local function add_chunk(pos) end prev = d end - chunks[#chunks] = {n, n} + chunks[#chunks+1] = {n, n} end function mcl_mapgen_core.is_generated(pos) local n = mcl_vars.get_chunk_number(pos) -- unsigned int @@ -1790,6 +1790,8 @@ local generate_nether_decorations = function(minp, maxp, seed) return end + minetest.log("action", "[mcl_mapgen_core] Nether decorations " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp)) + -- TODO: Generate everything based on Perlin noise instead of PseudoRandom local bpos @@ -1847,6 +1849,7 @@ local generate_nether_decorations = function(minp, maxp, seed) end minetest.register_on_generated(function(minp, maxp, blockseed) + minetest.log("action", "[mcl_mapgen_core] Generating chunk " .. minetest.pos_to_string(minp) .. " ... " .. minetest.pos_to_string(maxp)) add_chunk(minp) local p1, p2 = {x=minp.x, y=minp.y, z=minp.z}, {x=maxp.x, y=maxp.y, z=maxp.z} if lvm > 0 then @@ -2132,24 +2135,32 @@ local function basic(vm, data, data2, emin, emax, area, minp, maxp, blockseed) -- * Replace water with Nether lava. -- * Replace stone, sand dirt in v6 so the Nether works in v6. elseif minp.y <= mcl_vars.mg_nether_max and maxp.y >= mcl_vars.mg_nether_min then - local nodes if mg_name == "v6" then - nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"}) - else - nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source"}) - end - for n=1, #nodes do - local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z) - if data[p_pos] == c_water then - data[p_pos] = c_nether_lava - lvm_used = true - elseif data[p_pos] == c_stone then - data[p_pos] = c_netherrack - lvm_used = true - elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then - data[p_pos] = c_soul_sand - lvm_used = true + local nodes = minetest.find_nodes_in_area(minp, maxp, {"mcl_core:water_source", "mcl_core:stone", "mcl_core:sand", "mcl_core:dirt"}) + for n=1, #nodes do + local p_pos = area:index(nodes[n].x, nodes[n].y, nodes[n].z) + if data[p_pos] == c_water then + data[p_pos] = c_nether_lava + lvm_used = true + elseif data[p_pos] == c_stone then + data[p_pos] = c_netherrack + lvm_used = true + elseif data[p_pos] == c_sand or data[p_pos] == c_dirt then + data[p_pos] = c_soul_sand + lvm_used = true + end end + else + minetest.emerge_area(minp, maxp, function(blockpos, action, calls_remaining, param) + if calls_remaining > 0 then return end + -- local nodes = minetest.find_nodes_in_area(param.minp, param.maxp, {"mcl_core:water_source"}) + local nodes = minetest.find_nodes_in_area(param.minp, param.maxp, {"group:water"}) + local sn=(mcl_observers and mcl_observers.swap_node) or minetest.swap_node + local l = {name="mcl_nether:nether_lava_source"} + for _, n in pairs(nodes) do + sn(n, l) + end + end, {minp=vector.new(minp), maxp=vector.new(maxp)}) end -- End block fixes: diff --git a/mods/MAPGEN/mcl_structures/init.lua b/mods/MAPGEN/mcl_structures/init.lua index 96c620c99..0d6bc62ab 100644 --- a/mods/MAPGEN/mcl_structures/init.lua +++ b/mods/MAPGEN/mcl_structures/init.lua @@ -534,7 +534,7 @@ end -- Debug command minetest.register_chatcommand("spawnstruct", { - params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | dungeon", + params = "desert_temple | desert_well | igloo | witch_hut | boulder | ice_spike_small | ice_spike_large | fossil | end_exit_portal | end_portal_shrine | nether_portal | dungeon", description = S("Generate a pre-defined structure near your position."), privs = {debug = true}, func = function(name, param) @@ -570,6 +570,8 @@ minetest.register_chatcommand("spawnstruct", { mcl_structures.generate_end_portal_shrine(pos, rot, pr) elseif param == "dungeon" and mcl_dungeons and mcl_dungeons.spawn_dungeon then mcl_dungeons.spawn_dungeon(pos, rot, pr) + elseif param == "nether_portal" and mcl_portals and mcl_portals.spawn_nether_portal then + mcl_portals.spawn_nether_portal(pos, rot, pr, name) elseif param == "" then message = S("Error: No structure type given. Please use “/spawnstruct ”.") errord = true From 01df02667baa64f4b8c6e1870d564d41bd37723e Mon Sep 17 00:00:00 2001 From: epCode Date: Sun, 21 Mar 2021 17:53:57 -0700 Subject: [PATCH 21/58] Make setting for swim on lava --- mods/ENTITIES/mcl_mobs/api.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index 93b7bc146..f8881d741 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -2856,6 +2856,18 @@ local falling = function(self, pos) self.object:set_acceleration({x = 0, y = 0, z = 0}) end + if minetest.registered_nodes[node_ok(pos).name].groups.lava then + + if self.floats_on_lava == 1 then + + self.object:set_acceleration({ + x = 0, + y = -self.fall_speed / (max(1, v.y) ^ 2), + z = 0 + }) + end + end + -- in water then float up if minetest.registered_nodes[node_ok(pos).name].groups.water then @@ -3773,6 +3785,7 @@ minetest.register_entity(name, { knock_back = def.knock_back ~= false, shoot_offset = def.shoot_offset or 0, floats = def.floats or 1, -- floats in water by default + floats_on_lava = def.floats_on_lava or 0, replace_rate = def.replace_rate, replace_what = def.replace_what, replace_with = def.replace_with, From 7fe3217cd060557b14160c64e2691ac075161d7d Mon Sep 17 00:00:00 2001 From: kay27 Date: Mon, 22 Mar 2021 11:32:28 +0400 Subject: [PATCH 22/58] [mcl_portals] Remove debug messages --- mods/ITEMS/mcl_portals/portal_nether.lua | 101 +---------------------- 1 file changed, 1 insertion(+), 100 deletions(-) diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index c63c78384..f67980bbf 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -324,10 +324,8 @@ function build_nether_portal(pos, width, height, orientation, name) local pp_1 = {x = x, y = pos.y - 2, z = z} local nn = get_node(pp).name local nn_1 = get_node(pp_1).name - log("warning", "[mcl_portals] pos=" .. pos_to_string(pp) .. " nn=" .. nn .. " name=" .. name .. " width=" .. tostring(width) .. " height=" .. tostring(height).." orientation=" ..tostring(orientation).." gc="..tostring(registered_nodes[nn].is_ground_content) .." for obsidian platform:") if ((nn=="air" and nn_1 == "air") or not registered_nodes[nn].is_ground_content) and not is_protected(pp, name) then set_node(pp, {name = OBSIDIAN}) - minetest.log("warning", "set!") end end end @@ -432,96 +430,12 @@ local function get_lava_level(pos, pos1, pos2) return max(min(mcl_vars.mg_lava_nether_max, pos2.y-1), pos1.y+1) end -local function ecb_scan_area(blockpos, action, calls_remaining, param) - if calls_remaining and calls_remaining > 0 then return end - local pos, pos1, pos2, name, obj = param.pos, param.pos1, param.pos2, param.name or "", param.obj - local lava = get_lava_level(pos, pos1, pos2) - - local ttt1 = minetest.get_us_time() -- !!debug - -- loop in a spiral around pos - local cs, x, z, dx, dz, p0x, p0z, p1x, p1y, p1z, p2x, p2y, p2z = mcl_vars.chunk_size_in_nodes, 0, 0, 0, -1, pos.x, pos.z, pos1.x, pos1.y, pos1.z, pos2.x, pos2.y, pos2.z - - local i_max = (cs*2-1) * (cs*2-1) - log("action", "[mcl_portals] Area for destination Nether portal emerged! We about to iterate " .. tostring(i_max) .. " positions of spiral around "..pos_to_string(pos)) - - local backup_pos, bnc = nil, 0 -- 'better than nothing' - - local p1 = {x=0, y=p1y, z=0} - local p2 = {x=0, y=p2y, z=0} - for i = 1, i_max do - local px, pz = p0x + x, p0z + z - if ((i%100) == 1) then - log("action", "[mcl_portals] i=" ..tostring(i) .." px=" .. tostring(px) .." pz=" .. tostring(pz) .. " x:"..tostring(p1x) .."-"..tostring(p2x) .. " z:"..tostring(p1z) .."-"..tostring(p2z)) - end - if px >= p1x and pz >= p1z and px <= p2x and pz <= p2z then - p1.x, p2.x, p1.z, p2.z = px, px, pz, pz - local nodes = find_nodes_in_area_under_air(p1, p2, {"group:building_block"}) - log("action", "[mcl_portals] check " .. pos_to_string(p1) .. "-" .. pos_to_string(p2) .. ": " .. tostring(nodes and #nodes)) - if nodes and #nodes > 0 then - for j = 1, #nodes do - local node = nodes[j] - if not is_protected(node, name) then - node.y = node.y + 2 - local node2 = {x = node.x, y = node.y + 2, z = node.z} - if not is_protected(node2, name) then - local nodes_j = find_nodes_in_area(node, node2, {"air"}) - local nc = #nodes_j - if nc >= 3 then - node2.x = node2.x + 2 - node2.z = node2.z + 2 - nodes_j = find_nodes_in_area(node, node2, {"air"}) - if #nodes_j == 36 then - local msg1 = "DEBUG message: space found using algorithm 1, elapsed time: " .. tostring(minetest.get_us_time()-ttt1) .." us" -- !!debug - log("warning", "[mcl_portals] " .. msg1) -- !!debug - minetest.chat_send_all(msg1) -- !!debug - log("action", "[mcl_portals] found space at pos "..pos_to_string(node).." - creating a portal") - create_portal_2({x=node.x, y=node.y+1, z=node.z}, name, obj) - return - end - elseif nc > bnc or ((nc > max(bnc-2,0)) and backup_pos.y lava) then - bnc = nc - backup_pos = {x = node2.x, y = node2.y, z = node2.z} - log("action", "[mcl_portals] set backup pos "..pos_to_string(backup_pos).." with "..tostring(nc).." air node(s)") - end - end - end - end - end - end - if x == z or (x < 0 and x == -z) or (x > 0 and x == 1-z) then - dx, dz = -dz, dx - end - x, z = x+dx, z+dz - px, pz = p0x + x, p0z + z - end - if backup_pos then -- several nodes of air might be better than lava lake, right? - local msg1 = "DEBUG message: space partially found using algorithm 1, elapsed time: " .. tostring(minetest.get_us_time()-ttt1) .." us" -- !!debug - log("warning", "[mcl_portals] " .. msg1) -- !!debug - minetest.chat_send_all(msg1) -- !!debug - log("action", "[mcl_portals] using backup pos "..pos_to_string(backup_pos).." to create a portal") - create_portal_2(backup_pos, name, obj) - return - end - local msg1 = "DEBUG message: space not found using algorithm 1, elapsed time: " .. tostring(minetest.get_us_time()-ttt1) .." us" -- !!debug - log("warning", "[mcl_portals] " .. msg1) -- !!debug - minetest.chat_send_all(msg1) -- !!debug - log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") - if pos.y < lava then - pos.y = lava + 1 - else - pos.y = pos.y + 1 - end - create_portal_2(pos, name, obj) -end - local function ecb_scan_area_2(blockpos, action, calls_remaining, param) if calls_remaining and calls_remaining > 0 then return end local pos, pos1, pos2, name, obj = param.pos, param.pos1, param.pos2, param.name or "", param.obj local pos0, distance local lava = get_lava_level(pos, pos1, pos2) - local ttt2 = minetest.get_us_time() -- !!debug - local nodes = find_nodes_in_area_under_air(pos1, pos2, {"group:building_block"}) if nodes then local nc = #nodes @@ -538,9 +452,6 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param) if nc2 == 27 and not is_area_protected(node, node2, name) then local distance0 = dist(pos, node) if distance0 < 2 then - local msg1 = "DEBUG message: space found using algorithm 2, elapsed time: " .. tostring(minetest.get_us_time()-ttt2) .." us" -- !!debug - log("warning", "[mcl_portals] " .. msg1) -- !!debug - minetest.chat_send_all(msg1) -- !!debug log("action", "[mcl_portals] found space at pos "..pos_to_string(node).." - creating a portal") create_portal_2(node1, name, obj) return @@ -556,16 +467,10 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param) end end if distance then -- several nodes of air might be better than lava lake, right? - local msg1 = "DEBUG message: space partially found using algorithm 2, elapsed time: " .. tostring(minetest.get_us_time()-ttt2) .." us" -- !!debug - log("warning", "[mcl_portals] " .. msg1) -- !!debug - minetest.chat_send_all(msg1) -- !!debug log("action", "[mcl_portals] using backup pos "..pos_to_string(pos0).." to create a portal") create_portal_2(pos0, name, obj) return end - local msg1 = "DEBUG message: space not found using algorithm 2, elapsed time: " .. tostring(minetest.get_us_time()-ttt2) .." us" -- !!debug - log("warning", "[mcl_portals] " .. msg1) -- !!debug - minetest.chat_send_all(msg1) -- !!debug log("action", "[mcl_portals] found no space, reverting to target pos "..pos_to_string(pos).." - creating a portal") if pos.y < lava then pos.y = lava + 1 @@ -598,11 +503,7 @@ local function create_portal(pos, limit1, limit2, name, obj) pos2 = {x = min(max(limit2.x, pos.x), pos2.x), y = min(max(limit2.y, pos.y), pos2.y), z = min(max(limit2.z, pos.z), pos2.z)} end - if random(1,2) == 2 then - minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj}) - else - minetest.emerge_area(pos1, pos2, ecb_scan_area, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj}) - end + minetest.emerge_area(pos1, pos2, ecb_scan_area_2, {pos = vector.new(pos), pos1 = pos1, pos2 = pos2, name=name, obj=obj}) end local function available_for_nether_portal(p) From 66a64439c6cfd3431c97b87bd66849d67338274e Mon Sep 17 00:00:00 2001 From: kay27 Date: Mon, 22 Mar 2021 17:31:24 +0400 Subject: [PATCH 23/58] [mcl_weather] Fix crash on saving uninitialized data, https://git.minetest.land/MineClone2/MineClone2/issues/1361 --- mods/ENVIRONMENT/mcl_weather/weather_core.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/mods/ENVIRONMENT/mcl_weather/weather_core.lua b/mods/ENVIRONMENT/mcl_weather/weather_core.lua index 365f6e549..d3772dc7e 100644 --- a/mods/ENVIRONMENT/mcl_weather/weather_core.lua +++ b/mods/ENVIRONMENT/mcl_weather/weather_core.lua @@ -38,6 +38,7 @@ mcl_weather.reg_weathers["none"] = { local storage = minetest.get_mod_storage() -- Save weather into mod storage, so it can be loaded after restarting the server local save_weather = function() + if not mcl_weather.end_time then return end storage:set_string("mcl_weather_state", mcl_weather.state) storage:set_int("mcl_weather_end_time", mcl_weather.end_time) minetest.log("verbose", "[mcl_weather] Weather data saved: state="..mcl_weather.state.." end_time="..mcl_weather.end_time) From 910c9083e530a43bd0ab2ebcdb0323a9df922421 Mon Sep 17 00:00:00 2001 From: ArTee3 Date: Mon, 22 Mar 2021 21:55:57 +0100 Subject: [PATCH 24/58] Fix player speed on soul sand, https://git.minetest.land/MineClone2/MineClone2/issues/1356 --- mods/PLAYER/mcl_playerplus/init.lua | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index 7122cc894..767b275e4 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -252,13 +252,7 @@ minetest.register_globalstep(function(dtime) playerphysics.add_physics_factor(player, "speed", "mcl_playerplus:surface", 0.4) end end - else - -- Reset speed decrease - playerphysics.remove_physics_factor(player, "speed", "mcl_playerplus:surface") - end - - -- Swimming? Check if boots are enchanted with depth strider - if get_item_group(node_feet, "liquid") ~= 0 and mcl_enchanting.get_enchantment(player:get_inventory():get_stack("armor", 5), "depth_strider") then + elseif get_item_group(node_feet, "liquid") ~= 0 and mcl_enchanting.get_enchantment(player:get_inventory():get_stack("armor", 5), "depth_strider") then local boots = player:get_inventory():get_stack("armor", 5) local depth_strider = mcl_enchanting.get_enchantment(boots, "depth_strider") From 44c4999b3706ec2efb836b94046ec1b07860684d Mon Sep 17 00:00:00 2001 From: Blue Blancmange <> Date: Mon, 22 Mar 2021 21:50:14 +0000 Subject: [PATCH 25/58] Move item renaming to tt. This allows additional information such as enchantments to be displayed on named items --- mods/HELP/tt/init.lua | 6 +++++- mods/ITEMS/mcl_anvils/init.lua | 11 ++--------- 2 files changed, 7 insertions(+), 10 deletions(-) diff --git a/mods/HELP/tt/init.lua b/mods/HELP/tt/init.lua index f23778b6c..88dbc7165 100644 --- a/mods/HELP/tt/init.lua +++ b/mods/HELP/tt/init.lua @@ -2,6 +2,7 @@ tt = {} tt.COLOR_DEFAULT = "#d0ffd0" tt.COLOR_DANGER = "#ffff00" tt.COLOR_GOOD = "#00ff00" +tt.NAME_COLOR = "#FFFF4C" -- API tt.registered_snippets = {} @@ -63,12 +64,15 @@ tt.reload_itemstack_description = function(itemstack) local meta = itemstack:get_meta() if def and def._mcl_generate_description then def._mcl_generate_description(itemstack) - elseif should_change(itemstring, def) and meta:get_string("name") == "" then + elseif should_change(itemstring, def) then local toolcaps if def.tool_capabilities then toolcaps = itemstack:get_tool_capabilities() end local orig_desc = def._tt_original_description or def.description + if meta:get_string("name") ~= "" then + orig_desc = minetest.colorize(tt.NAME_COLOR, meta:get_string("name")) + end local desc = apply_snippets(orig_desc, itemstring, toolcaps or def.tool_capabilities, itemstack) if desc ~= orig_desc then meta:set_string("description", desc) diff --git a/mods/ITEMS/mcl_anvils/init.lua b/mods/ITEMS/mcl_anvils/init.lua index 91f4eaa80..9e2f4b7fe 100644 --- a/mods/ITEMS/mcl_anvils/init.lua +++ b/mods/ITEMS/mcl_anvils/init.lua @@ -9,7 +9,6 @@ local MATERIAL_TOOL_REPAIR_BOOST = { math.ceil(MAX_WEAR * 0.75), -- 75% MAX_WEAR, -- 100% } -local NAME_COLOR = "#FFFF4C" local function get_anvil_formspec(set_name) if not set_name then @@ -172,14 +171,8 @@ local function update_anvil_slots(meta) if new_name ~= old_name then -- Save the raw name internally meta:set_string("name", new_name) - -- Rename item - if new_name == "" then - tt.reload_itemstack_description(name_item) - else - -- Custom name set. Colorize it! - -- This makes the name visually different from unnamed items - meta:set_string("description", minetest.colorize(NAME_COLOR, new_name)) - end + -- Rename item handled by tt + tt.reload_itemstack_description(name_item) new_output = name_item elseif just_rename then new_output = "" From 06280e3bba47729ae52c915351d303ce6fbb7bee Mon Sep 17 00:00:00 2001 From: kay27 Date: Tue, 23 Mar 2021 03:17:23 +0400 Subject: [PATCH 26/58] [mcl_portals] Generate target map chunks on portal creation --- mods/ITEMS/mcl_portals/portal_nether.lua | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index f67980bbf..862965bbb 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -592,6 +592,11 @@ function mcl_portals.light_nether_portal(pos) local orientation = random(0, 1) for orientation_iteration = 1, 2 do if check_and_light_shape(pos, orientation) then + minetest.after(0.2, function(pos) -- generate target map chunk + local pos1 = add(mul(mcl_vars.pos_to_chunk(pos), mcl_vars.chunk_size_in_nodes), mcl_vars.central_chunk_offset_in_nodes) + local pos2 = add(pos1, mcl_vars.chunk_size_in_nodes - 1) + minetest.emerge_area(pos1, pos2) + end, vector.new(pos)) return true end orientation = 1 - orientation From 3e58e989a17546847410b97007f735ee4a361c02 Mon Sep 17 00:00:00 2001 From: kay27 Date: Tue, 23 Mar 2021 03:19:17 +0400 Subject: [PATCH 27/58] [mcl_portals] Support Nether portals from 0.71 and earlier --- mods/ITEMS/mcl_portals/portal_nether.lua | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/mods/ITEMS/mcl_portals/portal_nether.lua b/mods/ITEMS/mcl_portals/portal_nether.lua index 862965bbb..29368af30 100644 --- a/mods/ITEMS/mcl_portals/portal_nether.lua +++ b/mods/ITEMS/mcl_portals/portal_nether.lua @@ -436,6 +436,21 @@ local function ecb_scan_area_2(blockpos, action, calls_remaining, param) local pos0, distance local lava = get_lava_level(pos, pos1, pos2) + -- THIS IS A TEMPORATY CODE SECTION FOR COMPATIBILITY REASONS -- + local portals = find_nodes_in_area(pos1, pos2, {PORTAL}) + if portals and #portals>0 then + for _, p in pairs(portals) do + add_exit(p) + end + local exit = find_exit(pos) + if exit then + finalize_teleport(obj, exit) + end + return + end + -- TEMPORATY CODE SECTION ENDS HERE -- + + local nodes = find_nodes_in_area_under_air(pos1, pos2, {"group:building_block"}) if nodes then local nc = #nodes From 0d7c2c49883a45133541da91f29f4bfee0ea78da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Elias=20=C3=85str=C3=B6m?= Date: Tue, 23 Mar 2021 12:02:00 +0100 Subject: [PATCH 28/58] Fix #1358 for real --- mods/CORE/_mcl_autogroup/init.lua | 5 ++++- mods/ITEMS/mcl_enchanting/groupcaps.lua | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/mods/CORE/_mcl_autogroup/init.lua b/mods/CORE/_mcl_autogroup/init.lua index 75ed4ce2b..c8475d0bd 100644 --- a/mods/CORE/_mcl_autogroup/init.lua +++ b/mods/CORE/_mcl_autogroup/init.lua @@ -178,6 +178,10 @@ end -- Add the groupcaps from a field in "_mcl_diggroups" to the groupcaps of a -- tool. local function add_groupcaps(toolname, groupcaps, groupcaps_def, efficiency) + if not groupcaps_def then + return + end + for g, capsdef in pairs(groupcaps_def) do local mult = capsdef.speed or 1 local uses = capsdef.uses @@ -196,7 +200,6 @@ local function add_groupcaps(toolname, groupcaps, groupcaps_def, efficiency) groupcaps[g .. "_dig"] = get_groupcap(g, level > 0, mult, efficiency, uses) end end - return groupcaps end -- Checks if the given node would drop its useful drop if dug by a given tool. diff --git a/mods/ITEMS/mcl_enchanting/groupcaps.lua b/mods/ITEMS/mcl_enchanting/groupcaps.lua index 216457d05..375029547 100644 --- a/mods/ITEMS/mcl_enchanting/groupcaps.lua +++ b/mods/ITEMS/mcl_enchanting/groupcaps.lua @@ -45,7 +45,7 @@ end -- To make it more efficient it will first check a hash value to determine if -- the tool needs to be updated. function mcl_enchanting.update_groupcaps(itemstack) - if not itemstack:get_tool_capabilities() then + if not itemstack:get_meta():get("tool_capabilities") then return end From fe937665f93d027f4daf7f6b0fc45629ed5f466b Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 24 Mar 2021 08:27:31 +0100 Subject: [PATCH 29/58] Fix #1336 --- mods/ENTITIES/mcl_burning/api.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_burning/api.lua b/mods/ENTITIES/mcl_burning/api.lua index 4eac333a2..b08a0fb70 100644 --- a/mods/ENTITIES/mcl_burning/api.lua +++ b/mods/ENTITIES/mcl_burning/api.lua @@ -167,7 +167,7 @@ function mcl_burning.set_on_fire(obj, burn_time, reason) hud_elem_type = "image", position = {x = 0.5, y = 0.5}, scale = {x = -100, y = -100}, - text = "mcl_burning_hud_flame_animated.png", + text = "mcl_burning_entity_flame_animated.png^[opacity:180^[verticalframe:" .. mcl_burning.animation_frames .. ":" .. 1, z_index = 1000, }) + 1 end From a47eda44e98627cab07f4ee69a043e45fbb0b388 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 24 Mar 2021 08:54:23 +0100 Subject: [PATCH 30/58] Slimes can burn --- mods/ENTITIES/mobs_mc/slime+magma_cube.lua | 1 - 1 file changed, 1 deletion(-) diff --git a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua index 54269b46e..7c21fb812 100644 --- a/mods/ENTITIES/mobs_mc/slime+magma_cube.lua +++ b/mods/ENTITIES/mobs_mc/slime+magma_cube.lua @@ -109,7 +109,6 @@ local slime_big = { fear_height = 0, spawn_small_alternative = "mobs_mc:slime_small", on_die = spawn_children_on_die("mobs_mc:slime_small", 4, 1.0, 1.5), - fire_resistant = true, use_texture_alpha = true, } mobs:register_mob("mobs_mc:slime_big", slime_big) From 43a60e0c57204b71fe0a2ee6ca00bcfe8635c9b6 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Wed, 24 Mar 2021 09:00:31 +0100 Subject: [PATCH 31/58] Fix #1357 --- mods/ITEMS/mcl_enchanting/engine.lua | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_enchanting/engine.lua b/mods/ITEMS/mcl_enchanting/engine.lua index 83149862a..ce6e3543a 100644 --- a/mods/ITEMS/mcl_enchanting/engine.lua +++ b/mods/ITEMS/mcl_enchanting/engine.lua @@ -582,7 +582,12 @@ function mcl_enchanting.allow_inventory_action(player, action, inventory, invent local listname = inventory_info.to_list local stack = inventory:get_stack(inventory_info.from_list, inventory_info.from_index) if stack:get_name() == "mcl_dye:blue" and listname ~= "enchanting_item" then - return math.min(inventory:get_stack("enchanting_lapis", 1):get_free_space(), stack:get_count()) + local count = stack:get_count() + local old_stack = inventory:get_stack("enchanting_lapis", 1) + if old_stack:get_name() ~= "" then + count = math.min(count, old_stack:get_free_space()) + end + return count elseif inventory:get_stack("enchanting_item", 1):get_count() == 0 and listname ~= "enchanting_lapis" then return 1 else From 46c632843237165ada8453d5c076fe1278c530c9 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 25 Mar 2021 09:24:38 +0100 Subject: [PATCH 32/58] Something secret :P --- mods/ENTITIES/mcl_mobs/api.lua | 31 ++++++++++++++++++++++- mods/ENTITIES/mobs_mc/sheep.lua | 44 +++++++++++++++++++++++++++++++-- 2 files changed, 72 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mcl_mobs/api.lua b/mods/ENTITIES/mcl_mobs/api.lua index f8881d741..f1df87e8b 100644 --- a/mods/ENTITIES/mcl_mobs/api.lua +++ b/mods/ENTITIES/mcl_mobs/api.lua @@ -283,6 +283,33 @@ local get_velocity = function(self) return 0 end +local function update_roll(self) + local is_Fleckenstein = self.nametag == "Fleckenstein" + local was_Fleckenstein = false + + local rot = self.object:get_rotation() + rot.z = is_Fleckenstein and pi or 0 + self.object:set_rotation(rot) + + local cbox = table.copy(self.collisionbox) + local acbox = self.object:get_properties().collisionbox + + if math.abs(cbox[2] - acbox[2]) > 0.1 then + was_Fleckenstein = true + end + + if is_Fleckenstein ~= was_Fleckenstein then + local pos = self.object:get_pos() + pos.y = pos.y + (acbox[2] + acbox[5]) + self.object:set_pos(pos) + end + + if is_Fleckenstein then + cbox[2], cbox[5] = -cbox[5], -cbox[2] + end + + self.object:set_properties({collisionbox = cbox}) +end -- set and return valid yaw local set_yaw = function(self, yaw, delay, dtime) @@ -298,6 +325,7 @@ local set_yaw = function(self, yaw, delay, dtime) yaw = yaw + (math.random() * 2 - 1) * 5 * dtime end self.object:set_yaw(yaw) + update_roll(self) return yaw end @@ -645,9 +673,9 @@ local update_tag = function(self) nametag = tag, }) + update_roll(self) end - -- drop items local item_drop = function(self, cooked, looting_level) @@ -3487,6 +3515,7 @@ local mob_step = function(self, dtime) yaw = yaw + (math.random() * 2 - 1) * 5 * dtime end self.object:set_yaw(yaw) + update_roll(self) end -- end rotation diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 681c68e1b..84650b4dd 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -25,6 +25,19 @@ local colors = { unicolor_black = { mobs_mc.items.wool_black, "#000000D0" }, } +local rainbow_colors = { + "unicolor_light_red", + "unicolor_red", + "unicolor_orange", + "unicolor_yellow", + "unicolor_green", + "unicolor_dark_green", + "unicolor_light_blue", + "unicolor_blue", + "unicolor_violet", + "unicolor_red_violet" +} + if minetest.get_modpath("mcl_wool") ~= nil then colors["unicolor_light_blue"] = { mobs_mc.items.wool_light_blue, "#5050FFD0" } end @@ -112,7 +125,7 @@ mobs:register_mob("mobs_mc:sheep", { end, -- Set random color on spawn - do_custom = function(self) + do_custom = function(self, dtime) if not self.initial_color_set then local r = math.random(0,100000) local textures @@ -149,8 +162,35 @@ mobs:register_mob("mobs_mc:sheep", { } self.initial_color_set = true end + + local is_kay27 = self.nametag == "kay27" + + if self.color_change_timer then + local old_color = self.color + if is_kay27 then + self.color_change_timer = self.color_change_timer - dtime + if self.color_change_timer < 0 then + self.color_change_timer = 0.5 + self.color_index = (self.color_index + 1) % #rainbow_colors + self.color = rainbow_colors[self.color_index + 1] + end + else + self.color_change_timer = nil + self.color_index = nil + self.color = self.initial_color + end + + if old_color ~= self.color then + self.base_texture = sheep_texture(self.color) + self.object:set_properties({textures = self.base_texture}) + end + elseif is_kay27 then + self.initial_color = self.color + self.color_change_timer = 0 + self.color_index = -1 + end end, - + on_rightclick = function(self, clicker) local item = clicker:get_wielded_item() From dbc6dd8cb3c8bc2c3e0fdf1b5c9b12a71227e224 Mon Sep 17 00:00:00 2001 From: epCode Date: Thu, 25 Mar 2021 08:52:32 -0700 Subject: [PATCH 33/58] Add villager sounds --- .../mobs_mc/sounds/mobs_mc_villager.1.ogg | Bin 0 -> 14734 bytes .../mobs_mc/sounds/mobs_mc_villager.2.ogg | Bin 0 -> 14564 bytes .../mobs_mc/sounds/mobs_mc_villager.3.ogg | Bin 0 -> 14773 bytes .../mobs_mc/sounds/mobs_mc_villager.4.ogg | Bin 0 -> 10341 bytes .../mobs_mc/sounds/mobs_mc_villager.5.ogg | Bin 0 -> 14731 bytes .../mobs_mc/sounds/mobs_mc_villager.6.ogg | Bin 0 -> 11187 bytes .../mobs_mc/sounds/mobs_mc_villager.7.ogg | Bin 0 -> 11068 bytes mods/ENTITIES/mobs_mc/villager.lua | 4 ++++ 8 files changed, 4 insertions(+) create mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.1.ogg create mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.2.ogg create mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.3.ogg create mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg create mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg create mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg create mode 100644 mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.1.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.1.ogg new file mode 100644 index 0000000000000000000000000000000000000000..9c56b0f65bc367e060329fee2843eb9ccc5c9753 GIT binary patch literal 14734 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 Fe*pY9T<8D* literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.2.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.2.ogg new file mode 100644 index 0000000000000000000000000000000000000000..bafc77b7eab6f58d17dbd56ddc2f4c1da53d86db GIT binary patch literal 14564 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 ZUU0tu;-eYfb3&=*j_1BOjmEXW{|EX3(7*ry literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.4.ogg new file mode 100644 index 0000000000000000000000000000000000000000..5c9ee492ba4d2315ab820b8149dcb5b73cfc62f6 GIT binary patch literal 10341 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 F{0E)bG4}uf literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.5.ogg new file mode 100644 index 0000000000000000000000000000000000000000..acb236445e2b530640a1c98a54c81d20a9a3672a GIT binary patch literal 14731 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 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.6.ogg new file mode 100644 index 0000000000000000000000000000000000000000..1ef7a522744a727da6082e2a3a1f2bf36fc77604 GIT binary patch literal 11187 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 literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg b/mods/ENTITIES/mobs_mc/sounds/mobs_mc_villager.7.ogg new file mode 100644 index 0000000000000000000000000000000000000000..c2743fbcc640651eedc1529bbed4e3c209552fc1 GIT binary patch literal 11068 zcmeHtcT|%}+xLVTstF_^AYkYr1|>jPKy*V1hAIgJLjWbANVOrX-B1kyEP#j<7eWyt zQ6dBtcNLHzh#*K2u`D($h-=wZS=)OD+X=Do%5XUzjw|s%v^KLT=!gM<~IXt zHf#t23gBBhA9tB1uO>}S&%lgfX`8lk<5T1W1P4u6zgqWS6q$XQCdus*JQT2rNy~2Y*ap}=g$J? z5RC>v3Gnc02WqCh69%0(V66^pt#XbJa5{lg70{=g)w+JSjM`Y=TA#Ra(Aom76{-v^ z98hQ`*(ip*;POp!uu!qzaBHv0iHfc2godgNb-P|%rk~xj+M)oLXALz6T%O}whuk%6 zT5tIHk;X!zPW`MBu{&kZ`ANmMLT!E>IOtp4RrI3~?r{0^eCztstX#S}44bccL!|4HhwZ6B!TwArrADkxi@BMWdNXZLXlZuXxjmuhvco2_Bi?6o zusPrIhdsZ%m*@GV<6xl5%(>*Dwb0Z+_`q4Hn3dC{0HWn8!KoFRS{K%M*T*KDiZ5@A zJK2`pe}>q9MsuD8z#tZRs){eG|G#oaaS+;Yx}tlvi)_>?`&g_|0$8pGJ_I9RLc+P`1Ue57Gw1W@IaQZOY1< zDgHMhRme5+Kd1D0e}NWaQW;y4z=PW#;>@ds2ThBuhI?o(NP-yn)sJvxLuGFVoVCjy zS2d!_M>=zZ%dO5gmX^<3FlkW#A!JMItH)$j$A-#M2E8@Q>K1A{bjnr5jW-~g{*wyr z9(@kP7k{Hnwec1U8XG!PHr;R@1=Vtk%dMp6gBRxe<`#|XDh4~9??WSUC(9Ght3^Py zx#)_Q18Q>GKi!7{*^M)S?WxSb?Kz;rMVZu_6d7+js9jV=>b0≦!)j)0i2^(6_4F zmNCC_8~|B}c`yF6n0Ms`FRm>V5U%1|uG#ey*f5@vHpr200m9fd`uQ|^GR1K zG6USz77YAn*xdJwx&IB~z#E4(ZyknpsdNYbAaukqI&}mS6XX~%LXH_> z#*C%K+-i#nJG&>e?OVVsgv~EEQ~wq@@(?j~KJbuMsPx~FQ-we9!0CXQccFP`q2-Q} z4Y_5F$BsX16srFta^eIhN(CqQf+zd~_}r5C+%nO5Vbax8GwuI2{}nl_x0*v4iX7@z z^S?z-2g%R_il#F}|F;WkTsaIWbQ@Lg?*;&%BCvUV%88=4R8@!!UW=pbBk!a8Ruew6DMn{S^&;6`{zJC+`v9kAe;8%1;j{ zbqqUDbXQVzsSC~jtb_zP(3PP4Z5l|>a4>Ax;hQW-N{2m_;sBi_|9Scsvgl;kn!m}S zIQUb7{r_`G|2xC~YT(~$0CI7dHuQsWuQpk#z;l9u{SPUHIPX^uyr|GuuG`RUfH z4QC}NxQ=AScR6rG|N7&20PtX{fCqH1QvUj;8k!COPKD8-5Wb)l#=rnCCiJ)}0EIC- zjQ{mC|L@d)2!!$Q0PGjCFq;kg6%Is&QVNM0k)gm}ak~Kp1(P!?$iHr}g9Szv?+|SP z5XxX`GphfF1O1UxNnO0KcMH*X#Pe_r1cGu+9iS@m_>&#=YS-UF>&6R&@e0uK0;yeD zu6D;bAEI_(T(1wnnS+k|P9=|b2=M|4KZ&kxA@;xZq@(CW1~E1vwKl;^vVUUOY6e{S;9#c%iLdB@#VvKee?k8YL1^f%_N$^AXwL_yAv#qFx+T$ zwG2BSo4OK)vdNJ`pGI6QgJG=3C}dWDU8ZEc)d( zY7~joq1FhbsBAgj6^UlL+T{Abnaa5>SN=?U2c-AZ82xkdIh(FauY49@5PxEf@2H$Lg9d2ykS586H78E(NhJE5 zhiDQRHnD(;FAtOVCW^_{k5halW9+CVsbx)mp`6wv9XBmz*!7@-pjug$ZO?mbR1@h5 zyGW<&gK>}z#GDBEf?0GyV-Fj09JQGI0-LeoltE=cS?L5Q7FahceI|xeqo!xfn>WmP z=ne_FUXR?vmVu5jn5CGG8{zYfy8cTrc5-oDMRE7^qWSm*1VY;zZ2lyq02my;aN(4<;qZl* z4$AlQ!Pn}U)A5wepUXe`o|w{!qLC~dNs=B zp=iiuj7k4`%C+A9l)51w z7W+re@>OK_fdR!RuTAxvK0F9A8@=QD>hPHcA>PB^BmteBkJqScb-vr#*_l4!mM=3j zG~^#EJ$4NGT!DZk36a4=x`iS64N?U!abtD?E9i1-M_^N!o2T1wLNFbrghJSMw{rw& zi{*CoQ(g1`9j+|edCQX-^WWNC+!HKoo|hy>owareb$VxYd8_l9w-Qm9is6+>Fhc+0i}y!%zDz3J{lkFJ{methN1ZF2g6!ZQ?IkrXS#M+FkMkFK^1pk#LK>BA z-Y2WIh)~U=Pb#=(l|FyPdhV{Or>}cChj*~q2)L?%y|IR={+pZeDm`TKqYxLnL0bGNtd#zv&qStk{0Qt zM%ue~6QL|!4M{?E4qH$*E^ZVM*kV&Iy@1Z_honeVk_ru%Eza`Y*w}8sBI)A%Mx~7wPK2& zsp;mp!?4vNVG;&+0_);_8i;bOe^B=*Fqyf`;odaKIOsKFYeO61QZya9`8+Cdf6?of zZ{*BJ<~dhJ$HvA&Ac+;+1Q#IDQGQFu#cY9%m_32#GP^P3#AfeN5jKYram>De|)XDJ$a+n14JHAC9FB&w)nHo{@|IQwta0b4AH>OM$DI+ zvWvf%@xQK(c+cs`m@s8~X5|X~b%~R%hn)O=*`+SivDr>gZOqiasA$3(;pu7Fqz?zflA4S@X+$dZ>D0> zqFWR_x61d1e*Jq$83K-%Gis0ntG zzjX3;n7=fr8znKogzY*h5{8_#SzBmjUI16~=Igj!EIoHF;G_zy8E#Nuibc60>2f?q z%e9z~9};?Igb4W^i3{@s@eG2!}Y$w;u_%O$wx{mx04zkcN6 zDsRSH>Du(38(SlNPpPRb0>O@FJ$AMwz4O{RN)3xiSy8*8KXy~?>WJ3Lu`+`~wZfvq z3OuZot8}@&EK-eq+lxAu;q@rzWryhm` zO1fD9$1>IuLbSZN@wVK2nwghOgc~==loBvONiUL`*-2>KDYyomU?S5i>Onryoe62u zpQtKP5SFMoicCsFAW#L!5`jvSfJ^UQ8l5U-{Hp7@ZTDd%6eVBS$!lbB?+0R#krL(YgZlc-LRwPkQ$tT$5oD45#X;9$a0 zA^V>k*P?i8l3=&T^1AglBA!`?=CoypL-6E<|63lIg%aVo?I~CAicKgRo zv<)%`8?BMn1X(+*L4FQ#@!Zc}o)xiJ2s5rt6&u-vOW?$p<&c*WFoF=O3{05z?ZENy zIIfYebR(5W7Cs%d#%QX5<$$je<(cOwRqHsNEkxQ9Od(~pTD>Dr{yL z!aYPN1ug=DwSae{3D;r{0-;)lg3!>qtELHm)XG8z!>Saz7u$x@-Mn})tj)@E?%@hK z$jWgRin`xRiZv4o#3BrJDP|ZA{B#o&usJ4J;e(1q1-K(zgwYuHU+g~`tc!FSTm(1e zPq3E?1YTneA<9g8#|{7jmCc?uW89d5AStNvV5-Nk5Fc5aNtQlNN_ImiSB zm=K3?fk40qpmVd0=Eh}O;Lw9$u`Dhy8Gw7ADVZ!Jaui+`OPjmzrrXx?k%&xNNFRXT zK$$cXg@h?0FLNabb9#)XdCH6^$W(}5jw5*Qe@2ir(R5`*qPkGv#Z=CW#C+YsNk1Xtlj(HL;9x}hN*+nX zLW?t)Vm@7#0dE@(Z(t+LTqM+O33<*+E?_%~ro|IrS$r0E%wXI<33}6YQwHO?(xLi~ zYT(erwc8pDlqD)iU_3lMckpD43NQ3c@71(LS`dg@r&gIkD$mPYfARBk&56uQ`fLA5 zc#j5=YmOA^>h=UbFwOTX)nLHwk6<}COX$)7fO#OGobS5PouyyWk38}ybTX3K#Kv>| zlj1Yu2ik4Kp`Fd9B{@tfYN=&{h@+gy<*(S_wdOCZl!H_r5!?&|UkaF;OrLf>+-3)n$TZy<%#%F7QD4Hq}_3{$^dk=`!RlNEb5 z1%B6;aM$N*x>1;q;GAK%p|cN+V}me5=<05s$CS;&9`*5zPUA3=Cu(HeOCsPDX_aKe z$5&^dC4>;B7T(1Zodi?PS9eJ=!br!KX~Kr9$ExF)p6J0Jf0QK)F5R+JBH2*U9&Y3< zsubL<$4g%xAHA{CwwXZnJK502>Tbh^8#Vi)NM00GA(P7V9C{k81;7p}RcoXzl(hp zM=W;ir7d~)`~Cb`&Zgmwb{k^6k1x5gf6pGLs9h6bt$LiWv^7T_^maBL;BSlU^5H0u zFt~iV?SW)+Lcs1G7q+E^_(@xX-TW7$X4+coY?|1mEINehP()9y%Vlh7y=jR;2_X{3 zbZDretr}1Q5>uBZLWa%prkkl7#Va1`7jM85jrZhtzu z0IhUe=$@&Z(ZG*q3k7xLpfx6o0dCo_nhH=tNNsJB14mGq7&kKS*@^zX69?}VX#&#R zP7b(FO-cFX5ig9RjGzy*gKrmT1LMB%Bj?Y>T0K7cX6{+n>URg0tus4z(oXN@i`q|& zRo_Q^=)E^An^^>KeQ-N7>dJS)8ivjhNxC#y))CVlZY|&_(V(4>l2J(OR##U^EWj!T zzN+1>X-1(^l+86s$??!Pjs;3=Q6sILH*7~42#;V2;v`1w)g&P7Rso*fqU=-&g{~c6 z_<=FEb{k(^#7)xR=Vp-6fv{JE-&g3I1x#lY6-^o|tEJM!KeAeybg#fdv&($O^QAA6#h8}{xA*DJq3p1!f{@yPb3=hsdjoUsoU zMbj6BVgNXbiMOF4kD5uWPX+sxHgP(L{wYa>+*MrW2(0MmW_K(%Zyv3dB3!-Ke>uGmm*o^A$7;377EqD z=1^=Sqdqe;(=3)t;$os6pkjGYxHqwvay>_J3P6Zhe3BO*l_NEPB(6dY_b_?}MdV1rfsJ1XS0 zX|JnYLpC(e-73{KJ?l1bBw{!I;Fx~WUdQ@P4UJU)N>u0~j{l|~cKQTVJea~~D|Z`~ z9;0osk_SB{ut_LjN^qDkw6vu~fF4;lDqt>lvk{w=V8#(ic4!Ta#cuxS4tJ!6pWo89 z;NRX7ct~V{*3(wmX@OV)3M98+2jN5{&a@t9nPj*wlUQApOxZ6`UflF~{d!u$ebJ1s z-~Q?w5`Bb`$P0yLo}kub;4*AL2WIK6+M1`T(91I)tF=2~f#VWSo%(i>zea@B=> zPM4CuXu;mlDk+MaLo)@YTuu$ggn+LnFZNefLPUbSaX*Ew4BJIpGI^R=Z@+%|N{4$* z$Hgma7tP)zj2t_CbZ=FYZgrtWD8|#$v~KdMzd9Bt;|P!^ba2N?b90X=Gq5;KX#J>6 zVNay;NiQ+h)=P|3%&->K|NJwdo;uddMV=Jlg>X1KxBx>9F3|3|&QMR*E0|*qD77_A zhy)n~7b;|bmIR&UJ!Y_e`G!lc=ia)<#i%(DCwfFu_EMKkQ*}W`XUoc>P^%MRdc`U9MdQ}$XvW{;tD-jGQk%=rHqDmr|9lqa(Gb~bnPn-UwaSgKknYtvmy2VYG=bu z`~hnYeerb9{z!nNrSeG^a7dj;*;r- zn~+Fx54(v@7U40T!AM1699a*21%uyQhCL(%Ssl@yNbCp@bCwT_tSh z>hsBCIoV;oClz<^IQ-0%2hNz++rtkP&rwap;P28-(;c9l2ul$_n=;-E2O0lFB z2zy-wgmftgG?E#WkA}&B3aoP?j>Cz+i_#!VIs_0X^$Og^7fDSO1d=MDz=k_(1LE@0 z1>+Mc$XnAp?B3swj)XQm;8sVdHaGH$4j<7*w)AKmT7yC{hX^iYk%%><770_NynI6b zXuh-2K-uzm*7sY!9PP@UZdn&`N$~<@ylL>7l3T#n_FcbPyw7am?@(Cr^Xl=rrn5J| za(A=l?HZ&L}uP->(3(d>pUYdDj@33i;d~HrmXB%!g;z#^F@0$IdCwJoR z>y^E`yQAGmVv7?J#>J%xxz$ZKZTYJRc>_|k4Lg%Y-dp5QbtxkL?p$WlwxS<~SV_&W z^7hKp`fcS_`jyVl4)FIp+&FEI&^9ZnC?d1`c}=|aZyJCRaLRb+vb)5CIOE-y1CumT<*1NTxjEpl(z6?-94>( zBjbo&(&oUWj$vmv@@=$yHD>B<{6;K&gZxmJQ6pV0s2R_bkxeYL8J?g{$Os8`z}hN! z)y;e=h;I3O=Fa=_FP?Dk3_cw}X}0YC+P$v*{scQs$Cf8TcJjl|n>d|i@4CadmoiGN zVP48!{P=O0q$jr)Nsk?A@+jE? zN(hmusk^le_1*VuQk$>=hc!9mWSJ4KO8cN&^kedku>SMiq9Cay%jko;v-##h#s=rq z+M3!e*M4_htvFPOUmh3y^yyd)c~iDS@9-bpE_3JNnN~5YkZfAuFLt#V46R30aoU=% zry5UfTys0spM3W1=oBgX6IkQ`i^=O=v)~ z57?YYM{559-EEL5;u1wz zq82?dMA96HCI`1ZMHsPK<77P|H#CyoDMZ=;UL@UrHun*YnBBKiGUB-ee)zyavG&`p zpLMMH}ZpiqyXFB!ckJp|d+VDRrT9$K1 z!-o&m+|=J%_xa$XmkIYXnTMV{Ku@%Ar${CKmBcOG4w+lO&Lm$0A98smx?ol8ww;UC zMJ^h*{j<`%sgVJ_WgGEj{M=(Q2wBKVp{pd1BU2$I2QID8wn=K`w(!xx#N;!SBs*Ez zfTKuxBD$uO%QIo&G6D)jip(Y~rIY2EBo@#XMM+H}TYJ37k5+21UFH@=XlobJc9~w# z+tD|hudemxB1ZR=UkWPJ)cr)9`yZZZDP~Uf+Y(I+XI9?&`ts(xmv8IBV~GC8XK!xw zjK9MAczUw%Y-6+LVpntN)z`W3Hal1hNV`*Hzt7{uXUtxkrI^h; zPT&43EE8S4;R_{jFD7Zbps=CJX`BAy<3e)+UR#gmD0zm%mH5ct?n`rz9Xl2cMIpJH zz?B4PBw*`h?FAv4OA}Zv!(JLAtq0ibvvu+QNH_XObF7U>DiC#w2!h$2>-O9^O-%k> z-K&WiNXB|fMCx(*Or)n}LZxiv_1CqBFaMC&tk5H{5vDJ?@HFL9QOiLg8h&xF%{o z-I}vUX?0HdY3Wqo^(8cuqU*I|zdznI_@S0Uh*D72+?xU08*@kS_->Q%XjqVyVZ+)U zG3(v{Vdr^rYFGMB⪼8)D-TJ`->@>Uw(8fCdv}Jn*&O4Gn>9R&mbhvv@|5CwbLtc zT+Cv#3`9_)uRYtkD#uzl*1!*`QQ&9q{K3jO=+~DCVyXK5Nwr6Jz1JP#%{V^kRk?WK zk1wAdXUG%)Uo=b*VVkj(it<5m*jbmmFMI|soRp3ewj4R&hvv_;U7I_@W6{w}I&?nG zLNkqDeRBQBOBYUs;7Egg+2OG#H{KP6UGYwtXixpBZ+GjCdh_|;wK^{TaqIK$WBy*> T_m77=o*i6O^uzS|W#GR6*1vMu literal 0 HcmV?d00001 diff --git a/mods/ENTITIES/mobs_mc/villager.lua b/mods/ENTITIES/mobs_mc/villager.lua index a38c78719..9429a691b 100644 --- a/mods/ENTITIES/mobs_mc/villager.lua +++ b/mods/ENTITIES/mobs_mc/villager.lua @@ -967,6 +967,10 @@ mobs:register_mob("mobs_mc:villager", { drops = {}, can_despawn = false, -- TODO: sounds + sounds = { + random = "mobs_mc_villager", + distance = 10, + }, animation = { stand_speed = 25, stand_start = 40, From 322578df6a9c1aff193bd41eeeaa7c387c66d737 Mon Sep 17 00:00:00 2001 From: Code-Sploit Date: Thu, 25 Mar 2021 16:03:54 +0000 Subject: [PATCH 34/58] Something even more secret! --- mods/ENTITIES/mobs_mc/sheep.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 84650b4dd..963b3c26d 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -163,11 +163,11 @@ mobs:register_mob("mobs_mc:sheep", { self.initial_color_set = true end - local is_kay27 = self.nametag == "kay27" + local is_codesploit = self.nametag == "Code-Sploit" if self.color_change_timer then local old_color = self.color - if is_kay27 then + if is_codesploit then self.color_change_timer = self.color_change_timer - dtime if self.color_change_timer < 0 then self.color_change_timer = 0.5 @@ -184,7 +184,7 @@ mobs:register_mob("mobs_mc:sheep", { self.base_texture = sheep_texture(self.color) self.object:set_properties({textures = self.base_texture}) end - elseif is_kay27 then + elseif is_codesploit then self.initial_color = self.color self.color_change_timer = 0 self.color_index = -1 From d555fce8bc3cbf1c6485e829e014e7142c483e11 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 25 Mar 2021 17:29:15 +0100 Subject: [PATCH 35/58] Bruh. kay27 has 20 times more commits than you. This reverts commit 322578df6a9c1aff193bd41eeeaa7c387c66d737. --- mods/ENTITIES/mobs_mc/sheep.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 963b3c26d..84650b4dd 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -163,11 +163,11 @@ mobs:register_mob("mobs_mc:sheep", { self.initial_color_set = true end - local is_codesploit = self.nametag == "Code-Sploit" + local is_kay27 = self.nametag == "kay27" if self.color_change_timer then local old_color = self.color - if is_codesploit then + if is_kay27 then self.color_change_timer = self.color_change_timer - dtime if self.color_change_timer < 0 then self.color_change_timer = 0.5 @@ -184,7 +184,7 @@ mobs:register_mob("mobs_mc:sheep", { self.base_texture = sheep_texture(self.color) self.object:set_properties({textures = self.base_texture}) end - elseif is_codesploit then + elseif is_kay27 then self.initial_color = self.color self.color_change_timer = 0 self.color_index = -1 From 630e7e8acb517a06aec56cad1839e05728e6f7a4 Mon Sep 17 00:00:00 2001 From: Code-Sploit Date: Thu, 25 Mar 2021 16:20:02 +0000 Subject: [PATCH 36/58] Do a secre thing even more secret then the secret thing of secret --- mods/ENTITIES/mobs_mc/sheep.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 84650b4dd..963b3c26d 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -163,11 +163,11 @@ mobs:register_mob("mobs_mc:sheep", { self.initial_color_set = true end - local is_kay27 = self.nametag == "kay27" + local is_codesploit = self.nametag == "Code-Sploit" if self.color_change_timer then local old_color = self.color - if is_kay27 then + if is_codesploit then self.color_change_timer = self.color_change_timer - dtime if self.color_change_timer < 0 then self.color_change_timer = 0.5 @@ -184,7 +184,7 @@ mobs:register_mob("mobs_mc:sheep", { self.base_texture = sheep_texture(self.color) self.object:set_properties({textures = self.base_texture}) end - elseif is_kay27 then + elseif is_codesploit then self.initial_color = self.color self.color_change_timer = 0 self.color_index = -1 From 97991d138cf7294e7d85b0febc685399ead53ab9 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Thu, 25 Mar 2021 17:34:03 +0100 Subject: [PATCH 37/58] Revert "Do a secre thing even more secret then the secret thing of secret" This reverts commit 630e7e8acb517a06aec56cad1839e05728e6f7a4. --- mods/ENTITIES/mobs_mc/sheep.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mobs_mc/sheep.lua b/mods/ENTITIES/mobs_mc/sheep.lua index 963b3c26d..84650b4dd 100644 --- a/mods/ENTITIES/mobs_mc/sheep.lua +++ b/mods/ENTITIES/mobs_mc/sheep.lua @@ -163,11 +163,11 @@ mobs:register_mob("mobs_mc:sheep", { self.initial_color_set = true end - local is_codesploit = self.nametag == "Code-Sploit" + local is_kay27 = self.nametag == "kay27" if self.color_change_timer then local old_color = self.color - if is_codesploit then + if is_kay27 then self.color_change_timer = self.color_change_timer - dtime if self.color_change_timer < 0 then self.color_change_timer = 0.5 @@ -184,7 +184,7 @@ mobs:register_mob("mobs_mc:sheep", { self.base_texture = sheep_texture(self.color) self.object:set_properties({textures = self.base_texture}) end - elseif is_codesploit then + elseif is_kay27 then self.initial_color = self.color self.color_change_timer = 0 self.color_index = -1 From 86a18802dc790a9c2cead1466665082223eda41d Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Thu, 25 Mar 2021 21:57:07 +0100 Subject: [PATCH 38/58] use proper colors --- mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua index c5c3b3dc8..bbecd07dc 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua @@ -1,6 +1,8 @@ local S = minetest.get_translator("mesecons_commandblock") local F = minetest.formspec_escape +local color_red = mcl_colors.RED + local function construct(pos) local meta = minetest.get_meta(pos) @@ -78,7 +80,7 @@ local function check_commands(commands, player_name) if string.sub(cmd, 1, 1) == "/" then msg = S("Error: The command “@1” does not exist; your command block has not been changed. Use the “help” chat command for a list of available commands. Hint: Try to remove the leading slash.", cmd) end - return false, minetest.colorize("#FF0000", msg) + return false, minetest.colorize(color_red, msg) end if player_name then local player_privs = minetest.get_player_privs(player_name) @@ -86,7 +88,7 @@ local function check_commands(commands, player_name) for cmd_priv, _ in pairs(cmddef.privs) do if player_privs[cmd_priv] ~= true then local msg = S("Error: You have insufficient privileges to use the command “@1” (missing privilege: @2)! The command block has not been changed.", cmd, cmd_priv) - return false, minetest.colorize("#FF0000", msg) + return false, minetest.colorize(color_red, msg) end end end From b9301f12ce1b65fac9d2319bcddab715d449a4be Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Thu, 25 Mar 2021 21:59:21 +0100 Subject: [PATCH 39/58] Update mod.conf --- mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf b/mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf index 4a743406c..a35c425f5 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/mod.conf @@ -1,3 +1,3 @@ name = mesecons_commandblock -depends = mesecons +depends = mesecons, mcl_colors optional_depends = doc, doc_items From e4a6244fddb16be0868f52d366f81b543ae4e160 Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Thu, 25 Mar 2021 22:07:38 +0100 Subject: [PATCH 40/58] add basic setting --- mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua | 2 ++ settingtypes.txt | 3 +++ 2 files changed, 5 insertions(+) diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua index bbecd07dc..247a0718b 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua @@ -3,6 +3,8 @@ local F = minetest.formspec_escape local color_red = mcl_colors.RED +local command_blocks_activated = minetest.settings:get_bool("mcl_enable_commandblocks", true) + local function construct(pos) local meta = minetest.get_meta(pos) diff --git a/settingtypes.txt b/settingtypes.txt index af0e18d85..67e686d1e 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -129,6 +129,9 @@ mcl_superflat_classic (Classic superflat map generation) bool false # If disabled, no ores will be generated. mcl_generate_ores (Generate Ores) bool true +# If disabled, command blocks will be unusuable (but still present). +mcl_enable_commandblocks (Enable Command Blocks) bool true + # Make some blocks emit decorative particles like flames. This setting # specifies the detail level of particles, with higher levels being # more CPU demanding. From 8258dae1b80afe2d58a3efd459b9cb0892247404 Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Thu, 25 Mar 2021 22:13:37 +0100 Subject: [PATCH 41/58] setting working --- .../REDSTONE/mesecons_commandblock/init.lua | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua index 247a0718b..481ed5d6e 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua @@ -4,6 +4,7 @@ local F = minetest.formspec_escape local color_red = mcl_colors.RED local command_blocks_activated = minetest.settings:get_bool("mcl_enable_commandblocks", true) +local msg_not_activated = S("Command Blocks are not activated on the server") --TODO: real mc message and translation local function construct(pos) local meta = minetest.get_meta(pos) @@ -102,10 +103,15 @@ local function commandblock_action_on(pos, node) if node.name ~= "mesecons_commandblock:commandblock_off" then return end - - minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"}) - + local meta = minetest.get_meta(pos) + local commander = meta:get_string("commander") + + if not command_blocks_activated then + minetest.chat_send_player(commander, msg_not_activated) + return + end + minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"}) local commands = resolve_commands(meta:get_string("commands"), pos) for _, command in pairs(commands:split("\n")) do @@ -121,7 +127,6 @@ local function commandblock_action_on(pos, node) return end -- Execute command in the name of commander - local commander = meta:get_string("commander") cmddef.func(commander, param) end end @@ -133,6 +138,10 @@ local function commandblock_action_off(pos, node) end local on_rightclick = function(pos, node, player, itemstack, pointed_thing) + if not command_blocks_activated then + minetest.chat_send_player(player:get_player_name(), msg_not_activated) + return + end local can_edit = true -- Only allow write access in Creative Mode if not minetest.is_creative_enabled(player:get_player_name()) then From 25f6a9ee23cc899a5bd151ed8b1f9c0c939f8a89 Mon Sep 17 00:00:00 2001 From: kay27 Date: Fri, 26 Mar 2021 09:29:05 +0400 Subject: [PATCH 42/58] [mcl_core] Set obsidian.is_ground_content to false, see https://git.minetest.land/MineClone2/MineClone2/issues/1372 --- mods/ITEMS/mcl_core/nodes_base.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_core/nodes_base.lua b/mods/ITEMS/mcl_core/nodes_base.lua index cc6a0e6ae..f4fe12155 100644 --- a/mods/ITEMS/mcl_core/nodes_base.lua +++ b/mods/ITEMS/mcl_core/nodes_base.lua @@ -808,7 +808,7 @@ minetest.register_node("mcl_core:obsidian", { description = S("Obsidian"), _doc_items_longdesc = S("Obsidian is an extremely hard mineral with an enourmous blast-resistance. Obsidian is formed when water meets lava."), tiles = {"default_obsidian.png"}, - is_ground_content = true, + is_ground_content = false, sounds = mcl_sounds.node_sound_stone_defaults(), stack_max = 64, groups = {pickaxey=5, building_block=1, material_stone=1}, From 0e5bbd6d3df2d5332073ff684eb6746bb36eddbc Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Fri, 26 Mar 2021 09:57:28 +0100 Subject: [PATCH 43/58] fix msg to be mc like https://www.digminecraft.com/game_commands/enable_command_blocks.php --- mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua index 481ed5d6e..58355dafc 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua @@ -4,7 +4,7 @@ local F = minetest.formspec_escape local color_red = mcl_colors.RED local command_blocks_activated = minetest.settings:get_bool("mcl_enable_commandblocks", true) -local msg_not_activated = S("Command Blocks are not activated on the server") --TODO: real mc message and translation +local msg_not_activated = S("Command blocks are not enabled on this server") --TODO: translation local function construct(pos) local meta = minetest.get_meta(pos) From 78bad87a72b0c322ef5b034c393e08c2501cdf98 Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Fri, 26 Mar 2021 09:59:58 +0100 Subject: [PATCH 44/58] fix transation --- mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua | 2 +- .../mesecons_commandblock/locale/mesecons_commandblock.de.tr | 1 + .../mesecons_commandblock/locale/mesecons_commandblock.es.tr | 1 + .../mesecons_commandblock/locale/mesecons_commandblock.fr.tr | 1 + .../mesecons_commandblock/locale/mesecons_commandblock.ru.tr | 1 + mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt | 1 + 6 files changed, 6 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua index 58355dafc..4b389090d 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua @@ -4,7 +4,7 @@ local F = minetest.formspec_escape local color_red = mcl_colors.RED local command_blocks_activated = minetest.settings:get_bool("mcl_enable_commandblocks", true) -local msg_not_activated = S("Command blocks are not enabled on this server") --TODO: translation +local msg_not_activated = S("Command blocks are not enabled on this server") local function construct(pos) local meta = minetest.get_meta(pos) diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.de.tr b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.de.tr index 9c9b1df1d..a149feef9 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.de.tr +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.de.tr @@ -27,3 +27,4 @@ Access denied. You need the “maphack” privilege to edit command blocks.=Zugr Editing the command block has failed! You can only change the command block in Creative Mode!=Bearbeitung des Befehlsblocks fehlgeschlagen! Sie können den Befehlsblock nur im Kreativmodus ändern! Editing the command block has failed! The command block is gone.=Bearbeiten des Befehlsblocks fehlgeschlagen! Der Befehlsblock ist verschwunden. Executes server commands when powered by redstone power=Führt Serverbefehle aus, wenn mit Redstoneenergie versorgt +Command blocks are not enabled on this server= diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.es.tr b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.es.tr index 8826ab9a6..938c710b9 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.es.tr +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.es.tr @@ -28,3 +28,4 @@ Example 2:@n give @@n mcl_core:apple 5@nGives the nearest player 5 apples=2. Access denied. You need the “maphack” privilege to edit command blocks.=Acceso denegado. Necesita el privilegio "maphack" para editar bloques de comandos. Editing the command block has failed! You can only change the command block in Creative Mode!=¡La edición del bloque de comando ha fallado! ¡Solo puede cambiar el bloque de comandos en modo creativo! Editing the command block has failed! The command block is gone.=¡La edición del bloque de comando ha fallado! El bloque de comando se ha ido. +Command blocks are not enabled on this server= diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.fr.tr b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.fr.tr index 061ac08a0..b397c979c 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.fr.tr +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.fr.tr @@ -27,3 +27,4 @@ Access denied. You need the “maphack” privilege to edit command blocks.=Acc Editing the command block has failed! You can only change the command block in Creative Mode!=La modification du bloc de commandes a échoué! Vous ne pouvez modifier le bloc de commandes qu'en mode créatif! Editing the command block has failed! The command block is gone.=La modification du bloc de commandes a échoué! Le bloc de commande a disparu. Executes server commands when powered by redstone power=Exécute les commandes du serveur lorsqu'il est alimenté par l'alimentation Redstone +Command blocks are not enabled on this server=Les blocks de commandes ne sont pas activés sur ce serveur diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.ru.tr b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.ru.tr index 8671099c7..85bed4b95 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.ru.tr +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/mesecons_commandblock.ru.tr @@ -27,3 +27,4 @@ Access denied. You need the “maphack” privilege to edit command blocks.=До Editing the command block has failed! You can only change the command block in Creative Mode!=Попытка редактирования командного блока потерпела неудачу. Вы можете изменять командные блоки только в творческом режиме! Editing the command block has failed! The command block is gone.=Попытка редактирования командного блока потерпела неудачу. Командный блок исчез. Executes server commands when powered by redstone power=При подаче энергии редстоуна выполняет серверные команды +Command blocks are not enabled on this server= diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt index 0e0c3caa5..49e98ef2b 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/locale/template.txt @@ -27,3 +27,4 @@ Access denied. You need the “maphack” privilege to edit command blocks.= Editing the command block has failed! You can only change the command block in Creative Mode!= Editing the command block has failed! The command block is gone.= Executes server commands when powered by redstone power= +Command blocks are not enabled on this server= From 53d7134437ef11f05506ea1eb7d45dd28dee1bc9 Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Fri, 26 Mar 2021 10:00:48 +0100 Subject: [PATCH 45/58] remove unuseful spamming messages --- mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua index 4b389090d..1928f809c 100644 --- a/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua +++ b/mods/ITEMS/REDSTONE/mesecons_commandblock/init.lua @@ -108,7 +108,7 @@ local function commandblock_action_on(pos, node) local commander = meta:get_string("commander") if not command_blocks_activated then - minetest.chat_send_player(commander, msg_not_activated) + --minetest.chat_send_player(commander, msg_not_activated) return end minetest.swap_node(pos, {name = "mesecons_commandblock:commandblock_on"}) From c0308c7c0821b032e5bd7dc0778fc113ac04eabc Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Fri, 26 Mar 2021 11:49:41 +0100 Subject: [PATCH 46/58] fix weird death message (#1378) --- mods/HUD/mcl_death_messages/init.lua | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mods/HUD/mcl_death_messages/init.lua b/mods/HUD/mcl_death_messages/init.lua index b2c656ac4..8ca686701 100644 --- a/mods/HUD/mcl_death_messages/init.lua +++ b/mods/HUD/mcl_death_messages/init.lua @@ -1,5 +1,8 @@ local S = minetest.get_translator("mcl_death_messages") local N = function(s) return s end +local C = minetest.colorize + +local color_skyblue = mcl_colors.AQUA local function get_tool_name(item) local name = item:get_meta():get_string("name") @@ -41,6 +44,9 @@ local msgs = { ["murder"] = { N("@1 was slain by @2 using [@3]"), }, + ["murder_hand"] = { + N("@1 was slain by @2"), + }, ["murder_any"] = { N("@1 was killed."), }, @@ -131,7 +137,7 @@ local last_damages = { } minetest.register_on_dieplayer(function(player, reason) -- Death message - local message = minetest.settings:get_bool("mcl_showDeathMessages") + local message = minetest.settings:get_bool("mcl_showDeathMessages") --Maybe cache the setting? if message == nil then message = true end @@ -201,7 +207,11 @@ minetest.register_on_dieplayer(function(player, reason) elseif hitter:is_player() then hittername = hitter:get_player_name() if hittername ~= nil then - msg = dmsg("murder", name, hittername, minetest.colorize("#00FFFF", hitter_toolname)) + if hitter_toolname == "" then + msg = dmsg("murder_hand", name, hittername) + else + msg = dmsg("murder", name, hittername, C(color_skyblue, hitter_toolname)) + end else msg = dmsg("murder_any", name) end @@ -229,7 +239,7 @@ minetest.register_on_dieplayer(function(player, reason) if shooter == nil then msg = dmsg("arrow", name) elseif shooter:is_player() then - msg = dmsg("arrow_name", name, shooter:get_player_name(), minetest.colorize("#00FFFF", get_tool_name(shooter:get_wielded_item()))) + msg = dmsg("arrow_name", name, shooter:get_player_name(), C(color_skyblue, get_tool_name(shooter:get_wielded_item()))) elseif s_ent and s_ent._cmi_is_mob then if s_ent.nametag ~= "" then msg = dmsg("arrow_name", name, shooter:get_player_name(), get_tool_name(shooter:get_wielded_item())) From 41768e95a109b0a06c4ea0fb19098f4a52860cb6 Mon Sep 17 00:00:00 2001 From: AFCMS <61794590+AFCMS@users.noreply.github.com> Date: Fri, 26 Mar 2021 11:50:14 +0100 Subject: [PATCH 47/58] fix --- mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr | 1 + mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr | 1 + mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr | 1 + mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr | 1 + mods/HUD/mcl_death_messages/locale/template.txt | 1 + mods/HUD/mcl_death_messages/mod.conf | 1 + 6 files changed, 6 insertions(+) diff --git a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr index b9ef6680d..ffb567b8b 100644 --- a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr +++ b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.de.tr @@ -56,3 +56,4 @@ A ghast scared @1 to death.=Ein Ghast hat @1 zu Tode erschrocken. @1 was killed by a baby husk.=@1 wurde von einem Wüstenzombiebaby getötet. @1 was killed by a zombie pigman.=@1 wurde von einem Schweinezombie getötet. @1 was killed by a baby zombie pigman.=@1 wurde von einem Schweinezombiebaby getötet. +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr index 6ed106db8..a56199e00 100644 --- a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr +++ b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.es.tr @@ -55,3 +55,4 @@ A ghast scared @1 to death.=Se ha asustado @1 hasta morir. @1 was killed by a baby husk.=@1 fue asesinado por un bebé husk. @1 was killed by a zombie pigman.=@1 fue asesinado por un cerdo zombie. @1 was killed by a baby zombie pigman.=@1 fue asesinado por un bebé cerdo zombie. +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr index 6d0a5115c..05cf99976 100644 --- a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr +++ b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.fr.tr @@ -56,3 +56,4 @@ A ghast scared @1 to death.=Un ghast a éffrayé @1 à mort. @1 was killed by a baby husk.=@1 a été tué par un bébé zombie momie. @1 was killed by a zombie pigman.=@1 a été tué par un zombie-couchon. @1 was killed by a baby zombie pigman.=@1 a été tué par un bébé zombie-couchon +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr index f9f164dd3..d5b6ec396 100644 --- a/mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr +++ b/mods/HUD/mcl_death_messages/locale/mcl_death_messages.ru.tr @@ -56,3 +56,4 @@ A ghast scared @1 to death.=Гаст напугал @1 до смерти. @1 was killed by a baby husk.=@1 был(а) убит(а) машылом-кадавром. @1 was killed by a zombie pigman.=@1 был(а) убит(а) зомби-свиночеловеком. @1 was killed by a baby zombie pigman.=@1 был(а) убит(а) малышом-зомби-свиночеловеком. +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/locale/template.txt b/mods/HUD/mcl_death_messages/locale/template.txt index db074f756..d1e3b832b 100644 --- a/mods/HUD/mcl_death_messages/locale/template.txt +++ b/mods/HUD/mcl_death_messages/locale/template.txt @@ -56,3 +56,4 @@ A ghast scared @1 to death.= @1 was killed by a baby husk.= @1 was killed by a zombie pigman.= @1 was killed by a baby zombie pigman.= +@1 was slain by @2.= diff --git a/mods/HUD/mcl_death_messages/mod.conf b/mods/HUD/mcl_death_messages/mod.conf index 23d2852e7..a634e16de 100644 --- a/mods/HUD/mcl_death_messages/mod.conf +++ b/mods/HUD/mcl_death_messages/mod.conf @@ -1,3 +1,4 @@ name = mcl_death_messages author = 4Evergreen4 description = Shows messages in chat when a player dies. +depends = mcl_colors From 01eba30058ee57af7a4957f7961e26196f6227cd Mon Sep 17 00:00:00 2001 From: AFCMS Date: Fri, 26 Mar 2021 14:32:08 +0100 Subject: [PATCH 48/58] Fix #1234 --- mods/HUD/mcl_inventory/creative.lua | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/mods/HUD/mcl_inventory/creative.lua b/mods/HUD/mcl_inventory/creative.lua index 1cebed0cd..b3ee40bf7 100644 --- a/mods/HUD/mcl_inventory/creative.lua +++ b/mods/HUD/mcl_inventory/creative.lua @@ -489,8 +489,8 @@ mcl_inventory.set_creative_formspec = function(player, start_i, pagenum, inv_siz if filter == nil then filter = "" end - formspec = formspec .. "field[5.3,1.34;4,0.75;suche;;"..minetest.formspec_escape(filter).."]" - formspec = formspec .. "field_close_on_enter[suche;false]" + formspec = formspec .. "field[5.3,1.34;4,0.75;search;;"..minetest.formspec_escape(filter).."]" + formspec = formspec .. "field_close_on_enter[search;false]" end if pagenum ~= nil then formspec = formspec .. "p"..tostring(pagenum) end @@ -561,11 +561,11 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) elseif fields.inv then if players[name].page == "inv" then return end page = "inv" - elseif fields.suche == "" and not fields.creative_next and not fields.creative_prev then + elseif fields.search == "" and not fields.creative_next and not fields.creative_prev then set_inv_page("all", player) page = "nix" - elseif fields.suche ~= nil and not fields.creative_next and not fields.creative_prev then - set_inv_search(string.lower(fields.suche),player) + elseif fields.search ~= nil and not fields.creative_next and not fields.creative_prev then + set_inv_search(string.lower(fields.search),player) page = "nix" end @@ -612,8 +612,8 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) players[name].start_i = start_i local filter = "" - if not fields.nix and fields.suche ~= nil and fields.suche ~= "" then - filter = fields.suche + if not fields.nix and fields.search ~= nil and fields.search ~= "" then + filter = fields.search players[name].filter = filter end From 88fc515cff20edb16d627a7973f10575618678e6 Mon Sep 17 00:00:00 2001 From: AFCMS Date: Fri, 26 Mar 2021 17:38:25 +0100 Subject: [PATCH 49/58] make mobs take damage of falling anvils --- mods/ENTITIES/mcl_falling_nodes/init.lua | 71 +++++++++++++++++++++++- 1 file changed, 68 insertions(+), 3 deletions(-) diff --git a/mods/ENTITIES/mcl_falling_nodes/init.lua b/mods/ENTITIES/mcl_falling_nodes/init.lua index 1ffc87b34..8f72cc13d 100644 --- a/mods/ENTITIES/mcl_falling_nodes/init.lua +++ b/mods/ENTITIES/mcl_falling_nodes/init.lua @@ -13,9 +13,8 @@ local deal_falling_damage = function(self, dtime) if minetest.get_item_group(self.node.name, "falling_node_damage") == 0 then return end - -- Cause damage to any player it hits. + -- Cause damage to any entity it hits. -- Algorithm based on MC anvils. - -- TODO: Support smashing other objects, too. local pos = self.object:get_pos() if not self._startpos then -- Fallback @@ -23,6 +22,72 @@ local deal_falling_damage = function(self, dtime) end local objs = minetest.get_objects_inside_radius(pos, 1) for _,v in ipairs(objs) do + if v:is_player() then + local hp = v:get_hp() + local name = v:get_player_name() + if hp ~= 0 then + if not self._hit_players then + self._hit_players = {} + end + local hit = false + for _,v in ipairs(self._hit_players) do + if name == v then + hit = true + end + end + if not hit then + table.insert(self._hit_players, name) + local way = self._startpos.y - pos.y + local damage = (way - 1) * 2 + damage = math.min(40, math.max(0, damage)) + if damage >= 1 then + hp = hp - damage + if hp < 0 then + hp = 0 + end + -- TODO: Reduce damage if wearing a helmet + local msg + if minetest.get_item_group(self.node.name, "anvil") ~= 0 then + msg = S("@1 was smashed by a falling anvil.", v:get_player_name()) + else + msg = S("@1 was smashed by a falling block.", v:get_player_name()) + end + if dmes then + mcl_death_messages.player_damage(v, msg) + end + v:set_hp(hp, { type = "punch", from = "mod" }) + end + end + end + else + local hp = v:get_luaentity().health + if hp and hp ~= 0 then + if not self._hit_mobs then + self._hit_mobs = {} + end + local hit = false + for _,mob in ipairs(self._hit_mobs) do + if v == mob then + hit = true + end + end + if not hit then + table.insert(self._hit_mobs, v) + local way = self._startpos.y - pos.y + local damage = (way - 1) * 2 + damage = math.min(40, math.max(0, damage)) + if damage >= 1 then + hp = hp - damage + if hp < 0 then + hp = 0 + end + v:get_luaentity().health = hp + end + end + end + end + end +--[[ for _,v in ipairs(objs) do local hp = v:get_hp() if v:is_player() and hp ~= 0 then if not self._hit_players then @@ -61,7 +126,7 @@ local deal_falling_damage = function(self, dtime) end end end - end + end ]] end minetest.register_entity(":__builtin:falling_node", { From 041300cde4918b5b0b6ee9fec6f411c01fcd9ede Mon Sep 17 00:00:00 2001 From: AFCMS Date: Fri, 26 Mar 2021 17:39:25 +0100 Subject: [PATCH 50/58] remove unuseful code --- mods/ENTITIES/mcl_falling_nodes/init.lua | 40 ------------------------ 1 file changed, 40 deletions(-) diff --git a/mods/ENTITIES/mcl_falling_nodes/init.lua b/mods/ENTITIES/mcl_falling_nodes/init.lua index 8f72cc13d..f173cbade 100644 --- a/mods/ENTITIES/mcl_falling_nodes/init.lua +++ b/mods/ENTITIES/mcl_falling_nodes/init.lua @@ -87,46 +87,6 @@ local deal_falling_damage = function(self, dtime) end end end ---[[ for _,v in ipairs(objs) do - local hp = v:get_hp() - if v:is_player() and hp ~= 0 then - if not self._hit_players then - self._hit_players = {} - end - local name = v:get_player_name() - local hit = false - for _,v in ipairs(self._hit_players) do - if name == v then - hit = true - end - end - if not hit then - table.insert(self._hit_players, name) - local way = self._startpos.y - pos.y - local damage = (way - 1) * 2 - damage = math.min(40, math.max(0, damage)) - if damage >= 1 then - hp = hp - damage - if hp < 0 then - hp = 0 - end - if v:is_player() then - -- TODO: Reduce damage if wearing a helmet - local msg - if minetest.get_item_group(self.node.name, "anvil") ~= 0 then - msg = S("@1 was smashed by a falling anvil.", v:get_player_name()) - else - msg = S("@1 was smashed by a falling block.", v:get_player_name()) - end - if dmes then - mcl_death_messages.player_damage(v, msg) - end - end - v:set_hp(hp, { type = "punch", from = "mod" }) - end - end - end - end ]] end minetest.register_entity(":__builtin:falling_node", { From 6f8d0d4de0a3f5e93557aea40c91e26d4468cc48 Mon Sep 17 00:00:00 2001 From: Elias Fleckenstein Date: Fri, 26 Mar 2021 17:51:13 +0100 Subject: [PATCH 51/58] Fix #1375 --- mods/ENTITIES/mcl_boats/init.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_boats/init.lua b/mods/ENTITIES/mcl_boats/init.lua index 9a9b65cc9..29d5c2256 100644 --- a/mods/ENTITIES/mcl_boats/init.lua +++ b/mods/ENTITIES/mcl_boats/init.lua @@ -247,7 +247,7 @@ function boat.on_step(self, dtime, moveresult) else local ctrl = self._passenger:get_player_control() if ctrl and ctrl.sneak then - detach_player(self._passenger, true) + detach_object(self._passenger, true) self._passenger = nil end end From 8c002671c0e16f805788be2ea2966c4b6712bd2e Mon Sep 17 00:00:00 2001 From: AFCMS Date: Fri, 26 Mar 2021 18:24:08 +0100 Subject: [PATCH 52/58] make helmet protect from falling anvils --- mods/ENTITIES/mcl_falling_nodes/init.lua | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/mods/ENTITIES/mcl_falling_nodes/init.lua b/mods/ENTITIES/mcl_falling_nodes/init.lua index f173cbade..5b94373d9 100644 --- a/mods/ENTITIES/mcl_falling_nodes/init.lua +++ b/mods/ENTITIES/mcl_falling_nodes/init.lua @@ -1,5 +1,8 @@ local S = minetest.get_translator("mcl_falling_nodes") local dmes = minetest.get_modpath("mcl_death_messages") ~= nil +local has_mcl_armor = minetest.get_modpath("mcl_armor") + +local his_creative_enabled = minetest.is_creative_enabled local get_falling_depth = function(self) if not self._startpos then @@ -45,7 +48,16 @@ local deal_falling_damage = function(self, dtime) if hp < 0 then hp = 0 end - -- TODO: Reduce damage if wearing a helmet + -- Reduce damage if wearing a helmet + local inv = v:get_inventory() + local helmet = inv:get_stack("armor", 2) + if has_mcl_armor and not helmet:is_empty() then + hp = hp/4*3 + if not his_creative_enabled(name) then + helmet:add_wear(65535/helmet:get_definition().groups.mcl_armor_uses) --TODO: be sure damage is exactly like mc (informations are missing in the mc wiki) + inv:set_stack("armor", 2, helmet) + end + end local msg if minetest.get_item_group(self.node.name, "anvil") ~= 0 then msg = S("@1 was smashed by a falling anvil.", v:get_player_name()) @@ -71,6 +83,7 @@ local deal_falling_damage = function(self, dtime) hit = true end end + --TODO: reduce damage for mobs then they will be able to wear armor if not hit then table.insert(self._hit_mobs, v) local way = self._startpos.y - pos.y From 202e30a78211a4f44a902e4843baf54a27abb24a Mon Sep 17 00:00:00 2001 From: AFCMS Date: Fri, 26 Mar 2021 21:37:10 +0100 Subject: [PATCH 53/58] Add API to mcl_tmp_message --- mods/HUD/mcl_tmp_message/API.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 mods/HUD/mcl_tmp_message/API.md diff --git a/mods/HUD/mcl_tmp_message/API.md b/mods/HUD/mcl_tmp_message/API.md new file mode 100644 index 000000000..0a3fc06a3 --- /dev/null +++ b/mods/HUD/mcl_tmp_message/API.md @@ -0,0 +1,7 @@ +# mcl_temp_message + +Allow mods to show short messages in the hud of players. + +## mcl_tmp_message.message(player, message) + +Show above the hotbar a hud message to player . \ No newline at end of file From e3c99c5be212e4882257c5ccf7cc971bb36fe4cc Mon Sep 17 00:00:00 2001 From: AFCMS Date: Fri, 26 Mar 2021 22:31:15 +0100 Subject: [PATCH 54/58] add basic API to mcl_throwing remove hard depends to mcl_fishing --- mods/ITEMS/mcl_fishing/init.lua | 48 +++- mods/ITEMS/mcl_fishing/mod.conf | 2 +- mods/ITEMS/mcl_throwing/API.md | 3 + mods/ITEMS/mcl_throwing/init.lua | 398 +-------------------------- mods/ITEMS/mcl_throwing/mod.conf | 2 +- mods/ITEMS/mcl_throwing/register.lua | 335 ++++++++++++++++++++++ 6 files changed, 398 insertions(+), 390 deletions(-) create mode 100644 mods/ITEMS/mcl_throwing/API.md create mode 100644 mods/ITEMS/mcl_throwing/register.lua diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index 1ff56c277..d431ee10c 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -173,7 +173,7 @@ local fish = function(itemstack, player, pointed_thing) if noent == true then local playerpos = player:get_pos() local dir = player:get_look_dir() - local obj = mcl_throwing.throw("mcl_throwing:flying_bobber", {x=playerpos.x, y=playerpos.y+1.5, z=playerpos.z}, dir, 15, player:get_player_name()) + local obj = mcl_throwing.throw("mcl_fishing:flying_bobber", {x=playerpos.x, y=playerpos.y+1.5, z=playerpos.z}, dir, 15, player:get_player_name()) end end @@ -295,6 +295,52 @@ bobber_ENTITY.on_step = bobber_on_step minetest.register_entity("mcl_fishing:bobber_entity", bobber_ENTITY) +local flying_bobber_ENTITY={ + physical = false, + timer=0, + textures = {"mcl_fishing_bobber.png"}, --FIXME: Replace with correct texture. + visual_size = {x=0.5, y=0.5}, + collisionbox = {0,0,0,0,0,0}, + pointable = false, + + get_staticdata = get_staticdata, + on_activate = on_activate, + + _lastpos={}, + _thrower = nil, + objtype="fishing", +} + +-- Movement function of flying bobber +local flying_bobber_on_step = function(self, dtime) + self.timer=self.timer+dtime + local pos = self.object:get_pos() + local node = minetest.get_node(pos) + local def = minetest.registered_nodes[node.name] + --local player = minetest.get_player_by_name(self._thrower) + + -- Destroy when hitting a solid node + if self._lastpos.x~=nil then + if (def and (def.walkable or def.liquidtype == "flowing" or def.liquidtype == "source")) or not def then + local make_child= function(object) + local ent = object:get_luaentity() + ent.player = self._thrower + ent.child = true + end + make_child(minetest.add_entity(self._lastpos, "mcl_fishing:bobber_entity")) + self.object:remove() + return + end + end + self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node +end + +flying_bobber_ENTITY.on_step = flying_bobber_on_step + +minetest.register_entity("mcl_fishing:flying_bobber_entity", flying_bobber_ENTITY) + +mcl_throwing.register_throwable_object("mcl_fishing:flying_bobber", "mcl_fishing:flying_bobber_entity", 5) + -- If player leaves area, remove bobber. minetest.register_on_leaveplayer(function(player) local objs = minetest.get_objects_inside_radius(player:get_pos(), 250) diff --git a/mods/ITEMS/mcl_fishing/mod.conf b/mods/ITEMS/mcl_fishing/mod.conf index 56a3305a0..65c2f68a9 100644 --- a/mods/ITEMS/mcl_fishing/mod.conf +++ b/mods/ITEMS/mcl_fishing/mod.conf @@ -1,3 +1,3 @@ name = mcl_fishing description = Adds fish and fishing poles to go fishing. -depends = mcl_core, mcl_sounds, mcl_loot, mcl_mobs, mcl_enchanting +depends = mcl_core, mcl_sounds, mcl_loot, mcl_mobs, mcl_enchanting, mcl_throwing diff --git a/mods/ITEMS/mcl_throwing/API.md b/mods/ITEMS/mcl_throwing/API.md new file mode 100644 index 000000000..a75a71635 --- /dev/null +++ b/mods/ITEMS/mcl_throwing/API.md @@ -0,0 +1,3 @@ +# mcl_throwing + +## mcl_throwing.throw(throw_item, pos, dir, velocity, thrower) \ No newline at end of file diff --git a/mods/ITEMS/mcl_throwing/init.lua b/mods/ITEMS/mcl_throwing/init.lua index 5fe34b45e..4d6dcfe5c 100644 --- a/mods/ITEMS/mcl_throwing/init.lua +++ b/mods/ITEMS/mcl_throwing/init.lua @@ -2,7 +2,7 @@ mcl_throwing = {} local S = minetest.get_translator("mcl_throwing") local mod_death_messages = minetest.get_modpath("mcl_death_messages") -local mod_fishing = minetest.get_modpath("mcl_fishing") +local modpath = minetest.get_modpath(minetest.get_current_modname()) -- -- Snowballs and other throwable items @@ -10,21 +10,15 @@ local mod_fishing = minetest.get_modpath("mcl_fishing") local GRAVITY = tonumber(minetest.settings:get("movement_gravity")) -local entity_mapping = { - ["mcl_throwing:flying_bobber"] = "mcl_throwing:flying_bobber_entity", - ["mcl_throwing:snowball"] = "mcl_throwing:snowball_entity", - ["mcl_throwing:egg"] = "mcl_throwing:egg_entity", - ["mcl_throwing:ender_pearl"] = "mcl_throwing:ender_pearl_entity", -} +local entity_mapping = {} +local velocities = {} -local velocities = { - ["mcl_throwing:flying_bobber_entity"] = 5, - ["mcl_throwing:snowball_entity"] = 22, - ["mcl_throwing:egg_entity"] = 22, - ["mcl_throwing:ender_pearl_entity"] = 22, -} +function mcl_throwing.register_throwable_object(name, entity, velocity) + entity_mapping[name] = entity + velocities[name] = velocity +end -mcl_throwing.throw = function(throw_item, pos, dir, velocity, thrower) +function mcl_throwing.throw(throw_item, pos, dir, velocity, thrower) if velocity == nil then velocity = velocities[throw_item] end @@ -44,7 +38,7 @@ mcl_throwing.throw = function(throw_item, pos, dir, velocity, thrower) end -- Throw item -local player_throw_function = function(entity_name, velocity) +function mcl_throwing.get_player_throw_function(entity_name, velocity) local func = function(item, player, pointed_thing) local playerpos = player:get_pos() local dir = player:get_look_dir() @@ -57,7 +51,7 @@ local player_throw_function = function(entity_name, velocity) return func end -local dispense_function = function(stack, dispenserpos, droppos, dropnode, dropdir) +function mcl_throwing.dispense_function(stack, dispenserpos, droppos, dropnode, dropdir) -- Launch throwable item local shootpos = vector.add(dispenserpos, vector.multiply(dropdir, 0.51)) mcl_throwing.throw(stack:get_name(), shootpos, dropdir) @@ -85,374 +79,4 @@ local on_activate = function(self, staticdata, dtime_s) end end --- The snowball entity -local snowball_ENTITY={ - physical = false, - timer=0, - textures = {"mcl_throwing_snowball.png"}, - visual_size = {x=0.5, y=0.5}, - collisionbox = {0,0,0,0,0,0}, - pointable = false, - - get_staticdata = get_staticdata, - on_activate = on_activate, - _thrower = nil, - - _lastpos={}, -} -local egg_ENTITY={ - physical = false, - timer=0, - textures = {"mcl_throwing_egg.png"}, - visual_size = {x=0.45, y=0.45}, - collisionbox = {0,0,0,0,0,0}, - pointable = false, - - get_staticdata = get_staticdata, - on_activate = on_activate, - _thrower = nil, - - _lastpos={}, -} --- Ender pearl entity -local pearl_ENTITY={ - physical = false, - timer=0, - textures = {"mcl_throwing_ender_pearl.png"}, - visual_size = {x=0.9, y=0.9}, - collisionbox = {0,0,0,0,0,0}, - pointable = false, - - get_staticdata = get_staticdata, - on_activate = on_activate, - - _lastpos={}, - _thrower = nil, -- Player ObjectRef of the player who threw the ender pearl -} - -local flying_bobber_ENTITY={ - physical = false, - timer=0, - textures = {"mcl_fishing_bobber.png"}, --FIXME: Replace with correct texture. - visual_size = {x=0.5, y=0.5}, - collisionbox = {0,0,0,0,0,0}, - pointable = false, - - get_staticdata = get_staticdata, - on_activate = on_activate, - - _lastpos={}, - _thrower = nil, - objtype="fishing", -} - -local check_object_hit = function(self, pos, dmg) - for _,object in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do - - local entity = object:get_luaentity() - - if entity - and entity.name ~= self.object:get_luaentity().name then - - if object:is_player() and self._thrower ~= object:get_player_name() then - -- TODO: Deal knockback - self.object:remove() - return true - elseif (entity._cmi_is_mob == true or entity._hittable_by_projectile) and (self._thrower ~= object) then - -- FIXME: Knockback is broken - object:punch(self.object, 1.0, { - full_punch_interval = 1.0, - damage_groups = dmg, - }, nil) - return true - end - end - end - return false -end - -local snowball_particles = function(pos, vel) - local vel = vector.normalize(vector.multiply(vel, -1)) - minetest.add_particlespawner({ - amount = 20, - time = 0.001, - minpos = pos, - maxpos = pos, - minvel = vector.add({x=-2, y=3, z=-2}, vel), - maxvel = vector.add({x=2, y=5, z=2}, vel), - minacc = {x=0, y=-9.81, z=0}, - maxacc = {x=0, y=-9.81, z=0}, - minexptime = 1, - maxexptime = 3, - minsize = 0.7, - maxsize = 0.7, - collisiondetection = true, - collision_removal = true, - object_collision = false, - texture = "weather_pack_snow_snowflake"..math.random(1,2)..".png", - }) -end - --- Snowball on_step()--> called when snowball is moving. -local snowball_on_step = function(self, dtime) - self.timer=self.timer+dtime - local pos = self.object:get_pos() - local vel = self.object:get_velocity() - local node = minetest.get_node(pos) - local def = minetest.registered_nodes[node.name] - - - -- Destroy when hitting a solid node - if self._lastpos.x~=nil then - if (def and def.walkable) or not def then - minetest.sound_play("mcl_throwing_snowball_impact_hard", { pos = pos, max_hear_distance=16, gain=0.7 }, true) - snowball_particles(self._lastpos, vel) - self.object:remove() - return - end - end - - if check_object_hit(self, pos, {snowball_vulnerable = 3}) then - minetest.sound_play("mcl_throwing_snowball_impact_soft", { pos = pos, max_hear_distance=16, gain=0.7 }, true) - snowball_particles(pos, vel) - self.object:remove() - return - end - - self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set _lastpos-->Node will be added at last pos outside the node -end - --- Movement function of egg -local egg_on_step = function(self, dtime) - self.timer=self.timer+dtime - local pos = self.object:get_pos() - local node = minetest.get_node(pos) - local def = minetest.registered_nodes[node.name] - - -- Destroy when hitting a solid node with chance to spawn chicks - if self._lastpos.x~=nil then - if (def and def.walkable) or not def then - -- 1/8 chance to spawn a chick - -- FIXME: Chicks have a quite good chance to spawn in walls - local r = math.random(1,8) - - -- Turn given object into a child - local make_child= function(object) - local ent = object:get_luaentity() - object:set_properties({ - visual_size = { x = ent.base_size.x/2, y = ent.base_size.y/2 }, - collisionbox = { - ent.base_colbox[1]/2, - ent.base_colbox[2]/2, - ent.base_colbox[3]/2, - ent.base_colbox[4]/2, - ent.base_colbox[5]/2, - ent.base_colbox[6]/2, - } - }) - ent.child = true - end - if r == 1 then - make_child(minetest.add_entity(self._lastpos, "mobs_mc:chicken")) - - -- BONUS ROUND: 1/32 chance to spawn 3 additional chicks - local r = math.random(1,32) - if r == 1 then - local offsets = { - { x=0.7, y=0, z=0 }, - { x=-0.7, y=0, z=-0.7 }, - { x=-0.7, y=0, z=0.7 }, - } - for o=1, 3 do - local pos = vector.add(self._lastpos, offsets[o]) - make_child(minetest.add_entity(pos, "mobs_mc:chicken")) - end - end - end - minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) - self.object:remove() - return - end - end - - -- Destroy when hitting a mob or player (no chick spawning) - if check_object_hit(self, pos) then - minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) - self.object:remove() - return - end - - self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node -end - --- Movement function of ender pearl -local pearl_on_step = function(self, dtime) - self.timer=self.timer+dtime - local pos = self.object:get_pos() - pos.y = math.floor(pos.y) - local node = minetest.get_node(pos) - local nn = node.name - local def = minetest.registered_nodes[node.name] - - -- Destroy when hitting a solid node - if self._lastpos.x~=nil then - local walkable = (def and def.walkable) - - -- No teleport for hitting ignore for now. Otherwise the player could get stuck. - -- FIXME: This also means the player loses an ender pearl for throwing into unloaded areas - if node.name == "ignore" then - self.object:remove() - -- Activate when hitting a solid node or a plant - elseif walkable or nn == "mcl_core:vine" or nn == "mcl_core:deadbush" or minetest.get_item_group(nn, "flower") ~= 0 or minetest.get_item_group(nn, "sapling") ~= 0 or minetest.get_item_group(nn, "plant") ~= 0 or minetest.get_item_group(nn, "mushroom") ~= 0 or not def then - local player = minetest.get_player_by_name(self._thrower) - if player then - -- Teleport and hurt player - - -- First determine good teleport position - local dir = {x=0, y=0, z=0} - - local v = self.object:get_velocity() - if walkable then - local vc = table.copy(v) -- vector for calculating - -- Node is walkable, we have to find a place somewhere outside of that node - vc = vector.normalize(vc) - - -- Zero-out the two axes with a lower absolute value than - -- the axis with the strongest force - local lv, ld - lv, ld = math.abs(vc.y), "y" - if math.abs(vc.x) > lv then - lv, ld = math.abs(vc.x), "x" - end - if math.abs(vc.z) > lv then - lv, ld = math.abs(vc.z), "z" - end - if ld ~= "x" then vc.x = 0 end - if ld ~= "y" then vc.y = 0 end - if ld ~= "z" then vc.z = 0 end - - -- Final tweaks to the teleporting pos, based on direction - -- Impact from the side - dir.x = vc.x * -1 - dir.z = vc.z * -1 - - -- Special case: top or bottom of node - if vc.y > 0 then - -- We need more space when impact is from below - dir.y = -2.3 - elseif vc.y < 0 then - -- Standing on top - dir.y = 0.5 - end - end - -- If node was not walkable, no modification to pos is made. - - -- Final teleportation position - local telepos = vector.add(pos, dir) - local telenode = minetest.get_node(telepos) - - --[[ It may be possible that telepos is walkable due to the algorithm. - Especially when the ender pearl is faster horizontally than vertical. - This applies final fixing, just to be sure we're not in a walkable node ]] - if not minetest.registered_nodes[telenode.name] or minetest.registered_nodes[telenode.name].walkable then - if v.y < 0 then - telepos.y = telepos.y + 0.5 - else - telepos.y = telepos.y - 2.3 - end - end - - local oldpos = player:get_pos() - -- Teleport and hurt player - player:set_pos(telepos) - player:set_hp(player:get_hp() - 5, { type = "fall", from = "mod" }) - - -- 5% chance to spawn endermite at the player's origin - local r = math.random(1,20) - if r == 1 then - minetest.add_entity(oldpos, "mobs_mc:endermite") - end - - end - self.object:remove() - return - end - end - self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node -end - --- Movement function of flying bobber -local flying_bobber_on_step = function(self, dtime) - self.timer=self.timer+dtime - local pos = self.object:get_pos() - local node = minetest.get_node(pos) - local def = minetest.registered_nodes[node.name] - --local player = minetest.get_player_by_name(self._thrower) - - -- Destroy when hitting a solid node - if self._lastpos.x~=nil then - if (def and (def.walkable or def.liquidtype == "flowing" or def.liquidtype == "source")) or not def then - local make_child= function(object) - local ent = object:get_luaentity() - ent.player = self._thrower - ent.child = true - end - make_child(minetest.add_entity(self._lastpos, "mcl_fishing:bobber_entity")) - self.object:remove() - return - end - end - self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node -end - -snowball_ENTITY.on_step = snowball_on_step -egg_ENTITY.on_step = egg_on_step -pearl_ENTITY.on_step = pearl_on_step -flying_bobber_ENTITY.on_step = flying_bobber_on_step - -minetest.register_entity("mcl_throwing:snowball_entity", snowball_ENTITY) -minetest.register_entity("mcl_throwing:egg_entity", egg_ENTITY) -minetest.register_entity("mcl_throwing:ender_pearl_entity", pearl_ENTITY) -minetest.register_entity("mcl_throwing:flying_bobber_entity", flying_bobber_ENTITY) - -local how_to_throw = S("Use the punch key to throw.") - --- Snowball -minetest.register_craftitem("mcl_throwing:snowball", { - description = S("Snowball"), - _tt_help = S("Throwable"), - _doc_items_longdesc = S("Snowballs can be thrown or launched from a dispenser for fun. Hitting something with a snowball does nothing."), - _doc_items_usagehelp = how_to_throw, - inventory_image = "mcl_throwing_snowball.png", - stack_max = 16, - groups = { weapon_ranged = 1 }, - on_use = player_throw_function("mcl_throwing:snowball_entity"), - _on_dispense = dispense_function, -}) - --- Egg -minetest.register_craftitem("mcl_throwing:egg", { - description = S("Egg"), - _tt_help = S("Throwable").."\n"..S("Chance to hatch chicks when broken"), - _doc_items_longdesc = S("Eggs can be thrown or launched from a dispenser and breaks on impact. There is a small chance that 1 or even 4 chicks will pop out of the egg."), - _doc_items_usagehelp = how_to_throw, - inventory_image = "mcl_throwing_egg.png", - stack_max = 16, - on_use = player_throw_function("mcl_throwing:egg_entity"), - _on_dispense = dispense_function, - groups = { craftitem = 1 }, -}) - --- Ender Pearl -minetest.register_craftitem("mcl_throwing:ender_pearl", { - description = S("Ender Pearl"), - _tt_help = S("Throwable").."\n"..minetest.colorize("#FFFF00", S("Teleports you on impact for cost of 5 HP")), - _doc_items_longdesc = S("An ender pearl is an item which can be used for teleportation at the cost of health. It can be thrown and teleport the thrower to its impact location when it hits a solid block or a plant. Each teleportation hurts the user by 5 hit points."), - _doc_items_usagehelp = how_to_throw, - wield_image = "mcl_throwing_ender_pearl.png", - inventory_image = "mcl_throwing_ender_pearl.png", - stack_max = 16, - on_use = player_throw_function("mcl_throwing:ender_pearl_entity"), - groups = { transport = 1 }, -}) - +dofile(modpath.."/register.lua") \ No newline at end of file diff --git a/mods/ITEMS/mcl_throwing/mod.conf b/mods/ITEMS/mcl_throwing/mod.conf index 4bfc2efb5..60d3e31a7 100644 --- a/mods/ITEMS/mcl_throwing/mod.conf +++ b/mods/ITEMS/mcl_throwing/mod.conf @@ -1,3 +1,3 @@ name = mcl_throwing -depends = mcl_fishing +depends = mcl_colors optional_depends = mcl_core, mcl_mobitems, doc diff --git a/mods/ITEMS/mcl_throwing/register.lua b/mods/ITEMS/mcl_throwing/register.lua new file mode 100644 index 000000000..eace01612 --- /dev/null +++ b/mods/ITEMS/mcl_throwing/register.lua @@ -0,0 +1,335 @@ +local S = minetest.get_translator(minetest.get_current_modname()) + +-- The snowball entity +local snowball_ENTITY={ + physical = false, + timer=0, + textures = {"mcl_throwing_snowball.png"}, + visual_size = {x=0.5, y=0.5}, + collisionbox = {0,0,0,0,0,0}, + pointable = false, + + get_staticdata = get_staticdata, + on_activate = on_activate, + _thrower = nil, + + _lastpos={}, +} +local egg_ENTITY={ + physical = false, + timer=0, + textures = {"mcl_throwing_egg.png"}, + visual_size = {x=0.45, y=0.45}, + collisionbox = {0,0,0,0,0,0}, + pointable = false, + + get_staticdata = get_staticdata, + on_activate = on_activate, + _thrower = nil, + + _lastpos={}, +} +-- Ender pearl entity +local pearl_ENTITY={ + physical = false, + timer=0, + textures = {"mcl_throwing_ender_pearl.png"}, + visual_size = {x=0.9, y=0.9}, + collisionbox = {0,0,0,0,0,0}, + pointable = false, + + get_staticdata = get_staticdata, + on_activate = on_activate, + + _lastpos={}, + _thrower = nil, -- Player ObjectRef of the player who threw the ender pearl +} + +local check_object_hit = function(self, pos, dmg) + for _,object in pairs(minetest.get_objects_inside_radius(pos, 1.5)) do + + local entity = object:get_luaentity() + + if entity + and entity.name ~= self.object:get_luaentity().name then + + if object:is_player() and self._thrower ~= object:get_player_name() then + -- TODO: Deal knockback + self.object:remove() + return true + elseif (entity._cmi_is_mob == true or entity._hittable_by_projectile) and (self._thrower ~= object) then + -- FIXME: Knockback is broken + object:punch(self.object, 1.0, { + full_punch_interval = 1.0, + damage_groups = dmg, + }, nil) + return true + end + end + end + return false +end + +local snowball_particles = function(pos, vel) + local vel = vector.normalize(vector.multiply(vel, -1)) + minetest.add_particlespawner({ + amount = 20, + time = 0.001, + minpos = pos, + maxpos = pos, + minvel = vector.add({x=-2, y=3, z=-2}, vel), + maxvel = vector.add({x=2, y=5, z=2}, vel), + minacc = {x=0, y=-9.81, z=0}, + maxacc = {x=0, y=-9.81, z=0}, + minexptime = 1, + maxexptime = 3, + minsize = 0.7, + maxsize = 0.7, + collisiondetection = true, + collision_removal = true, + object_collision = false, + texture = "weather_pack_snow_snowflake"..math.random(1,2)..".png", + }) +end + +-- Snowball on_step()--> called when snowball is moving. +local snowball_on_step = function(self, dtime) + self.timer=self.timer+dtime + local pos = self.object:get_pos() + local vel = self.object:get_velocity() + local node = minetest.get_node(pos) + local def = minetest.registered_nodes[node.name] + + + -- Destroy when hitting a solid node + if self._lastpos.x~=nil then + if (def and def.walkable) or not def then + minetest.sound_play("mcl_throwing_snowball_impact_hard", { pos = pos, max_hear_distance=16, gain=0.7 }, true) + snowball_particles(self._lastpos, vel) + self.object:remove() + return + end + end + + if check_object_hit(self, pos, {snowball_vulnerable = 3}) then + minetest.sound_play("mcl_throwing_snowball_impact_soft", { pos = pos, max_hear_distance=16, gain=0.7 }, true) + snowball_particles(pos, vel) + self.object:remove() + return + end + + self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set _lastpos-->Node will be added at last pos outside the node +end + +-- Movement function of egg +local egg_on_step = function(self, dtime) + self.timer=self.timer+dtime + local pos = self.object:get_pos() + local node = minetest.get_node(pos) + local def = minetest.registered_nodes[node.name] + + -- Destroy when hitting a solid node with chance to spawn chicks + if self._lastpos.x~=nil then + if (def and def.walkable) or not def then + -- 1/8 chance to spawn a chick + -- FIXME: Chicks have a quite good chance to spawn in walls + local r = math.random(1,8) + + -- Turn given object into a child + local make_child= function(object) + local ent = object:get_luaentity() + object:set_properties({ + visual_size = { x = ent.base_size.x/2, y = ent.base_size.y/2 }, + collisionbox = { + ent.base_colbox[1]/2, + ent.base_colbox[2]/2, + ent.base_colbox[3]/2, + ent.base_colbox[4]/2, + ent.base_colbox[5]/2, + ent.base_colbox[6]/2, + } + }) + ent.child = true + end + if r == 1 then + make_child(minetest.add_entity(self._lastpos, "mobs_mc:chicken")) + + -- BONUS ROUND: 1/32 chance to spawn 3 additional chicks + local r = math.random(1,32) + if r == 1 then + local offsets = { + { x=0.7, y=0, z=0 }, + { x=-0.7, y=0, z=-0.7 }, + { x=-0.7, y=0, z=0.7 }, + } + for o=1, 3 do + local pos = vector.add(self._lastpos, offsets[o]) + make_child(minetest.add_entity(pos, "mobs_mc:chicken")) + end + end + end + minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) + self.object:remove() + return + end + end + + -- Destroy when hitting a mob or player (no chick spawning) + if check_object_hit(self, pos) then + minetest.sound_play("mcl_throwing_egg_impact", { pos = self.object:get_pos(), max_hear_distance=10, gain=0.5 }, true) + self.object:remove() + return + end + + self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node +end + +-- Movement function of ender pearl +local pearl_on_step = function(self, dtime) + self.timer=self.timer+dtime + local pos = self.object:get_pos() + pos.y = math.floor(pos.y) + local node = minetest.get_node(pos) + local nn = node.name + local def = minetest.registered_nodes[node.name] + + -- Destroy when hitting a solid node + if self._lastpos.x~=nil then + local walkable = (def and def.walkable) + + -- No teleport for hitting ignore for now. Otherwise the player could get stuck. + -- FIXME: This also means the player loses an ender pearl for throwing into unloaded areas + if node.name == "ignore" then + self.object:remove() + -- Activate when hitting a solid node or a plant + elseif walkable or nn == "mcl_core:vine" or nn == "mcl_core:deadbush" or minetest.get_item_group(nn, "flower") ~= 0 or minetest.get_item_group(nn, "sapling") ~= 0 or minetest.get_item_group(nn, "plant") ~= 0 or minetest.get_item_group(nn, "mushroom") ~= 0 or not def then + local player = minetest.get_player_by_name(self._thrower) + if player then + -- Teleport and hurt player + + -- First determine good teleport position + local dir = {x=0, y=0, z=0} + + local v = self.object:get_velocity() + if walkable then + local vc = table.copy(v) -- vector for calculating + -- Node is walkable, we have to find a place somewhere outside of that node + vc = vector.normalize(vc) + + -- Zero-out the two axes with a lower absolute value than + -- the axis with the strongest force + local lv, ld + lv, ld = math.abs(vc.y), "y" + if math.abs(vc.x) > lv then + lv, ld = math.abs(vc.x), "x" + end + if math.abs(vc.z) > lv then + lv, ld = math.abs(vc.z), "z" + end + if ld ~= "x" then vc.x = 0 end + if ld ~= "y" then vc.y = 0 end + if ld ~= "z" then vc.z = 0 end + + -- Final tweaks to the teleporting pos, based on direction + -- Impact from the side + dir.x = vc.x * -1 + dir.z = vc.z * -1 + + -- Special case: top or bottom of node + if vc.y > 0 then + -- We need more space when impact is from below + dir.y = -2.3 + elseif vc.y < 0 then + -- Standing on top + dir.y = 0.5 + end + end + -- If node was not walkable, no modification to pos is made. + + -- Final teleportation position + local telepos = vector.add(pos, dir) + local telenode = minetest.get_node(telepos) + + --[[ It may be possible that telepos is walkable due to the algorithm. + Especially when the ender pearl is faster horizontally than vertical. + This applies final fixing, just to be sure we're not in a walkable node ]] + if not minetest.registered_nodes[telenode.name] or minetest.registered_nodes[telenode.name].walkable then + if v.y < 0 then + telepos.y = telepos.y + 0.5 + else + telepos.y = telepos.y - 2.3 + end + end + + local oldpos = player:get_pos() + -- Teleport and hurt player + player:set_pos(telepos) + player:set_hp(player:get_hp() - 5, { type = "fall", from = "mod" }) + + -- 5% chance to spawn endermite at the player's origin + local r = math.random(1,20) + if r == 1 then + minetest.add_entity(oldpos, "mobs_mc:endermite") + end + + end + self.object:remove() + return + end + end + self._lastpos={x=pos.x, y=pos.y, z=pos.z} -- Set lastpos-->Node will be added at last pos outside the node +end + +snowball_ENTITY.on_step = snowball_on_step +egg_ENTITY.on_step = egg_on_step +pearl_ENTITY.on_step = pearl_on_step + +minetest.register_entity("mcl_throwing:snowball_entity", snowball_ENTITY) +minetest.register_entity("mcl_throwing:egg_entity", egg_ENTITY) +minetest.register_entity("mcl_throwing:ender_pearl_entity", pearl_ENTITY) + + +local how_to_throw = S("Use the punch key to throw.") + +-- Snowball +minetest.register_craftitem("mcl_throwing:snowball", { + description = S("Snowball"), + _tt_help = S("Throwable"), + _doc_items_longdesc = S("Snowballs can be thrown or launched from a dispenser for fun. Hitting something with a snowball does nothing."), + _doc_items_usagehelp = how_to_throw, + inventory_image = "mcl_throwing_snowball.png", + stack_max = 16, + groups = { weapon_ranged = 1 }, + on_use = mcl_throwing.get_player_throw_function("mcl_throwing:snowball_entity"), + _on_dispense = mcl_throwing.dispense_function, +}) + +-- Egg +minetest.register_craftitem("mcl_throwing:egg", { + description = S("Egg"), + _tt_help = S("Throwable").."\n"..S("Chance to hatch chicks when broken"), + _doc_items_longdesc = S("Eggs can be thrown or launched from a dispenser and breaks on impact. There is a small chance that 1 or even 4 chicks will pop out of the egg."), + _doc_items_usagehelp = how_to_throw, + inventory_image = "mcl_throwing_egg.png", + stack_max = 16, + on_use = mcl_throwing.get_player_throw_function("mcl_throwing:egg_entity"), + _on_dispense = mcl_throwing.dispense_function, + groups = { craftitem = 1 }, +}) + +-- Ender Pearl +minetest.register_craftitem("mcl_throwing:ender_pearl", { + description = S("Ender Pearl"), + _tt_help = S("Throwable").."\n"..minetest.colorize("#FFFF00", S("Teleports you on impact for cost of 5 HP")), + _doc_items_longdesc = S("An ender pearl is an item which can be used for teleportation at the cost of health. It can be thrown and teleport the thrower to its impact location when it hits a solid block or a plant. Each teleportation hurts the user by 5 hit points."), + _doc_items_usagehelp = how_to_throw, + wield_image = "mcl_throwing_ender_pearl.png", + inventory_image = "mcl_throwing_ender_pearl.png", + stack_max = 16, + on_use = mcl_throwing.get_player_throw_function("mcl_throwing:ender_pearl_entity"), + groups = { transport = 1 }, +}) + +mcl_throwing.register_throwable_object("mcl_throwing:snowball", "mcl_throwing:snowball_entity", 22) +mcl_throwing.register_throwable_object("mcl_throwing:egg", "mcl_throwing:egg_entity", 22) +mcl_throwing.register_throwable_object("mcl_throwing:ender_pearl", "mcl_throwing:ender_pearl_entity", 22) From e11941c107fb9418ed91c23dcced84fd1853c249 Mon Sep 17 00:00:00 2001 From: AFCMS Date: Fri, 26 Mar 2021 22:43:18 +0100 Subject: [PATCH 55/58] Add API documentation for mcl_throwing --- mods/ITEMS/mcl_throwing/API.md | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_throwing/API.md b/mods/ITEMS/mcl_throwing/API.md index a75a71635..f2b1c7374 100644 --- a/mods/ITEMS/mcl_throwing/API.md +++ b/mods/ITEMS/mcl_throwing/API.md @@ -1,3 +1,35 @@ # mcl_throwing -## mcl_throwing.throw(throw_item, pos, dir, velocity, thrower) \ No newline at end of file +## mcl_throwing.throw(throw_item, pos, dir, velocity, thrower) +Throw a throwable item. + +* throw_item: itemstring of the throwable item +* pos: initial position of the entity +* dir: direction where the throwable item will be thrown +* velocity: (optional) will overide the default velocity value (can be nil) +* thrower: (optional) player/entity who throw the object (can be nil) + +## mcl_throwing.register_throwable_object(name, entity, velocity) +Register a throwable item. + +* name: itemname of the throwable object +* entity: entity thrown +* velocity: initial velocity of the entity + +## mcl_throwing.dispense_function(stack, dispenserpos, droppos, dropnode, dropdir) +Throw throwable item from dispencer. + +Shouldn't be called directly. + +Must be used in item definition: + +`_on_dispense = mcl_throwing.dispense_function,` + +## mcl_throwing.get_player_throw_function(entity_name, velocity) + +Return a function who handle item throwing (to be used in item definition) + +Handle creative mode, and throw params. + +* entity_name: the name of the entity to throw +* velocity: (optional) velocity overide (can be nil) From e2adead7003f43fba70a9ea6522030bf64ec2106 Mon Sep 17 00:00:00 2001 From: AFCMS Date: Fri, 26 Mar 2021 22:50:37 +0100 Subject: [PATCH 56/58] use proper colors --- mods/ITEMS/mcl_fishing/init.lua | 2 +- mods/ITEMS/mcl_fishing/mod.conf | 2 +- mods/ITEMS/mcl_throwing/register.lua | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mods/ITEMS/mcl_fishing/init.lua b/mods/ITEMS/mcl_fishing/init.lua index d431ee10c..228d490ea 100644 --- a/mods/ITEMS/mcl_fishing/init.lua +++ b/mods/ITEMS/mcl_fishing/init.lua @@ -495,7 +495,7 @@ minetest.register_craftitem("mcl_fishing:clownfish_raw", { minetest.register_craftitem("mcl_fishing:pufferfish_raw", { description = S("Pufferfish"), - _tt_help = minetest.colorize("#FFFF00", S("Very poisonous")), + _tt_help = minetest.colorize(mcl_colors.YELLOW, S("Very poisonous")), _doc_items_longdesc = S("Pufferfish are a common species of fish and can be obtained by fishing. They can technically be eaten, but they are very bad for humans. Eating a pufferfish only restores 1 hunger point and will poison you very badly (which drains your health non-fatally) and causes serious food poisoning (which increases your hunger)."), inventory_image = "mcl_fishing_pufferfish_raw.png", on_place = minetest.item_eat(1), diff --git a/mods/ITEMS/mcl_fishing/mod.conf b/mods/ITEMS/mcl_fishing/mod.conf index 65c2f68a9..c4e5f5f2e 100644 --- a/mods/ITEMS/mcl_fishing/mod.conf +++ b/mods/ITEMS/mcl_fishing/mod.conf @@ -1,3 +1,3 @@ name = mcl_fishing description = Adds fish and fishing poles to go fishing. -depends = mcl_core, mcl_sounds, mcl_loot, mcl_mobs, mcl_enchanting, mcl_throwing +depends = mcl_core, mcl_sounds, mcl_loot, mcl_mobs, mcl_enchanting, mcl_throwing, mcl_colors diff --git a/mods/ITEMS/mcl_throwing/register.lua b/mods/ITEMS/mcl_throwing/register.lua index eace01612..027ff4e93 100644 --- a/mods/ITEMS/mcl_throwing/register.lua +++ b/mods/ITEMS/mcl_throwing/register.lua @@ -320,7 +320,7 @@ minetest.register_craftitem("mcl_throwing:egg", { -- Ender Pearl minetest.register_craftitem("mcl_throwing:ender_pearl", { description = S("Ender Pearl"), - _tt_help = S("Throwable").."\n"..minetest.colorize("#FFFF00", S("Teleports you on impact for cost of 5 HP")), + _tt_help = S("Throwable").."\n"..minetest.colorize(mcl_colors.YELLOW, S("Teleports you on impact for cost of 5 HP")), _doc_items_longdesc = S("An ender pearl is an item which can be used for teleportation at the cost of health. It can be thrown and teleport the thrower to its impact location when it hits a solid block or a plant. Each teleportation hurts the user by 5 hit points."), _doc_items_usagehelp = how_to_throw, wield_image = "mcl_throwing_ender_pearl.png", From e2fd0823b95af552c34d15af6a7d362e31649803 Mon Sep 17 00:00:00 2001 From: AFCMS Date: Sat, 27 Mar 2021 07:10:50 +0100 Subject: [PATCH 57/58] Fix #1398 --- mods/ITEMS/mcl_anvils/init.lua | 2 -- 1 file changed, 2 deletions(-) diff --git a/mods/ITEMS/mcl_anvils/init.lua b/mods/ITEMS/mcl_anvils/init.lua index 4495fb618..c3c238e7f 100644 --- a/mods/ITEMS/mcl_anvils/init.lua +++ b/mods/ITEMS/mcl_anvils/init.lua @@ -488,7 +488,6 @@ S("The anvil has limited durability and 3 damage levels: undamaged, slightly dam local anvildef1 = table.copy(anvildef) anvildef1.description = S("Slightly Damaged Anvil") anvildef1._doc_items_create_entry = false -anvildef1.groups.not_in_creative_inventory = 1 anvildef1.groups.anvil = 2 anvildef1._doc_items_create_entry = false anvildef1.tiles = {"mcl_anvils_anvil_top_damaged_1.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png"} @@ -496,7 +495,6 @@ anvildef1.tiles = {"mcl_anvils_anvil_top_damaged_1.png^[transformR90", "mcl_anvi local anvildef2 = table.copy(anvildef) anvildef2.description = S("Very Damaged Anvil") anvildef2._doc_items_create_entry = false -anvildef2.groups.not_in_creative_inventory = 1 anvildef2.groups.anvil = 3 anvildef2._doc_items_create_entry = false anvildef2.tiles = {"mcl_anvils_anvil_top_damaged_2.png^[transformR90", "mcl_anvils_anvil_base.png", "mcl_anvils_anvil_side.png"} From 61c9d065fb4c4836f930c8587ef378603c7a43cb Mon Sep 17 00:00:00 2001 From: AFCMS Date: Sat, 27 Mar 2021 07:19:35 +0100 Subject: [PATCH 58/58] =?UTF-8?q?Fix=20=C2=A0#1400?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- mods/ITEMS/mcl_end/eye_of_ender.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mods/ITEMS/mcl_end/eye_of_ender.lua b/mods/ITEMS/mcl_end/eye_of_ender.lua index 16f1c906b..afac9ebfc 100644 --- a/mods/ITEMS/mcl_end/eye_of_ender.lua +++ b/mods/ITEMS/mcl_end/eye_of_ender.lua @@ -29,7 +29,7 @@ minetest.register_entity("mcl_end:ender_eye", { if self._age >= 3 then -- End of life local r = math.random(1,5) - if r == 1 or minetest.is_creative_enabled("") then + if r == 1 then -- 20% chance to get destroyed completely. -- 100% if in Creative Mode self.object:remove()