Respect object property hp_max field for players (#6287)
authorSmallJoker <SmallJoker@users.noreply.github.com>
Wed, 23 Aug 2017 20:32:10 +0000 (22:32 +0200)
committerLoïc Blot <nerzhul@users.noreply.github.com>
Wed, 23 Aug 2017 20:32:10 +0000 (22:32 +0200)
* Respect object property hp_max field for players
This allows modders to configure the maximal HP per player

* Statbars: Downscale bar to full 20 HP when exceeding this value
Add default max HP for players and breath constants to builtin
Document the constants

* Rename PLAYER_MAX_HP -> PLAYER_MAX_HP_DEFAULT

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

index 50c515b24875b6fefc2abd68787b58b9fdf1a1db..29eeb83307bbdf8ed964f953fede698f14190241 100644 (file)
@@ -21,6 +21,10 @@ core.EMERGE_GENERATED   = 4
 -- constants.h
 -- Size of mapblocks in nodes
 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
 
 -- light.h
 -- Maximum value for node 'light_source' parameter
index 6aa106140cdf6f39768d44f4cc70c1f62041653a..1b83dd4ac6a66dea3d4af56211da72080dcedd1c 100644 (file)
@@ -6,7 +6,7 @@ local health_bar_definition =
        hud_elem_type = "statbar",
        position = { x=0.5, y=1 },
        text = "heart.png",
-       number = 20,
+       number = core.PLAYER_MAX_HP_DEFAULT,
        direction = 0,
        size = { x=24, y=24 },
        offset = { x=(-10*24)-25, y=-(48+24+16)},
@@ -37,39 +37,45 @@ local function initialize_builtin_statbars(player)
                return
        end
 
-       if (hud_ids[name] == nil) then
+       if not hud_ids[name] then
                hud_ids[name] = {}
                -- flags are not transmitted to client on connect, we need to make sure
                -- our current flags are transmitted by sending them actively
                player:hud_set_flags(player:hud_get_flags())
        end
+       local hud = hud_ids[name]
 
        if player:hud_get_flags().healthbar and enable_damage then
-               if hud_ids[name].id_healthbar == nil then
-                       health_bar_definition.number = player:get_hp()
-                       hud_ids[name].id_healthbar  = player:hud_add(health_bar_definition)
+               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_ids[name].id_healthbar ~= nil then
-                       player:hud_remove(hud_ids[name].id_healthbar)
-                       hud_ids[name].id_healthbar = nil
+               if hud.id_healthbar ~= nil then
+                       player:hud_remove(hud.id_healthbar)
+                       hud.id_healthbar = nil
                end
        end
 
-       if (player:get_breath() < 11) then
+       if player:get_breath() < core.PLAYER_MAX_BREATH then
                if player:hud_get_flags().breathbar and enable_damage then
-                       if hud_ids[name].id_breathbar == nil then
-                               hud_ids[name].id_breathbar = player:hud_add(breath_bar_definition)
+                       if hud.id_breathbar == nil then
+                               hud.id_breathbar = player:hud_add(breath_bar_definition)
                        end
                else
-                       if hud_ids[name].id_breathbar ~= nil then
-                               player:hud_remove(hud_ids[name].id_breathbar)
-                               hud_ids[name].id_breathbar = nil
+                       if hud.id_breathbar ~= nil then
+                               player:hud_remove(hud.id_breathbar)
+                               hud.id_breathbar = nil
                        end
                end
-       elseif hud_ids[name].id_breathbar ~= nil then
-               player:hud_remove(hud_ids[name].id_breathbar)
-               hud_ids[name].id_breathbar = nil
+       elseif hud.id_breathbar ~= nil then
+               player:hud_remove(hud.id_breathbar)
+               hud.id_breathbar = nil
        end
 end
 
@@ -101,7 +107,12 @@ local function player_event_handler(player,eventname)
                initialize_builtin_statbars(player)
 
                if hud_ids[name].id_healthbar ~= nil then
-                       player:hud_change(hud_ids[name].id_healthbar,"number",player:get_hp())
+                       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)
                        return true
                end
        end
@@ -110,7 +121,7 @@ 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", player:get_breath() * 2)
                        return true
                end
        end
index 37c754c9d339b98741734311ad91ca6f056f8ba0..7af935056e146a7a67687e254da7b79e45c872cf 100644 (file)
@@ -3276,6 +3276,7 @@ This is basically a reference to a C++ `ServerActiveObject`
         * `0`: player is drowning,
         * `1`-`10`: remaining number of bubbles
         * `11`: bubbles bar is not shown
+        * See constant: `minetest.PLAYER_MAX_BREATH`
 * `set_attribute(attribute, value)`:
     * Sets an extra attribute with value on player.
     * `value` must be a string.
@@ -3980,6 +3981,7 @@ Definition tables
 
     {
         hp_max = 1,
+    --  ^ For players, the maximal HP defaults to `minetest.PLAYER_MAX_HP_DEFAULT`
         physical = true,
         collide_with_objects = true, -- collide with other objects if physical = true
         weight = 5,
index 4da66cc531bde00ebe2a1999fd05f359990ee965..ddf7218e278b11bd92095fb5a02b5cdd48ded1d8 100644 (file)
@@ -90,7 +90,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #define PLAYER_INVENTORY_SIZE (8 * 4)
 
 // Maximum hit points of a player
-#define PLAYER_MAX_HP 20
+#define PLAYER_MAX_HP_DEFAULT 20
 
 // Maximal breath of a player
 #define PLAYER_MAX_BREATH 11
index 621a64de0bdfe91ac88aaf043625cfd7da9c2da7..bc5fb164b4c2183976d25173a21db41dbb01deb7 100644 (file)
@@ -782,7 +782,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id
 {
        assert(m_peer_id != 0); // pre-condition
 
-       m_prop.hp_max = PLAYER_MAX_HP;
+       m_prop.hp_max = PLAYER_MAX_HP_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);
@@ -799,7 +799,7 @@ PlayerSAO::PlayerSAO(ServerEnvironment *env_, RemotePlayer *player_, u16 peer_id
        m_prop.is_visible = true;
        m_prop.makes_footstep_sound = true;
        m_prop.stepheight = PLAYER_DEFAULT_STEPHEIGHT * BS;
-       m_hp = PLAYER_MAX_HP;
+       m_hp = m_prop.hp_max;
 }
 
 PlayerSAO::~PlayerSAO()
@@ -1235,8 +1235,8 @@ void PlayerSAO::setHP(s16 hp)
 
        if (hp < 0)
                hp = 0;
-       else if (hp > PLAYER_MAX_HP)
-               hp = PLAYER_MAX_HP;
+       else if (hp > m_prop.hp_max)
+               hp = m_prop.hp_max;
 
        if (hp < oldhp && !g_settings->getBool("enable_damage")) {
                return;
index 20c18ee155c3ce18495f4f4e23472763163aa63f..c108ad3f1bec660155bff56ed116926b233f0a77 100644 (file)
@@ -100,7 +100,7 @@ void RemotePlayer::deSerialize(std::istream &is, const std::string &playername,
                try {
                        sao->setHPRaw(args.getS32("hp"));
                } catch(SettingNotFoundException &e) {
-                       sao->setHPRaw(PLAYER_MAX_HP);
+                       sao->setHPRaw(PLAYER_MAX_HP_DEFAULT);
                }
 
                try {
index ddcdd803d88070085514fd1a8de3f33db020a5e9..47443493b8a751129adc5e6599674b0502a896a4 100644 (file)
@@ -183,7 +183,9 @@ void read_object_properties(lua_State *L, int index,
        if(!lua_istable(L, index))
                return;
 
-       prop->hp_max = getintfield_default(L, -1, "hp_max", 10);
+       int hp_max = 0;
+       if (getintfield(L, -1, "hp_max", hp_max))
+               prop->hp_max = (s16)rangelim(hp_max, 0, S16_MAX);
 
        getboolfield(L, -1, "physical", prop->physical);
        getboolfield(L, -1, "collide_with_objects", prop->collideWithObjects);
index 46ac61f2749e51788e0e6c09c845e3e8f2cb357e..24fdeca4bfce9b955778eb4079550c24a645cade 100644 (file)
@@ -751,6 +751,11 @@ int ObjectRef::l_set_properties(lua_State *L)
        if (!prop)
                return 0;
        read_object_properties(L, 2, prop, getServer(L)->idef());
+       if (prop->hp_max < co->getHP()) {
+               co->setHP(prop->hp_max);
+               if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
+                       getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co);
+       }
        co->notifyObjectPropertiesModified();
        return 0;
 }
index f48066fad51c742a2fe7c4c498e878d5e566dea4..7d9cfbf592eb171bc64bb19576aaa1d3e78e30f8 100644 (file)
@@ -2588,7 +2588,7 @@ void Server::RespawnPlayer(u16 peer_id)
                        << playersao->getPlayer()->getName()
                        << " respawns" << std::endl;
 
-       playersao->setHP(PLAYER_MAX_HP);
+       playersao->setHP(playersao->accessObjectProperties()->hp_max);
        playersao->setBreath(PLAYER_MAX_BREATH);
 
        bool repositioned = m_script->on_respawnplayer(playersao);