mirror of
https://github.com/Refactorio/RedMew.git
synced 2025-09-16 09:16:22 +02:00
Add Market chest and Train station teleport (#1478)
This commit is contained in:
29
config.lua
29
config.lua
@@ -216,7 +216,10 @@ storage.config = {
|
||||
{name = 'coin', count = 20000},
|
||||
{name = 'infinity-pipe', count = 10},
|
||||
{name = 'heat-interface', count = 10},
|
||||
{name = 'selection-tool', count = 1}
|
||||
{name = 'selection-tool', count = 1},
|
||||
{name = 'linked-chest', count = 10},
|
||||
{name = 'train-stop', count = 10},
|
||||
{name = 'rail', count = 100},
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -469,6 +472,10 @@ storage.config = {
|
||||
battery_charge = true,
|
||||
}
|
||||
},
|
||||
train_station_teleport = {
|
||||
enabled = false,
|
||||
radius = 13,
|
||||
},
|
||||
admin_panel = {
|
||||
enabled = true,
|
||||
},
|
||||
@@ -572,6 +579,26 @@ storage.config = {
|
||||
override_sound_type = 'ambient' -- Menu > Settings > Sounds > Music
|
||||
}
|
||||
},
|
||||
market_chest = {
|
||||
enabled = false,
|
||||
market_provides_chests = true,
|
||||
-- What market provides
|
||||
offers = {
|
||||
['coal'] = 2,
|
||||
['copper-ore'] = 2,
|
||||
['iron-ore'] = 2,
|
||||
['stone'] = 2,
|
||||
['uranium-ore'] = 10,
|
||||
},
|
||||
-- What market requests
|
||||
requests = {
|
||||
['coal'] = 1,
|
||||
['copper-ore'] = 1,
|
||||
['iron-ore'] = 1,
|
||||
['stone'] = 1,
|
||||
['uranium-ore'] = 5,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
return storage.config
|
||||
|
@@ -176,6 +176,12 @@ end
|
||||
if config.player_shortcuts.enabled then
|
||||
require 'features.gui.shortcuts'
|
||||
end
|
||||
if config.train_station_teleport.enabled then
|
||||
require 'features.train_station_teleport'
|
||||
end
|
||||
if config.market_chest.enabled then
|
||||
require 'features.market_chest'
|
||||
end
|
||||
if config.experience.enabled then
|
||||
require 'features.gui.experience'
|
||||
end
|
||||
|
311
features/market_chest.lua
Normal file
311
features/market_chest.lua
Normal file
@@ -0,0 +1,311 @@
|
||||
-- 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.unit_number
|
||||
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
|
@@ -133,6 +133,7 @@ local item_worths = {
|
||||
['passive-provider-chest'] = 256,
|
||||
['requester-chest'] = 512,
|
||||
['storage-chest'] = 256,
|
||||
['linked-chest'] = 4096,
|
||||
['logistic-robot'] = 256,
|
||||
['logistic-science-pack'] = 16,
|
||||
['long-handed-inserter'] = 16,
|
||||
@@ -246,6 +247,18 @@ function Public.is_unlocked(name)
|
||||
return item_unlocked[name] ~= nil
|
||||
end
|
||||
|
||||
function Public.set_unlocked(name, unlocked, value)
|
||||
if unlocked then
|
||||
item_unlocked[name] = value or item_worths[name] or 64
|
||||
if not table.contains(item_names, name) then
|
||||
table_insert(item_names, name)
|
||||
end
|
||||
else
|
||||
item_unlocked[name] = nil
|
||||
table.remove_element(item_names, name)
|
||||
end
|
||||
end
|
||||
|
||||
local function get_raffle_keys()
|
||||
local raffle_keys = {}
|
||||
for i = 1, #item_names do
|
||||
@@ -370,7 +383,6 @@ function Public.get_unlocked_item_values()
|
||||
return item_unlocked
|
||||
end
|
||||
|
||||
|
||||
function Public.get_items_worth()
|
||||
return item_worths
|
||||
end
|
||||
|
96
features/train_station_teleport.lua
Normal file
96
features/train_station_teleport.lua
Normal file
@@ -0,0 +1,96 @@
|
||||
-- This feature adds teleport shortcuts in train stop's GUI to allow players to teleport between tran stations.
|
||||
-- A player must stand nearby a train station to be able to teleport, and must teleport to a physical train stop (not ghost).
|
||||
|
||||
local Event = require 'utils.event'
|
||||
local Gui = require 'utils.gui'
|
||||
local Global = require 'utils.global'
|
||||
local config = require 'config'.train_station_teleport
|
||||
|
||||
local relative_frame_name = Gui.uid_name()
|
||||
local teleport_button_name = Gui.uid_name()
|
||||
|
||||
local this = {
|
||||
relative_gui = {},
|
||||
radius = config.radius or 13,
|
||||
enabled = config.enabled or false,
|
||||
}
|
||||
|
||||
Global.register(this, function(tbl) this = tbl 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 ~= 'train-stop' 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.train_stop_gui,
|
||||
position = defines.relative_gui_position.top,
|
||||
}
|
||||
}
|
||||
Gui.set_style(frame, { horizontally_stretchable = false, padding = 3 })
|
||||
|
||||
local canvas = frame.add { type = 'frame', style = 'inside_deep_frame', direction = 'vertical' }
|
||||
Gui.set_style(canvas, { padding = 4 })
|
||||
|
||||
local button = canvas.add { type = 'button', name = teleport_button_name, caption = 'Teleport' , style = 'confirm_button_without_tooltip' }
|
||||
Gui.set_data(button, { entity = entity })
|
||||
|
||||
this.relative_gui[event.player_index] = frame
|
||||
end)
|
||||
|
||||
Gui.on_click(teleport_button_name, function(event)
|
||||
local player = event.player
|
||||
if player.physical_surface.count_entities_filtered({
|
||||
position = player.physical_position,
|
||||
radius = this.radius,
|
||||
name = 'train-stop',
|
||||
limit = 1,
|
||||
}) == 0 then
|
||||
player.print({ 'train_station_teleport.err_no_nearby_station' })
|
||||
return
|
||||
end
|
||||
|
||||
local entity = Gui.get_data(event.element).entity
|
||||
if not (entity and entity.valid) then
|
||||
return
|
||||
end
|
||||
|
||||
local position = entity.surface.find_non_colliding_position('character', entity.position, this.radius, 0.2)
|
||||
if position then
|
||||
player.print({ 'train_station_teleport.success_destination', entity.backer_name })
|
||||
player.teleport(position, entity.surface)
|
||||
else
|
||||
player.print({ 'train_station_teleport.err_no_valid_position' })
|
||||
end
|
||||
end)
|
||||
|
||||
local Public = {}
|
||||
|
||||
Public.get = function(key)
|
||||
return this[key]
|
||||
end
|
||||
|
||||
Public.set = function(key, value)
|
||||
this[key] = value
|
||||
end
|
||||
|
||||
return Public
|
@@ -220,3 +220,14 @@ err_no_accumulators=[color=blue][Battery recharge][/color] No accumulators nearb
|
||||
[clear_corpses]
|
||||
count=[color=blue][Cleaner][/color] __1__ __plural_for_parameter__1__{1=corpse|rest=corpses}__ removed.
|
||||
clear=[color=blue][Cleaner][/color] already clear.
|
||||
|
||||
[train_station_teleport]
|
||||
err_no_nearby_station=[color=blue][Teleporter][/color] You must be near a train station before teleporting! Please move closer to a train station to initiate the teleport.
|
||||
err_no_valid_position=[color=blue][Teleporter][/color] No valid position was found at the selected train station. Please ensure the destination is accessible and try again.
|
||||
success_destination=[color=blue][Teleporter][/color] You have been teleported to [color=green]__1__[/color]! Enjoy your journey!
|
||||
|
||||
[market_chest]
|
||||
description=Automatically trade materials with the Market from anywhere. The [font=default-semibold][color=128,205,240]Market[/color][/font] will constantly provide your selected [font=default-semibold][color=255,230,192]Offer[/color][/font] as long as the selected [font=default-semibold][color=255,230,192]Request[/color][/font] is provided to make the trade.\n\nThe exchange fee is computed based on the ratio of the worths of selected items.
|
||||
requests_tooltip=Select an item that will be removed
|
||||
offers_tooltip=Select an item that will be provided
|
||||
item_tooltip=This item is worth __1__ [img=item/coin] __plural_for_parameter__1__{1=coin|rest=coins}__
|
@@ -56,10 +56,17 @@ function Scenario.register(diggy_config)
|
||||
redmew_config.reactor_meltdown.enabled = false
|
||||
redmew_config.hodor.enabled = false
|
||||
redmew_config.paint.enabled = false
|
||||
redmew_config.player_shortcuts.enabled = true
|
||||
redmew_config.train_station_teleport.enabled = true
|
||||
redmew_config.experience.enabled = true
|
||||
redmew_config.experience.sound.path = 'diggy-diggy-chorus'
|
||||
redmew_config.experience.sound.duration = 5 * 60 * 60
|
||||
redmew_config.player_shortcuts.enabled = true
|
||||
table.insert(redmew_config.experience.unlockables, {
|
||||
level = 120,
|
||||
price = 3000,
|
||||
name = 'linked-chest'
|
||||
})
|
||||
redmew_config.market_chest.enabled = true
|
||||
|
||||
restart_command({scenario_name = diggy_config.scenario_name})
|
||||
|
||||
|
@@ -61,6 +61,10 @@ function Market.spawn_exchange_market(position)
|
||||
local max_attempts = 10
|
||||
|
||||
local most_expensive_item = { value = 0 }
|
||||
|
||||
if storage.config.market_chest.enabled then
|
||||
PriceRaffle.set_unlocked('linked-chest', true)
|
||||
end
|
||||
local unlocked_items = PriceRaffle.get_unlocked_item_names()
|
||||
for _ = 1, offers_count do
|
||||
local inserted = false
|
||||
@@ -77,7 +81,7 @@ function Market.spawn_exchange_market(position)
|
||||
if price / stack_size < 80 then
|
||||
market.add_market_item {
|
||||
offer = { type = 'give-item', item = expensive, count = 1 },
|
||||
price = {{ name = cheap, type = 'item', amount = price }},
|
||||
price = {{ name = cheap, type = 'item', count = price }},
|
||||
}
|
||||
if expensive_value > most_expensive_item.value then
|
||||
most_expensive_item.name = expensive
|
||||
@@ -101,7 +105,7 @@ function Market.spawn_exchange_market(position)
|
||||
if price / stack_size < 50 then
|
||||
market.add_market_item {
|
||||
offer = { type = 'give-item', item = expensive, count = 1 },
|
||||
price = {{ name = cheap, type = 'item', amount = price }},
|
||||
price = {{ name = cheap, type = 'item', count = price }},
|
||||
}
|
||||
if expensive_value > most_expensive_item.value then
|
||||
most_expensive_item.name = expensive
|
||||
|
@@ -72,6 +72,8 @@ Config.market.enabled = false
|
||||
Config.player_rewards.enabled = false
|
||||
Config.player_shortcuts.enabled = true
|
||||
Config.dump_offline_inventories.enabled = true
|
||||
Config.market_chest.enabled = true
|
||||
Config.train_station_teleport.enabled = true
|
||||
Config.player_create.starting_items = {
|
||||
{ name = 'burner-mining-drill', count = 1 },
|
||||
{ name = 'stone-furnace', count = 1 },
|
||||
@@ -80,6 +82,7 @@ Config.player_create.starting_items = {
|
||||
{ name = 'wood', count = 1 },
|
||||
}
|
||||
|
||||
|
||||
if script.active_mods['Krastorio2'] then
|
||||
Config.paint.enabled = false
|
||||
storage.config.redmew_qol.loaders = false
|
||||
|
@@ -36,4 +36,12 @@ Public.default_pusher = {
|
||||
}
|
||||
}
|
||||
|
||||
Public.default_dragger = {
|
||||
style = {
|
||||
vertically_stretchable = true,
|
||||
horizontally_stretchable = true,
|
||||
margin = 0
|
||||
}
|
||||
}
|
||||
|
||||
return Public
|
||||
|
83
utils/buckets.lua
Normal file
83
utils/buckets.lua
Normal file
@@ -0,0 +1,83 @@
|
||||
local DEFAULT_INTERVAL = 60
|
||||
|
||||
local Buckets = {}
|
||||
|
||||
---@param interval? number
|
||||
function Buckets.new(interval)
|
||||
return { list = {}, interval = interval or DEFAULT_INTERVAL }
|
||||
end
|
||||
|
||||
---@param bucket table
|
||||
---@param id number|string
|
||||
---@param data any
|
||||
function Buckets.add(bucket, id, data)
|
||||
local bucket_id = id % bucket.interval
|
||||
bucket.list[bucket_id] = bucket.list[bucket_id] or {}
|
||||
bucket.list[bucket_id][id] = data or {}
|
||||
end
|
||||
|
||||
---@param bucket table
|
||||
---@param id number|string
|
||||
function Buckets.get(bucket, id)
|
||||
if not id then return end
|
||||
local bucket_id = id % bucket.interval
|
||||
return bucket.list[bucket_id] and bucket.list[bucket_id][id]
|
||||
end
|
||||
|
||||
---@param bucket table
|
||||
---@param id number|string
|
||||
function Buckets.remove(bucket, id)
|
||||
if not id then return end
|
||||
local bucket_id = id % bucket.interval
|
||||
if bucket.list[bucket_id] then
|
||||
bucket.list[bucket_id][id] = nil
|
||||
end
|
||||
end
|
||||
|
||||
---@param bucket table
|
||||
---@param id number|string
|
||||
function Buckets.get_bucket(bucket, id)
|
||||
local bucket_id = id % bucket.interval
|
||||
bucket.list[bucket_id] = bucket.list[bucket_id] or {}
|
||||
return bucket.list[bucket_id]
|
||||
end
|
||||
|
||||
-- Redistributes current buckets content over a new time interval
|
||||
---@param bucket table
|
||||
---@param new_interval number
|
||||
function Buckets.reallocate(bucket, new_interval)
|
||||
new_interval = new_interval or DEFAULT_INTERVAL
|
||||
if bucket.interval == new_interval then
|
||||
return
|
||||
end
|
||||
local tmp = {}
|
||||
|
||||
-- Collect data from existing buckets
|
||||
for b_id = 0, bucket.interval - 1 do
|
||||
for id, data in pairs(bucket.list[b_id] or {}) do
|
||||
tmp[id] = data
|
||||
end
|
||||
end
|
||||
|
||||
-- Clear old buckets
|
||||
bucket.list = {}
|
||||
|
||||
-- Update interval and reinsert data
|
||||
bucket.interval = new_interval
|
||||
for id, data in pairs(tmp) do
|
||||
Buckets.add(bucket, id, data)
|
||||
end
|
||||
end
|
||||
|
||||
-- Distributes a table's content over a time interval
|
||||
---@param tbl table
|
||||
---@param interval? number
|
||||
function Buckets.migrate(tbl, interval)
|
||||
local bucket = Buckets.new(interval)
|
||||
for id, data in pairs(tbl) do
|
||||
Buckets.add(bucket, id, data)
|
||||
end
|
||||
return bucket
|
||||
end
|
||||
|
||||
return Buckets
|
@@ -112,7 +112,7 @@ local generate_event_name = script.generate_event_name
|
||||
|
||||
local Event = {}
|
||||
|
||||
local handlers_added = false -- set to true after the removeable event handlers have been added.
|
||||
local handlers_added = false -- set to true after the removable event handlers have been added.
|
||||
|
||||
local event_handlers = EventCore.get_event_handlers()
|
||||
local on_nth_tick_event_handlers = EventCore.get_on_nth_tick_event_handlers()
|
||||
@@ -142,7 +142,7 @@ local function remove(tbl, handler)
|
||||
return
|
||||
end
|
||||
|
||||
-- the handler we are looking for is more likly to be at the back of the array.
|
||||
-- the handler we are looking for is more likely to be at the back of the array.
|
||||
for i = #tbl, 1, -1 do
|
||||
if tbl[i] == handler then
|
||||
table_remove(tbl, i)
|
||||
@@ -213,6 +213,41 @@ function Event.on_nth_tick(tick, handler)
|
||||
core_on_nth_tick(tick, handler)
|
||||
end
|
||||
|
||||
local function handler_factory(event_list)
|
||||
return function(handler)
|
||||
for _, event_name in pairs(event_list) do
|
||||
Event.add(event_name, handler)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
Event.on_built = handler_factory {
|
||||
defines.events.on_biter_base_built,
|
||||
defines.events.on_built_entity,
|
||||
defines.events.on_robot_built_entity,
|
||||
defines.events.on_space_platform_built_entity,
|
||||
defines.events.script_raised_built,
|
||||
defines.events.script_raised_revive,
|
||||
defines.events.on_entity_cloned,
|
||||
}
|
||||
Event.on_destroyed = handler_factory {
|
||||
defines.events.on_entity_died,
|
||||
defines.events.on_player_mined_entity,
|
||||
defines.events.on_robot_mined_entity,
|
||||
defines.events.on_space_platform_mined_entity,
|
||||
defines.events.script_raised_destroy,
|
||||
}
|
||||
Event.on_built_tile = handler_factory {
|
||||
defines.events.on_player_built_tile,
|
||||
defines.events.on_robot_built_tile,
|
||||
defines.events.on_space_platform_built_tile,
|
||||
}
|
||||
Event.on_mined_tile = handler_factory {
|
||||
defines.events.on_player_mined_tile,
|
||||
defines.events.on_robot_mined_tile,
|
||||
defines.events.on_space_platform_mined_tile,
|
||||
}
|
||||
|
||||
--- Register a token handler that can be safely added and removed at runtime.
|
||||
-- Do NOT call this method during on_load.
|
||||
-- See documentation at top of file for details on using events.
|
||||
|
@@ -214,6 +214,17 @@ function Gui.add_pusher(parent, direction)
|
||||
return pusher
|
||||
end
|
||||
|
||||
Gui.add_dragger = function(parent, target)
|
||||
local dragger = parent.add { type = 'empty-widget', style = 'draggable_space_header' }
|
||||
Gui.set_style(dragger, Styles.default_dragger.style)
|
||||
|
||||
if target then
|
||||
dragger.drag_target = target
|
||||
end
|
||||
|
||||
return dragger
|
||||
end
|
||||
|
||||
local function handler_factory(event_id)
|
||||
local handlers
|
||||
|
||||
|
Reference in New Issue
Block a user