From 6cedcc7b84371d18ec3a4733f4a98fb1018ab7de Mon Sep 17 00:00:00 2001 From: philipmi Date: Thu, 3 Jun 2021 15:19:35 +0200 Subject: [PATCH] Add playerplus mod --- mods/other/playerplus/README.md | 63 +++++ mods/other/playerplus/depends.txt | 4 + mods/other/playerplus/description.txt | 1 + mods/other/playerplus/init.lua | 324 +++++++++++++++++++++++ mods/other/playerplus/license.txt | 21 ++ mods/other/playerplus/mod.conf | 4 + mods/other/playerplus/screenshot.png | Bin 0 -> 7273 bytes mods/other/playerplus/settingtypes.txt | 4 + mods/other/playerplus/textures/trans.png | Bin 0 -> 75 bytes 9 files changed, 421 insertions(+) create mode 100644 mods/other/playerplus/README.md create mode 100644 mods/other/playerplus/depends.txt create mode 100644 mods/other/playerplus/description.txt create mode 100644 mods/other/playerplus/init.lua create mode 100644 mods/other/playerplus/license.txt create mode 100644 mods/other/playerplus/mod.conf create mode 100644 mods/other/playerplus/screenshot.png create mode 100644 mods/other/playerplus/settingtypes.txt create mode 100644 mods/other/playerplus/textures/trans.png diff --git a/mods/other/playerplus/README.md b/mods/other/playerplus/README.md new file mode 100644 index 0000000..4bfdcbf --- /dev/null +++ b/mods/other/playerplus/README.md @@ -0,0 +1,63 @@ +PlayerPlus mod for minetest + +This mod lets the player move faster when walking on ice, slows down the player +when walking on snow, makes touching a cactus hurt and suffocates player when +their head is inside a solid node... enjoy! + +https://forum.minetest.net/viewtopic.php?t=10090&p=153667 + +- 0.1 - Initial release +- 0.2 - 3d_armor mod compatibility +- 0.3 - Optimized code +- 0.4 - Added suffocation when inside nodes +- 0.5 - Slow down when walking in water +- 0.6 - Code tidy and tweak, increased damage by cactus and suffocation +- 0.7 - Added global 'playerplus' table to hold node names gathered around player +- 0.8 - Player knock-back added +- 0.9 - 'on_walk_over' function support added for nodes +- 1.0 - Update to newer functions, requires Minetest 0.4.16 and above to run +- 1.1 - Added support for player_monoids mod (thanks tacotexmex) +- 1.2 - Added POVA support, tweaked code slightly +- 1.3 - Add setting under Advanced to enable older sneak glitch movement +- 1.4 - Add minetest 5.0 check for knockback y_offset +- 1.5 - Use Minetext 5.x functions for proper player knockback + +API: + +Every second the mod checks which node the player is standing on, which node is +at foot and head level and stores inside a global table to be used by mods: + +- playerplus[name].nod_stand +- playerplus[name].nod_feet +- playerplus[name].nod_head + + +Older Sneak-glitch: + +When enabled this allows players to use the old sneak glitch movement that lets +you climb sneak ladders and jump double blocks when using sneak+jump, + +old_sneak = false + + +Player Knock-back: + +This feature is enabled by default and can be turned off by adding this line to +your minetest.conf file: + +player_knockback = false + + +Knock-back is determined by tool strength or a specific 'knockback' value which +can be added to the tool damage_groups itself. A player with the privelage +'no_knockback' will not be affected when it's enabled. + + +Node 'on_walk_over' function: + +When added to a node definition the function will be called whenever a player +walks on top of the node e.g. + + on_walk_over = function(pos, node, player) + print ("---", node.name, player:get_player_name() ) + end diff --git a/mods/other/playerplus/depends.txt b/mods/other/playerplus/depends.txt new file mode 100644 index 0000000..b5f672e --- /dev/null +++ b/mods/other/playerplus/depends.txt @@ -0,0 +1,4 @@ +default? +3d_armor? +player_monoids? +pova? diff --git a/mods/other/playerplus/description.txt b/mods/other/playerplus/description.txt new file mode 100644 index 0000000..c931dd8 --- /dev/null +++ b/mods/other/playerplus/description.txt @@ -0,0 +1 @@ +Add speed effects, suffocation and cactus damage to players. \ No newline at end of file diff --git a/mods/other/playerplus/init.lua b/mods/other/playerplus/init.lua new file mode 100644 index 0000000..779b112 --- /dev/null +++ b/mods/other/playerplus/init.lua @@ -0,0 +1,324 @@ +--[[ + walking on ice makes player walk faster, + stepping through snow slows player down, + touching a cactus hurts player, + suffocation when head is inside solid node, + player knock-back effects when punched. + + PlayerPlus by TenPlus1 +]] + +playerplus = {} + +-- detect minetest 5.0 +local mt50 = minetest.registered_nodes["default:permafrost"] + +-- cache if player_monoids mod active? +local monoids = minetest.get_modpath("player_monoids") +local pova_mod = minetest.get_modpath("pova") + +-- get node but use fallback for nil or unknown +local node_ok = function(pos, fallback) + + fallback = fallback or "air" + + local node = minetest.get_node_or_nil(pos) + + if node and minetest.registered_nodes[node.name] then + return node.name + end + + return fallback +end + + +local armor_mod = minetest.get_modpath("3d_armor") +local time = 0 + + +minetest.register_globalstep(function(dtime) + + time = time + dtime + + -- every 1 second + if time < 1 then + return + end + + -- reset time for next check + time = 0 + + -- define locals outside loop + local name, pos, ndef, def, nslow, nfast, prop + + -- get list of players + local players = minetest.get_connected_players() + + -- loop through players + for _,player in pairs(players) do + + -- who am I? + name = player:get_player_name() + +if name and playerplus[name] then + + -- where am I? + pos = player:get_pos() + + -- what is around me? + playerplus[name].nod_stand = node_ok({ + x = pos.x, y = pos.y - 0.1, z = pos.z}) + + -- Does the node below me have an on_walk_over function set? + ndef = minetest.registered_nodes[playerplus[name].nod_stand] + if ndef and ndef.on_walk_over then + ndef.on_walk_over(pos, ndef, player) + end + + prop = player:get_properties() + + -- node at eye level + playerplus[name].nod_head = node_ok({ + x = pos.x, y = pos.y + prop.eye_height, z = pos.z}) + + -- node at foot level + playerplus[name].nod_feet = node_ok({ + x = pos.x, y = pos.y + 0.2, z = pos.z}) + + -- get player physics + def = player:get_physics_override() + + if armor_mod and armor and armor.def then + -- get player physics from armor + def.speed = armor.def[name].speed or def.speed + def.jump = armor.def[name].jump or def.jump + def.gravity = armor.def[name].gravity or def.gravity + end + + -- are we standing on any nodes that speed player up? + nfast = nil + if playerplus[name].nod_stand == "default:ice" then + nfast = true + end + + -- are we standing on any nodes that slow player down? + nslow = nil + if playerplus[name].nod_stand == "default:snow" + or playerplus[name].nod_stand == "default:snowblock" then + nslow = true + end + + -- apply speed changes + if nfast and not playerplus[name].nfast then + if monoids then + playerplus[name].nfast = player_monoids.speed:add_change( + player, def.speed + 0.4) + elseif pova_mod then + pova.add_override(name, "playerplus:nfast", {speed = 0.4}) + pova.do_override(player) + else + def.speed = def.speed + 0.4 + end + + playerplus[name].nfast = true + + elseif not nfast and playerplus[name].nfast then + if monoids then + player_monoids.speed:del_change(player, playerplus[name].nfast) + playerplus[name].nfast = nil + elseif pova_mod then + pova.del_override(name, "playerplus:nfast") + pova.do_override(player) + else + def.speed = def.speed - 0.4 + end + + playerplus[name].nfast = nil + end + + -- apply slowdown changes + if nslow and not playerplus[name].nslow then + if monoids then + playerplus[name].nslow = player_monoids.speed:add_change( + player, def.speed - 0.3) + elseif pova_mod then + pova.add_override(name, "playerplus:nslow", {speed = -0.3}) + pova.do_override(player) + else + def.speed = def.speed - 0.3 + end + + playerplus[name].nslow = true + + elseif not nslow and playerplus[name].nslow then + if monoids then + player_monoids.speed:del_change(player, playerplus[name].nslow) + playerplus[name].nslow = nil + elseif pova_mod then + pova.del_override(name, "playerplus:nslow") + pova.do_override(player) + else + def.speed = def.speed + 0.3 + end + + playerplus[name].nslow = nil + end + + -- set player physics + if not monoids and not pova_mod then + + player:set_physics_override({ + speed = def.speed, + jump = def.jump, + gravity = def.gravity + }) + end +--[[ + print ("Speed: " .. def.speed + .. " / Jump: " .. def.jump + .. " / Gravity: " .. def.gravity) +]] + -- Is player suffocating inside a normal node without no_clip privs? + local ndef = minetest.registered_nodes[playerplus[name].nod_head] + + if ndef.walkable == true + and ndef.drowning == 0 + and ndef.damage_per_second <= 0 + and ndef.groups.disable_suffocation ~= 1 + and ndef.drawtype == "normal" + and not minetest.check_player_privs(name, {noclip = true}) then + + if player:get_hp() > 0 then + player:set_hp(player:get_hp() - 2) + end + end + + -- am I near a cactus? + local near = minetest.find_node_near(pos, 1, "default:cactus") + + if near then + + -- am I touching the cactus? if so it hurts + for _,object in pairs(minetest.get_objects_inside_radius(near, 1.1)) do + + if object:get_hp() > 0 then + object:set_hp(object:get_hp() - 2) + end + end + + end + +end -- END if name + + end +end) + + +-- check for old sneak_glitch setting +local old_sneak = minetest.settings:get_bool("old_sneak") + +-- set to blank on join (for 3rd party mods) +minetest.register_on_joinplayer(function(player) + + local name = player:get_player_name() + + playerplus[name] = {} + playerplus[name].nod_head = "" + playerplus[name].nod_feet = "" + playerplus[name].nod_stand = "" + + -- apply old sneak glitch if enabled + if old_sneak then + player:set_physics_override({new_move = false, sneak_glitch = true}) + end +end) + + +-- clear when player leaves +minetest.register_on_leaveplayer(function(player) + + playerplus[ player:get_player_name() ] = nil +end) + + +-- add privelage to disable knock-back +minetest.register_privilege("no_knockback", { + description = "Disables player knock-back effect", + give_to_singleplayer = false}) + +-- is player knock-back effect enabled? +if minetest.settings:get_bool("player_knockback") == true then + +-- player knock-back function +local punchy = function( + player, hitter, time_from_last_punch, tool_capabilities, dir, damage) + + if not dir then return end + + -- check if player has 'no_knockback' privelage + local privs = minetest.get_player_privs(player:get_player_name()) + + if privs["no_knockback"] then + return + end + + local damage = 0 + + -- get tool damage + if tool_capabilities then + + local armor = player:get_armor_groups() or {} + local tmp + + for group,_ in pairs( (tool_capabilities.damage_groups or {}) ) do + + tmp = time_from_last_punch / (tool_capabilities.full_punch_interval or 1.4) + + if tmp < 0 then + tmp = 0.0 + elseif tmp > 1 then + tmp = 1.0 + end + + damage = damage + (tool_capabilities.damage_groups[group] or 0) * tmp + end + + -- check for knockback value + if tool_capabilities.damage_groups["knockback"] then + damage = tool_capabilities.damage_groups["knockback"] + end + + end + -- END tool damage + +-- print ("---", player:get_player_name(), damage) + + -- knock back player + player:add_velocity({ + x = dir.x * (damage * 2), + y = -1, + z = dir.z * (damage * 2) + }) +end + +minetest.register_on_punchplayer(punchy) + +end -- END if + +minetest.register_tool("playerplus:stick", { + description = "KB Stick", + inventory_image = "default_stick.png", + wield_image = "default_stick.png", + tool_capabilities = { + full_punch_interval = 1.4, + damage_groups = {fleshy = 0, knockback = 11}, + }, +}) + +--[[ +minetest.override_item("default:mese", { + on_walk_over = function(pos, node, player) + print ("---", node.name, player:get_player_name() ) + end +}) +]] diff --git a/mods/other/playerplus/license.txt b/mods/other/playerplus/license.txt new file mode 100644 index 0000000..fec6f6a --- /dev/null +++ b/mods/other/playerplus/license.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2016 TenPlus1 + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/mods/other/playerplus/mod.conf b/mods/other/playerplus/mod.conf new file mode 100644 index 0000000..60ad6fb --- /dev/null +++ b/mods/other/playerplus/mod.conf @@ -0,0 +1,4 @@ +name = playerplus +depends = +optional_depends = default, 3d_armor, player_monoids, pova +description = Add speed effects, suffocation and cactus damage to players. diff --git a/mods/other/playerplus/screenshot.png b/mods/other/playerplus/screenshot.png new file mode 100644 index 0000000000000000000000000000000000000000..3e3d06dfac1ab3723b973617202586677f23f221 GIT binary patch literal 7273 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