Version: 1.2.8
Date: 2022-1-5
  Features:
    - Improved placeholder cybernetic combinator art
    - Added a wagon control setting to bar unfiltered slots in adjacent cargo wagons
    - Added a setting and keybind for toggling on or off the central planner
  Changes:
    - Sped up the rate at which copy-paste by blueprint will be noticed
  Bugfixes:
    - Fixed a bug with combinators sometimes failing to connect with train stops
    - Fixed wagon control combinators outputting wagon contents after inserters have already taken out items
    - Fixed a rare crash on world migration
  Scripting:
    - Added missing return values to some interface functions
    - Migrated to non-deprecated flib modules
This commit is contained in:
Monica Moniot
2023-01-06 19:24:24 -05:00
committed by GitHub
parent 9014c834f2
commit b144a06f1a
115 changed files with 6013 additions and 474 deletions

View File

@@ -47,66 +47,66 @@ function create_delivery(map_data, r_station_id, p_station_id, train_id, manifes
--NOTE: we assume that the train is not being teleported at this time
--NOTE: set_manifest_schedule is allowed to cancel the delivery at the last second if applying the schedule to the train makes it lost
if set_manifest_schedule(map_data, train.entity, depot.entity_stop, not train.use_any_depot, p_station.entity_stop, p_station.enable_inactive, r_station.entity_stop, mod_settings.allow_cargo_in_depot and r_station.enable_inactive--[[@as boolean]], manifest, is_at_depot) then
local old_status = train.status
train.status = STATUS_TO_P
train.p_station_id = p_station_id
train.r_station_id = r_station_id
train.manifest = manifest
train.last_manifest_tick = map_data.total_ticks
local old_status = train.status
train.status = STATUS_TO_P
train.p_station_id = p_station_id
train.r_station_id = r_station_id
train.manifest = manifest
train.last_manifest_tick = map_data.total_ticks
r_station.last_delivery_tick = map_data.total_ticks
p_station.last_delivery_tick = map_data.total_ticks
r_station.last_delivery_tick = map_data.total_ticks
p_station.last_delivery_tick = map_data.total_ticks
r_station.deliveries_total = r_station.deliveries_total + 1
p_station.deliveries_total = p_station.deliveries_total + 1
r_station.deliveries_total = r_station.deliveries_total + 1
p_station.deliveries_total = p_station.deliveries_total + 1
local r_is_each = r_station.network_name == NETWORK_EACH
local p_is_each = p_station.network_name == NETWORK_EACH
for item_i, item in ipairs(manifest) do
assert(item.count > 0, "main.lua error, transfer amount was not positive")
local r_is_each = r_station.network_name == NETWORK_EACH
local p_is_each = p_station.network_name == NETWORK_EACH
for item_i, item in ipairs(manifest) do
assert(item.count > 0, "main.lua error, transfer amount was not positive")
r_station.deliveries[item.name] = (r_station.deliveries[item.name] or 0) + item.count
p_station.deliveries[item.name] = (p_station.deliveries[item.name] or 0) - item.count
r_station.deliveries[item.name] = (r_station.deliveries[item.name] or 0) + item.count
p_station.deliveries[item.name] = (p_station.deliveries[item.name] or 0) - item.count
if item_i > 1 or r_is_each or p_is_each then
local f, a
if r_is_each then
f, a = pairs(r_station.network_flag--[[@as {[string]: int}]])
if p_is_each then
for network_name, _ in f, a do
local item_network_name = network_name..":"..item.name
economy.all_r_stations[item_network_name] = nil
economy.all_p_stations[item_network_name] = nil
end
f, a = pairs(p_station.network_flag--[[@as {[string]: int}]])
if item_i > 1 or r_is_each or p_is_each then
local f, a
if r_is_each then
f, a = pairs(r_station.network_flag--[[@as {[string]: int}]])
if p_is_each then
for network_name, _ in f, a do
local item_network_name = network_name..":"..item.name
economy.all_r_stations[item_network_name] = nil
economy.all_p_stations[item_network_name] = nil
end
elseif p_is_each then
f, a = pairs(p_station.network_flag--[[@as {[string]: int}]])
else
f, a = once, r_station.network_name
end
--prevent deliveries from being processed for these items until their stations are re-polled
--if we don't wait until they are repolled a duplicate delivery might be generated for stations that share inventories
for network_name, _ in f, a do
local item_network_name = network_name..":"..item.name
economy.all_r_stations[item_network_name] = nil
economy.all_p_stations[item_network_name] = nil
end
elseif p_is_each then
f, a = pairs(p_station.network_flag--[[@as {[string]: int}]])
else
f, a = once, r_station.network_name
end
--prevent deliveries from being processed for these items until their stations are re-polled
--if we don't wait until they are repolled a duplicate delivery might be generated for stations that share inventories
for network_name, _ in f, a do
local item_network_name = network_name..":"..item.name
economy.all_r_stations[item_network_name] = nil
economy.all_p_stations[item_network_name] = nil
end
end
set_comb2(map_data, p_station)
set_comb2(map_data, r_station)
p_station.display_state = 1
update_display(map_data, p_station)
r_station.display_state = 1
update_display(map_data, r_station)
interface_raise_train_status_changed(train_id, old_status, STATUS_TO_P)
else
interface_raise_train_dispatch_failed(train_id)
end
set_comb2(map_data, p_station)
set_comb2(map_data, r_station)
p_station.display_state = 1
update_display(map_data, p_station)
r_station.display_state = 1
update_display(map_data, r_station)
interface_raise_train_status_changed(train_id, old_status, STATUS_TO_P)
else
interface_raise_train_dispatch_failed(train_id)
end
end
---@param map_data MapData
---@param r_station_id uint
@@ -654,9 +654,39 @@ local function tick_poll_station(map_data, mod_settings)
end
---@param map_data MapData
---@param mod_settings CybersynModSettings
function tick_init(map_data, mod_settings)
function tick_poll_entities(map_data, mod_settings)
local tick_data = map_data.tick_data
--NOTE: the following have undefined behaviour if the item on tick_data is deleted
if map_data.total_ticks%5 == 0 then
local train_id, train = next(map_data.trains, tick_data.last_train)
tick_data.last_train = train_id
if train then
if train.manifest and not train.se_is_being_teleported and train.last_manifest_tick + mod_settings.stuck_train_time*mod_settings.tps < map_data.total_ticks then
if mod_settings.stuck_train_alert_enabled then
send_alert_stuck_train(map_data, train.entity)
end
interface_raise_train_stuck(train_id)
end
end
local refueler_id, _ = next(map_data.each_refuelers, tick_data.last_refueler)
tick_data.last_refueler = refueler_id
if refueler_id then
set_refueler_from_comb(map_data, mod_settings, refueler_id)
end
else
local comb_id, comb = next(map_data.to_comb, tick_data.last_comb)
tick_data.last_comb = comb_id
if comb and comb.valid then
combinator_update(map_data, comb, true)
end
end
end
---@param map_data MapData
---@param mod_settings CybersynModSettings
function tick_init(map_data, mod_settings)
map_data.economy.all_p_stations = {}
map_data.economy.all_r_stations = {}
map_data.economy.all_names = {}
@@ -667,6 +697,7 @@ function tick_init(map_data, mod_settings)
if station.last_delivery_tick + mod_settings.warmup_time*mod_settings.tps < map_data.total_ticks then
map_data.active_station_ids[#map_data.active_station_ids + 1] = id
map_data.warmup_station_ids[i] = nil
combinator_update(map_data, station.entity_comb1)
end
else
map_data.warmup_station_ids[i] = nil
@@ -686,30 +717,6 @@ function tick_init(map_data, mod_settings)
map_data.queue_station_update = nil
end
--NOTE: the following has undefined behavior if last_train is deleted, this should be ok since the following doesn't care how inconsistent our access pattern is
local train_id, train = next(map_data.trains, tick_data.last_train)
tick_data.last_train = train_id
if train and train.manifest and not train.se_is_being_teleported and train.last_manifest_tick + mod_settings.stuck_train_time*mod_settings.tps < map_data.total_ticks then
if mod_settings.stuck_train_alert_enabled then
send_alert_stuck_train(map_data, train.entity)
end
interface_raise_train_stuck(train_id)
end
--NOTE: the following has undefined behavior if last_comb is deleted
local comb_id, comb = next(map_data.to_comb, tick_data.last_comb)
tick_data.last_comb = comb_id
local refueler_id, _ = next(map_data.each_refuelers, tick_data.last_refueler)
tick_data.last_refueler = refueler_id
if comb and comb.valid then
combinator_update(map_data, comb, true)
end
if refueler_id then
set_refueler_from_comb(map_data, mod_settings, refueler_id)
end
map_data.tick_state = STATE_POLL_STATIONS
interface_raise_tick_init()
end
@@ -718,21 +725,30 @@ end
function tick(map_data, mod_settings)
map_data.total_ticks = map_data.total_ticks + 1
if map_data.active_alerts then
if map_data.total_ticks%(8*mod_settings.tps) < 1 then
process_active_alerts(map_data)
end
end
if map_data.tick_state == STATE_INIT then
tick_init(map_data, mod_settings)
elseif map_data.tick_state == STATE_POLL_STATIONS then
for i = 1, mod_settings.update_rate do
if tick_poll_station(map_data, mod_settings) then break end
tick_poll_entities(map_data, mod_settings)
if mod_settings.enable_planner then
if map_data.tick_state == STATE_INIT then
tick_init(map_data, mod_settings)
end
elseif map_data.tick_state == STATE_DISPATCH then
for i = 1, mod_settings.update_rate do
tick_dispatch(map_data, mod_settings)
if map_data.tick_state == STATE_POLL_STATIONS then
for i = 1, mod_settings.update_rate do
if tick_poll_station(map_data, mod_settings) then break end
end
elseif map_data.tick_state == STATE_DISPATCH then
for i = 1, mod_settings.update_rate do
tick_dispatch(map_data, mod_settings)
end
end
else
map_data.tick_state = STATE_INIT
end
end

View File

@@ -27,6 +27,7 @@ SETTING_IS_STACK = 3
SETTING_ENABLE_INACTIVE = 4
SETTING_USE_ANY_DEPOT = 5
SETTING_DISABLE_DEPOT_BYPASS = 6
SETTING_ENABLE_SLOT_BARRING = 7
NETWORK_SIGNAL_DEFAULT = {name="signal-A", type="virtual"}
NETWORK_EACH = "signal-each"

View File

@@ -1,5 +1,5 @@
--By Mami
local get_distance = require("__flib__.misc").get_distance
local get_distance = require("__flib__.position").distance
local table_insert = table.insert
local bit_extract = bit32.extract
local bit_replace = bit32.replace
@@ -21,7 +21,7 @@ end
function get_stop_dist(entity0, entity1)
local surface0 = entity0.surface.index
local surface1 = entity1.surface.index
return (surface0 == surface1 and get_distance(entity0.position, entity1.position) or DIFFERENT_SURFACE_DISTANCE)--[[@as number]]
return (surface0 == surface1 and get_distance(entity0.position, entity1.position) or DIFFERENT_SURFACE_DISTANCE)
end
@@ -566,7 +566,7 @@ function get_comb_gui_settings(comb)
elseif op == MODE_WAGON then
selected_index = 5
end
return selected_index, params.first_signal, switch_state, bits
return selected_index--[[@as uint]], params.first_signal, switch_state, bits
end
---@param comb LuaEntity
---@param is_pr_state 0|1|2

View File

@@ -104,6 +104,7 @@
--NOTE: any setting labeled as an "interface setting" can only be changed through the remote-interface, these settings are not save and have to be set at initialization
--As a modder using the remote-interface, you may override any of these settings, including user settings. They will have to be overriden at initialization and whenever a user tries to change one.
---@class CybersynModSettings
---@field public enable_planner boolean
---@field public tps double
---@field public update_rate int
---@field public r_threshold int

View File

@@ -1,6 +1,5 @@
--By Mami
local flib_gui = require("__flib__.gui")
local flib_event = require("__flib__.event")
local flib_gui = require("__flib__.gui-lite")
local RED = "utility/status_not_working"
local GREEN = "utility/status_working"
@@ -41,6 +40,7 @@ end
local function set_visibility(main_window, selected_index)
local is_station = selected_index == 1
local is_depot = selected_index == 2
local is_wagon = selected_index == 5
local uses_network = is_station or is_depot or selected_index == 3
local uses_allow_list = is_station or selected_index == 3
@@ -56,107 +56,107 @@ local function set_visibility(main_window, selected_index)
first_settings.allow_list.visible = uses_allow_list
first_settings.is_stack.visible = is_station
bottom_flow.enable_inactive.visible = is_station
top_flow.enable_slot_barring.visible = is_wagon
depot_settings.visible = is_depot
end
---@param comb LuaEntity
---@param player LuaPlayer
function gui_opened(comb, player)
combinator_update(global, comb, true)
---@param e EventData.on_gui_click
local function handle_close(e)
local element = e.element
if not element then return end
local comb = global.to_comb[element.tags.id]
if not comb or not comb.valid then return end
local player = game.get_player(e.player_index)
if not player then return end
local rootgui = player.gui.screen
local selected_index, signal, switch_state, bits = get_comb_gui_settings(comb)
local window = flib_gui.build(rootgui, {
{type="frame", direction="vertical", ref={"main_window"}, name=COMBINATOR_NAME, children={
--title bar
{type="flow", ref={"titlebar"}, children={
{type="label", style="frame_title", caption={"cybersyn-gui.combinator-title"}, elem_mods={ignored_by_interaction=true}},
{type="empty-widget", style="flib_titlebar_drag_handle", elem_mods={ignored_by_interaction=true}},
{type="sprite-button", style="frame_action_button", mouse_button_filter={"left"}, sprite="utility/close_white", hovered_sprite="utility/close_black", name=COMBINATOR_NAME, actions={
on_click = {"close", comb.unit_number}
}}
}},
{type="frame", name="frame", style="inside_shallow_frame_with_padding", style_mods={padding=12, bottom_padding=9}, children={
{type="flow", name="vflow", direction="vertical", style_mods={horizontal_align="left"}, children={
--status
{type="flow", style="status_flow", direction="horizontal", style_mods={vertical_align="center", horizontally_stretchable=true, bottom_padding=4}, children={
{type="sprite", sprite=STATUS_SPRITES[comb.status] or STATUS_SPRITES_DEFAULT, style="status_image", style_mods={stretch_image_to_widget_size=true}},
{type="label", caption={STATUS_NAMES[comb.status] or STATUS_NAMES_DEFAULT}}
}},
--preview
{type="frame", style="deep_frame_in_shallow_frame", style_mods={minimal_width=0, horizontally_stretchable=true, padding=0}, children={
{type="entity-preview", style="wide_entity_button", ref={"preview"}},
}},
--drop down
{type="label", style="heading_3_label", caption={"cybersyn-gui.operation"}, style_mods={top_padding=8}},
{type="flow", name="top", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="drop-down", style_mods={top_padding=3, right_margin=8}, ref={"operation"}, actions={
on_selection_state_changed={"drop-down", comb.unit_number}
}, selected_index=selected_index, items={
{"cybersyn-gui.comb1"},
{"cybersyn-gui.depot"},
{"cybersyn-gui.refueler"},
{"cybersyn-gui.comb2"},
{"cybersyn-gui.wagon-manifest"},
}},
{type="switch", name="is_pr_switch", ref={"is_pr_switch"}, allow_none_state=true, switch_state=switch_state, left_label_caption={"cybersyn-gui.switch-provide"}, right_label_caption={"cybersyn-gui.switch-request"}, left_label_tooltip={"cybersyn-gui.switch-provide-tooltip"}, right_label_tooltip={"cybersyn-gui.switch-request-tooltip"}, actions={
on_switch_state_changed={"is_pr_switch", comb.unit_number}
}}
}},
---choose-elem-button
{type="line", style_mods={top_padding=10}},
{type="label", name="network_label", style="heading_3_label", caption={"cybersyn-gui.network"}, style_mods={top_padding=8}},
{type="flow", name="bottom", direction="horizontal", style_mods={vertical_align="top"}, children={
{type="choose-elem-button", name="network", style="slot_button_in_shallow_frame", elem_type="signal", tooltip={"cybersyn-gui.network-tooltip"}, signal=signal, style_mods={bottom_margin=1, right_margin=6, top_margin=2}, actions={
on_elem_changed={"choose-elem-button", comb.unit_number}
}},
{type="flow", name="depot", direction="vertical", style_mods={horizontal_align="left"}, children={
{type="flow", name="use_any_depot", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="use_same_depot", state=setting_flip(bits, SETTING_USE_ANY_DEPOT), tooltip={"cybersyn-gui.use-same-depot-tooltip"}, actions={
on_checked_state_changed={"setting-flip", comb.unit_number, SETTING_USE_ANY_DEPOT}
}},
{type="label", name="use_same_depot_label", style_mods={left_padding=3}, caption={"cybersyn-gui.use-same-depot-description"}},
}},
{type="flow", name="depot_bypass", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="depot_bypass", state=setting_flip(bits, SETTING_DISABLE_DEPOT_BYPASS), tooltip={"cybersyn-gui.depot-bypass-tooltip"}, actions={
on_checked_state_changed={"setting-flip", comb.unit_number, SETTING_DISABLE_DEPOT_BYPASS}
}},
{type="label", name="depot_bypass_label", style_mods={left_padding=3}, caption={"cybersyn-gui.depot-bypass-description"}},
}},
}},
{type="flow", name="first", direction="vertical", style_mods={horizontal_align="left", right_margin=8}, children={
{type="flow", name="allow_list", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="allow_list", state=setting_flip(bits, SETTING_DISABLE_ALLOW_LIST), tooltip={"cybersyn-gui.allow-list-tooltip"}, actions={
on_checked_state_changed={"setting-flip", comb.unit_number, SETTING_DISABLE_ALLOW_LIST}
}},
{type="label", name="allow_list_label", style_mods={left_padding=3}, caption={"cybersyn-gui.allow-list-description"}},
}},
{type="flow", name="is_stack", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="is_stack", state=setting(bits, SETTING_IS_STACK), tooltip={"cybersyn-gui.is-stack-tooltip"}, actions={
on_checked_state_changed={"setting", comb.unit_number, SETTING_IS_STACK}
}},
{type="label", name="is_stack_label", style_mods={left_padding=3}, caption={"cybersyn-gui.is-stack-description"}},
}},
}},
{type="flow", name="enable_inactive", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="enable_inactive", state=setting(bits, SETTING_ENABLE_INACTIVE), tooltip={"cybersyn-gui.enable-inactive-tooltip"}, actions={
on_checked_state_changed={"setting", comb.unit_number, SETTING_ENABLE_INACTIVE}
}},
{type="label", name="enable_inactive_label", style_mods={left_padding=3}, caption={"cybersyn-gui.enable-inactive-description"}},
}},
}}
}}
}}
}}
})
if rootgui[COMBINATOR_NAME] then
rootgui[COMBINATOR_NAME].destroy()
player.play_sound({path = COMBINATOR_CLOSE_SOUND})
end
end
---@param e EventData.on_gui_selection_state_changed
local function handle_drop_down(e)
local element = e.element
if not element then return end
local comb = global.to_comb[element.tags.id]
if not comb or not comb.valid then return end
window.preview.entity = comb
window.titlebar.drag_target = window.main_window
window.main_window.force_auto_center()
set_visibility(element.parent.parent.parent.parent, element.selected_index)
set_visibility(window.main_window, selected_index)
player.opened = window.main_window
if element.selected_index == 1 then
set_comb_operation(comb, MODE_PRIMARY_IO)
elseif element.selected_index == 2 then
set_comb_operation(comb, MODE_DEPOT)
--prevent the use of the each signal with depots
local network = element.parent.parent.bottom.network--[[@as LuaGuiElement]]
local signal = network.elem_value--[[@as SignalID]]
if signal.name == NETWORK_EACH then
network.elem_value = nil
set_comb_network_name(comb, nil)
end
elseif element.selected_index == 3 then
set_comb_operation(comb, MODE_REFUELER)
elseif element.selected_index == 4 then
set_comb_operation(comb, MODE_SECONDARY_IO)
elseif element.selected_index == 5 then
set_comb_operation(comb, MODE_WAGON)
else
return
end
combinator_update(global, comb)
end
---@param e EventData.on_gui_switch_state_changed
local function handle_pr_switch(e)
local element = e.element
if not element then return end
local comb = global.to_comb[element.tags.id]
if not comb or not comb.valid then return end
local is_pr_state = (element.switch_state == "none" and 0) or (element.switch_state == "left" and 1) or 2
set_comb_is_pr_state(comb, is_pr_state)
combinator_update(global, comb)
end
---@param e EventData.on_gui_elem_changed
local function handle_network(e)
local element = e.element
if not element then return end
local comb = global.to_comb[element.tags.id]
if not comb or not comb.valid then return end
local signal = element.elem_value--[[@as SignalID]]
if signal and (signal.name == "signal-everything" or signal.name == "signal-anything" or signal.name == "signal-each") then
signal.name = NETWORK_EACH
element.elem_value = signal
end
set_comb_network_name(comb, signal)
combinator_update(global, comb)
end
---@param e EventData.on_gui_checked_state_changed
local function handle_setting(e)
local element = e.element
if not element then return end
local comb = global.to_comb[element.tags.id]
if not comb or not comb.valid then return end
set_comb_setting(comb, element.tags.bit--[[@as int]], element.state)
combinator_update(global, comb)
end
---@param e EventData.on_gui_checked_state_changed
local function handle_setting_flip(e)
local element = e.element
if not element then return end
local comb = global.to_comb[element.tags.id]
if not comb or not comb.valid then return end
set_comb_setting(comb, element.tags.bit--[[@as int]], not element.state)
combinator_update(global, comb)
end
local function on_gui_opened(event)
@@ -180,94 +180,103 @@ local function on_gui_closed(event)
end
end
function register_gui_actions()
flib_gui.hook_events(function(event)
local msg = flib_gui.read_action(event)
if msg then
local player = game.get_player(event.player_index)
if not player then return end
local rootgui = player.gui.screen
-- read the action to determine what to do
if msg[1] == "close" then
if rootgui[COMBINATOR_NAME] then
rootgui[COMBINATOR_NAME].destroy()
player.play_sound({path = COMBINATOR_CLOSE_SOUND})
end
elseif msg[1] == "drop-down" then
local element = event.element
if not element then return end
local comb = global.to_comb[msg[2]]
if not comb or not comb.valid then return end
set_visibility(rootgui[COMBINATOR_NAME], element.selected_index)
if element.selected_index == 1 then
set_comb_operation(comb, MODE_PRIMARY_IO)
elseif element.selected_index == 2 then
set_comb_operation(comb, MODE_DEPOT)
--prevent the use of the each signal with depots
local network = element.parent.parent.bottom.network
local signal = network.elem_value
if signal.name == NETWORK_EACH then
network.elem_value = nil
set_comb_network_name(comb, nil)
end
elseif element.selected_index == 3 then
set_comb_operation(comb, MODE_REFUELER)
elseif element.selected_index == 4 then
set_comb_operation(comb, MODE_SECONDARY_IO)
elseif element.selected_index == 5 then
set_comb_operation(comb, MODE_WAGON)
else
return
end
combinator_update(global, comb)
elseif msg[1] == "choose-elem-button" then
local element = event.element
if not element then return end
local comb = global.to_comb[msg[2]]
if not comb or not comb.valid then return end
local signal = element.elem_value
if signal and (signal.name == "signal-everything" or signal.name == "signal-anything" or signal.name == "signal-each") then
signal.name = NETWORK_EACH
element.elem_value = signal
end
set_comb_network_name(comb, signal)
combinator_update(global, comb)
elseif msg[1] == "setting" then
local element = event.element
if not element then return end
local comb = global.to_comb[msg[2]]
if not comb or not comb.valid then return end
set_comb_setting(comb, msg[3], element.state)
combinator_update(global, comb)
elseif msg[1] == "setting-flip" then
local element = event.element
if not element then return end
local comb = global.to_comb[msg[2]]
if not comb or not comb.valid then return end
set_comb_setting(comb, msg[3], not element.state)
combinator_update(global, comb)
elseif msg[1] == "is_pr_switch" then
local element = event.element
if not element then return end
local comb = global.to_comb[msg[2]]
if not comb or not comb.valid then return end
local is_pr_state = (element.switch_state == "none" and 0) or (element.switch_state == "left" and 1) or 2
set_comb_is_pr_state(comb, is_pr_state)
combinator_update(global, comb)
end
end
end)
flib_event.register(defines.events.on_gui_opened, on_gui_opened)
flib_event.register(defines.events.on_gui_closed, on_gui_closed)
flib_gui.add_handlers({
["close"] = handle_close,
["drop_down"] = handle_drop_down,
["pr_switch"] = handle_pr_switch,
["network"] = handle_network,
["setting"] = handle_setting,
["setting_flip"] = handle_setting_flip,
})
script.on_event(defines.events.on_gui_opened, on_gui_opened)
script.on_event(defines.events.on_gui_closed, on_gui_closed)
flib_gui.handle_events()
end
---@param comb LuaEntity
---@param player LuaPlayer
function gui_opened(comb, player)
combinator_update(global, comb, true)
local rootgui = player.gui.screen
local selected_index, signal, switch_state, bits = get_comb_gui_settings(comb)
local _, main_window = flib_gui.add(rootgui, {
{type="frame", direction="vertical", name=COMBINATOR_NAME, children={
--title bar
{type="flow", name="titlebar", children={
{type="label", style="frame_title", caption={"cybersyn-gui.combinator-title"}, elem_mods={ignored_by_interaction=true}},
{type="empty-widget", style="flib_titlebar_drag_handle", elem_mods={ignored_by_interaction=true}},
{type="sprite-button", style="frame_action_button", mouse_button_filter={"left"}, sprite="utility/close_white", hovered_sprite="utility/close_black", name=COMBINATOR_NAME, handler=handle_close, tags={id=comb.unit_number}}
}},
{type="frame", name="frame", style="inside_shallow_frame_with_padding", style_mods={padding=12, bottom_padding=9}, children={
{type="flow", name="vflow", direction="vertical", style_mods={horizontal_align="left"}, children={
--status
{type="flow", style="status_flow", direction="horizontal", style_mods={vertical_align="center", horizontally_stretchable=true, bottom_padding=4}, children={
{type="sprite", sprite=STATUS_SPRITES[comb.status] or STATUS_SPRITES_DEFAULT, style="status_image", style_mods={stretch_image_to_widget_size=true}},
{type="label", caption={STATUS_NAMES[comb.status] or STATUS_NAMES_DEFAULT}}
}},
--preview
{type="frame", name="preview_frame", style="deep_frame_in_shallow_frame", style_mods={minimal_width=0, horizontally_stretchable=true, padding=0}, children={
{type="entity-preview", name="preview", style="wide_entity_button"},
}},
--drop down
{type="label", style="heading_3_label", caption={"cybersyn-gui.operation"}, style_mods={top_padding=8}},
{type="flow", name="top", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="drop-down", style_mods={top_padding=3, right_margin=8}, handler=handle_drop_down, tags={id=comb.unit_number}, selected_index=selected_index, items={
{"cybersyn-gui.comb1"},
{"cybersyn-gui.depot"},
{"cybersyn-gui.refueler"},
{"cybersyn-gui.comb2"},
{"cybersyn-gui.wagon-manifest"},
}},
{type="switch", name="is_pr_switch", allow_none_state=true, switch_state=switch_state, left_label_caption={"cybersyn-gui.switch-provide"}, right_label_caption={"cybersyn-gui.switch-request"}, left_label_tooltip={"cybersyn-gui.switch-provide-tooltip"}, right_label_tooltip={"cybersyn-gui.switch-request-tooltip"}, handler=handle_pr_switch, tags={id=comb.unit_number}},
{type="flow", name="enable_slot_barring", direction="horizontal", style_mods={vertical_align="center", left_padding=6}, children={
{type="checkbox", name="enable_slot_barring", state=setting(bits, SETTING_ENABLE_SLOT_BARRING), handler=handle_setting, tags={id=comb.unit_number, bit=SETTING_ENABLE_SLOT_BARRING}, tooltip={"cybersyn-gui.enable-slot-barring-tooltip"}},
{type="label", name="enable_slot_barring_label", style_mods={left_padding=3}, caption={"cybersyn-gui.enable-slot-barring-description"}},
}},
}},
---choose-elem-button
{type="line", style_mods={top_padding=10}},
{type="label", name="network_label", style="heading_3_label", caption={"cybersyn-gui.network"}, style_mods={top_padding=8}},
{type="flow", name="bottom", direction="horizontal", style_mods={vertical_align="top"}, children={
{type="choose-elem-button", name="network", style="slot_button_in_shallow_frame", elem_type="signal", tooltip={"cybersyn-gui.network-tooltip"}, signal=signal, style_mods={bottom_margin=1, right_margin=6, top_margin=2}, handler=handle_network, tags={id=comb.unit_number}},
{type="flow", name="depot", direction="vertical", style_mods={horizontal_align="left"}, children={
{type="flow", name="use_any_depot", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="use_same_depot", state=setting_flip(bits, SETTING_USE_ANY_DEPOT), handler=handle_setting_flip, tags={id=comb.unit_number, bit=SETTING_USE_ANY_DEPOT}, tooltip={"cybersyn-gui.use-same-depot-tooltip"}},
{type="label", name="use_same_depot_label", style_mods={left_padding=3}, caption={"cybersyn-gui.use-same-depot-description"}},
}},
{type="flow", name="depot_bypass", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="depot_bypass", state=setting_flip(bits, SETTING_DISABLE_DEPOT_BYPASS), handler=handle_setting_flip, tags={id=comb.unit_number, bit=SETTING_DISABLE_DEPOT_BYPASS}, tooltip={"cybersyn-gui.depot-bypass-tooltip"}},
{type="label", name="depot_bypass_label", style_mods={left_padding=3}, caption={"cybersyn-gui.depot-bypass-description"}},
}},
}},
{type="flow", name="first", direction="vertical", style_mods={horizontal_align="left", right_margin=8}, children={
{type="flow", name="allow_list", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="allow_list", state=setting_flip(bits, SETTING_DISABLE_ALLOW_LIST), handler=handle_setting_flip, tags={id=comb.unit_number, bit=SETTING_DISABLE_ALLOW_LIST}, tooltip={"cybersyn-gui.allow-list-tooltip"}},
{type="label", name="allow_list_label", style_mods={left_padding=3}, caption={"cybersyn-gui.allow-list-description"}},
}},
{type="flow", name="is_stack", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="is_stack", state=setting(bits, SETTING_IS_STACK), handler=handle_setting, tags={id=comb.unit_number, bit=SETTING_IS_STACK}, tooltip={"cybersyn-gui.is-stack-tooltip"}},
{type="label", name="is_stack_label", style_mods={left_padding=3}, caption={"cybersyn-gui.is-stack-description"}},
}},
}},
{type="flow", name="enable_inactive", direction="horizontal", style_mods={vertical_align="center"}, children={
{type="checkbox", name="enable_inactive", state=setting(bits, SETTING_ENABLE_INACTIVE), handler=handle_setting, tags={id=comb.unit_number, bit=SETTING_ENABLE_INACTIVE}, tooltip={"cybersyn-gui.enable-inactive-tooltip"}},
{type="label", name="enable_inactive_label", style_mods={left_padding=3}, caption={"cybersyn-gui.enable-inactive-description"}},
}},
}}
}}
}}
}}
})
main_window.frame.vflow.preview_frame.preview.entity = comb
main_window.titlebar.drag_target = main_window
main_window.force_auto_center()
set_visibility(main_window, selected_index)
player.opened = main_window
end

View File

@@ -1,10 +1,11 @@
--By Mami
local area = require("__flib__.area")
local area = require("__flib__.bounding-box")
local abs = math.abs
local floor = math.floor
local ceil = math.ceil
local min = math.min
local max = math.max
local bit_extract = bit32.extract
---@param layout_pattern (0|1|2|3)[]
@@ -204,14 +205,15 @@ function set_p_wagon_combs(map_data, station, train)
break
end
end
if carriage.type == "cargo-wagon" and item_i <= #manifest then
if carriage.type == "cargo-wagon" then
local inv = carriage.get_inventory(defines.inventory.cargo_wagon)
if inv then
---@type ConstantCombinatorParameters
local signals = {}
local inv_filter_i = 1
local item_slots_capacity = max(ceil((#inv - locked_slots)*percent_slots_to_use_per_wagon), 1)
while item_slots_capacity > 0 do
while item_slots_capacity > 0 and item_i <= #manifest do
local do_inc
if item.type == "item" then
local stack_size = get_stack_size(map_data, item.name)
@@ -222,11 +224,13 @@ function set_p_wagon_combs(map_data, station, train)
signals[i] = {index = i, signal = {type = item.type, name = item.name}, count = sign*count_to_fill}
item_count = item_count - count_to_fill
item_slots_capacity = item_slots_capacity - slots_to_fill
for j = 1, slots_to_fill do
inv.set_filter(inv_filter_i, item.name)
inv_filter_i = inv_filter_i + 1
if comb then
for j = 1, slots_to_fill do
inv.set_filter(inv_filter_i, item.name)
inv_filter_i = inv_filter_i + 1
end
train.has_filtered_wagon = true
end
train.has_filtered_wagon = true
do_inc = item_count == 0
else
do_inc = true
@@ -243,14 +247,18 @@ function set_p_wagon_combs(map_data, station, train)
end
if comb then
if bit_extract(get_comb_params(comb).second_constant, SETTING_ENABLE_SLOT_BARRING) > 0 then
inv.set_bar(inv_filter_i--[[@as uint]])
train.has_filtered_wagon = true
end
set_combinator_output(map_data, comb, signals)
end
end
elseif carriage.type == "fluid-wagon" and fluid_i <= #manifest then
elseif carriage.type == "fluid-wagon" then
local fluid_capacity = carriage.prototype.fluid_capacity
local signals = {}
while fluid_capacity > 0 do
while fluid_capacity > 0 and fluid_i <= #manifest do
local do_inc
if fluid.type == "fluid" then
local count_to_fill = min(fluid_count, fluid_capacity)

View File

@@ -189,12 +189,9 @@ local function search_for_station_combinator(map_data, stop, comb_operation, com
{pos_x - 2, pos_y - 2},
{pos_x + 2, pos_y + 2}
}
local entities = stop.surface.find_entities(search_area)
local entities = stop.surface.find_entities_filtered({area = search_area, name = COMBINATOR_NAME})
for _, entity in pairs(entities) do
if
entity.valid and entity.name == COMBINATOR_NAME and
entity ~= comb_forbidden and map_data.to_stop[entity.unit_number] == stop
then
if entity.valid and entity ~= comb_forbidden and map_data.to_stop[entity.unit_number] == stop then
local param = get_comb_params(entity)
if param.operation == comb_operation then
return entity
@@ -223,7 +220,7 @@ local function on_combinator_built(map_data, comb)
end
local stop = nil
local rail = nil
local entities = comb.surface.find_entities(search_area)
local entities = comb.surface.find_entities_filtered({area = search_area, name = {"train-stop", "straight-rail"}})
for _, cur_entity in pairs(entities) do
if cur_entity.valid then
if cur_entity.name == "train-stop" then
@@ -325,7 +322,7 @@ function on_combinator_broken(map_data, comb)
if station then
if station.entity_comb1 == comb then
on_station_broken(map_data, id, station)
on_stop_built(map_data, stop, comb)
on_stop_built_or_updated(map_data, stop, comb)
elseif station.entity_comb2 == comb then
station.entity_comb2 = search_for_station_combinator(map_data, stop, MODE_SECONDARY_IO, comb)
end
@@ -334,13 +331,13 @@ function on_combinator_broken(map_data, comb)
if depot then
if depot.entity_comb == comb then
on_depot_broken(map_data, id, depot)
on_stop_built(map_data, stop, comb)
on_stop_built_or_updated(map_data, stop, comb)
end
else
local refueler = map_data.refuelers[id]
if refueler and refueler.entity_comb == comb then
on_refueler_broken(map_data, id, refueler)
on_stop_built(map_data, stop, comb)
on_stop_built_or_updated(map_data, stop, comb)
end
end
end
@@ -468,7 +465,8 @@ end
---@param map_data MapData
---@param stop LuaEntity
---@param comb_forbidden LuaEntity?
function on_stop_built(map_data, stop, comb_forbidden)
function on_stop_built_or_updated(map_data, stop, comb_forbidden)
--NOTE: this stop must not be a part of any station before entering this function
local pos_x = stop.position.x
local pos_y = stop.position.y
@@ -480,20 +478,24 @@ function on_stop_built(map_data, stop, comb_forbidden)
local comb1 = nil
local depot_comb = nil
local refueler_comb = nil
local entities = stop.surface.find_entities(search_area)
local entities = stop.surface.find_entities_filtered({area = search_area, name = COMBINATOR_NAME})
for _, entity in pairs(entities) do
if entity.valid and entity ~= comb_forbidden and entity.name == COMBINATOR_NAME and map_data.to_stop[entity.unit_number] == nil then
map_data.to_stop[entity.unit_number] = stop
local param = get_comb_params(entity)
local op = param.operation
if op == MODE_PRIMARY_IO then
comb1 = entity
elseif op == MODE_SECONDARY_IO then
comb2 = entity
elseif op == MODE_DEPOT then
depot_comb = entity
elseif op == MODE_REFUELER then
refueler_comb = entity
if entity.valid and entity ~= comb_forbidden then
local id = entity.unit_number--[[@as uint]]
local adj_stop = map_data.to_stop[id]
if adj_stop == nil or adj_stop == stop then
map_data.to_stop[id] = stop
local param = get_comb_params(entity)
local op = param.operation
if op == MODE_PRIMARY_IO then
comb1 = entity
elseif op == MODE_SECONDARY_IO then
comb2 = entity
elseif op == MODE_DEPOT then
depot_comb = entity
elseif op == MODE_REFUELER then
refueler_comb = entity
end
end
end
end
@@ -515,7 +517,7 @@ local function on_stop_broken(map_data, stop)
{pos_x - 2, pos_y - 2},
{pos_x + 2, pos_y + 2}
}
local entities = stop.surface.find_entities(search_area)
local entities = stop.surface.find_entities_filtered({area = search_area, name = COMBINATOR_NAME})
for _, entity in pairs(entities) do
if entity.valid and map_data.to_stop[entity.unit_number] == stop then
map_data.to_stop[entity.unit_number] = nil
@@ -592,7 +594,7 @@ local function on_built(event)
if not entity or not entity.valid then return end
if entity.name == "train-stop" then
on_stop_built(global, entity)
on_stop_built_or_updated(global, entity)
elseif entity.name == COMBINATOR_NAME then
on_combinator_built(global, entity)
elseif entity.type == "inserter" then
@@ -778,6 +780,7 @@ end
local function grab_all_settings()
mod_settings.enable_planner = settings.global["cybersyn-enable-planner"].value --[[@as boolean]]
mod_settings.tps = settings.global["cybersyn-ticks-per-second"].value --[[@as double]]
mod_settings.update_rate = settings.global["cybersyn-update-rate"].value --[[@as int]]
mod_settings.r_threshold = settings.global["cybersyn-request-threshold"].value--[[@as int]]
@@ -845,6 +848,15 @@ local function main()
script.on_event(defines.events.on_entity_settings_pasted, on_paste)
script.on_event(defines.events.on_train_created, on_train_built)
script.on_event(defines.events.on_train_changed_state, on_train_changed)
script.on_event(defines.events.on_entity_renamed, on_rename)
script.on_event(defines.events.on_runtime_mod_setting_changed, on_settings_changed)
register_gui_actions()
if mod_settings.tps > DELTA then
local nth_tick = ceil(60/mod_settings.tps)--[[@as uint]];
script.on_nth_tick(nth_tick, function()
@@ -854,14 +866,11 @@ local function main()
script.on_nth_tick(nil)
end
script.on_event(defines.events.on_train_created, on_train_built)
script.on_event(defines.events.on_train_changed_state, on_train_changed)
script.on_event(defines.events.on_entity_renamed, on_rename)
script.on_event(defines.events.on_runtime_mod_setting_changed, on_settings_changed)
register_gui_actions()
script.on_event("cybersyn-toggle-planner", function(event)
local setting = settings.global["cybersyn-enable-planner"]
setting.value = not setting.value
settings.global["cybersyn-enable-planner"] = setting
end)
script.on_init(function()
local setting = settings.global["cybersyn-invert-sign"]

View File

@@ -185,13 +185,15 @@ local migrations_table = {
for train_id, train in pairs(map_data.trains) do
train.depot_id = train.parked_at_depot_id
if not train.depot_id then
local e = get_any_train_entity(train.entity)
local stops = e.force.get_train_stops({name = train.depot_name, surface = e.surface})
for stop in rnext_consume, stops do
local new_depot_id = stop.unit_number
if map_data.depots[new_depot_id] then
train.depot_id = new_depot_id--[[@as uint]]
break
if train.entity.valid then
local e = get_any_train_entity(train.entity)
local stops = e.force.get_train_stops({name = train.depot_name, surface = e.surface})
for stop in rnext_consume, stops do
local new_depot_id = stop.unit_number
if map_data.depots[new_depot_id] then
train.depot_id = new_depot_id--[[@as uint]]
break
end
end
end
end
@@ -200,7 +202,9 @@ local migrations_table = {
end
if not train.depot_id then
train.entity.manual_mode = true
send_alert_depot_of_train_broken(map_data, train.entity)
if train.entity.valid then
send_alert_depot_of_train_broken(map_data, train.entity)
end
local layout_id = train.layout_id
local count = global.layout_train_count[layout_id]
if count <= 1 then

View File

@@ -115,6 +115,7 @@ end
--[[helper functions]]
------------------------------------------------------------------
--NOTE: the policy of cybersyn is to give modders access to as much of the raw data of the mod as possible. Factorio only allows me to return copies of the original data rather than the actual thing, which sucks. The unsafe api has some tools to help you bypass this limitation.
--Some of these functions are so simplistic I'd recommend not even using them and just copy-pasting their internal code.
function interface.get_mod_settings()
return mod_settings
@@ -246,12 +247,13 @@ end
--[[unsafe API]]
------------------------------------------------------------------
--NOTE: The following functions can cause serious longterm damage to someone's world if they are given bad parameters. Please refer to global.lua for type information. Use caution.
--If there is any useful function missing from this API I'd be happy to add it. Join the Cybersyn discord to request it be added.
---@param value any
---@param ... string|int
function interface.write_global(value, ...)
--this can write anything into cybersyn's map_data, please be very careful with anything you write, it can cause permanent damage
--so interface.read_global(nil, "trains", 31415, "manifest") will cause global.trains[31415].manifest = nil (or return false if train 31415 does not exist)
--so interface.write_global(nil, "trains", 31415, "manifest") will cause global.trains[31415].manifest = nil (or return false if train 31415 does not exist)
local params = {...}
local size = #params
local key = params[size]
@@ -271,7 +273,7 @@ end
function interface.remove_manifest_from_station_deliveries(station_id, manifest, sign)
local station = global.stations[station_id]
assert(station)
remove_manifest(global, station, manifest, sign)
return remove_manifest(global, station, manifest, sign)
end
---@param r_station_id uint
---@param p_station_id uint
@@ -279,7 +281,7 @@ end
function interface.create_manifest(r_station_id, p_station_id, train_id)
local train = global.trains[train_id]
assert(global.stations[r_station_id] and global.stations[p_station_id] and train and train.is_available)
create_manifest(global, r_station_id, p_station_id, train_id)
return create_manifest(global, r_station_id, p_station_id, train_id)
end
---@param r_station_id uint
---@param p_station_id uint
@@ -288,19 +290,19 @@ end
function interface.create_delivery(r_station_id, p_station_id, train_id, manifest)
local train = global.trains[train_id]
assert(global.stations[r_station_id] and global.stations[p_station_id] and train and train.is_available and manifest)
create_delivery(global, r_station_id, p_station_id, train_id, manifest)
return create_delivery(global, r_station_id, p_station_id, train_id, manifest)
end
---@param train_id uint
function interface.fail_delivery(train_id)
local train = global.trains[train_id]
assert(train)
on_failed_delivery(global, train_id, train)
return on_failed_delivery(global, train_id, train)
end
---@param train_id uint
function interface.remove_train(train_id)
local train = global.trains[train_id]
assert(train)
remove_train(global, train_id, train)
return remove_train(global, train_id, train)
end
---@param train_id uint
@@ -320,14 +322,14 @@ function interface.add_available_train_to_depot(train_id, depot_id)
local train = global.trains[train_id]
local depot = global.depots[depot_id]
assert(train and depot)
add_available_train_to_depot(global, mod_settings, train_id, train, depot_id, depot)
return add_available_train_to_depot(global, mod_settings, train_id, train, depot_id, depot)
end
---@param train_id uint
function interface.remove_available_train(train_id)
--this function removes a train from the available trains list so it cannot be rescheduled and dispatched. if the train was not already available nothing will happen
local train = global.trains[train_id]
assert(train)
remove_available_train(global, train_id, train)
return remove_available_train(global, train_id, train)
end
------------------------------------------------------------------

View File

@@ -52,11 +52,12 @@ function on_failed_delivery(map_data, train_id, train)
train.has_filtered_wagon = nil
for carriage_i, carriage in ipairs(train.entity.cargo_wagons) do
local inv = carriage.get_inventory(defines.inventory.cargo_wagon)
if inv and inv.is_filtered() then
if inv then
---@type uint
for i = 1, #inv do
for i = 1, inv.get_bar() - 1 do
inv.set_filter(i, nil)
end
inv.set_bar()
end
end
end
@@ -211,38 +212,19 @@ end
---@param train_id uint
---@param train Train
local function on_train_arrives_station(map_data, station_id, train_id, train)
if train.manifest then
---@type uint
if train.status == STATUS_TO_P then
if train.p_station_id == station_id then
train.status = STATUS_P
local station = map_data.stations[station_id]
set_comb1(map_data, station, train.manifest, mod_settings.invert_sign and 1 or -1)
set_p_wagon_combs(map_data, station, train)
interface_raise_train_status_changed(train_id, STATUS_TO_P, STATUS_P)
end
elseif train.status == STATUS_TO_R then
if train.r_station_id == station_id then
train.status = STATUS_R
local station = map_data.stations[station_id]
set_comb1(map_data, station, train.manifest, mod_settings.invert_sign and -1 or 1)
set_r_wagon_combs(map_data, station, train)
interface_raise_train_status_changed(train_id, STATUS_TO_R, STATUS_R)
end
elseif train.status == STATUS_P and train.p_station_id == station_id then
--this is player intervention that is considered valid
elseif (train.status == STATUS_R or train.status == STATUS_TO_D or train.status == STATUS_TO_D_BYPASS) and train.r_station_id == station_id then
--this is player intervention that is considered valid
elseif mod_settings.react_to_train_at_incorrect_station then
on_failed_delivery(map_data, train_id, train)
remove_train(map_data, train_id, train)
lock_train(train.entity)
send_alert_train_at_incorrect_station(map_data, train.entity)
end
elseif mod_settings.react_to_train_at_incorrect_station then
--train is lost somehow, probably from player intervention
remove_train(map_data, train_id, train)
send_alert_train_at_incorrect_station(map_data, train.entity)
---@type uint
if train.status == STATUS_TO_P then
train.status = STATUS_P
local station = map_data.stations[station_id]
set_comb1(map_data, station, train.manifest, mod_settings.invert_sign and 1 or -1)
set_p_wagon_combs(map_data, station, train)
interface_raise_train_status_changed(train_id, STATUS_TO_P, STATUS_P)
elseif train.status == STATUS_TO_R then
train.status = STATUS_R
local station = map_data.stations[station_id]
set_comb1(map_data, station, train.manifest, mod_settings.invert_sign and -1 or 1)
set_r_wagon_combs(map_data, station, train)
interface_raise_train_status_changed(train_id, STATUS_TO_R, STATUS_R)
end
end
@@ -274,11 +256,12 @@ local function on_train_leaves_stop(map_data, mod_settings, train_id, train)
train.has_filtered_wagon = nil
for carriage_i, carriage in ipairs(train.entity.cargo_wagons) do
local inv = carriage.get_inventory(defines.inventory.cargo_wagon)
if inv and inv.is_filtered() then
if inv then
---@type uint
for i = 1, #inv do
for i = 1, inv.get_bar() - 1 do
inv.set_filter(i, nil)
end
inv.set_bar()
end
end
end
@@ -426,19 +409,21 @@ function on_train_built(event)
end
end
function on_train_changed(event)
---@type MapData
local map_data = global
local train_e = event.train--[[@as LuaTrain]]
if not train_e.valid then return end
local train_id = train_e.id
if global.active_alerts then
if map_data.active_alerts then
--remove the alert if the train is interacted with at all
local data = global.active_alerts[train_id]
local data = map_data.active_alerts[train_id]
if data then
--we need to wait for the train to come to a stop from being locked
if data[3] + 10*mod_settings.tps < global.total_ticks then
global.active_alerts[train_id] = nil
if next(global.active_alerts) == nil then
global.active_alerts = nil
if data[3] + 10*mod_settings.tps < map_data.total_ticks then
map_data.active_alerts[train_id] = nil
if next(map_data.active_alerts) == nil then
map_data.active_alerts = nil
end
end
end
@@ -448,24 +433,48 @@ function on_train_changed(event)
local stop = train_e.station
if stop and stop.valid and stop.name == "train-stop" then
local id = stop.unit_number--[[@as uint]]
if global.stations[id] then
local train = global.trains[train_id]
if train then
on_train_arrives_station(global, id, train_id, train)
end
elseif global.depots[id] then
on_train_arrives_depot(global, id, train_e)
elseif global.refuelers[id] then
local train = global.trains[train_id]
if train then
on_train_arrives_refueler(global, id, train_id, train)
if map_data.depots[id] then
on_train_arrives_depot(map_data, id, train_e)
end
else
local train = map_data.trains[train_id]
if train then
local schedule = train_e.schedule
if schedule then
local rail = schedule.records[schedule.current].rail
if rail then
local id, station, is_station
if train.status == STATUS_TO_P then
id = train.p_station_id
station = map_data.stations[id]
is_station = true
elseif train.status == STATUS_TO_R then
id = train.r_station_id
station = map_data.stations[id]
is_station = true
elseif train.status == STATUS_TO_F then
id = train.refueler_id
station = map_data.refuelers[id]
is_station = false
end
if id and station.entity_stop.connected_rail == rail then
if is_station then
on_train_arrives_station(map_data, id, train_id, train)
else
on_train_arrives_refueler(map_data, id, train_id, train)
end
end
end
end
end
end
elseif event.old_state == defines.train_state.wait_station then
local train = global.trains[train_id]
if train then
on_train_leaves_stop(global, mod_settings, train_id, train)
local path = train_e.path
if path and path.total_distance > 4 then
local train = map_data.trains[train_id]
if train then
on_train_leaves_stop(map_data, mod_settings, train_id, train)
end
end
end
end