mirror of
https://github.com/Refactorio/RedMew.git
synced 2025-03-11 14:49:59 +02:00
Refactor corpse features:
- Turn dump_offline_inventories on by default. - Reduce corpse_util to storing and removing corpse tags. - Add death_corpse_tags which handles adding tags for dead players. This prevents dump_offline_inventories from needing a dependency on what is now death_corpse_tags. - If a player dies with no items, don't create a map tag and remove the corpse. - Changed the message slightly for dump_offline_inventories to make it consistent with the other corpse messages.
This commit is contained in:
parent
132ba7627c
commit
ac78f22277
@ -81,10 +81,9 @@ global.config = {
|
||||
tag_group = {
|
||||
enabled = true
|
||||
},
|
||||
-- enables dumping of inventories of offline players to a corpse near spawn
|
||||
-- This feature is dependant upon corpse_util and will enable it
|
||||
-- enables dumping of inventories of offline players to a corpse at the player's last location
|
||||
dump_offline_inventories = {
|
||||
enabled = false,
|
||||
enabled = true,
|
||||
offline_timout_mins = 15, -- time after which a player logs off that their inventory is provided to the team
|
||||
},
|
||||
-- enables players to create and prioritize tasks
|
||||
@ -287,7 +286,7 @@ global.config = {
|
||||
enabled = true
|
||||
},
|
||||
-- when a player dies, leaves a map marker until the corpse expires or is looted
|
||||
corpse_util = {
|
||||
death_corpse_tags = {
|
||||
enabled = true
|
||||
},
|
||||
-- adds many commands for users and admins alike
|
||||
|
@ -49,8 +49,8 @@ end
|
||||
if config.hodor.enabled or config.auto_respond.enabled or config.mentions.enabled then
|
||||
require 'features.chat_triggers'
|
||||
end
|
||||
if config.corpse_util.enabled then
|
||||
require 'features.corpse_util'
|
||||
if config.death_corpse_tags.enabled then
|
||||
require 'features.death_corpse_tags'
|
||||
end
|
||||
if config.dump_offline_inventories.enabled then
|
||||
require 'features.dump_offline_inventories'
|
||||
|
@ -4,96 +4,33 @@ local Task = require 'utils.task'
|
||||
local Token = require 'utils.token'
|
||||
local table = require 'utils.table'
|
||||
local Utils = require 'utils.core'
|
||||
local Settings = require 'utils.redmew_settings'
|
||||
|
||||
local Public = {}
|
||||
|
||||
local ping_own_death_name = 'corpse_util.ping_own_death'
|
||||
local ping_other_death_name = 'corpse_util.ping_other_death'
|
||||
|
||||
Public.ping_own_death_name = ping_own_death_name
|
||||
Public.ping_other_death_name = ping_other_death_name
|
||||
|
||||
Settings.register(ping_own_death_name, Settings.types.boolean, true, 'corpse_util.ping_own_death')
|
||||
Settings.register(ping_other_death_name, Settings.types.boolean, false, 'corpse_util.ping_other_death')
|
||||
|
||||
local player_corpses = {}
|
||||
|
||||
Global.register(player_corpses, function(tbl)
|
||||
player_corpses = tbl
|
||||
end)
|
||||
|
||||
local function add_tag(tag, player_index, death_tick)
|
||||
player_corpses[player_index * 0x100000000 + death_tick] = tag
|
||||
local function get_index(player_index, tick)
|
||||
return player_index * 0x100000000 + tick
|
||||
end
|
||||
|
||||
local function player_died(event)
|
||||
local player_index = event.player_index
|
||||
local player = game.get_player(player_index)
|
||||
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local pos = player.position
|
||||
local entities = player.surface.find_entities_filtered {
|
||||
area = {{pos.x - 0.5, pos.y - 0.5}, {pos.x + 0.5, pos.y + 0.5}},
|
||||
name = 'character-corpse'
|
||||
}
|
||||
|
||||
local tick = game.tick
|
||||
local entity
|
||||
for _, e in ipairs(entities) do
|
||||
if e.character_corpse_player_index == event.player_index and e.character_corpse_tick_of_death == tick then
|
||||
entity = e
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not entity or not entity.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local text = player.name .. "'s corpse"
|
||||
local position = entity.position
|
||||
local tag = player.force.add_chart_tag(player.surface, {
|
||||
icon = {type = 'item', name = 'power-armor-mk2'},
|
||||
position = position,
|
||||
text = text
|
||||
})
|
||||
|
||||
if not tag then
|
||||
return
|
||||
end
|
||||
|
||||
if Settings.get(player_index, ping_own_death_name) then
|
||||
player.print({
|
||||
'corpse_util.own_corpse_location',
|
||||
string.format('%.1f', position.x),
|
||||
string.format('%.1f', position.y),
|
||||
player.surface.name
|
||||
})
|
||||
end
|
||||
|
||||
for _, other_player in pairs(player.force.players) do
|
||||
if other_player ~= player and Settings.get(other_player.index, ping_other_death_name) then
|
||||
other_player.print({
|
||||
'corpse_util.other_corpse_location',
|
||||
player.name,
|
||||
string.format('%.1f', position.x),
|
||||
string.format('%.1f', position.y),
|
||||
player.surface.name
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
add_tag(tag, player_index, tick)
|
||||
local function get_data(player_index, tick)
|
||||
local index = get_index(player_index, tick)
|
||||
return player_corpses[index]
|
||||
end
|
||||
|
||||
local function remove_tag(player_index, tick)
|
||||
local index = player_index * 0x100000000 + tick
|
||||
local index = get_index(player_index, tick)
|
||||
|
||||
local tag = player_corpses[index]
|
||||
local data = player_corpses[index]
|
||||
if not data then
|
||||
return
|
||||
end
|
||||
|
||||
local tag = data.tag
|
||||
player_corpses[index] = nil
|
||||
|
||||
if not tag or not tag.valid then
|
||||
@ -126,18 +63,24 @@ local function mined_entity(event)
|
||||
return
|
||||
end
|
||||
|
||||
local corpse_owner_index = entity.character_corpse_player_index
|
||||
local death_tick = entity.character_corpse_tick_of_death
|
||||
|
||||
-- The corpse may be mined but not removed (if player doesn't have inventory space)
|
||||
-- so we wait one tick to see if the corpse is gone.
|
||||
Task.set_timeout_in_ticks(1, corpse_util_mined_entity, {
|
||||
entity = entity,
|
||||
player_index = entity.character_corpse_player_index,
|
||||
tick = entity.character_corpse_tick_of_death
|
||||
player_index = corpse_owner_index,
|
||||
tick = death_tick
|
||||
})
|
||||
|
||||
local player_index = event.player_index
|
||||
local corpse_owner_index = entity.character_corpse_player_index
|
||||
if player_index == corpse_owner_index then
|
||||
return
|
||||
end
|
||||
|
||||
if player_index == corpse_owner_index or not entity.active then
|
||||
local data = get_data(corpse_owner_index, death_tick)
|
||||
if not data or not data.alert_looting then
|
||||
return
|
||||
end
|
||||
|
||||
@ -159,7 +102,13 @@ local function on_gui_opened(event)
|
||||
local player_index = event.player_index
|
||||
local corpse_owner_index = entity.character_corpse_player_index
|
||||
|
||||
if player_index == corpse_owner_index or not entity.active then
|
||||
if player_index == corpse_owner_index then
|
||||
return
|
||||
end
|
||||
|
||||
local death_tick = entity.character_corpse_tick_of_death
|
||||
local data = get_data(corpse_owner_index, death_tick)
|
||||
if not data or not data.alert_looting then
|
||||
return
|
||||
end
|
||||
|
||||
@ -194,7 +143,6 @@ local function on_gui_closed(event)
|
||||
end
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_player_died, player_died)
|
||||
Event.add(defines.events.on_character_corpse_expired, corpse_expired)
|
||||
Event.add(defines.events.on_pre_player_mined_item, mined_entity)
|
||||
Event.add(defines.events.on_gui_opened, on_gui_opened)
|
||||
@ -204,9 +152,9 @@ function Public.clear()
|
||||
table.clear_table(player_corpses)
|
||||
end
|
||||
|
||||
Public.add_tag = add_tag
|
||||
|
||||
Public._player_died = player_died
|
||||
Public.player_corpses = player_corpses
|
||||
function Public.add_tag(tag, player_index, death_tick, alert_looting)
|
||||
local index = get_index(player_index, death_tick)
|
||||
player_corpses[index] = {tag = tag, alert_looting = alert_looting}
|
||||
end
|
||||
|
||||
return Public
|
||||
|
94
features/death_corpse_tags.lua
Normal file
94
features/death_corpse_tags.lua
Normal file
@ -0,0 +1,94 @@
|
||||
local Event = require 'utils.event'
|
||||
local Settings = require 'utils.redmew_settings'
|
||||
local CorpseUtil = require 'features.corpse_util'
|
||||
|
||||
local Public = {}
|
||||
|
||||
local ping_own_death_name = 'death_corpse_tags.ping_own_death'
|
||||
local ping_other_death_name = 'death_corpse_tags.ping_other_death'
|
||||
|
||||
Public.ping_own_death_name = ping_own_death_name
|
||||
Public.ping_other_death_name = ping_other_death_name
|
||||
|
||||
Settings.register(ping_own_death_name, Settings.types.boolean, true, 'death_corpse_tags.ping_own_death')
|
||||
Settings.register(ping_other_death_name, Settings.types.boolean, false, 'death_corpse_tags.ping_other_death')
|
||||
|
||||
local function player_died(event)
|
||||
local player_index = event.player_index
|
||||
local player = game.get_player(player_index)
|
||||
|
||||
if not player or not player.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local pos = player.position
|
||||
local entities = player.surface.find_entities_filtered {
|
||||
area = {{pos.x - 0.5, pos.y - 0.5}, {pos.x + 0.5, pos.y + 0.5}},
|
||||
name = 'character-corpse'
|
||||
}
|
||||
|
||||
local tick = game.tick
|
||||
local entity
|
||||
for _, e in ipairs(entities) do
|
||||
if e.character_corpse_player_index == event.player_index and e.character_corpse_tick_of_death == tick then
|
||||
entity = e
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not entity or not entity.valid then
|
||||
return
|
||||
end
|
||||
|
||||
local inv_corpse = entity.get_inventory(defines.inventory.character_corpse)
|
||||
if not inv_corpse or not inv_corpse.valid then
|
||||
return
|
||||
end
|
||||
|
||||
if inv_corpse.is_empty() then
|
||||
entity.destroy()
|
||||
player.print({'death_corpse_tags.empty_corpse'})
|
||||
return
|
||||
end
|
||||
|
||||
local text = player.name .. "'s corpse"
|
||||
local position = entity.position
|
||||
local tag = player.force.add_chart_tag(player.surface, {
|
||||
icon = {type = 'item', name = 'power-armor-mk2'},
|
||||
position = position,
|
||||
text = text
|
||||
})
|
||||
|
||||
if not tag then
|
||||
return
|
||||
end
|
||||
|
||||
if Settings.get(player_index, ping_own_death_name) then
|
||||
player.print({
|
||||
'death_corpse_tags.own_corpse_location',
|
||||
string.format('%.1f', position.x),
|
||||
string.format('%.1f', position.y),
|
||||
player.surface.name
|
||||
})
|
||||
end
|
||||
|
||||
for _, other_player in pairs(player.force.players) do
|
||||
if other_player ~= player and Settings.get(other_player.index, ping_other_death_name) then
|
||||
other_player.print({
|
||||
'death_corpse_tags.other_corpse_location',
|
||||
player.name,
|
||||
string.format('%.1f', position.x),
|
||||
string.format('%.1f', position.y),
|
||||
player.surface.name
|
||||
})
|
||||
end
|
||||
end
|
||||
|
||||
CorpseUtil.add_tag(tag, player_index, tick, true)
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_player_died, player_died)
|
||||
|
||||
Public._player_died = player_died
|
||||
|
||||
return Public
|
@ -4,6 +4,7 @@ local Assert = require 'utils.test.assert'
|
||||
local Helper = require 'utils.test.helper'
|
||||
local Settings = require 'utils.redmew_settings'
|
||||
local CorpseUtil = require 'features.corpse_util'
|
||||
local DeathCorpseTags = require 'features.death_corpse_tags'
|
||||
|
||||
local function test_teardown(context)
|
||||
context:add_teardown(CorpseUtil.clear)
|
||||
@ -18,7 +19,7 @@ local function declare_test(name, func)
|
||||
Declare.test(name, test_func)
|
||||
end
|
||||
|
||||
Declare.module({'features', 'corpse_util'}, function()
|
||||
Declare.module({'features', 'death_corpse_tags'}, function()
|
||||
local teardown
|
||||
|
||||
Declare.module_startup(function(context)
|
||||
@ -46,20 +47,26 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
end)
|
||||
end
|
||||
|
||||
local function fake_death(player)
|
||||
local function fake_death(player, has_items)
|
||||
local surface = player.surface
|
||||
local position = player.position
|
||||
|
||||
local entity = surface.create_entity {
|
||||
name = 'character-corpse',
|
||||
position = position,
|
||||
player_index = player.index
|
||||
player_index = player.index,
|
||||
inventory_size = has_items and 1 or nil
|
||||
}
|
||||
|
||||
if not entity or not entity.valid then
|
||||
error('no corpse')
|
||||
end
|
||||
|
||||
if has_items then
|
||||
local inventory = entity.get_inventory(defines.inventory.character_corpse)
|
||||
inventory.insert('iron-plate')
|
||||
end
|
||||
|
||||
return EventFactory.on_player_died(player.index)
|
||||
end
|
||||
|
||||
@ -77,13 +84,13 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
return player
|
||||
end)
|
||||
|
||||
local event = fake_death(player)
|
||||
local event = fake_death(player, true)
|
||||
|
||||
-- Act.
|
||||
CorpseUtil._player_died(event)
|
||||
DeathCorpseTags._player_died(event)
|
||||
|
||||
-- Assert.
|
||||
local expected = {'corpse_util.own_corpse_location', '0.0', '0.0', player.surface.name}
|
||||
local expected = {'death_corpse_tags.own_corpse_location', '0.0', '0.0', player.surface.name}
|
||||
Assert.table_equal(expected, actual_text)
|
||||
end)
|
||||
|
||||
@ -105,7 +112,7 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
position = EventFactory.position({1, 1})
|
||||
}
|
||||
|
||||
change_settings_for_test(context, CorpseUtil.ping_other_death_name, true)
|
||||
change_settings_for_test(context, DeathCorpseTags.ping_other_death_name, true)
|
||||
|
||||
Helper.modify_lua_object(context, game, 'get_player', function(index)
|
||||
if index == player.index then
|
||||
@ -123,20 +130,20 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
actual_text = text
|
||||
end)
|
||||
|
||||
local event = fake_death(second_player)
|
||||
local event = fake_death(second_player, true)
|
||||
|
||||
-- Act.
|
||||
CorpseUtil._player_died(event)
|
||||
DeathCorpseTags._player_died(event)
|
||||
|
||||
-- Assert.
|
||||
local expected = {'corpse_util.other_corpse_location', second_player.name, '1.0', '1.0', player.surface.name}
|
||||
local expected = {'death_corpse_tags.other_corpse_location', second_player.name, '1.0', '1.0', player.surface.name}
|
||||
Assert.table_equal(expected, actual_text)
|
||||
end)
|
||||
|
||||
declare_test('do not ping player corpse location when died and setting disabled', function(context)
|
||||
-- Arrange.
|
||||
local player = context.player
|
||||
change_settings_for_test(context, CorpseUtil.ping_own_death_name, false)
|
||||
change_settings_for_test(context, DeathCorpseTags.ping_own_death_name, false)
|
||||
|
||||
local actual_text
|
||||
|
||||
@ -148,10 +155,10 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
return player
|
||||
end)
|
||||
|
||||
local event = fake_death(player)
|
||||
local event = fake_death(player, true)
|
||||
|
||||
-- Act.
|
||||
CorpseUtil._player_died(event)
|
||||
DeathCorpseTags._player_died(event)
|
||||
|
||||
-- Assert.
|
||||
Assert.is_nil(actual_text)
|
||||
@ -176,7 +183,7 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
position = EventFactory.position({1, 1})
|
||||
}
|
||||
|
||||
change_settings_for_test(context, CorpseUtil.ping_other_death_name, false)
|
||||
change_settings_for_test(context, DeathCorpseTags.ping_other_death_name, false)
|
||||
|
||||
Helper.modify_lua_object(context, game, 'get_player', function(index)
|
||||
if index == player.index then
|
||||
@ -194,10 +201,10 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
actual_text = text
|
||||
end)
|
||||
|
||||
local event = fake_death(second_player)
|
||||
local event = fake_death(second_player, true)
|
||||
|
||||
-- Act.
|
||||
CorpseUtil._player_died(event)
|
||||
DeathCorpseTags._player_died(event)
|
||||
|
||||
-- Assert.
|
||||
Assert.is_nil(actual_text)
|
||||
@ -210,8 +217,8 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
|
||||
local actual_text
|
||||
|
||||
change_settings_for_test(context, CorpseUtil.ping_own_death_name, false)
|
||||
change_settings_for_test(context, CorpseUtil.ping_other_death_name, true)
|
||||
change_settings_for_test(context, DeathCorpseTags.ping_own_death_name, false)
|
||||
change_settings_for_test(context, DeathCorpseTags.ping_other_death_name, true)
|
||||
|
||||
Helper.modify_lua_object(context, game, 'get_player', function()
|
||||
return player
|
||||
@ -224,12 +231,44 @@ Declare.module({'features', 'corpse_util'}, function()
|
||||
actual_text = text
|
||||
end)
|
||||
|
||||
local event = fake_death(player)
|
||||
local event = fake_death(player, true)
|
||||
|
||||
-- Act.
|
||||
CorpseUtil._player_died(event)
|
||||
DeathCorpseTags._player_died(event)
|
||||
|
||||
-- Assert.
|
||||
Assert.is_nil(actual_text)
|
||||
end)
|
||||
|
||||
declare_test('corpse removed and empty message when corpse is empty', function(context)
|
||||
-- Arrange.
|
||||
local player = context.player
|
||||
player.teleport({5, 5})
|
||||
|
||||
context:add_teardown(function()
|
||||
player.teleport({0, 0})
|
||||
end)
|
||||
|
||||
local actual_text
|
||||
|
||||
Helper.modify_lua_object(context, player, 'print', function(text)
|
||||
actual_text = text
|
||||
end)
|
||||
|
||||
Helper.modify_lua_object(context, game, 'get_player', function()
|
||||
return player
|
||||
end)
|
||||
|
||||
local event = fake_death(player, false)
|
||||
|
||||
-- Act.
|
||||
DeathCorpseTags._player_died(event)
|
||||
|
||||
-- Assert.
|
||||
local corpses = player.surface.find_entities_filtered({name = 'character-corpse', position = player.position, radius = 1})
|
||||
Assert.equal(0, #corpses)
|
||||
|
||||
local expected = {'death_corpse_tags.empty_corpse'}
|
||||
Assert.table_equal(expected, actual_text)
|
||||
end)
|
||||
end)
|
@ -72,10 +72,18 @@ local spawn_player_corpse =
|
||||
text = text
|
||||
})
|
||||
|
||||
game.print("[gps="..position.x..","..position.y..",redmew] "..player.name.." has been offline "..offline_timout_mins.." minutes. Their inventory is now available.")
|
||||
local message = {
|
||||
'dump_offline_inventories.inventory_location',
|
||||
player.name,
|
||||
offline_timout_mins,
|
||||
string.format('%.1f', position.x),
|
||||
string.format('%.1f', position.y),
|
||||
player.surface.name
|
||||
}
|
||||
game.print(message)
|
||||
|
||||
if tag then
|
||||
CorpseUtil.add_tag(tag, player_index, game.tick)
|
||||
CorpseUtil.add_tag(tag, player_index, game.tick, false)
|
||||
end
|
||||
end
|
||||
)
|
||||
|
@ -181,8 +181,12 @@ select_brush=Select Brush Tile.
|
||||
instructions=Select a brush tile to replace [item=refined-concrete] and [item=refined-hazard-concrete].\nOnly works when Paint Brush window is open.
|
||||
no_place_landfill=Coloured concrete can not be placed on landfill tiles.
|
||||
|
||||
[corpse_util]
|
||||
[death_corpse_tags]
|
||||
ping_own_death=Ping the location when you die.
|
||||
ping_other_death=Ping the location when other players die.
|
||||
own_corpse_location=[color=red][Corpse][/color] Your corpse is located at [gps=__1__,__2__,__3__]
|
||||
other_corpse_location=[color=red][Corpse][/color] __1__'s corpse is located at [gps=__2__,__3__,__4__]
|
||||
empty_corpse=[color=red][Corpse][/color]Your corpse was empty and has been removed.
|
||||
|
||||
[dump_offline_inventories]
|
||||
inventory_location=[color=blue][Corpse][/color] __1__ has been offline __2__ minutes. Their inventory is now available at [gps=__3__,__4__,__5__]
|
||||
|
Loading…
x
Reference in New Issue
Block a user