Customizeable max breath for players (#6411)
authorSmallJoker <SmallJoker@users.noreply.github.com>
Fri, 15 Sep 2017 10:18:47 +0000 (12:18 +0200)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Fri, 15 Sep 2017 10:18:47 +0000 (12:18 +0200)
* Customizeable maximal breath for players

builtin/game/constants.lua
builtin/game/statbars.lua
doc/lua_api.txt
src/constants.h
src/content_sao.cpp
src/content_sao.h
src/localplayer.h
src/object_properties.cpp
src/object_properties.h
src/script/common/c_content.cpp
src/server.cpp

index 29eeb83307bbdf8ed964f953fede698f14190241..0ee2a72371aece9403cf98c38aef419b6437c07a 100644 (file)
@@ -23,8 +23,8 @@ core.EMERGE_GENERATED   = 4
 core.MAP_BLOCKSIZE = 16
 -- Default maximal HP of a player
 core.PLAYER_MAX_HP_DEFAULT = 20
--- Maximal breath of a player
-core.PLAYER_MAX_BREATH = 11
+-- Default maximal breath of a player
+core.PLAYER_MAX_BREATH_DEFAULT = 11
 
 -- light.h
 -- Maximum value for node 'light_source' parameter
index 1b83dd4ac6a66dea3d4af56211da72080dcedd1c..e095acf2bb94dd06f1149e47a55862e5a91255aa 100644 (file)
@@ -17,7 +17,7 @@ local breath_bar_definition =
        hud_elem_type = "statbar",
        position = { x=0.5, y=1 },
        text = "bubble.png",
-       number = 20,
+       number = core.PLAYER_MAX_BREATH_DEFAULT,
        direction = 0,
        size = { x=24, y=24 },
        offset = {x=25,y=-(48+24+16)},
@@ -25,6 +25,15 @@ local breath_bar_definition =
 
 local hud_ids = {}
 
+local function scaleToDefault(player, field)
+       -- Scale "hp" or "breath" to the default dimensions
+       local current = player["get_" .. field](player)
+       local nominal = core["PLAYER_MAX_".. field:upper() .. "_DEFAULT"]
+       local max_display = math.max(nominal,
+               math.max(player:get_properties()[field .. "_max"], current))
+       return current / max_display * nominal 
+end
+
 local function initialize_builtin_statbars(player)
 
        if not player:is_player() then
@@ -47,31 +56,22 @@ local function initialize_builtin_statbars(player)
 
        if player:hud_get_flags().healthbar and enable_damage then
                if hud.id_healthbar == nil then
-                       local hp = player:get_hp()
-                       local max_display_hp = math.max(core.PLAYER_MAX_HP_DEFAULT,
-                               math.max(player:get_properties().hp_max, hp))
-                       -- Limit width of health bar: Scale to the default maximal HP
-                       health_bar_definition.number =
-                               hp / max_display_hp * core.PLAYER_MAX_HP_DEFAULT
-                       hud.id_healthbar  = player:hud_add(health_bar_definition)
-               end
-       else
-               if hud.id_healthbar ~= nil then
-                       player:hud_remove(hud.id_healthbar)
-                       hud.id_healthbar = nil
+                       local hud_def = table.copy(health_bar_definition)
+                       hud_def.number = scaleToDefault(player, "hp")
+                       hud.id_healthbar = player:hud_add(hud_def)
                end
+       elseif hud.id_healthbar ~= nil then
+               player:hud_remove(hud.id_healthbar)
+               hud.id_healthbar = nil
        end
 
-       if player:get_breath() < core.PLAYER_MAX_BREATH then
-               if player:hud_get_flags().breathbar and enable_damage then
-                       if hud.id_breathbar == nil then
-                               hud.id_breathbar = player:hud_add(breath_bar_definition)
-                       end
-               else
-                       if hud.id_breathbar ~= nil then
-                               player:hud_remove(hud.id_breathbar)
-                               hud.id_breathbar = nil
-                       end
+       local breath_max = player:get_properties().breath_max
+       if player:hud_get_flags().breathbar and enable_damage and
+                       player:get_breath() < breath_max then
+               if hud.id_breathbar == nil then
+                       local hud_def = table.copy(breath_bar_definition)
+                       hud_def.number = 2 * scaleToDefault(player, "breath")
+                       hud.id_breathbar = player:hud_add(hud_def)
                end
        elseif hud.id_breathbar ~= nil then
                player:hud_remove(hud.id_breathbar)
@@ -107,12 +107,8 @@ local function player_event_handler(player,eventname)
                initialize_builtin_statbars(player)
 
                if hud_ids[name].id_healthbar ~= nil then
-                       local hp = player:get_hp()
-                       local max_display_hp = math.max(core.PLAYER_MAX_HP_DEFAULT,
-                               math.max(player:get_properties().hp_max, hp))
-                       -- Limit width of health bar: Scale to the default maximal HP
-                       local hp_count = hp / max_display_hp * core.PLAYER_MAX_HP_DEFAULT
-                       player:hud_change(hud_ids[name].id_healthbar, "number", hp_count)
+                       player:hud_change(hud_ids[name].id_healthbar,
+                               "number", scaleToDefault(player, "hp"))
                        return true
                end
        end
@@ -121,7 +117,8 @@ local function player_event_handler(player,eventname)
                initialize_builtin_statbars(player)
 
                if hud_ids[name].id_breathbar ~= nil then
-                       player:hud_change(hud_ids[name].id_breathbar, "number", player:get_breath() * 2)
+                       player:hud_change(hud_ids[name].id_breathbar,
+                               "number", 2 * scaleToDefault(player, "breath"))
                        return true
                end
        end
index eac6f6697fa9bfc02feb298d6e0735b4a9ac6bf4..de3927a74331f3a40cd23a1adb204845bf32dedd 100644 (file)
@@ -3397,10 +3397,9 @@ This is basically a reference to a C++ `ServerActiveObject`
 * `get_breath()`: returns players breath
 * `set_breath(value)`: sets players breath
      * values:
-        * `0`: player is drowning,
-        * `1`-`10`: remaining number of bubbles
-        * `11`: bubbles bar is not shown
-        * See constant: `minetest.PLAYER_MAX_BREATH`
+        * `0`: player is drowning
+        * max: bubbles bar is not shown
+        * See Object Properties for more information
 * `set_attribute(attribute, value)`:
     * Sets an extra attribute with value on player.
     * `value` must be a string.
@@ -4105,7 +4104,9 @@ Definition tables
 
     {
         hp_max = 1,
-    --  ^ For players, the maximal HP defaults to `minetest.PLAYER_MAX_HP_DEFAULT`
+    --  ^ For players: Defaults to `minetest.PLAYER_MAX_HP_DEFAULT`
+        breath_max = 0,
+    --  ^ For players only. Defaults to `minetest.PLAYER_MAX_BREATH_DEFAULT`
         physical = true,
         collide_with_objects = true, -- collide with other objects if physical = true
         weight = 5,
index ddf7218e278b11bd92095fb5a02b5cdd48ded1d8..5ddb5465621739bb424f01632a67ccb452511e45 100644 (file)
@@ -89,11 +89,11 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 // Size of player's main inventory
 #define PLAYER_INVENTORY_SIZE (8 * 4)
 
-// Maximum hit points of a player
+// Default maximum hit points of a player
 #define PLAYER_MAX_HP_DEFAULT 20
 
-// Maximal breath of a player
-#define PLAYER_MAX_BREATH 11
+// Default maximal breath of a player
+#define PLAYER_MAX_BREATH_DEFAULT 11
 
 // Number of different files to try to save a player to if the first fails
 // (because of a case-insensitive filesystem)
index ece9214726ba4d0cf5867516b71d00a655cff3a1..2a2384b3d8d5d8e0d2149c227b4f524a96bcd3bb 100644 (file)
@@ -797,6 +797,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id
        assert(m_peer_id != 0); // pre-condition
 
        m_prop.hp_max = PLAYER_MAX_HP_DEFAULT;
+       m_prop.breath_max = PLAYER_MAX_BREATH_DEFAULT;
        m_prop.physical = false;
        m_prop.weight = 75;
        m_prop.collisionbox = aabb3f(-0.3f, 0.0f, -0.3f, 0.3f, 1.77f, 0.3f);
@@ -817,6 +818,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id
        m_prop.stepheight = PLAYER_DEFAULT_STEPHEIGHT * BS;
        m_prop.can_zoom = true;
        m_hp = m_prop.hp_max;
+       m_breath = m_prop.breath_max;
 }
 
 PlayerSAO::~PlayerSAO()
@@ -943,7 +945,7 @@ void PlayerSAO::step(float dtime, bool send_recommended)
                MapNode n = m_env->getMap().getNodeNoEx(p);
                const ContentFeatures &c = m_env->getGameDef()->ndef()->get(n);
                // If player is alive & no drowning, breath
-               if (m_hp > 0 && m_breath < PLAYER_MAX_BREATH && c.drowning == 0)
+               if (m_hp > 0 && m_breath < m_prop.breath_max && c.drowning == 0)
                        setBreath(m_breath + 1);
        }
 
@@ -1274,7 +1276,7 @@ void PlayerSAO::setBreath(const u16 breath, bool send)
        if (m_player && breath != m_breath)
                m_player->setDirty(true);
 
-       m_breath = MYMIN(breath, PLAYER_MAX_BREATH);
+       m_breath = MYMIN(breath, m_prop.breath_max);
 
        if (send)
                m_env->getGameDef()->SendPlayerBreath(this);
index 019397d83ce75930498dcf71a1378a9c24c0bc36..0ff95059ed770f5308dbbe32406da33f4c140dec 100644 (file)
@@ -397,7 +397,7 @@ private:
        std::set<std::string> m_privs;
        bool m_is_singleplayer;
 
-       u16 m_breath = PLAYER_MAX_BREATH;
+       u16 m_breath = PLAYER_MAX_BREATH_DEFAULT;
        f32 m_pitch = 0.0f;
        f32 m_fov = 0.0f;
        s16 m_wanted_range = 0.0f;
index 35c8b64ba0ea946ed266f2ba1deabb961eb04848..a407181b15088d07b70b202a7c66f8b75d5c9daa 100644 (file)
@@ -173,7 +173,7 @@ private:
        // ***** End of variables for temporary option *****
 
        bool m_can_jump = false;
-       u16 m_breath = PLAYER_MAX_BREATH;
+       u16 m_breath = PLAYER_MAX_BREATH_DEFAULT;
        f32 m_yaw = 0.0f;
        f32 m_pitch = 0.0f;
        bool camera_barely_in_ceiling = false;
index 4171317de0d068388140847f90d7be057a834c9e..9cbaadc64db36af52cfeb885a6d0d3fbd74b3f91 100644 (file)
@@ -34,6 +34,7 @@ std::string ObjectProperties::dump()
 {
        std::ostringstream os(std::ios::binary);
        os << "hp_max=" << hp_max;
+       os << ", breath_max=" << breath_max;
        os << ", physical=" << physical;
        os << ", collideWithObjects=" << collideWithObjects;
        os << ", weight=" << weight;
@@ -108,6 +109,7 @@ void ObjectProperties::serialize(std::ostream &os) const
        os << serializeString(wield_item);
        writeU8(os, can_zoom);
        writeS8(os, glow);
+       writeU16(os, breath_max);
 
        // Add stuff only at the bottom.
        // Never remove anything, because we don't want new versions of this
@@ -155,5 +157,9 @@ void ObjectProperties::deSerialize(std::istream &is)
        infotext = deSerializeString(is);
        wield_item = deSerializeString(is);
        can_zoom = readU8(is);
-       glow = readS8(is);
+
+       try {
+               glow = readS8(is);
+               breath_max = readU16(is);
+       } catch (SerializationError &e) {}
 }
index 8ab1fa7fd4a302b18a7c2891120d7bc1419fb23c..7589cec3ceca3df2ce48b5bd23d4a102218df141 100644 (file)
@@ -27,11 +27,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 struct ObjectProperties
 {
-       // Values are BS=1
        s16 hp_max = 1;
+       u16 breath_max = 0;
        bool physical = false;
        bool collideWithObjects = true;
        float weight = 5.0f;
+       // Values are BS=1
        aabb3f collisionbox = aabb3f(-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f);
        aabb3f selectionbox = aabb3f(-0.5f, -0.5f, -0.5f, 0.5f, 0.5f, 0.5f);
        bool pointable = true;
index 206ca55d02e19a03ef7a7dfbe6c65e4b727f003e..5574304717aee819cbf0003db12843910301ec0e 100644 (file)
@@ -193,6 +193,7 @@ void read_object_properties(lua_State *L, int index,
        if (getintfield(L, -1, "hp_max", hp_max))
                prop->hp_max = (s16)rangelim(hp_max, 0, S16_MAX);
 
+       getintfield(L, -1, "breath_max", prop->breath_max);
        getboolfield(L, -1, "physical", prop->physical);
        getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
 
@@ -306,6 +307,8 @@ void push_object_properties(lua_State *L, ObjectProperties *prop)
        lua_newtable(L);
        lua_pushnumber(L, prop->hp_max);
        lua_setfield(L, -2, "hp_max");
+       lua_pushnumber(L, prop->breath_max);
+       lua_setfield(L, -2, "breath_max");
        lua_pushboolean(L, prop->physical);
        lua_setfield(L, -2, "physical");
        lua_pushboolean(L, prop->collideWithObjects);
index 33ff6fcef34fe8c1009ed30fe2139f47395037d4..2fdd76c22541d65207bcf819c7bde352e23c0d24 100644 (file)
@@ -2542,7 +2542,7 @@ void Server::RespawnPlayer(u16 peer_id)
                        << " respawns" << std::endl;
 
        playersao->setHP(playersao->accessObjectProperties()->hp_max);
-       playersao->setBreath(PLAYER_MAX_BREATH);
+       playersao->setBreath(playersao->accessObjectProperties()->breath_max);
 
        bool repositioned = m_script->on_respawnplayer(playersao);
        if (!repositioned) {