174 lines
5.7 KiB
Lua
174 lines
5.7 KiB
Lua
local RecipeChange = {}
|
|
|
|
local function add_contents(contents1, contents2)
|
|
for name, count in pairs(contents2) do
|
|
if contents1[name] then
|
|
contents1[name] = contents1[name] + count
|
|
else
|
|
contents1[name] = count
|
|
end
|
|
end
|
|
end
|
|
|
|
local function get_inventory_contents(entity, inventory_defines)
|
|
local inventory = entity.get_inventory(inventory_defines)
|
|
if inventory then
|
|
return inventory.get_contents()
|
|
else
|
|
return {}
|
|
end
|
|
end
|
|
|
|
local function get_machine_contents(entity)
|
|
local contents = {}
|
|
add_contents(contents, get_inventory_contents(entity, defines.inventory.assembling_machine_input))
|
|
add_contents(contents, get_inventory_contents(entity, defines.inventory.assembling_machine_output))
|
|
add_contents(contents, get_inventory_contents(entity, defines.inventory.assembling_machine_modules))
|
|
|
|
-- Also add internal items currently being used to craft
|
|
if entity.crafting_progress > 0 then
|
|
local recipe = entity.get_recipe()
|
|
if recipe then
|
|
for _, ingredient in pairs(recipe.ingredients) do
|
|
if ingredient.type == "item" then
|
|
add_contents(contents, {[ingredient.name] = ingredient.amount})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return contents
|
|
end
|
|
|
|
local function get_player_contents(entity)
|
|
local contents = {}
|
|
add_contents(contents, get_inventory_contents(entity, defines.inventory.character_main))
|
|
add_contents(contents, get_inventory_contents(entity, defines.inventory.character_guns))
|
|
add_contents(contents, get_inventory_contents(entity, defines.inventory.character_ammo))
|
|
add_contents(contents, get_inventory_contents(entity, defines.inventory.character_armor))
|
|
add_contents(contents, get_inventory_contents(entity, defines.inventory.character_trash))
|
|
return contents
|
|
end
|
|
|
|
local function diff_contents(old_contents, new_contents)
|
|
local diff = {}
|
|
for name, count in pairs(old_contents) do
|
|
if new_contents[name] then
|
|
if new_contents[name] ~= count and (new_contents[name] - count ~= 0) then
|
|
diff[name] = new_contents[name] - count
|
|
end
|
|
else
|
|
diff[name] = -count
|
|
end
|
|
end
|
|
for name, count in pairs(new_contents) do
|
|
if not old_contents[name] then
|
|
diff[name] = count
|
|
end
|
|
end
|
|
return diff
|
|
end
|
|
|
|
local function ensure_positive(diff)
|
|
for name, count in pairs(diff) do
|
|
if count <= 0 then
|
|
diff[name] = nil
|
|
end
|
|
end
|
|
return diff
|
|
end
|
|
|
|
function RecipeChange.on_remote_gui_opened(player)
|
|
local entity = player.opened
|
|
if entity.type == "assembling-machine" then
|
|
local recipe = entity.get_recipe() or {name = "rc-no-recipe"}
|
|
if recipe then
|
|
global[player.index] = {
|
|
player = player,
|
|
recipe = recipe.name,
|
|
entity = entity,
|
|
player_contents = get_player_contents(player),
|
|
entity_contents = get_machine_contents(entity),
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
function RecipeChange.on_gui_closed(player)
|
|
global[player.index] = nil
|
|
end
|
|
|
|
local function on_recipe_changed(player_data)
|
|
local entity = player_data.entity
|
|
local entity_diff = ensure_positive(diff_contents(get_machine_contents(entity), player_data.entity_contents))
|
|
if table_size(entity_diff) == 0 then return end
|
|
|
|
-- Entity contents changed
|
|
local player_diff = diff_contents(player_data.player_contents, get_player_contents(player_data.player))
|
|
|
|
-- Positive count in entity_diff means items were lost
|
|
-- Positive count in player_diff means items were gained
|
|
-- We need to find the subset of items lost in entity_diff that were gained in player_diff
|
|
|
|
local surface = entity.surface
|
|
local position = entity.position
|
|
local player = player_data.player
|
|
local force = player.force
|
|
for name, count in pairs(entity_diff) do
|
|
if player_diff[name] then
|
|
local to_spill = math.min(count, player_diff[name])
|
|
--game.print(game.tick .. " Trying to spill " .. to_spill .. " " .. name)
|
|
local removed = player.remove_item({name = name, count = to_spill}) -- Handles main, ammo, cursor
|
|
to_spill = to_spill - removed
|
|
if to_spill > 0 then
|
|
-- Handle guns, armor, trash
|
|
removed = player.get_inventory(defines.inventory.character_trash).remove({name = name, count = to_spill})
|
|
to_spill = to_spill - removed
|
|
if to_spill > 0 then
|
|
removed = player.get_inventory(defines.inventory.character_armor).remove({name = name, count = to_spill})
|
|
to_spill = to_spill - removed
|
|
if to_spill > 0 then
|
|
removed = player.get_inventory(defines.inventory.character_guns).remove({name = name, count = to_spill})
|
|
to_spill = to_spill - removed
|
|
end
|
|
end
|
|
end
|
|
if removed > 0 then
|
|
--game.print(game.tick .. " Spilling " .. removed .. " " .. name)
|
|
surface.spill_item_stack(
|
|
position,
|
|
{name = name, count = removed},
|
|
true, -- enabled_looted
|
|
force, -- force for deconstruction
|
|
false -- allow_on_belts
|
|
)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
local function process_player(player_data)
|
|
local entity = player_data.entity
|
|
if not entity.valid then return end
|
|
local recipe = entity.get_recipe() or {name = "rc-no-recipe"}
|
|
if recipe.name ~= player_data.recipe then
|
|
on_recipe_changed(player_data)
|
|
player_data.recipe = recipe.name
|
|
--game.print(game.tick .. " Recipe changed to " .. recipe.name)
|
|
end
|
|
-- Update stored info
|
|
player_data.player_contents = get_player_contents(player_data.player)
|
|
player_data.entity_contents = get_machine_contents(player_data.entity)
|
|
end
|
|
|
|
script.on_event(defines.events.on_tick,
|
|
function(event)
|
|
global.my_data = true
|
|
for _, player_data in pairs(global) do
|
|
if type(player_data) == "table" and player_data.player then
|
|
process_player(player_data)
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
return RecipeChange |