mirror of
https://github.com/Refactorio/RedMew.git
synced 2025-12-26 00:42:20 +02:00
316 lines
8.5 KiB
Lua
316 lines
8.5 KiB
Lua
-- This feature replaces placed linked-chests with buffer chests that can automatically trade items
|
|
|
|
local Buckets = require 'utils.buckets'
|
|
local Event = require 'utils.event'
|
|
local Global = require 'utils.global'
|
|
local Gui = require 'utils.gui'
|
|
local Retailer = require 'features.retailer'
|
|
local config = require 'config'.market_chest
|
|
|
|
local floor = math.floor
|
|
local b_get = Buckets.get
|
|
local b_add = Buckets.add
|
|
local b_remove = Buckets.remove
|
|
local b_bucket = Buckets.get_bucket
|
|
local register_on_object_destroyed = script.register_on_object_destroyed
|
|
|
|
local relative_frame_name = Gui.uid_name()
|
|
local offer_tag_name = Gui.uid_name()
|
|
local request_tag_name = Gui.uid_name()
|
|
local standard_market_name = 'fish_market'
|
|
|
|
-- What market provides
|
|
local DEFAULT_OFFERS = {
|
|
['coal'] = 2,
|
|
['copper-ore'] = 2,
|
|
['iron-ore'] = 2,
|
|
['stone'] = 2,
|
|
['uranium-ore'] = 10,
|
|
}
|
|
-- What market requests
|
|
local DEFAULT_REQUESTS = {
|
|
['coal'] = 1,
|
|
['copper-ore'] = 1,
|
|
['iron-ore'] = 1,
|
|
['stone'] = 1,
|
|
['uranium-ore'] = 5,
|
|
}
|
|
|
|
local this = {
|
|
chests = Buckets.new(),
|
|
enabled = config.enabled or false,
|
|
offers = config.offers or DEFAULT_OFFERS,
|
|
requests = config.requests or DEFAULT_REQUESTS,
|
|
relative_gui = {},
|
|
}
|
|
|
|
Global.register(this, function(tbl) this = tbl end)
|
|
|
|
local function update_entity(entity)
|
|
if not (entity and entity.valid) then
|
|
return
|
|
end
|
|
|
|
local data = b_get(this.chests, entity.unit_number)
|
|
local offer, request, ratio = data.offer, data.request, data.ratio
|
|
if not offer or not request or not ratio then
|
|
return
|
|
end
|
|
|
|
local inv = entity.get_inventory(defines.inventory.chest)
|
|
if not (inv and inv.valid) then
|
|
return
|
|
end
|
|
|
|
local r_count = inv.get_item_count(request)
|
|
local o_count = floor(r_count * ratio)
|
|
if o_count == 0 or r_count == 0 then
|
|
return
|
|
end
|
|
|
|
local removed = inv.remove {
|
|
name = request,
|
|
quality = request.quality,
|
|
count = o_count / ratio,
|
|
}
|
|
if removed > 0 then
|
|
local inserted = inv.insert {
|
|
name = offer,
|
|
count = o_count,
|
|
}
|
|
if inserted < o_count then
|
|
inv.insert {
|
|
name = request,
|
|
count = floor((o_count - inserted) / ratio),
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
local function update_market(enabled, price)
|
|
if enabled then
|
|
if not price then
|
|
local chest = Retailer.get_items(standard_market_name)['linked-chest']
|
|
price = chest and chest.price or 3000
|
|
end
|
|
Retailer.set_item(standard_market_name, { name = 'linked-chest', price = price })
|
|
else
|
|
Retailer.remove_item(standard_market_name, 'linked-chest')
|
|
end
|
|
end
|
|
|
|
Event.on_built(function(event)
|
|
local entity = event.entity
|
|
if not (entity and entity.valid and entity.name == 'linked-chest') then
|
|
return
|
|
end
|
|
|
|
-- Replace with buffer chest
|
|
local force = entity.force
|
|
local position = entity.position
|
|
local surface = entity.surface
|
|
entity.destroy()
|
|
|
|
local chest = surface.create_entity{
|
|
name = 'buffer-chest',
|
|
position = position,
|
|
force = force,
|
|
}
|
|
|
|
chest.destructible = false
|
|
b_add(this.chests, chest.unit_number, { entity = chest })
|
|
register_on_object_destroyed(chest)
|
|
update_entity(chest)
|
|
rendering.draw_sprite {
|
|
sprite = 'entity.market',
|
|
surface = chest.surface,
|
|
only_in_alt_mode = true,
|
|
target = {
|
|
entity = chest,
|
|
offset = { 0, 0 },
|
|
},
|
|
}
|
|
end)
|
|
|
|
Event.on_destroyed(function(event)
|
|
local id = event.useful_id or (event.entity and event.entity.valid and event.entity.unit_number)
|
|
if not id then
|
|
return
|
|
end
|
|
|
|
local data = b_get(this.chests, id)
|
|
local inv = event.buffer
|
|
if data and inv and inv.valid and inv.get_item_count { name = 'buffer-chest' } > 0 then
|
|
update_entity(data.entity)
|
|
b_remove(this.chests, id)
|
|
inv.remove { name = 'buffer-chest', count = 1 }
|
|
inv.insert { name = 'linked-chest', count = 1 }
|
|
end
|
|
end)
|
|
|
|
Event.add(defines.events.on_tick, function(event)
|
|
if not this.enabled then
|
|
return
|
|
end
|
|
|
|
for unit_number, data in pairs(b_bucket(this.chests, event.tick)) do
|
|
local entity = data.entity
|
|
if entity.valid then
|
|
update_entity(entity)
|
|
else
|
|
b_remove(this.chests, unit_number)
|
|
end
|
|
end
|
|
end)
|
|
|
|
Event.add(defines.events.on_gui_opened, function(event)
|
|
if event.gui_type ~= defines.gui_type.entity then
|
|
return
|
|
end
|
|
|
|
local old = this.relative_gui[event.player_index]
|
|
if old and old.valid then
|
|
Gui.destroy(old)
|
|
end
|
|
|
|
if not this.enabled then
|
|
return
|
|
end
|
|
|
|
local entity = event.entity
|
|
if not entity or entity.name ~= 'buffer-chest' then
|
|
return
|
|
end
|
|
|
|
local data = b_get(this.chests, entity.unit_number)
|
|
if not data then
|
|
return
|
|
end
|
|
|
|
local player = game.get_player(event.player_index)
|
|
local frame = player.gui.relative.add {
|
|
type = 'frame',
|
|
name = relative_frame_name,
|
|
direction = 'vertical',
|
|
anchor = {
|
|
gui = defines.relative_gui_type.container_gui,
|
|
position = defines.relative_gui_position.right,
|
|
}
|
|
}
|
|
Gui.set_style(frame, { horizontally_stretchable = false, padding = 3 })
|
|
|
|
local flow = frame.add { type = 'flow', direction = 'horizontal' }
|
|
flow.add { type = 'label', style = 'frame_title' }
|
|
|
|
local canvas = frame.add { type = 'frame', style = 'entity_frame', direction = 'vertical' }
|
|
|
|
local info = canvas.add { type = 'frame', style = 'deep_frame_in_shallow_frame_for_description', direction = 'vertical' }
|
|
info.add { type = 'label', caption = '[img=entity/market] Market chest', style = 'tooltip_heading_label_category' }
|
|
info.add { type = 'line', direction = 'horizontal', style = 'tooltip_category_line' }
|
|
local description = info.add { type = 'label', caption = {'market_chest.description'} }
|
|
Gui.set_style(description, { single_line = false, maximal_width = 184 })
|
|
|
|
local tables = {}
|
|
|
|
canvas.add { type = 'label', style = 'bold_label', caption = 'Requests [img=info]', tooltip = {'market_chest.requests_tooltip'} }
|
|
tables.requests = canvas
|
|
.add { type = 'frame', style = 'slot_button_deep_frame' }
|
|
.add { type = 'table', style = 'filter_slot_table', column_count = 5 }
|
|
for name, value in pairs(this.requests) do
|
|
local button = tables.requests.add {
|
|
type = 'sprite-button',
|
|
sprite = 'item/'..name,
|
|
number = value,
|
|
tooltip = {'market_chest.item_tooltip', value},
|
|
tags = { name = request_tag_name, item = name, id = entity.unit_number },
|
|
toggled = data.request and data.request == name,
|
|
}
|
|
Gui.set_data(button, tables)
|
|
end
|
|
|
|
canvas.add { type = 'line', direction = 'horizontal' }
|
|
canvas.add { type = 'label', style = 'bold_label', caption = 'Offers [img=info]', tooltip = {'market_chest.offers_tooltip'} }
|
|
tables.offers = canvas
|
|
.add { type = 'frame', style = 'slot_button_deep_frame' }
|
|
.add { type = 'table', style = 'filter_slot_table', column_count = 5 }
|
|
for name, value in pairs(this.offers) do
|
|
local button = tables.offers.add {
|
|
type = 'sprite-button',
|
|
sprite = 'item/'..name,
|
|
number = value,
|
|
tooltip = {'market_chest.item_tooltip', value},
|
|
tags = { name = offer_tag_name, item = name, id = entity.unit_number },
|
|
toggled = data.offer and data.offer == name,
|
|
}
|
|
Gui.set_data(button, tables)
|
|
end
|
|
|
|
this.relative_gui[event.player_index] = frame
|
|
end)
|
|
|
|
Event.add(defines.events.on_gui_click, function(event)
|
|
local element = event.element
|
|
if not (element and element.valid) then
|
|
return
|
|
end
|
|
|
|
local tag = element.tags and element.tags.name
|
|
if not tag or not (tag == request_tag_name or tag == offer_tag_name) then
|
|
return
|
|
end
|
|
|
|
local toggled = not element.toggled
|
|
for _, button in pairs(element.parent.children) do
|
|
button.toggled = false
|
|
end
|
|
element.toggled = toggled
|
|
|
|
local item_name = element.tags.item
|
|
local data = b_get(this.chests, element.tags.id)
|
|
|
|
if tag == request_tag_name then
|
|
data.request = toggled and item_name or nil
|
|
elseif tag == offer_tag_name then
|
|
data.offer = toggled and item_name or nil
|
|
end
|
|
|
|
if data.request == data.offer then
|
|
data.request, data.offer = nil, nil
|
|
for _, t in pairs(Gui.get_data(element)) do
|
|
for _, button in pairs(t.children) do
|
|
button.toggled = false
|
|
end
|
|
end
|
|
end
|
|
|
|
if data.request and data.offer then
|
|
data.ratio = this.requests[data.request] / this.offers[data.offer]
|
|
else
|
|
data.ratio = nil
|
|
end
|
|
end)
|
|
|
|
Event.on_init(function()
|
|
update_market(config.market_provides_chests, 3000)
|
|
end)
|
|
|
|
local Public = {}
|
|
|
|
Public.get = function(key)
|
|
return this[key]
|
|
end
|
|
|
|
Public.set = function(key, value)
|
|
this[key] = value
|
|
end
|
|
|
|
Public.distribute_linked_chests = function(enabled, price)
|
|
update_market(enabled, price)
|
|
end
|
|
|
|
Public.spread = function(ticks)
|
|
Buckets.reallocate(this.chests, ticks)
|
|
end
|
|
|
|
return Public
|