From f2c66b9ceb4930dfd7b510c77037c235b161e603 Mon Sep 17 00:00:00 2001 From: sfence Date: Wed, 21 Aug 2024 20:24:43 +0200 Subject: [PATCH] Add possibility to easier override HP and breath engine logic by Lua (#14179) Co-authored-by: Lars Mueller --- doc/lua_api.md | 8 +++++++ src/script/common/c_content.cpp | 2 +- src/script/lua_api/l_object.cpp | 37 +++++++++++++++++++++++++++++++++ src/script/lua_api/l_object.h | 6 ++++++ src/server/player_sao.cpp | 11 +++++++--- src/server/player_sao.h | 6 ++++++ 6 files changed, 66 insertions(+), 4 deletions(-) diff --git a/doc/lua_api.md b/doc/lua_api.md index dde797325..07c7b3c2e 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -8495,6 +8495,14 @@ child will follow movement and rotation of that bone. * Result is a table with the same fields as `light_definition` in `set_lighting`. * `respawn()`: Respawns the player using the same mechanism as the death screen, including calling `on_respawnplayer` callbacks. +* `get_flags()`: returns a table of player flags (the following boolean fields): + * `breathing`: Whether breathing (regaining air) is enabled, default `true`. + * `drowning`: Whether drowning (losing air) is enabled, default `true`. + * `node_damage`: Whether the player takes damage from nodes, default `true`. +* `set_flags(flags)`: sets flags + * takes a table in the same format as returned by `get_flags` + * absent fields are left unchanged + `PcgRandom` ----------- diff --git a/src/script/common/c_content.cpp b/src/script/common/c_content.cpp index 6f7d86447..bd76a3ad3 100644 --- a/src/script/common/c_content.cpp +++ b/src/script/common/c_content.cpp @@ -291,7 +291,7 @@ const std::array object_property_keys = { "use_texture_alpha", "shaded", "damage_texture_modifier", - "show_on_minimap" + "show_on_minimap", }; /******************************************************************************/ diff --git a/src/script/lua_api/l_object.cpp b/src/script/lua_api/l_object.cpp index 00c825ddc..eb0a375d4 100644 --- a/src/script/lua_api/l_object.cpp +++ b/src/script/lua_api/l_object.cpp @@ -2688,6 +2688,41 @@ int ObjectRef::l_respawn(lua_State *L) return 1; } +// set_flags(self, flags) +int ObjectRef::l_set_flags(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkObject(L, 1); + auto *psao = getplayersao(ref); + if (psao == nullptr) + return 0; + if (!lua_istable(L, -1)) + throw LuaError("expected a table of flags"); + auto &flags = psao->m_flags; + flags.drowning = getboolfield_default(L, -1, "drowning", flags.drowning); + flags.breathing = getboolfield_default(L, -1, "breathing", flags.breathing); + flags.node_damage = getboolfield_default(L, -1, "node_damage", flags.node_damage); + return 0; +} + +// get_flags(self) +int ObjectRef::l_get_flags(lua_State *L) +{ + NO_MAP_LOCK_REQUIRED; + ObjectRef *ref = checkObject(L, 1); + const auto *psao = getplayersao(ref); + if (psao == nullptr) + return 0; + lua_createtable(L, 0, 3); + lua_pushboolean(L, psao->m_flags.drowning); + lua_setfield(L, -2, "drowning"); + lua_pushboolean(L, psao->m_flags.breathing); + lua_setfield(L, -2, "breathing"); + lua_pushboolean(L, psao->m_flags.node_damage); + lua_setfield(L, -2, "node_damage"); + return 1; +} + ObjectRef::ObjectRef(ServerActiveObject *object): m_object(object) @@ -2838,6 +2873,8 @@ luaL_Reg ObjectRef::methods[] = { luamethod(ObjectRef, set_lighting), luamethod(ObjectRef, get_lighting), luamethod(ObjectRef, respawn), + luamethod(ObjectRef, set_flags), + luamethod(ObjectRef, get_flags), {0,0} }; diff --git a/src/script/lua_api/l_object.h b/src/script/lua_api/l_object.h index ace19e1f0..75e961438 100644 --- a/src/script/lua_api/l_object.h +++ b/src/script/lua_api/l_object.h @@ -411,4 +411,10 @@ private: // respawn(self) static int l_respawn(lua_State *L); + + // set_flags(self, flags) + static int l_set_flags(lua_State *L); + + // get_flags(self) + static int l_get_flags(lua_State *L); }; diff --git a/src/server/player_sao.cpp b/src/server/player_sao.cpp index 4abb1f920..11922b2c6 100644 --- a/src/server/player_sao.cpp +++ b/src/server/player_sao.cpp @@ -156,7 +156,10 @@ void PlayerSAO::getStaticData(std::string * result) const void PlayerSAO::step(float dtime, bool send_recommended) { - if (!isImmortal() && m_drowning_interval.step(dtime, 2.0f)) { + bool not_immortal = !isImmortal(); + + if (not_immortal && m_flags.drowning + && m_drowning_interval.step(dtime, 2.0f)) { // Get nose/mouth position, approximate with eye position v3s16 p = floatToInt(getEyePosition(), BS); MapNode n = m_env->getMap().getNode(p); @@ -174,7 +177,8 @@ void PlayerSAO::step(float dtime, bool send_recommended) } } - if (m_breathing_interval.step(dtime, 0.5f) && !isImmortal()) { + if (not_immortal && m_flags.breathing + && m_breathing_interval.step(dtime, 0.5f)) { // Get nose/mouth position, approximate with eye position v3s16 p = floatToInt(getEyePosition(), BS); MapNode n = m_env->getMap().getNode(p); @@ -185,7 +189,8 @@ void PlayerSAO::step(float dtime, bool send_recommended) setBreath(m_breath + 1); } - if (!isImmortal() && m_node_hurt_interval.step(dtime, 1.0f)) { + if (not_immortal && m_flags.node_damage + && m_node_hurt_interval.step(dtime, 1.0f)) { u32 damage_per_second = 0; std::string nodename; v3s16 node_pos; diff --git a/src/server/player_sao.h b/src/server/player_sao.h index b26304589..95bd1d109 100644 --- a/src/server/player_sao.h +++ b/src/server/player_sao.h @@ -228,6 +228,12 @@ private: SimpleMetadata m_meta; public: + struct { + bool breathing : 1; + bool drowning : 1; + bool node_damage : 1; + } m_flags = {true, true, true}; + bool m_physics_override_sent = false; };