2021-04-14 15:46:52 +02:00
mcl_damage = {
modifiers = { } ,
2021-04-25 13:50:07 +02:00
damage_callbacks = { } ,
death_callbacks = { } ,
2021-04-14 15:46:52 +02:00
types = {
in_fire = { is_fire = true } ,
lightning_bolt = { is_lightning = true } ,
2021-04-25 20:51:13 +02:00
on_fire = { is_fire = true , bypasses_armor = true } ,
2021-04-14 15:46:52 +02:00
lava = { is_fire = true } ,
hot_floor = { is_fire = true } ,
in_wall = { bypasses_armor = true } ,
drown = { bypasses_armor = true } ,
starve = { bypasses_armor = true , bypasses_magic = true } ,
cactus = { } ,
2022-10-24 16:03:24 +02:00
sweet_berry = { } ,
2021-04-14 15:46:52 +02:00
fall = { bypasses_armor = true } ,
fly_into_wall = { bypasses_armor = true } , -- unused
2022-05-25 23:25:15 +02:00
out_of_world = { bypasses_armor = true , bypasses_magic = true , bypasses_invulnerability = true , bypasses_totem = true } ,
2021-04-14 15:46:52 +02:00
generic = { bypasses_armor = true } ,
magic = { is_magic = true , bypasses_armor = true } ,
2021-04-25 16:42:38 +02:00
dragon_breath = { is_magic = true , bypasses_armor = true } , -- this is only used for dragon fireball; dragon fireball does not actually deal impact damage tho, so this is unreachable
2021-04-18 20:08:08 +02:00
wither = { bypasses_armor = true } , -- unused
2021-04-25 16:42:38 +02:00
wither_skull = { is_magic = true , is_explosion = true } , -- this is non-MC but a workaround to get the proper death message
2021-04-14 15:46:52 +02:00
anvil = { } ,
2021-04-25 16:42:38 +02:00
falling_node = { } , -- this is falling_block in MC
2021-04-14 15:46:52 +02:00
mob = { } ,
player = { } ,
arrow = { is_projectile = true } ,
fireball = { is_projectile = true , is_fire = true } ,
thorns = { is_magic = true } ,
explosion = { is_explosion = true } ,
2021-04-18 18:49:00 +02:00
cramming = { bypasses_armor = true } , -- unused
fireworks = { is_explosion = true } , -- unused
2021-04-14 15:46:52 +02:00
}
}
2024-06-10 04:09:07 +02:00
local damage_enabled = vl_tuning.setting ( " damage_enabled " , " bool " , {
default = minetest.settings : get_bool ( " enabled_damage " , true )
} )
2022-09-16 01:34:41 +02:00
2021-04-18 20:08:08 +02:00
function mcl_damage . register_modifier ( func , priority )
table.insert ( mcl_damage.modifiers , { func = func , priority = priority or 0 } )
end
2021-04-25 13:50:07 +02:00
function mcl_damage . register_on_damage ( func )
table.insert ( mcl_damage.damage_callbacks , func )
end
function mcl_damage . register_on_death ( func )
table.insert ( mcl_damage.death_callbacks , func )
end
function mcl_damage . run_modifiers ( obj , damage , reason )
2021-04-18 20:08:08 +02:00
for _ , modf in ipairs ( mcl_damage.modifiers ) do
2021-04-25 13:50:07 +02:00
damage = modf.func ( obj , damage , reason ) or damage
2021-04-18 20:08:08 +02:00
if damage == 0 then
return 0
end
end
return damage
end
2021-04-14 15:46:52 +02:00
2021-04-25 13:50:07 +02:00
local function run_callbacks ( funcs , ... )
for _ , func in pairs ( funcs ) do
func ( ... )
end
end
function mcl_damage . run_damage_callbacks ( obj , damage , reason )
run_callbacks ( mcl_damage.damage_callbacks , obj , damage , reason )
end
function mcl_damage . run_death_callbacks ( obj , reason )
run_callbacks ( mcl_damage.death_callbacks , obj , reason )
end
2021-04-18 20:08:08 +02:00
function mcl_damage . from_punch ( mcl_reason , object )
mcl_reason.direct = object
local luaentity = mcl_reason.direct : get_luaentity ( )
if luaentity then
if luaentity._is_arrow then
mcl_reason.type = " arrow "
elseif luaentity._is_fireball then
mcl_reason.type = " fireball "
2022-05-25 14:02:10 +02:00
elseif luaentity.is_mob then
2021-04-18 20:08:08 +02:00
mcl_reason.type = " mob "
end
mcl_reason.source = mcl_reason.source or luaentity._source_object
2021-04-14 15:46:52 +02:00
else
2021-04-18 20:08:08 +02:00
mcl_reason.type = " player "
2021-04-14 15:46:52 +02:00
end
end
2021-04-18 20:08:08 +02:00
function mcl_damage . finish_reason ( mcl_reason )
mcl_reason.source = mcl_reason.source or mcl_reason.direct
mcl_reason.flags = mcl_damage.types [ mcl_reason.type ]
2021-04-14 15:46:52 +02:00
end
2021-04-18 20:08:08 +02:00
function mcl_damage . from_mt ( mt_reason )
2023-07-30 11:16:02 +02:00
if mt_reason._mcl_cached_reason then
return mt_reason._mcl_cached_reason
2021-04-25 13:50:07 +02:00
end
2021-04-25 20:51:13 +02:00
local mcl_reason
if mt_reason._mcl_reason then
mcl_reason = mt_reason._mcl_reason
else
mcl_reason = { type = " generic " }
if mt_reason._mcl_type then
mcl_reason.type = mt_reason._mcl_type
elseif mt_reason.type == " fall " then
mcl_reason.type = " fall "
elseif mt_reason.type == " drown " then
mcl_reason.type = " drown "
elseif mt_reason.type == " punch " then
mcl_damage.from_punch ( mcl_reason , mt_reason.object )
elseif mt_reason.type == " node_damage " and mt_reason.node then
if minetest.get_item_group ( mt_reason.node , " fire " ) > 0 then
mcl_reason.type = " in_fire "
end
if minetest.get_item_group ( mt_reason.node , " lava " ) > 0 then
mcl_reason.type = " lava "
end
2021-04-14 17:20:51 +02:00
end
2021-04-14 15:46:52 +02:00
2021-04-25 20:51:13 +02:00
for key , value in pairs ( mt_reason ) do
if key : find ( " _mcl_ " ) == 1 then
mcl_reason [ key : sub ( 6 , # key ) ] = value
end
2021-04-14 15:46:52 +02:00
end
end
2021-04-18 20:08:08 +02:00
mcl_damage.finish_reason ( mcl_reason )
2021-04-25 20:51:13 +02:00
mt_reason._mcl_cached_reason = mcl_reason
2021-04-14 19:06:11 +02:00
return mcl_reason
2021-04-14 15:46:52 +02:00
end
function mcl_damage . register_type ( name , def )
mcl_damage.types [ name ] = def
end
2021-04-18 20:08:08 +02:00
minetest.register_on_player_hpchange ( function ( player , hp_change , mt_reason )
2024-06-10 04:09:07 +02:00
if not damage_enabled [ 1 ] then return 0 end
2021-04-18 20:08:08 +02:00
if hp_change < 0 then
2021-04-25 13:50:07 +02:00
if player : get_hp ( ) <= 0 then
return 0
end
hp_change = - mcl_damage.run_modifiers ( player , - hp_change , mcl_damage.from_mt ( mt_reason ) )
2021-04-14 15:46:52 +02:00
end
return hp_change
end , true )
2021-04-25 13:50:07 +02:00
minetest.register_on_player_hpchange ( function ( player , hp_change , mt_reason )
2024-06-10 04:09:07 +02:00
if not damage_enabled [ 1 ] then return 0 end
2021-05-05 13:27:30 +02:00
if player : get_hp ( ) > 0 then
2021-05-05 14:41:23 +02:00
if hp_change < 0 then
mcl_damage.run_damage_callbacks ( player , - hp_change , mcl_damage.from_mt ( mt_reason ) )
end
2021-05-05 13:27:30 +02:00
end
2021-04-25 13:50:07 +02:00
end , false )
minetest.register_on_dieplayer ( function ( player , mt_reason )
2023-01-18 22:36:21 +01:00
mcl_damage.run_death_callbacks ( player , mcl_damage.from_mt ( mt_reason ) )
2022-08-15 00:14:39 +02:00
minetest.log ( " action " , " Player " .. player : get_player_name ( ) .. " died at " .. minetest.pos_to_string ( vector.round ( player : get_pos ( ) ) ) )
2021-04-25 13:50:07 +02:00
end )
2021-04-14 15:46:52 +02:00
minetest.register_on_mods_loaded ( function ( )
table.sort ( mcl_damage.modifiers , function ( a , b ) return a.priority < b.priority end )
end )