Add reasons to on_dieplayer and on_hpchange

This commit is contained in:
Andrew Ward 2018-03-28 16:05:18 +01:00 committed by GitHub
parent 2323842dd3
commit dfc8198349
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 219 additions and 52 deletions

@ -529,11 +529,11 @@ end
core.registered_on_player_hpchanges = { modifiers = { }, loggers = { } } core.registered_on_player_hpchanges = { modifiers = { }, loggers = { } }
function core.registered_on_player_hpchange(player, hp_change) function core.registered_on_player_hpchange(player, hp_change, reason)
local last = false local last = false
for i = #core.registered_on_player_hpchanges.modifiers, 1, -1 do for i = #core.registered_on_player_hpchanges.modifiers, 1, -1 do
local func = core.registered_on_player_hpchanges.modifiers[i] local func = core.registered_on_player_hpchanges.modifiers[i]
hp_change, last = func(player, hp_change) hp_change, last = func(player, hp_change, reason)
if type(hp_change) ~= "number" then if type(hp_change) ~= "number" then
local debuginfo = debug.getinfo(func) local debuginfo = debug.getinfo(func)
error("The register_on_hp_changes function has to return a number at " .. error("The register_on_hp_changes function has to return a number at " ..
@ -544,7 +544,7 @@ function core.registered_on_player_hpchange(player, hp_change)
end end
end end
for i, func in ipairs(core.registered_on_player_hpchanges.loggers) do for i, func in ipairs(core.registered_on_player_hpchanges.loggers) do
func(player, hp_change) func(player, hp_change, reason)
end end
return hp_change return hp_change
end end

@ -1136,7 +1136,7 @@ previous.
This combination results in noise varying very roughly between -2.0 and 2.0 and This combination results in noise varying very roughly between -2.0 and 2.0 and
with an average value of 0.0, so `scale` and `offset` are then used to multiply with an average value of 0.0, so `scale` and `offset` are then used to multiply
and offset the noise variation. and offset the noise variation.
The final perlin noise variation is created as follows: The final perlin noise variation is created as follows:
@ -2779,8 +2779,6 @@ Call these functions only at load time!
is a bit faster than usually. is a bit faster than usually.
* `minetest.register_on_newplayer(func(ObjectRef))` * `minetest.register_on_newplayer(func(ObjectRef))`
* Called after a new player has been created * Called after a new player has been created
* `minetest.register_on_dieplayer(func(ObjectRef))`
* Called when a player dies
* `minetest.register_on_punchplayer(func(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))` * `minetest.register_on_punchplayer(func(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))`
* Called when a player is punched * Called when a player is punched
* `player` - ObjectRef - Player that was punched * `player` - ObjectRef - Player that was punched
@ -2792,15 +2790,28 @@ Call these functions only at load time!
the puncher to the punched. the puncher to the punched.
* `damage` - number that represents the damage calculated by the engine * `damage` - number that represents the damage calculated by the engine
* should return `true` to prevent the default damage mechanism * should return `true` to prevent the default damage mechanism
* `minetest.register_on_player_hpchange(func(player, hp_change), modifier)` * `minetest.register_on_player_hpchange(func(player, hp_change, reason), modifier)`
* Called when the player gets damaged or healed * Called when the player gets damaged or healed
* `player`: ObjectRef of the player * `player`: ObjectRef of the player
* `hp_change`: the amount of change. Negative when it is damage. * `hp_change`: the amount of change. Negative when it is damage.
* `reason`: a PlayerHPChangeReason table.
* The `type` field will have one of the following values:
* `set_hp` - A mod or the engine called `set_hp` without
giving a type - use this for custom damage types.
* `punch` - Was punched. `reason.object` will hold the puncher, or nil if none.
* `fall`
* `node_damage` - damage_per_second from a neighbouring node.
* `drown`
* `respawn`
* Any of the above types may have additional fields from mods.
* `reason.from` will be `mod` or `engine`.
* `modifier`: when true, the function should return the actual `hp_change`. * `modifier`: when true, the function should return the actual `hp_change`.
Note: modifiers only get a temporary hp_change that can be modified by Note: modifiers only get a temporary hp_change that can be modified by later modifiers.
later modifiers. modifiers can return true as a second argument to stop modifiers can return true as a second argument to stop the execution of further functions.
the execution of further functions. Non-modifiers receive the final hp Non-modifiers receive the final hp change calculated by the modifiers.
change calculated by the modifiers. * `minetest.register_on_dieplayer(func(ObjectRef, reason))`
* Called when a player dies
* `reason`: a PlayerHPChangeReason table, see register_on_player_hpchange
* `minetest.register_on_respawnplayer(func(ObjectRef))` * `minetest.register_on_respawnplayer(func(ObjectRef))`
* Called when player is to be respawned * Called when player is to be respawned
* Called _before_ repositioning of player occurs * Called _before_ repositioning of player occurs
@ -3939,7 +3950,8 @@ This is basically a reference to a C++ `ServerActiveObject`
* `direction`: can be `nil` * `direction`: can be `nil`
* `right_click(clicker)`; `clicker` is another `ObjectRef` * `right_click(clicker)`; `clicker` is another `ObjectRef`
* `get_hp()`: returns number of hitpoints (2 * number of hearts) * `get_hp()`: returns number of hitpoints (2 * number of hearts)
* `set_hp(hp)`: set number of hitpoints (2 * number of hearts) * `set_hp(hp, reason)`: set number of hitpoints (2 * number of hearts).
* See reason in register_on_player_hpchange
* `get_inventory()`: returns an `InvRef` * `get_inventory()`: returns an `InvRef`
* `get_wield_list()`: returns the name of the inventory list the wielded item * `get_wield_list()`: returns the name of the inventory list the wielded item
is in. is in.

@ -9,3 +9,32 @@ assert(pseudo:next() == 22290)
assert(pseudo:next() == 13854) assert(pseudo:next() == 13854)
--
-- HP Change Reasons
--
local expect = nil
minetest.register_on_joinplayer(function(player)
expect = { type = "set_hp", from = "mod" }
player:set_hp(3)
assert(expect == nil)
expect = { a = 234, type = "set_hp", from = "mod" }
player:set_hp(10, { a= 234 })
assert(expect == nil)
expect = { df = 3458973454, type = "fall", from = "mod" }
player:set_hp(10, { type = "fall", df = 3458973454 })
assert(expect == nil)
end)
minetest.register_on_player_hpchange(function(player, hp, reason)
for key, value in pairs(reason) do
assert(expect[key] == value)
end
for key, value in pairs(expect) do
assert(reason[key] == value)
end
expect = nil
end)

@ -921,8 +921,9 @@ void PlayerSAO::step(float dtime, bool send_recommended)
// No more breath, damage player // No more breath, damage player
if (m_breath == 0) { if (m_breath == 0) {
setHP(m_hp - c.drowning); PlayerHPChangeReason reason(PlayerHPChangeReason::DROWNING);
m_env->getGameDef()->SendPlayerHPOrDie(this); setHP(m_hp - c.drowning, reason);
m_env->getGameDef()->SendPlayerHPOrDie(this, reason);
} }
} }
} }
@ -961,8 +962,9 @@ void PlayerSAO::step(float dtime, bool send_recommended)
if (damage_per_second != 0 && m_hp > 0) { if (damage_per_second != 0 && m_hp > 0) {
s16 newhp = ((s32) damage_per_second > m_hp ? 0 : m_hp - damage_per_second); s16 newhp = ((s32) damage_per_second > m_hp ? 0 : m_hp - damage_per_second);
setHP(newhp); PlayerHPChangeReason reason(PlayerHPChangeReason::NODE_DAMAGE);
m_env->getGameDef()->SendPlayerHPOrDie(this); setHP(newhp, reason);
m_env->getGameDef()->SendPlayerHPOrDie(this, reason);
} }
} }
@ -1208,7 +1210,8 @@ int PlayerSAO::punch(v3f dir,
hitparams.hp); hitparams.hp);
if (!damage_handled) { if (!damage_handled) {
setHP(getHP() - hitparams.hp); setHP(getHP() - hitparams.hp,
PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher));
} else { // override client prediction } else { // override client prediction
if (puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) { if (puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
std::string str = gob_cmd_punched(0, getHP()); std::string str = gob_cmd_punched(0, getHP());
@ -1238,11 +1241,11 @@ s16 PlayerSAO::readDamage()
return damage; return damage;
} }
void PlayerSAO::setHP(s16 hp) void PlayerSAO::setHP(s16 hp, const PlayerHPChangeReason &reason)
{ {
s16 oldhp = m_hp; s16 oldhp = m_hp;
s16 hp_change = m_env->getScriptIface()->on_player_hpchange(this, hp - oldhp); s16 hp_change = m_env->getScriptIface()->on_player_hpchange(this, hp - oldhp, reason);
if (hp_change == 0) if (hp_change == 0)
return; return;
hp = oldhp + hp_change; hp = oldhp + hp_change;

@ -245,7 +245,7 @@ public:
ServerActiveObject *puncher, ServerActiveObject *puncher,
float time_from_last_punch); float time_from_last_punch);
void rightClick(ServerActiveObject *clicker) {} void rightClick(ServerActiveObject *clicker) {}
void setHP(s16 hp); void setHP(s16 hp, const PlayerHPChangeReason &reason);
void setHPRaw(s16 hp) { m_hp = hp; } void setHPRaw(s16 hp) { m_hp = hp; }
s16 readDamage(); s16 readDamage();
u16 getBreath() const { return m_breath; } u16 getBreath() const { return m_breath; }
@ -417,3 +417,64 @@ public:
bool m_physics_override_new_move = true; bool m_physics_override_new_move = true;
bool m_physics_override_sent = false; bool m_physics_override_sent = false;
}; };
struct PlayerHPChangeReason {
enum Type : u8 {
SET_HP,
PLAYER_PUNCH,
FALL,
NODE_DAMAGE,
DROWNING,
RESPAWN
};
Type type = SET_HP;
ServerActiveObject *object;
bool from_mod = false;
int lua_reference = -1;
bool setTypeFromString(const std::string &typestr)
{
if (typestr == "set_hp")
type = SET_HP;
else if (typestr == "punch")
type = PLAYER_PUNCH;
else if (typestr == "fall")
type = FALL;
else if (typestr == "node_damage")
type = NODE_DAMAGE;
else if (typestr == "drown")
type = DROWNING;
else if (typestr == "respawn")
type = RESPAWN;
else
return false;
return true;
}
std::string getTypeAsString() const
{
switch (type) {
case PlayerHPChangeReason::SET_HP:
return "set_hp";
case PlayerHPChangeReason::PLAYER_PUNCH:
return "punch";
case PlayerHPChangeReason::FALL:
return "fall";
case PlayerHPChangeReason::NODE_DAMAGE:
return "node_damage";
case PlayerHPChangeReason::DROWNING:
return "drown";
case PlayerHPChangeReason::RESPAWN:
return "respawn";
default:
return "?";
}
}
PlayerHPChangeReason(Type type, ServerActiveObject *object=NULL):
type(type), object(object)
{}
};

@ -812,8 +812,9 @@ void Server::handleCommand_Damage(NetworkPacket* pkt)
<< (int)damage << " hp at " << PP(playersao->getBasePosition() / BS) << (int)damage << " hp at " << PP(playersao->getBasePosition() / BS)
<< std::endl; << std::endl;
playersao->setHP(playersao->getHP() - damage); PlayerHPChangeReason reason(PlayerHPChangeReason::FALL);
SendPlayerHPOrDie(playersao); playersao->setHP(playersao->getHP() - damage, reason);
SendPlayerHPOrDie(playersao, reason);
} }
} }
@ -1175,12 +1176,14 @@ void Server::handleCommand_Interact(NetworkPacket* pkt)
// If the object is a player and its HP changed // If the object is a player and its HP changed
if (src_original_hp != pointed_object->getHP() && if (src_original_hp != pointed_object->getHP() &&
pointed_object->getType() == ACTIVEOBJECT_TYPE_PLAYER) { pointed_object->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
SendPlayerHPOrDie((PlayerSAO *)pointed_object); SendPlayerHPOrDie((PlayerSAO *)pointed_object,
PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, playersao));
} }
// If the puncher is a player and its HP changed // If the puncher is a player and its HP changed
if (dst_origin_hp != playersao->getHP()) if (dst_origin_hp != playersao->getHP())
SendPlayerHPOrDie(playersao); SendPlayerHPOrDie(playersao,
PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, pointed_object));
} }
} // action == 0 } // action == 0

@ -43,6 +43,7 @@ extern "C" {
#include <cstdio> #include <cstdio>
#include <cstdarg> #include <cstdarg>
#include "script/common/c_content.h" #include "script/common/c_content.h"
#include "content_sao.h"
#include <sstream> #include <sstream>
@ -151,7 +152,7 @@ void ScriptApiBase::clientOpenLibs(lua_State *L)
{ LUA_JITLIBNAME, luaopen_jit }, { LUA_JITLIBNAME, luaopen_jit },
#endif #endif
}; };
for (const std::pair<std::string, lua_CFunction> &lib : m_libs) { for (const std::pair<std::string, lua_CFunction> &lib : m_libs) {
lua_pushcfunction(L, lib.second); lua_pushcfunction(L, lib.second);
lua_pushstring(L, lib.first.c_str()); lua_pushstring(L, lib.first.c_str());
@ -381,6 +382,26 @@ void ScriptApiBase::objectrefGetOrCreate(lua_State *L,
} }
} }
void ScriptApiBase::pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason &reason)
{
if (reason.lua_reference >= 0) {
lua_rawgeti(L, LUA_REGISTRYINDEX, reason.lua_reference);
luaL_unref(L, LUA_REGISTRYINDEX, reason.lua_reference);
} else
lua_newtable(L);
lua_pushstring(L, reason.getTypeAsString().c_str());
lua_setfield(L, -2, "type");
lua_pushstring(L, reason.from_mod ? "mod" : "engine");
lua_setfield(L, -2, "from");
if (reason.object) {
objectrefGetOrCreate(L, reason.object);
lua_setfield(L, -2, "object");
}
}
Server* ScriptApiBase::getServer() Server* ScriptApiBase::getServer()
{ {
return dynamic_cast<Server *>(m_gamedef); return dynamic_cast<Server *>(m_gamedef);

@ -72,6 +72,7 @@ class IGameDef;
class Environment; class Environment;
class GUIEngine; class GUIEngine;
class ServerActiveObject; class ServerActiveObject;
class PlayerHPChangeReason;
class ScriptApiBase { class ScriptApiBase {
public: public:
@ -139,6 +140,8 @@ protected:
void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj); void objectrefGetOrCreate(lua_State *L, ServerActiveObject *cobj);
void pushPlayerHPChangeReason(lua_State *L, const PlayerHPChangeReason& reason);
std::recursive_mutex m_luastackmutex; std::recursive_mutex m_luastackmutex;
std::string m_last_run_mod; std::string m_last_run_mod;
bool m_secure = false; bool m_secure = false;

@ -36,16 +36,20 @@ void ScriptApiPlayer::on_newplayer(ServerActiveObject *player)
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
} }
void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player) void ScriptApiPlayer::on_dieplayer(ServerActiveObject *player, const PlayerHPChangeReason &reason)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
// Get core.registered_on_dieplayers // Get callback table
lua_getglobal(L, "core"); lua_getglobal(L, "core");
lua_getfield(L, -1, "registered_on_dieplayers"); lua_getfield(L, -1, "registered_on_dieplayers");
// Call callbacks
// Push arguments
objectrefGetOrCreate(L, player); objectrefGetOrCreate(L, player);
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST); pushPlayerHPChangeReason(L, reason);
// Run callbacks
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
} }
bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player, bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
@ -71,7 +75,7 @@ bool ScriptApiPlayer::on_punchplayer(ServerActiveObject *player,
} }
s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player, s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
s16 hp_change) s16 hp_change, const PlayerHPChangeReason &reason)
{ {
SCRIPTAPI_PRECHECKHEADER SCRIPTAPI_PRECHECKHEADER
@ -82,9 +86,13 @@ s16 ScriptApiPlayer::on_player_hpchange(ServerActiveObject *player,
lua_getfield(L, -1, "registered_on_player_hpchange"); lua_getfield(L, -1, "registered_on_player_hpchange");
lua_remove(L, -2); lua_remove(L, -2);
// Push arguments
objectrefGetOrCreate(L, player); objectrefGetOrCreate(L, player);
lua_pushnumber(L, hp_change); lua_pushnumber(L, hp_change);
PCALL_RES(lua_pcall(L, 2, 1, error_handler)); pushPlayerHPChangeReason(L, reason);
// Call callbacks
PCALL_RES(lua_pcall(L, 3, 1, error_handler));
hp_change = lua_tointeger(L, -1); hp_change = lua_tointeger(L, -1);
lua_pop(L, 2); // Pop result and error handler lua_pop(L, 2); // Pop result and error handler
return hp_change; return hp_change;

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/string.h" #include "util/string.h"
struct ToolCapabilities; struct ToolCapabilities;
struct PlayerHPChangeReason;
class ScriptApiPlayer : virtual public ScriptApiBase class ScriptApiPlayer : virtual public ScriptApiBase
{ {
@ -31,7 +32,7 @@ public:
virtual ~ScriptApiPlayer() = default; virtual ~ScriptApiPlayer() = default;
void on_newplayer(ServerActiveObject *player); void on_newplayer(ServerActiveObject *player);
void on_dieplayer(ServerActiveObject *player); void on_dieplayer(ServerActiveObject *player, const PlayerHPChangeReason &reason);
bool on_respawnplayer(ServerActiveObject *player); bool on_respawnplayer(ServerActiveObject *player);
bool on_prejoinplayer(const std::string &name, const std::string &ip, bool on_prejoinplayer(const std::string &name, const std::string &ip,
std::string *reason); std::string *reason);
@ -42,7 +43,8 @@ public:
bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter, bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter,
float time_from_last_punch, const ToolCapabilities *toolcap, float time_from_last_punch, const ToolCapabilities *toolcap,
v3f dir, s16 damage); v3f dir, s16 damage);
s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change); s16 on_player_hpchange(ServerActiveObject *player, s16 hp_change,
const PlayerHPChangeReason &reason);
void on_playerReceiveFields(ServerActiveObject *player, void on_playerReceiveFields(ServerActiveObject *player,
const std::string &formname, const StringMap &fields); const std::string &formname, const StringMap &fields);
void on_auth_failure(const std::string &name, const std::string &ip); void on_auth_failure(const std::string &name, const std::string &ip);

@ -194,13 +194,14 @@ int ObjectRef::l_punch(lua_State *L)
// If the punched is a player, and its HP changed // If the punched is a player, and its HP changed
if (src_original_hp != co->getHP() && if (src_original_hp != co->getHP() &&
co->getType() == ACTIVEOBJECT_TYPE_PLAYER) { co->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co); getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, puncher));
} }
// If the puncher is a player, and its HP changed // If the puncher is a player, and its HP changed
if (dst_origin_hp != puncher->getHP() && if (dst_origin_hp != puncher->getHP() &&
puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) { puncher->getType() == ACTIVEOBJECT_TYPE_PLAYER) {
getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher); getServer(L)->SendPlayerHPOrDie((PlayerSAO *)puncher,
PlayerHPChangeReason(PlayerHPChangeReason::PLAYER_PUNCH, co));
} }
return 0; return 0;
} }
@ -226,17 +227,36 @@ int ObjectRef::l_right_click(lua_State *L)
int ObjectRef::l_set_hp(lua_State *L) int ObjectRef::l_set_hp(lua_State *L)
{ {
NO_MAP_LOCK_REQUIRED; NO_MAP_LOCK_REQUIRED;
// Get Object
ObjectRef *ref = checkobject(L, 1); ObjectRef *ref = checkobject(L, 1);
luaL_checknumber(L, 2); luaL_checknumber(L, 2);
ServerActiveObject *co = getobject(ref); ServerActiveObject *co = getobject(ref);
if (co == NULL) return 0; if (co == NULL)
return 0;
// Get HP
int hp = lua_tonumber(L, 2); int hp = lua_tonumber(L, 2);
/*infostream<<"ObjectRef::l_set_hp(): id="<<co->getId()
<<" hp="<<hp<<std::endl;*/ // Get Reason
PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
reason.from_mod = true;
if (lua_istable(L, 3)) {
lua_pushvalue(L, 3);
lua_getfield(L, -1, "type");
if (lua_isstring(L, -1) && !reason.setTypeFromString(lua_tostring(L, -1))) {
errorstream << "Bad type given!" << std::endl;
}
lua_pop(L, 1);
reason.lua_reference = luaL_ref(L, LUA_REGISTRYINDEX);
}
// Do it // Do it
co->setHP(hp); co->setHP(hp, reason);
if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co); getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason);
// Return // Return
return 0; return 0;
@ -729,9 +749,10 @@ int ObjectRef::l_set_properties(lua_State *L)
return 0; return 0;
read_object_properties(L, 2, prop, getServer(L)->idef()); read_object_properties(L, 2, prop, getServer(L)->idef());
if (prop->hp_max < co->getHP()) { if (prop->hp_max < co->getHP()) {
co->setHP(prop->hp_max); PlayerHPChangeReason reason(PlayerHPChangeReason::SET_HP);
co->setHP(prop->hp_max, reason);
if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER) if (co->getType() == ACTIVEOBJECT_TYPE_PLAYER)
getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co); getServer(L)->SendPlayerHPOrDie((PlayerSAO *)co, reason);
} }
co->notifyObjectPropertiesModified(); co->notifyObjectPropertiesModified();
return 0; return 0;

@ -1029,7 +1029,8 @@ PlayerSAO* Server::StageTwoClientInit(session_t peer_id)
if (playersao->isDead()) if (playersao->isDead())
SendDeathscreen(peer_id, false, v3f(0,0,0)); SendDeathscreen(peer_id, false, v3f(0,0,0));
else else
SendPlayerHPOrDie(playersao); SendPlayerHPOrDie(playersao,
PlayerHPChangeReason(PlayerHPChangeReason::SET_HP));
// Send Breath // Send Breath
SendPlayerBreath(playersao); SendPlayerBreath(playersao);
@ -1392,7 +1393,7 @@ void Server::SendMovement(session_t peer_id)
Send(&pkt); Send(&pkt);
} }
void Server::SendPlayerHPOrDie(PlayerSAO *playersao) void Server::SendPlayerHPOrDie(PlayerSAO *playersao, const PlayerHPChangeReason &reason)
{ {
if (!g_settings->getBool("enable_damage")) if (!g_settings->getBool("enable_damage"))
return; return;
@ -1403,7 +1404,7 @@ void Server::SendPlayerHPOrDie(PlayerSAO *playersao)
if (is_alive) if (is_alive)
SendPlayerHP(peer_id); SendPlayerHP(peer_id);
else else
DiePlayer(peer_id); DiePlayer(peer_id, reason);
} }
void Server::SendHP(session_t peer_id, u16 hp) void Server::SendHP(session_t peer_id, u16 hp)
@ -2493,7 +2494,7 @@ void Server::sendDetachedInventories(session_t peer_id)
Something random Something random
*/ */
void Server::DiePlayer(session_t peer_id) void Server::DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason)
{ {
PlayerSAO *playersao = getPlayerSAO(peer_id); PlayerSAO *playersao = getPlayerSAO(peer_id);
// In some rare cases this can be NULL -- if the player is disconnected // In some rare cases this can be NULL -- if the player is disconnected
@ -2505,10 +2506,10 @@ void Server::DiePlayer(session_t peer_id)
<< playersao->getPlayer()->getName() << playersao->getPlayer()->getName()
<< " dies" << std::endl; << " dies" << std::endl;
playersao->setHP(0); playersao->setHP(0, reason);
// Trigger scripted stuff // Trigger scripted stuff
m_script->on_dieplayer(playersao); m_script->on_dieplayer(playersao, reason);
SendPlayerHP(peer_id); SendPlayerHP(peer_id);
SendDeathscreen(peer_id, false, v3f(0,0,0)); SendDeathscreen(peer_id, false, v3f(0,0,0));
@ -2523,7 +2524,8 @@ void Server::RespawnPlayer(session_t peer_id)
<< playersao->getPlayer()->getName() << playersao->getPlayer()->getName()
<< " respawns" << std::endl; << " respawns" << std::endl;
playersao->setHP(playersao->accessObjectProperties()->hp_max); playersao->setHP(playersao->accessObjectProperties()->hp_max,
PlayerHPChangeReason(PlayerHPChangeReason::RESPAWN));
playersao->setBreath(playersao->accessObjectProperties()->breath_max); playersao->setBreath(playersao->accessObjectProperties()->breath_max);
bool repositioned = m_script->on_respawnplayer(playersao); bool repositioned = m_script->on_respawnplayer(playersao);

@ -53,6 +53,7 @@ class Inventory;
class ModChannelMgr; class ModChannelMgr;
class RemotePlayer; class RemotePlayer;
class PlayerSAO; class PlayerSAO;
struct PlayerHPChangeReason;
class IRollbackManager; class IRollbackManager;
struct RollbackAction; struct RollbackAction;
class EmergeManager; class EmergeManager;
@ -328,7 +329,7 @@ public:
void printToConsoleOnly(const std::string &text); void printToConsoleOnly(const std::string &text);
void SendPlayerHPOrDie(PlayerSAO *player); void SendPlayerHPOrDie(PlayerSAO *player, const PlayerHPChangeReason &reason);
void SendPlayerBreath(PlayerSAO *sao); void SendPlayerBreath(PlayerSAO *sao);
void SendInventory(PlayerSAO* playerSAO); void SendInventory(PlayerSAO* playerSAO);
void SendMovePlayer(session_t peer_id); void SendMovePlayer(session_t peer_id);
@ -451,7 +452,7 @@ private:
Something random Something random
*/ */
void DiePlayer(session_t peer_id); void DiePlayer(session_t peer_id, const PlayerHPChangeReason &reason);
void RespawnPlayer(session_t peer_id); void RespawnPlayer(session_t peer_id);
void DeleteClient(session_t peer_id, ClientDeletionReason reason); void DeleteClient(session_t peer_id, ClientDeletionReason reason);
void UpdateCrafting(RemotePlayer *player); void UpdateCrafting(RemotePlayer *player);

@ -46,6 +46,7 @@ class ServerEnvironment;
struct ItemStack; struct ItemStack;
struct ToolCapabilities; struct ToolCapabilities;
struct ObjectProperties; struct ObjectProperties;
struct PlayerHPChangeReason;
class ServerActiveObject : public ActiveObject class ServerActiveObject : public ActiveObject
{ {
@ -139,7 +140,7 @@ public:
{ return 0; } { return 0; }
virtual void rightClick(ServerActiveObject *clicker) virtual void rightClick(ServerActiveObject *clicker)
{} {}
virtual void setHP(s16 hp) virtual void setHP(s16 hp, const PlayerHPChangeReason &reason)
{} {}
virtual s16 getHP() const virtual s16 getHP() const
{ return 0; } { return 0; }