From 69bb75036e0e8c295ef4e88cbb15086fda856d11 Mon Sep 17 00:00:00 2001 From: WillConker Date: Fri, 7 Jun 2024 16:20:44 +0100 Subject: [PATCH] New lua breath system, respiration enchant and water breating support --- mods/HUD/hudbars/default_settings.lua | 2 + mods/HUD/hudbars/init.lua | 104 +++++++++++++++++---- mods/ITEMS/mcl_enchanting/enchantments.lua | 6 +- mods/ITEMS/mcl_potions/functions.lua | 6 -- settingtypes.txt | 4 + 5 files changed, 95 insertions(+), 27 deletions(-) diff --git a/mods/HUD/hudbars/default_settings.lua b/mods/HUD/hudbars/default_settings.lua index 865a7cb6a..717a78e0e 100644 --- a/mods/HUD/hudbars/default_settings.lua +++ b/mods/HUD/hudbars/default_settings.lua @@ -52,3 +52,5 @@ else hb.settings.sorting_reverse[tonumber(v)] = k end end + +hb.settings.breath_max = hb.load_setting("mcl_breath_max", "number", 10) diff --git a/mods/HUD/hudbars/init.lua b/mods/HUD/hudbars/init.lua index 7f86a959d..23dade636 100644 --- a/mods/HUD/hudbars/init.lua +++ b/mods/HUD/hudbars/init.lua @@ -16,6 +16,7 @@ hb = { settings = {}, -- Table which contains all players with active default HUD bars (only for internal use) players = {}, + breath_time = {}, } function hb.load_setting(sname, stype, defaultval, valid_values) @@ -499,6 +500,17 @@ local function hide_builtin(player) player:hud_set_flags(flags) end +function hb.get_breath(player) + local breath = tonumber(player:get_meta():get_string("mcl_hudbars:breath")) or hb.settings.breath_max + return breath +end + +function hb.set_breath(player, value, update_hudbar) + player:get_meta():set_string("mcl_hudbars:breath", tostring(value)) + if update_hudbar == true then + update_breath(player) + end +end local function custom_hud(player) if minetest.settings:get_bool("enable_damage") or hb.settings.forceload_default_hudbars then @@ -511,8 +523,9 @@ local function custom_hud(player) local hp = player:get_hp() local hp_max = player:get_properties().hp_max hb.init_hudbar(player, "health", math.min(hp, hp_max), hp_max, hide) - local breath = player:get_breath() - local breath_max = player:get_properties().breath_max + local breath = hb.get_breath(player) + local breath_max = hb.settings.breath_max + hb.set_breath(player, math.min(breath_max, math.max(0, breath))) local hide_breath if breath >= breath_max and hb.settings.autohide_breath == true then hide_breath = true else hide_breath = false end hb.init_hudbar(player, "breath", math.min(breath, breath_max), breath_max, hide_breath or hide) @@ -526,23 +539,66 @@ local function update_health(player) hb.change_hudbar(player, "health", hp, hp_max) end +local function update_breath(player, in_water) + local breath = hb.get_breath(player) + local breath_max = hb.settings.breath_max + if breath >= breath_max and hb.settings.autohide_breath == true and not in_water then + hb.hide_hudbar(player, "breath") + else + hb.unhide_hudbar(player, "breath") + hb.change_hudbar(player, "breath", math.min(breath, breath_max), breath_max) + end +end + +local function do_breath_tick(player, dtime) + -- don't use default breath + player:set_breath(player:get_properties().breath_max) + + local breath_max = hb.settings.breath_max + local player_name = player:get_player_name() + local node_head = mcl_playerinfo[player_name].node_head + local in_water = node_head and minetest.get_item_group(node_head, "water") > 0 + local current_breath = hb.get_breath(player) + + local helmet = player:get_inventory():get_stack("armor", 2) + local respiration = mcl_enchanting.get_enchantment(helmet, "respiration") or 0 + local scaled_dtime = dtime / (respiration + 1) + + if in_water and not mcl_potions.has_effect(player, "water_breathing") then + -- in water, use respiration scaled_dtime + hb.breath_time[player] = (hb.breath_time[player] or 0) + scaled_dtime + if current_breath > 0 and hb.breath_time[player] > 1.5 then + -- min used to stop breath changing rapidly after extreme server lag + hb.breath_time[player] = math.min(hb.breath_time[player] - 1.5, 1.5) + hb.set_breath(player, current_breath - 1) + elseif current_breath == 0 and hb.breath_time[player] > 1 then + hb.breath_time[player] = math.min(hb.breath_time[player] - 1, 1) + if player:get_hp() > 0 then + mcl_util.deal_damage(player, 2, {type = "drown"}) + end + end + else + -- out of water/has water breathing, use normal dtime + hb.breath_time[player] = (hb.breath_time[player] or 0) + dtime + if current_breath == breath_max then hb.breath_time[player] = 0 + elseif hb.breath_time[player] > 0.2 then + -- no min here as players should be able to regen breath fast despite server lag + hb.breath_time[player] = hb.breath_time[player] - 0.2 + hb.set_breath(player, current_breath + 1) + end + end + return in_water +end + -- update built-in HUD bars -local function update_hud(player, has_damage) +local function update_hud(player, has_damage, in_water) if not player_exists(player) then return end if has_damage then if hb.settings.forceload_default_hudbars then hb.unhide_hudbar(player, "health") end --air - local breath_max = player:get_properties().breath_max - local breath = player:get_breath() - - if breath >= breath_max and hb.settings.autohide_breath == true then - hb.hide_hudbar(player, "breath") - else - hb.unhide_hudbar(player, "breath") - hb.change_hudbar(player, "breath", math.min(breath, breath_max), breath_max) - end + update_breath(player, in_water) --health update_health(player) elseif hb.settings.forceload_default_hudbars then @@ -559,10 +615,15 @@ end) minetest.register_on_respawnplayer(function(player) update_health(player) - hb.hide_hudbar(player, "breath") + + local breath_max = hb.settings.breath_max + hb.breath_time[player] = 0 + hb.set_breath(player, breath_max) + update_breath(player) end) minetest.register_on_joinplayer(function(player) +-- minetest.debug("Player joined:", player) hide_builtin(player) custom_hud(player) hb.players[player:get_player_name()] = player @@ -570,23 +631,30 @@ end) minetest.register_on_leaveplayer(function(player) hb.players[player:get_player_name()] = nil + hb.breath_time[player] = nil end) local main_timer = 0 local timer = 0 minetest.register_globalstep(function(dtime) + local is_hud_step = false + local has_dmg main_timer = main_timer + dtime timer = timer + dtime if main_timer > hb.settings.tick or timer > 4 then if main_timer > hb.settings.tick then main_timer = 0 end -- only proceed if damage is enabled - local has_dmg = minetest.settings:get_bool("enable_damage") + has_dmg = minetest.settings:get_bool("enable_damage") if has_dmg or hb.settings.forceload_default_hudbars then - for _, player in pairs(hb.players) do - -- update all hud elements - update_hud(player, has_dmg) - end + is_hud_step = true end end if timer > 4 then timer = 0 end + for _, player in pairs(hb.players) do + -- update all hud elements + local in_water = do_breath_tick(player, dtime) + if is_hud_step then + update_hud(player, has_dmg, in_water) + end + end end) diff --git a/mods/ITEMS/mcl_enchanting/enchantments.lua b/mods/ITEMS/mcl_enchanting/enchantments.lua index 379a18e07..e21080be9 100644 --- a/mods/ITEMS/mcl_enchanting/enchantments.lua +++ b/mods/ITEMS/mcl_enchanting/enchantments.lua @@ -586,8 +586,8 @@ mcl_enchanting.enchantments.quick_charge = { inv_tool_tab = false, } --- unimplemented ---[[mcl_enchanting.enchantments.respiration = { +-- implemented in mcl_hudbars +mcl_enchanting.enchantments.respiration = { name = S("Respiration"), max_level = 3, primary = {armor_head = true}, @@ -603,7 +603,7 @@ mcl_enchanting.enchantments.quick_charge = { power_range_table = {{10, 40}, {20, 50}, {30, 60}}, inv_combat_tab = true, inv_tool_tab = false, -}]]-- +} -- requires missing MineClone2 feature --[[mcl_enchanting.enchantments.riptide = { diff --git a/mods/ITEMS/mcl_potions/functions.lua b/mods/ITEMS/mcl_potions/functions.lua index 96028bb60..d404e108d 100644 --- a/mods/ITEMS/mcl_potions/functions.lua +++ b/mods/ITEMS/mcl_potions/functions.lua @@ -303,12 +303,6 @@ mcl_potions.register_effect({ res_condition = function(object) return (not object:is_player()) -- TODO add support for breath setting for mobs end, - on_step = function(dtime, object, factor, duration) - if object:get_breath() then - hb.hide_hudbar(object, "breath") - if object:get_breath() < 10 then object:set_breath(10) end - end - end, particle_color = "#2E5299", uses_factor = false, }) diff --git a/settingtypes.txt b/settingtypes.txt index ac3399498..8762ac2e7 100644 --- a/settingtypes.txt +++ b/settingtypes.txt @@ -109,6 +109,10 @@ mcl_health_regen_delay (Health regen delay) float 0.5 0 # Default: 1.61 s mcl_eating_delay (Eating delay) float 1.61 0 +# Default breath of players +# Default: 10 +mcl_breath_max (Maximum breath) int 10 0 + [Mobs] # If enabled, mobs will spawn naturally. This does not affect # affect mob spawners.