From 70d8dfe558fe002464bec564677738dbd53a969a Mon Sep 17 00:00:00 2001 From: the-real-herowl Date: Sun, 14 Apr 2024 07:45:39 +0200 Subject: [PATCH] Improved API mob support * various API functions now work with mobs properly * the following effects don't work with mobs at all: water breathing, dolphin's grace, leaping, swiftness, slowness, slow falling, night vision, darkness, frost, health boost, absorption, fire resistance, resistance, luck, bad luck, blindness, nausea, hunger, saturation, haste, fatigue, conduit power * the following effects should work with mobs: invisibility, regeneration, poison, withering, strength, weakness, levitation, glowing * the following effects have no effect on mobs (but can be applied with the API): bad omen, hero of the village --- mods/ITEMS/mcl_campfires/api.lua | 2 +- mods/ITEMS/mcl_mobitems/init.lua | 2 +- mods/ITEMS/mcl_nether/init.lua | 2 +- mods/ITEMS/mcl_potions/commands.lua | 2 +- mods/ITEMS/mcl_potions/functions.lua | 93 +++++++++++++++++----------- 5 files changed, 62 insertions(+), 39 deletions(-) diff --git a/mods/ITEMS/mcl_campfires/api.lua b/mods/ITEMS/mcl_campfires/api.lua index ba6a55960..98318f3f1 100644 --- a/mods/ITEMS/mcl_campfires/api.lua +++ b/mods/ITEMS/mcl_campfires/api.lua @@ -380,7 +380,7 @@ minetest.register_globalstep(function(dtime) etime = 0 for _,pl in pairs(minetest.get_connected_players()) do local armor_feet = pl:get_inventory():get_stack("armor", 5) - if pl and pl:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.has_effect(pl, "fire_proof")) then + if pl and pl:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.has_effect(pl, "fire_resistance")) then return end burn_in_campfire(pl) diff --git a/mods/ITEMS/mcl_mobitems/init.lua b/mods/ITEMS/mcl_mobitems/init.lua index 182bc8ced..01b9a5039 100644 --- a/mods/ITEMS/mcl_mobitems/init.lua +++ b/mods/ITEMS/mcl_mobitems/init.lua @@ -154,7 +154,7 @@ local function drink_milk_delayed(itemstack, player, pointed_thing) ) then mcl_hunger.stop_poison(player) end - mcl_potions._reset_player_effects(player) + mcl_potions._reset_effects(player) end -- Wrapper for handling mcl_hunger delayed eating diff --git a/mods/ITEMS/mcl_nether/init.lua b/mods/ITEMS/mcl_nether/init.lua index 3a57ae427..b69355d5d 100644 --- a/mods/ITEMS/mcl_nether/init.lua +++ b/mods/ITEMS/mcl_nether/init.lua @@ -135,7 +135,7 @@ minetest.register_node("mcl_nether:magma", { -- From walkover mod on_walk_over = function(loc, nodeiamon, player) local armor_feet = player:get_inventory():get_stack("armor", 5) - if player and player:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.has_effect(player, "fire_proof")) then + if player and player:get_player_control().sneak or (minetest.global_exists("mcl_enchanting") and mcl_enchanting.has_enchantment(armor_feet, "frost_walker")) or (minetest.global_exists("mcl_potions") and mcl_potions.has_effect(player, "fire_resistance")) then return end -- Hurt players standing on top of this block diff --git a/mods/ITEMS/mcl_potions/commands.lua b/mods/ITEMS/mcl_potions/commands.lua index 4b4aa0ba7..1c2cd7347 100644 --- a/mods/ITEMS/mcl_potions/commands.lua +++ b/mods/ITEMS/mcl_potions/commands.lua @@ -44,7 +44,7 @@ minetest.register_chatcommand("effect",{ end end elseif P[1] == "clear" then - mcl_potions._reset_player_effects(minetest.get_player_by_name(name)) + mcl_potions._reset_effects(minetest.get_player_by_name(name)) return true, S("Effects cleared for player @1", name) elseif P[1] == "remove" then if not P[2] then diff --git a/mods/ITEMS/mcl_potions/functions.lua b/mods/ITEMS/mcl_potions/functions.lua index d36b8db62..8d85b19b6 100644 --- a/mods/ITEMS/mcl_potions/functions.lua +++ b/mods/ITEMS/mcl_potions/functions.lua @@ -300,8 +300,10 @@ mcl_potions.register_effect({ get_tt = function(factor) return S("limitless breathing under water") end, + 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 not object:is_player() then return end if object:get_breath() then hb.hide_hudbar(object, "breath") if object:get_breath() < 10 then object:set_breath(10) end @@ -317,6 +319,9 @@ mcl_potions.register_effect({ get_tt = function(factor) return S("swimming gracefully") end, + res_condition = function(object) + return (not object:is_player()) -- TODO needs mob physics factor API + end, on_hit_timer = function(object, factor, duration) local node = minetest.get_node_or_nil(object:get_pos()) if node and minetest.registered_nodes[node.name] @@ -340,7 +345,7 @@ mcl_potions.register_effect({ return S("-@1% jumping power", math.floor(-factor*100)) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob physics factor API end, on_start = function(object, factor) playerphysics.add_physics_factor(object, "jump", "mcl_potions:leaping", 1+factor) @@ -361,7 +366,7 @@ mcl_potions.register_effect({ return S("decreases gravity effects") end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob physics factor API end, on_start = function(object, factor) playerphysics.add_physics_factor(object, "gravity", "mcl_potions:slow_falling", 0.5) @@ -383,7 +388,7 @@ mcl_potions.register_effect({ return S("+@1% running speed", math.floor(factor*100)) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob physics factor API end, on_start = function(object, factor) playerphysics.add_physics_factor(object, "speed", "mcl_potions:swiftness", 1+factor) @@ -404,7 +409,7 @@ mcl_potions.register_effect({ return S("-@1% running speed", math.floor(factor*100)) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob physics factor API end, on_start = function(object, factor) playerphysics.add_physics_factor(object, "speed", "mcl_potions:slowness", 1-factor) @@ -441,7 +446,7 @@ mcl_potions.register_effect({ return S("improved vision during the night") end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO what should it do for mobs? end, on_start = function(object, factor) object:get_meta():set_int("night_vision", 1) @@ -466,7 +471,7 @@ mcl_potions.register_effect({ return S("surrounded by darkness").."\n"..S("not seeing anything beyond @1 nodes", factor) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO what should it do for mobs? end, on_start = function(object, factor) object:get_meta():set_int("darkness", 1) @@ -580,7 +585,7 @@ mcl_potions.register_effect({ return S("HP increased by @1", factor) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob HP modifier API? end, on_start = function(object, factor) object:set_properties({hp_max = minetest.PLAYER_MAX_HP_DEFAULT+factor}) @@ -601,7 +606,7 @@ mcl_potions.register_effect({ return S("absorbs up to @1 incoming damage", factor) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO dmg modifiers don't work for mobs end, on_start = function(object, factor) hb.change_hudbar(object, "absorption", factor, (math.floor(factor/20-0.05)+1)*20) @@ -641,7 +646,7 @@ mcl_potions.register_effect({ return S("resistance to fire damage") end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO dmg modifiers don't work for mobs end, particle_color = "#E49A3A", uses_factor = false, @@ -655,7 +660,7 @@ mcl_potions.register_effect({ return S("resist @1% of incoming damage", math.floor(factor*100)) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO dmg modifiers don't work for mobs end, particle_color = "#2552A5", uses_factor = true, @@ -672,7 +677,7 @@ mcl_potions.register_effect({ description = S("Luck"), particle_color = "#7BFF42", res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO what should it do for mobs? end, on_start = function(object, factor) mcl_luck.apply_luck_modifier(object:get_player_name(), "mcl_potions:luck", factor) @@ -691,7 +696,7 @@ mcl_potions.register_effect({ description = S("Bad Luck"), particle_color = "#887343", res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO what should it do for mobs? end, on_start = function(object, factor) mcl_luck.apply_luck_modifier(object:get_player_name(), "mcl_potions:bad_luck", -factor) @@ -746,7 +751,7 @@ mcl_potions.register_effect({ return S("-1 HP / 1 s, can kill, -@1% running speed", math.floor(factor*100)) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob physics factor API end, on_start = function(object, factor) mcl_burning.extinguish(object) @@ -799,7 +804,7 @@ mcl_potions.register_effect({ return S("impaired sight") end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO what should it do for mobs? end, on_start = function(object, factor) EF.blindness[object].vignette = object:hud_add({ @@ -842,7 +847,7 @@ mcl_potions.register_effect({ return S("not feeling very well...").."\n"..S("frequency: @1 / 1 s", factor) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO what should it do for mobs? end, on_start = function(object, factor) object:set_lighting({ @@ -891,7 +896,7 @@ mcl_potions.register_effect({ return S("exhausts by @1 per second", factor) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO what should it do for mobs? end, on_start = function(object, factor) hb.change_hudbar(object, "hunger", nil, nil, "mcl_hunger_icon_foodpoison.png", nil, "mcl_hunger_bar_foodpoison.png") @@ -924,7 +929,7 @@ mcl_potions.register_effect({ return S("saturates by @1 per second", factor) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO what should it do for mobs? end, on_step = function(dtime, object, factor, duration) mcl_hunger.set_hunger(object, math.min(mcl_hunger.get_hunger(object)+dtime*factor, 20)) @@ -988,7 +993,7 @@ mcl_potions.register_effect({ return S("+@1% mining and attack speed", math.floor(factor*100)) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob API support end, on_start = haste_fatigue_hand_update, after_end = function(object) @@ -1009,7 +1014,7 @@ mcl_potions.register_effect({ return S("-@1% mining and attack speed", math.floor((1-factor)*100)) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob API support end, on_start = haste_fatigue_hand_update, after_end = function(object) @@ -1030,7 +1035,7 @@ mcl_potions.register_effect({ return S("+@1% mining and attack speed in water").."\n"..S("limitless breathing under water", math.floor(factor*100)) end, res_condition = function(object) - return (not object:is_player()) + return (not object:is_player()) -- TODO needs mob API support end, on_start = haste_fatigue_hand_update, on_step = function(dtime, object, factor, duration) @@ -1380,34 +1385,35 @@ function mcl_potions._reset_haste_fatigue_item_meta(player) end mcl_gamemode.register_on_gamemode_change(mcl_potions._reset_haste_fatigue_item_meta) -function mcl_potions._clear_cached_player_data(player) +function mcl_potions._clear_cached_effect_data(object) for name, effect in pairs(EF) do - effect[player] = nil + effect[object] = nil end - - local meta = player:get_meta() + if not object:is_player() then return end + local meta = object:get_meta() meta:set_int("night_vision", 0) end -function mcl_potions._reset_player_effects(player, set_hud) - if not player:is_player() then - return +function mcl_potions._reset_effects(object, set_hud) + local set_hud = set_hud + if not object:is_player() then + set_hud = false end local removed_effects = {} for name, effect in pairs(registered_effects) do - if EF[name][player] and effect.on_end then effect.on_end(player) end + if EF[name][object] and effect.on_end then effect.on_end(object) end if effect.after_end then table.insert(removed_effects, effect.after_end) end end - mcl_potions._clear_cached_player_data(player) + mcl_potions._clear_cached_effect_data(object) for i=1, #removed_effects do - removed_effects[i](player) + removed_effects[i](object) end if set_hud ~= false then - potions_set_hud(player) + potions_set_hud(object) end end @@ -1566,17 +1572,17 @@ end minetest.register_on_leaveplayer( function(player) mcl_potions._save_player_effects(player) - mcl_potions._clear_cached_player_data(player) -- clear the buffer to prevent looking for a player not there + mcl_potions._clear_cached_effect_data(player) -- clear the buffer to prevent looking for a player not there icon_ids[player:get_player_name()] = nil end) minetest.register_on_dieplayer( function(player) - mcl_potions._reset_player_effects(player) + mcl_potions._reset_effects(player) potions_set_hud(player) end) minetest.register_on_joinplayer( function(player) - mcl_potions._reset_player_effects(player, false) -- make sure there are no weird holdover effects + mcl_potions._reset_effects(player, false) -- make sure there are no weird holdover effects mcl_potions._load_player_effects(player) mcl_potions._reset_haste_fatigue_item_meta(player) potions_init_icons(player) @@ -1716,12 +1722,29 @@ end -- ██║░░░░░╚██████╔╝██║░╚███║╚█████╔╝░░░██║░░░██║╚█████╔╝██║░╚███║██████╔╝ -- ╚═╝░░░░░░╚═════╝░╚═╝░░╚══╝░╚════╝░░░░╚═╝░░░╚═╝░╚════╝░╚═╝░░╚══╝╚═════╝░ +local registered_res_predicates = {} +-- API +-- This is supposed to add custom resistance functions independent of effects +-- E.g. some entity could be resistant to all (or some) effects under specific conditions +-- predicate - function(object, effect_name) - return true if resists effect +function mcl_potions.register_generic_resistance_predicate(predicate) + if type(predicate) == "function" then + table.insert(registered_res_predicates, predicate) + else + error("Attempted to register non-function as a predicate") + end +end + local function target_valid(object, name) if not object or object:get_hp() <= 0 then return false end local entity = object:get_luaentity() if entity and entity.is_boss then return false end + for i=1, #registered_res_predicates do + if registered_res_predicates[i](object, name) then return false end + end + if not (registered_effects[name].res_condition and registered_effects[name].res_condition(object)) then return true end end