236 lines
6.5 KiB
Lua

local util = require("util")
local fuel_signal = "%[virtual%-signal=refuel%-signal]"
local fuel_signal_disabled = "%[virtual%-signal=refuel%-signal%-disabled]"
local depot_signal = "%[virtual%-signal=depot%-signal]"
local depot_signal_disabled = "%[virtual%-signal=depot%-signal%-disabled]"
local skip_signal = "%[virtual%-signal=skip%-signal]"
local train_needs_refueling = function(train)
local locomotives = train.locomotives
for k, movers in pairs (locomotives) do
for k, locomotive in pairs (movers) do
local fuel_inventory = locomotive.get_fuel_inventory()
if not fuel_inventory then return false end
if #fuel_inventory == 0 then return false end
fuel_inventory.sort_and_merge()
if #fuel_inventory > 1 then
if not fuel_inventory[2].valid_for_read then
return true
end
else
--Locomotive with only 1 fuel stack... idk, lets just guess
local stack = fuel_inventory[1]
if not stack.valid_for_read then
--Nothing in the stack, needs refueling.
return true
end
if stack.count < math.ceil(stack.prototype.stack_size / 4) then
return true
end
end
end
end
return false
end
local station_is_disabled = function(station)
return station:find(skip_signal)
end
local station_is_open_depot = function(station)
if not station then return false end
return station:find(depot_signal) and not station_is_disabled(station)
end
local train_needs_depot = function(train, old_state)
local schedule = train.schedule
if not schedule then return end
if train.state == defines.train_state.wait_station then
-- We just arrived at a station, if its a depot station keep it open
return station_is_open_depot(schedule.records[schedule.current].station)
end
if old_state == defines.train_state.no_path then
--We had no path, now we do
--We only keep depots open if we are going to a depot
return station_is_open_depot(schedule.records[schedule.current].station)
end
if old_state == defines.train_state.destination_full then
--We had no path, now we do
--We only keep depots open if we are going to a depot
return station_is_open_depot(schedule.records[schedule.current].station)
end
if old_state == defines.train_state.wait_station then
--We just left a station
if train.has_path then
--We have a path, if we're going to a depot, we keep it open.
return station_is_open_depot(schedule.records[schedule.current].station)
end
return true
end
end
local care_about =
{
[defines.train_state.wait_station] = true,
[defines.train_state.no_path] = true,
[defines.train_state.destination_full] = true,
}
local on_train_changed_state = function(event)
local train = event.train
if not (train and train.valid) then return end
if not (care_about[train.state] or care_about[event.old_state]) then
-- Some state that we don't care about
return
end
local schedule = train.schedule
if not schedule then return end
local needs_refuel = train_needs_refueling(train)
local needs_depot = train_needs_depot(train, event.old_state)
local changed = false
for k, record in pairs (schedule.records) do
local station = record.station
if station then
local enable = false
local disable = false
if station:find(fuel_signal) then
enable = needs_refuel
disable = not enable
end
if station:find(depot_signal) then
enable = enable or needs_depot
disable = not enable
end
if enable and station:find(skip_signal) then
record.station = station:gsub(skip_signal, "")
changed = true
end
if disable and not station:find(skip_signal) then
record.station = skip_signal:gsub("%%", "") .. station
changed = true
end
end
end
if not changed then return end
if needs_depot then
-- We are able to go to a depot, but we only want to do that if it is in the schedule in the correct order
-- What that means, is we just check if the previous station in the schedule is a depot, if so, go there, if not, we stay with destination full.
local current = schedule.current
local index = current
while true do
index = index - 1
if index == 0 then index = #schedule.records end
if index == current then break end
if station_is_open_depot(schedule.records[index].station) then
schedule.current = index
break
end
if not station_is_disabled(schedule.records[index].station) then
break
end
end
end
train.schedule = schedule
end
local check_rename_signal = function(entity, old_name, enabled_name)
local new_name = entity.backer_name
if new_name:find(skip_signal) then
--naughty...
entity.backer_name = new_name:gsub(skip_signal, "")
return
end
if not old_name:find(enabled_name) then
return
end
--old name had a control signal, lets emulate the base game thing where it fixes the schedules
local stops = entity.force.get_train_stops({surface = entity.surface, name = old_name})
if next(stops) then
--there are still some with the old name, do nothing
return
end
local old_disabled_name = skip_signal:gsub("%%", "") .. old_name
local new_disabled_name = skip_signal:gsub("%%", "") .. new_name
local trains = entity.force.get_trains(entity.surface)
for k, train in pairs (trains) do
local schedule = train.schedule
if schedule then
local changed = false
for k, record in pairs(schedule.records) do
if record.station then
if record.station == old_disabled_name then
changed = true
record.station = new_disabled_name
end
end
end
if changed then
train.schedule = schedule
end
end
end
end
local on_entity_renamed = function(event)
local entity = event.entity
if not (entity and entity.valid and entity.type == "train-stop") then
return
end
check_rename_signal(entity, event.old_name, fuel_signal)
check_rename_signal(entity, event.old_name, depot_signal)
end
local on_train_schedule_changed = function(event)
if event.player_index then
on_train_changed_state(event)
end
end
local lib = {}
lib.events =
{
[defines.events.on_train_changed_state] = on_train_changed_state,
[defines.events.on_entity_renamed] = on_entity_renamed,
[defines.events.on_train_schedule_changed] = on_train_schedule_changed,
}
lib.on_init = function()
end
lib.on_configuration_changed = function()
end
return lib