From 8f7a020a0d34ad638b66bc468cdadb401bd9ac78 Mon Sep 17 00:00:00 2001 From: teknomunk Date: Sun, 22 Sep 2024 07:04:20 -0500 Subject: [PATCH] Fix player-mcl_throwing collisions, fix chick spawning on egg collisions, luacheck fixes --- mods/ITEMS/mcl_throwing/egg.lua | 40 ++++-- mods/ITEMS/mcl_throwing/ender_pearl.lua | 166 +++++++++++++----------- mods/ITEMS/mcl_throwing/snowball.lua | 8 +- 3 files changed, 122 insertions(+), 92 deletions(-) diff --git a/mods/ITEMS/mcl_throwing/egg.lua b/mods/ITEMS/mcl_throwing/egg.lua index aa4adcef8..411afc4a2 100644 --- a/mods/ITEMS/mcl_throwing/egg.lua +++ b/mods/ITEMS/mcl_throwing/egg.lua @@ -17,6 +17,24 @@ minetest.register_craftitem("mcl_throwing:egg", { groups = { craftitem = 1 }, }) +local function egg_spawn_chicks(pos) + -- 1/8 chance to spawn a chick + if math.random(1,8) ~= 1 then return end + + pos.y = math.ceil(pos.y) + + if not mcl_mobs.spawn_child(pos, "mobs_mc:chicken") then + minetest.log("unable to spawn chick at "..vector.to_string(pos)) + end + + -- BONUS ROUND: 1/32 chance to spawn 3 additional chicks + if math.random(1,32) ~= 1 then return end + + mcl_mobs.spawn_child(vector.offset(pos, 0.7, 0, 0 ), "mobs_mc:chicken") + mcl_mobs.spawn_child(vector.offset(pos, -0.7, 0, -0.7), "mobs_mc:chicken") + mcl_mobs.spawn_child(vector.offset(pos, -0.7, 0, 0.7), "mobs_mc:chicken") +end + minetest.register_entity("mcl_throwing:egg_entity",{ physical = false, timer=0, @@ -34,24 +52,22 @@ minetest.register_entity("mcl_throwing:egg_entity",{ _vl_projectile = { behaviors = { vl_projectile.collides_with_solids, + vl_projectile.collides_with_entities, }, + allow_punching = function(self, _, _, object) + if self._owner == object:get_player_name() then + return self.timer > 1 + end + end, on_collide_with_solid = function(self, pos, node) if mod_target and node.name == "mcl_target:target_off" then mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks end - -- 1/8 chance to spawn a chick - -- FIXME: Chicks have a quite good chance to spawn in walls - if math.random(1,8) ~= 1 then return end - - mcl_mobs.spawn_child(pos, "mobs_mc:chicken") - - -- BONUS ROUND: 1/32 chance to spawn 3 additional chicks - if math.random(1,32) ~= 1 then return end - - mcl_mobs.spawn_child(vector.offset(pos, 0.7, 0, 0 ), "mobs_mc:chicken") - mcl_mobs.spawn_child(vector.offset(pos, -0.7, 0, -0.7), "mobs_mc:chicken") - mcl_mobs.spawn_child(vector.offset(pos, -0.7, 0, 0.7), "mobs_mc:chicken") + egg_spawn_chicks(pos) + end, + on_collide_with_entity = function(self, pos, obj) + egg_spawn_chicks(pos) end, sounds = { on_collision = {"mcl_throwing_egg_impact", {max_hear_distance=10, gain=0.5}, true} diff --git a/mods/ITEMS/mcl_throwing/ender_pearl.lua b/mods/ITEMS/mcl_throwing/ender_pearl.lua index 36de0fb27..9e48422db 100644 --- a/mods/ITEMS/mcl_throwing/ender_pearl.lua +++ b/mods/ITEMS/mcl_throwing/ender_pearl.lua @@ -1,5 +1,4 @@ local modname = minetest.get_current_modname() -local modpath = minetest.get_modpath(modname) local S = minetest.get_translator(modname) local math = math @@ -21,6 +20,85 @@ minetest.register_craftitem("mcl_throwing:ender_pearl", { groups = { transport = 1 }, }) +function on_collide(self, pos, node) + if mod_target and node.name == "mcl_target:target_off" then + mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + end + + if node.name == "ignore" then + -- FIXME: This also means the player loses an ender pearl for throwing into unloaded areas + return + end + + -- Make sure we have a reference to the player + local player = self._thrower and minetest.get_player_by_name(self._thrower) + if not player then return end + + -- Teleport and hurt player + + -- First determine good teleport position + local dir = vector.zero() + + local v = self.object:get_velocity() + local node_def = minetest.registered_nodes[node.name] + if node_def and node_def.walkable then + local vc = vector.normalize(v) -- vector for calculating + -- Node is walkable, we have to find a place somewhere outside of that node + + -- Zero-out the two axes with a lower absolute value than the axis with the strongest force + local 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 + ld = "z" --math.abs(vc.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 + if math.random(1,20) == 1 then + minetest.add_entity(oldpos, "mobs_mc:endermite") + end +end + -- Ender pearl entity vl_projectile.register("mcl_throwing:ender_pearl_entity",{ physical = false, @@ -39,90 +117,22 @@ vl_projectile.register("mcl_throwing:ender_pearl_entity",{ _vl_projectile = { behaviors = { vl_projectile.collides_with_solids, + vl_projectile.collides_with_entities, }, collides_with = { "mcl_core:vine", "mcl_core:deadbush", "group:flower", "group:sapling", "group:plant", "group:mushroom", }, - on_collide_with_solid = function(self, pos, node) - if mod_target and node.name == "mcl_target:target_off" then - mcl_target.hit(vector.round(pos), 0.4) --4 redstone ticks + allow_punching = function(self, _, _, object) + if self._owner == object:get_player_name() then + return self.timer > 1 end - - if node.name == "ignore" then - -- FIXME: This also means the player loses an ender pearl for throwing into unloaded areas - return - end - - -- Make sure we have a reference to the player - local player = self._thrower and minetest.get_player_by_name(self._thrower) - if not player then return end - - -- Teleport and hurt player - - -- First determine good teleport position - local dir = vector.zero() - - local v = self.object:get_velocity() - local node_def = minetest.registered_nodes[node.name] - if node_def and node_def.walkable then - local vc = vector.normalize(v) -- vector for calculating - -- Node is walkable, we have to find a place somewhere outside of that node - - -- Zero-out the two axes with a lower absolute value than the axis with the strongest force - local 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 - ld = "z" --math.abs(vc.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 - if math.random(1,20) == 1 then - minetest.add_entity(oldpos, "mobs_mc:endermite") - end - end + end, + on_collide_with_entity = function(self, pos, entity) + on_collide(self, pos, minetest.get_node(pos)) + end, + on_collide_with_solid = on_collide, }, }) mcl_throwing.register_throwable_object("mcl_throwing:ender_pearl", "mcl_throwing:ender_pearl_entity", 22) diff --git a/mods/ITEMS/mcl_throwing/snowball.lua b/mods/ITEMS/mcl_throwing/snowball.lua index a0a5a2f36..ed64feb8a 100644 --- a/mods/ITEMS/mcl_throwing/snowball.lua +++ b/mods/ITEMS/mcl_throwing/snowball.lua @@ -1,6 +1,7 @@ local modname = minetest.get_current_modname() local S = minetest.get_translator(modname) +local mod_target = minetest.get_modpath("mcl_target") local how_to_throw = S("Use the punch key to throw.") -- Snowball @@ -54,8 +55,11 @@ vl_projectile.register("mcl_throwing:snowball_entity", { vl_projectile.collides_with_entities, }, allow_punching = function(self, _, _, object) - return object.is_mob or object._hittable_by_projectile or - not object:is_player() or self._owner ~= object:get_player_name() + if self._owner == object:get_player_name() then + return self.timer > 1 + end + + return object.is_mob or object._hittable_by_projectile or object:is_player() end, on_collide_with_solid = function(self, pos, node) if mod_target and node.name == "mcl_target:target_off" then