Refactor, make "default" mod optional

master
Lars Mueller 2020-11-28 16:12:28 +01:00
parent bfcc16d67e
commit 0fc1846c7c
3 changed files with 242 additions and 282 deletions

View File

@ -4,7 +4,7 @@ A mod displaying a colored list of recent kills/deaths and the causes(killer, us
## About ## About
Depends on [`modlib`](https://github.com/appgurueu/modlib) and - depending on your configuration - also other mods. If you use the default configuration, it depends on `default` and `fire`. Depends on [`modlib`](https://github.com/appgurueu/modlib) and `fire`.
**Note: If there are other mods registering `on_punchplayer` or `on_hp_change` handlers, add them to the dependency list to make sure they execute before `deathlist`.** **Note: If there are other mods registering `on_punchplayer` or `on_hp_change` handlers, add them to the dependency list to make sure they execute before `deathlist`.**
Licensed under MIT. Licensed under MIT.

514
main.lua
View File

@ -1,309 +1,269 @@
modlib.log.create_channel("deathlist") -- Create modlib.log channel modlib.log.create_channel"deathlist"
-- Create modlib.log channel
local coordinate={ local coordinate = {
type="table", type = "table",
children={ children = { x = { type = "number" }, y = { type = "number" } }
x={type="number"},
y={type="number"}
}
} }
local color={ local component = { type = "number", interval = { 0, 255 }, int = true }
type="table", local color = { type = "table", children = { r = component, g = component, b = component } }
children={ local node_caused = {
r={type="number", interval={0,255}, int=true}, children = {
g={type="number", interval={0,255}, int=true}, color = color,
b={type="number", interval={0,255}, int=true} method = { type = "string" },
} nodes = {
type = "table",
keys = { type = "string" },
values = {
type = "table",
keys = {
possible_values = { name = true, color = true, method = true }
}
}
}
}
} }
local name_color_method = {
local node_caused={ children = { name = { type = "string" }, color = color, method = { type = "string" } }
children={
color=color,
method={type="string"},
nodes={
type="table",
keys={type="string"},
values={
type="table",
keys={possible_values={name=true, color=true, method=true}}
}
}
}
} }
local config=modlib.conf.import("deathlist", { local config = modlib.conf.import("deathlist", {
type="table", type = "table",
children={ children = {
max_messages={type="number", interval={1}}, max_messages = { type = "number", interval = { 1 } },
mode={type="string", possible_values={list=true,stack=true}}, mode = { type = "string", possible_values = { list = true, stack = true } },
autoremove_interval={func=function(interval) autoremove_interval = {
if type(interval) ~= "number" and interval ~= false then func = function(interval)
return "Wrong type: Expected number or false, found "..type(interval) if type(interval) ~= "number" and interval ~= false then
end return "Wrong type: Expected number or false, found " .. type(interval)
if interval <= 0 then end
return "Too small: Interval has to be > 0" if interval <= 0 then return "Too small: Interval has to be > 0" end
end end
end}, },
hud_pos=coordinate, hud_pos = coordinate,
hud_base_offset=coordinate, hud_base_offset = coordinate,
enable_environmental={type="boolean"}, enable_environmental = { type = "boolean" },
enable_unknown={type="boolean"}, enable_unknown = { type = "boolean" },
enable_forbidden_playernames={type="boolean"}, enable_forbidden_playernames = { type = "boolean" },
environmental_reasons = {
environmental_reasons={ children = {
children={ falling = name_color_method,
falling={ unknown = name_color_method,
children={ drowning = node_caused,
name={type="string"}, node_damage = node_caused
color=color, }
method={type="string"} }
} }
},
unknown={
children={
name={type="string"},
color=color,
method={type="string"}
}
},
drowning=node_caused,
node_damage=node_caused
}
}
}
}) })
modlib.table.add_all(getfenv(1), config) modlib.table.add_all(getfenv(1), config)
if enable_forbidden_playernames then if enable_forbidden_playernames then
modlib.player.register_forbidden_name(environmental_reasons.falling.name) modlib.player.register_forbidden_name(environmental_reasons.falling.name)
if enable_unknown then if enable_unknown then
modlib.player.register_forbidden_name(environmental_reasons.unknown.name) modlib.player.register_forbidden_name(environmental_reasons.unknown.name)
end end
for name, node in pairs(minetest.registered_nodes) do for name, node in pairs(minetest.registered_nodes) do
if (node.drowning or 0) > 0 then if (node.drowning or 0) > 0 then
local title=(environmental_reasons.drowning.nodes[name] or {}).name or node.description local title = (environmental_reasons.drowning.nodes[name] or {}).name or node.description
modlib.player.register_forbidden_name(title) modlib.player.register_forbidden_name(title)
end end
if (node.damage_per_second or 0) > 0 then if (node.damage_per_second or 0) > 0 then
local title=(environmental_reasons.node_damage.nodes[name] or {}).name or node.description local title = (environmental_reasons.node_damage.nodes[name] or {}).name or node.description
modlib.player.register_forbidden_name(title) modlib.player.register_forbidden_name(title)
end end
end end
end end
for _, table in pairs{ environmental_reasons, environmental_reasons.drowning.nodes, environmental_reasons.node_damage.nodes } do
modlib.table.map(environmental_reasons, function(v) for _, value in pairs(table) do
v.color=modlib.minetest.get_color_int(v.color) if value.color then
return v value.color = modlib.minetest.get_color_int(value.color)
end) end
end
modlib.table.map(environmental_reasons.drowning.nodes, function(v) end
if v.color then v.color=modlib.minetest.get_color_int(v.color) end hud_channels = {}
return v
end)
modlib.table.map(environmental_reasons.node_damage.nodes, function(v)
if v.color then v.color=modlib.minetest.get_color_int(v.color) end
return v
end)
hud_channels = {killers={}, items={}, victims={}} -- in order to reduce overhead
minetest.register_on_joinplayer(function(player) minetest.register_on_joinplayer(function(player)
hud_channels.killers[player:get_player_name()]={} hud_channels[player:get_player_name()] = { killers = {}, items = {}, victims = {} }
hud_channels.items[player:get_player_name()]={}
hud_channels.victims[player:get_player_name()]={}
end) end)
minetest.register_on_leaveplayer(function(player) hud_channels[player:get_player_name()] = nil end)
minetest.register_on_leaveplayer(function(player)
hud_channels.killers[player:get_player_name()]=nil
hud_channels.items[player:get_player_name()]=nil
hud_channels.victims[player:get_player_name()]=nil
end)
function remove_last_kill_msg_from_hud(listname, x_offset)
local list= hud_channels[listname]
for _,player in pairs(minetest.get_connected_players()) do
local name=player:get_player_name()
local hud_ids=list[name]
local i=#list[name]
if i > 0 then
if mode=="list" then
player:hud_remove(hud_ids[i])
hud_ids[i]=nil
else
player:hud_remove(hud_ids[1]) -- Will be replaced
for j=2,i do
local new={x=hud_base_offset.x+x_offset,y=hud_base_offset.y-((j-2)*20)}
player:hud_change(hud_ids[j],"offset",new)
hud_ids[j-1]=hud_ids[j] -- Perform index shift
end
hud_ids[i]=nil
end
list[name]=hud_ids
end
end
end
function remove_last_kill_message() function remove_last_kill_message()
remove_last_kill_msg_from_hud("killers",-20) for _, player in pairs(minetest.get_connected_players()) do
remove_last_kill_msg_from_hud("victims",20) local name = player:get_player_name()
remove_last_kill_msg_from_hud("items",0) local hud_ids = hud_channels[name]
for list, x_offset in pairs{ [hud_ids.killers] = -20, [hud_ids.victims] = 20, [hud_ids.items] = 0 } do
local last = #list
if last > 0 then
if mode == "list" then
player:hud_remove(hud_ids[last])
hud_ids[last] = nil
else
player:hud_remove(hud_ids[1])
-- Will be replaced
for j = 2, last do
local new = { x = hud_base_offset.x + x_offset, y = hud_base_offset.y - (j - 2) * 20 }
player:hud_change(hud_ids[j], "offset", new)
-- Perform index shift
hud_ids[j - 1] = hud_ids[j]
end
hud_ids[last] = nil
end
end
end
end
end end
local last_message=0 local last_message = 0
if autoremove_interval then if autoremove_interval then
minetest.register_globalstep(function(dtime) minetest.register_globalstep(function(dtime)
last_message=last_message+dtime last_message = last_message + dtime
if last_message > autoremove_interval then if last_message > autoremove_interval then
remove_last_kill_message() remove_last_kill_message()
last_message=0 last_message = 0
end end
end) end)
end end
function add_kill_msg_to_hud(msg, listname, hud_def, x_offset) -- MAY NOT BE CALLED ASYNC local function add_kill_msg_to_hud(msg, listname, hud_def, x_offset)
local _, value=next(hud_channels[listname]) hud_def.text = msg
if modlib.table.is_empty(value) then hud_def.offset = { x = x_offset + hud_base_offset.x }
last_message=0 for _, player in pairs(minetest.get_connected_players()) do
end local hud_ids = hud_channels[player:get_player_name()][listname] or {}
local list= hud_channels[listname] local i = #hud_ids
hud_def.text=msg if i == max_messages then
hud_def.offset={x=x_offset+hud_base_offset.x} -- Have to remove
for _,player in pairs(minetest.get_connected_players()) do if mode == "list" then player:hud_remove(hud_ids[i])
local name=player:get_player_name() else
local hud_ids=list[name] --Hud elem IDs player:hud_remove(hud_ids[1])
hud_ids=list[name] or {} -- Will be replaced
local i=#hud_ids for j = 2, i do
if (i == max_messages) then --Have to remove local new = { x = hud_def.offset.x, y = hud_base_offset.y - (j - 2) * 20 }
if mode=="list" then player:hud_change(hud_ids[j], "offset", new)
player:hud_remove(hud_ids[i]) -- Perform index shift
else hud_ids[j - 1] = hud_ids[j]
player:hud_remove(hud_ids[1]) -- Will be replaced end
for j=2,i do end
local new={x=hud_def.offset.x,y=hud_base_offset.y-((j-2)*20)} i = i - 1
player:hud_change(hud_ids[j],"offset",new) end
hud_ids[j-1]=hud_ids[j] --Perform index shift if mode == "list" then
end for j = i, 1, -1 do
end local new = { x = hud_def.offset.x, y = hud_base_offset.y - j * 20 }
i=i-1 player:hud_change(hud_ids[j], "offset", new)
end -- Perform index shift
if mode=="list" then hud_ids[j + 1] = hud_ids[j]
for j=i,1,-1 do end
local new={x=hud_def.offset.x,y=hud_base_offset.y-(j*20)} hud_def.offset.y = hud_base_offset.y
player:hud_change(hud_ids[j],"offset",new) hud_ids[1] = player:hud_add(hud_def)
hud_ids[j+1]=hud_ids[j] --Perform index shift else
end hud_def.offset.y = hud_base_offset.y - i * 20
hud_def.offset.y=hud_base_offset.y hud_ids[i + 1] = player:hud_add(hud_def)
hud_ids[1]=player:hud_add(hud_def) end
else end
hud_def.offset.y=hud_base_offset.y-(i*20)
hud_ids[i+1]=player:hud_add(hud_def)
end
list[name]=hud_ids --Update IDs
end
end end
function add_kill_message(killer, tool_image, victim) function add_kill_message(killer, tool_image, victim)
add_kill_msg_to_hud(killer.name,"killers",{hud_elem_type="text",position=hud_pos,scale={x=100,y=100}, number=killer.color or 0xFFFFFF, alignment = {x=-1,y=0}},-20) add_kill_msg_to_hud(killer.name, "killers", {
add_kill_msg_to_hud(victim.name,"victims",{hud_elem_type="text",position=hud_pos,number=victim.color or 0xFFFFFF,alignment = {x=1,y=0}},20) hud_elem_type = "text",
add_kill_msg_to_hud((tool_image or "deathlist_tombstone.png").."^[resize:16x16", "items",{hud_elem_type="image",position=hud_pos,scale={x=1,y=1}, alignment = {x=0,y=0}},0) position = hud_pos,
scale = { x = 100, y = 100 },
number = killer.color or 0xFFFFFF,
alignment = { x = -1, y = 0 }
}, -20)
add_kill_msg_to_hud(victim.name, "victims", {
hud_elem_type = "text",
position = hud_pos,
number = victim.color or 0xFFFFFF,
alignment = { x = 1, y = 0 }
}, 20)
add_kill_msg_to_hud((tool_image or "deathlist_tombstone.png") .. "^[resize:16x16", "items", {
hud_elem_type = "image",
position = hud_pos,
scale = { x = 1, y = 1 },
alignment = { x = 0, y = 0 }
}, 0)
end end
function add_environmental_kill_message(cause, victim) --Falling & Unknown function add_environmental_kill_message(cause, victim)
add_kill_message({name=environmental_reasons[cause].name, color=environmental_reasons[cause].color}, -- Falling & Unknown
environmental_reasons[cause].method,victim) add_kill_message({ name = environmental_reasons[cause].name, color = environmental_reasons[cause].color }, environmental_reasons[cause].method, victim)
end end
function add_node_kill_message(killing_node, cause, victim) --Drowning & Node Damage function add_node_kill_message(killing_node, cause, victim)
local override=environmental_reasons[cause].nodes[killing_node.name] or {} -- Drowning & Node Damage
local method=override.method or environmental_reasons[cause].method local override = environmental_reasons[cause].nodes[killing_node.name] or {}
if method=="generate" then local method = override.method or environmental_reasons[cause].method
method=modlib.minetest.get_node_inventory_image(killing_node.name) if method == "generate" then
end method = modlib.minetest.get_node_inventory_image(killing_node.name)
add_kill_message({ end
name=override.name or killing_node.description,color=override.color or environmental_reasons[cause].color add_kill_message({ name = override.name or killing_node.description, color = override.color or environmental_reasons[cause].color }, method, victim)
}, method, victim)
end end
function on_player_hpchange(player, hp_change, reason) function on_player_hpchange(player, hp_change, reason)
local type_type = type(reason.type) local type = reason.type
local type = reason.type if type == "punch" then
if type == "punch" then return
return -- punches are handled by on_punchplayer -- punches are handled by on_punchplayer
end end
if player:get_hp() > 0 and player:get_hp()+hp_change <= 0 then if player:get_hp() > 0 and player:get_hp() + hp_change <= 0 then
local victim={name=player:get_player_name(), color=modlib.player.get_color_int(player)} local victim = { name = player:get_player_name(), color = modlib.player.get_color_int(player) }
if type == "set_hp" and reason.killer and reason.method then if type == "set_hp" and reason.killer and reason.method then
if reason.victim then if reason.victim then
victim.name = reason.victim.name or victim.name victim.name = reason.victim.name or victim.name
victim.color = reason.victim.color or victim.color victim.color = reason.victim.color or victim.color
end end
local killer = { local killer = { name = reason.killer.name, color = reason.killer.color }
name = reason.killer.name, if not killer.color then
color = reason.killer.color local killer_obj = minetest.get_player_by_name(killer.name)
} if killer_obj then killer.color = modlib.player.get_color_int(killer_obj) end
if not killer.color then end
local killer_obj = minetest.get_player_by_name(killer.name) add_kill_message(killer, reason.method.image, victim)
if killer_obj then modlib.log.write("deathlist", "Player " .. killer.name .. " killed " .. victim.name .. " using " .. (reason.method.name or reason.method.image))
killer.color = modlib.player.get_color_int(killer_obj) return
end end
end if enable_environmental then
add_kill_message(killer, reason.method.image, victim) if type == "fall" then
modlib.log.write("deathlist", "Player "..killer.name.." killed "..victim.name.." using "..(reason.method.name or reason.method.image)) add_environmental_kill_message("falling", victim)
return modlib.log.write("deathlist", "Player " .. victim.name .. " died due to falling")
end return
if enable_environmental then end
if type=="fall" then if type == "drown" then
add_environmental_kill_message("falling", victim) local eye_pos = vector.add(player:get_pos(), { x = 0, z = 0, y = player:get_properties().eye_height })
modlib.log.write("deathlist", "Player "..victim.name.." died due to falling") local drowning_node = minetest.registered_nodes[minetest.get_node(eye_pos).name]
return add_node_kill_message(drowning_node, "drowning", victim)
end modlib.log.write("deathlist", "Player " .. victim.name .. " died due to drowning in " .. drowning_node.name)
if type=="drown" then return
local eye_pos=vector.add(player:get_pos(), {x=0, z=0, y=player:get_properties().eye_height}) end
local drowning_node=minetest.registered_nodes[minetest.get_node(eye_pos).name] if type == "node_damage" then
add_node_kill_message(drowning_node, "drowning", victim) local killing_node_feet = minetest.registered_nodes[minetest.get_node(player:get_pos()).name]
modlib.log.write("deathlist", "Player "..victim.name.." died due to drowning in "..drowning_node.name) local eye_pos = vector.add(player:get_pos(), { x = 0, z = 0, y = player:get_properties().eye_height })
return local killing_node_head = minetest.registered_nodes[minetest.get_node(eye_pos).name]
end local killing_node = killing_node_feet
if type=="node_damage" then if (killing_node_head.node_damage or 0) > (killing_node_feet.node_damage or 0) then killing_node = killing_node_head end
local killing_node_feet=minetest.registered_nodes[minetest.get_node(player:get_pos()).name] add_node_kill_message(killing_node, "node_damage", victim)
local eye_pos=vector.add(player:get_pos(), {x=0, z=0, y=player:get_properties().eye_height}) modlib.log.write("deathlist", "Player " .. victim.name .. " died due to node damage of " .. killing_node.name)
local killing_node_head=minetest.registered_nodes[minetest.get_node(eye_pos).name] return
local killing_node=killing_node_feet end
if (killing_node_head.node_damage or 0) > (killing_node_feet.node_damage or 0) then end
killing_node=killing_node_head if enable_unknown then
end add_environmental_kill_message("unknown", victim)
add_node_kill_message(killing_node, "node_damage", victim) modlib.log.write("deathlist", "Player " .. victim.name .. " died for unknown reasons.")
modlib.log.write("deathlist","Player "..victim.name.." died due to node damage of "..killing_node.name) end
return end
end
end
if enable_unknown then
add_environmental_kill_message("unknown", victim)
modlib.log.write("deathlist", "Player "..victim.name.." died for unknown reasons.")
end
end
end end
function on_punchplayer(player, hitter, time_from_last_punch, tool_capabilities, dir, damage) function on_punchplayer(player, hitter, _time_from_last_punch, _tool_capabilities, _dir, damage)
if player:get_hp() > 0 and player:get_hp()-damage <= 0 and hitter then if player:get_hp() > 0 and player:get_hp() - damage <= 0 and hitter then
local wielded_item_name=hitter:get_wielded_item():get_name() local wielded_item_name = hitter:get_wielded_item():get_name()
local tool local tool
if minetest.registered_nodes[wielded_item_name] then if minetest.registered_nodes[wielded_item_name] then
tool=modlib.minetest.get_node_inventory_image(wielded_item_name) tool = modlib.minetest.get_node_inventory_image(wielded_item_name)
else else
tool=(minetest.registered_items[wielded_item_name] or {inventory_image="deathlist_gravestone.png"}).inventory_image tool = (minetest.registered_items[wielded_item_name] or { inventory_image = "deathlist_gravestone.png" }).inventory_image
end end
local killer={name=hitter:get_player_name(), color=modlib.player.get_color_int(hitter)} local killer = { name = hitter:get_player_name(), color = modlib.player.get_color_int(hitter) }
local victim={name=player:get_player_name(), color=modlib.player.get_color_int(player)} local victim = { name = player:get_player_name(), color = modlib.player.get_color_int(player) }
add_kill_message(killer,tool,victim) add_kill_message(killer, tool, victim)
modlib.log.write("deathlist", "Player "..killer.name.." killed "..victim.name.." using "..wielded_item_name) modlib.log.write("deathlist", "Player " .. killer.name .. " killed " .. victim.name .. " using " .. wielded_item_name)
end end
end end
minetest.register_on_mods_loaded(function() minetest.register_on_mods_loaded(function()
minetest.register_on_player_hpchange(on_player_hpchange) minetest.register_on_player_hpchange(on_player_hpchange)
minetest.register_on_punchplayer(on_punchplayer) minetest.register_on_punchplayer(on_punchplayer)
end) end)

View File

@ -1,4 +1,4 @@
name=deathlist name = deathlist
description=Adds a kill history description = Adds a kill history
depends=modlib, default, fire depends = modlib, fire
optional_depends=3d_armor optional_depends = default, 3d_armor