-- environment_ers.lua if S.trains == nil then S.trains = {} end if S.train_duration == nil then S.train_duration = {} end if S.yards == nil then S.yards = {} end F.known_rcs = { ["LILSHUNTER"] = "LILSHUNTER", ["CRYSTAL"] = "CRYSTAL", ["DEPOTUNLOADING"] = "DEPOTUNLOADING", ["ERSBALLASTLOAD"] = "ERSBALLASTLOAD", ["CORNUNLOAD"] = "CORNUNLOAD", ["MEGACORNLOAD"] = "MEGACORNLOAD", ["XERXES"] = "XERXES", ["BLOCK"] = "BLOCK", ["FERTILIZER"] = "FERTILIZER", ["FERTRUNNER"] = "FERTRUNNER", ["MULCH"] = "MULCH", ["ERSTAZIDEPOTUNLOAD"] = "ERSTAZIDEPOTUNLOAD", ["ERSTAZIDEPOT"] = "ERSTAZIDEPOT", ["ERSSINENSISDEPOT"] = "ERSSINENSISDEPOT", ["ERSTAZITST"] = "ERSTAZITST", ["FACTORY"] = "FACTORY", ["OILEXTRACT"] = "OILEXTRACT", ["SHUNT04A"] = "SHUNT04A", ["ERSTAZISHOP"] = "ERSTAZISHOP", ["TYARD"] = "TYARD", ["TY_COLLECT_SINESIS"] = "TY_COLLECT_SINESIS", ["TY_RTS"] = "TY_RTS", ["FAREAST"] = "FAREAST", ["KLYARD"] = "KLYARD", } F.print = function (str) if F.debug then print("".. (str or "nil") ) end end F.isempty = function (s) return s == nil or s == "" end F.get_rc_safe = function() return get_rc() or "" end F.get_line_safe = function() return get_line() or "" end F.get_train_length_safe = function() return train_length() or 0 end F.avg = function(t) local sum = 0 local count = 0 for k,v in pairs(t) do if type(v) == "number" then sum = sum + v count = count + 1 end end return (sum / count) end if event.init then F.debug = true F.max_displays = 52 F.print("Initialized") end F.clear_main_depot_displays = function() for i = 1, F.max_displays, 1 do digiline_send("train_display" .. i, " ") end end --[[ EXAMPLE: F.has_rc("LILSHUNTER", F.get_rc_safe() ) Merged F.has_rc and F.does_train_have_rc F.does_train_have_rc is deprecated ]] F.has_rc = function(query,rc_list) -- query = string, single entry for word in rc_list:gmatch("[^%s]+") do if word == query then return true end end return false end F.send_route = function(passive_name, route, show_print) local message = "" local return_value = false if can_set_route(passive_name, route) then set_route(passive_name, route) message = passive_name .. " has been set to " .. route return_value = true else message = route .. " cannot be set for " .. passive_name .. ". Try another." return_value = false end if show_print == true then F.print(message) end return return_value end F.save_train = function() if not atc_id then return end if S.trains then S.trains[atc_id] = { ["id"] = atc_id, ["rc"] = F.get_rc_safe(), ["ln"] = F.get_line_safe(), ["cars_count"] = F.get_train_length_safe() } end end F.get_real_split_count = function(train_length_count, split_count) if split_count then if split_count == "all" then return 2 else F.print("train_length_count (" .. train_length_count .. ") - split_count (" .. split_count .. ")") train_length_count = train_length_count + 1 split_count = train_length_count - split_count return split_count end else return nil end end F.yard_siding_basic = function(yard, name, place) if event.train then if not atc_id then return end F.save_train() if place == "start" then if atc_arrow then atc_send("S5") else atc_send("B5S5") end elseif place == "end_alt" then do_something = false elseif place == "end" then if atc_arrow then atc_send("B0 W R") end else F.print("Place for " .. name .. " has not been defined") end end end F.yard_set_route = function(yard, train_id, atc_command) if atc_command == nil then atc_command = "A1 S5" end if S.yards[yard] and S.yards[yard]["state"] and S.yards[yard]["actions"] then status = S.yards[yard]["state"]["status"] current_sequence = S.yards[yard]["state"]["current"] current_operation = S.yards[yard]["actions"][current_sequence]["operation"] table_count = table.maxn(S.yards[yard]["actions"]) next_sequence = current_sequence + 1 -- F.print(next_sequence .. "/" .. table_count) if next_sequence <= table_count and S.yards[yard]["actions"][next_sequence] and S.yards[yard]["actions"][next_sequence]["route"] then next_route = S.yards[yard]["actions"][next_sequence]["route"] next_operation = S.yards[yard]["actions"][next_sequence]["operation"] use_this_signal = S.yards[yard]["actions"][next_sequence]["signal"] atc_send_status = atc_send_to_train(train_id, atc_command) if atc_send_status then if use_this_signal == nil then F.print(train_id .. " is waiting at: nil") --[[ Maybe change it so it shows which signal it is waiting at when completed with this message: F.print(train_id .. " has finished the sequences and is waiting.") ]] else can_set_route_response = can_set_route(use_this_signal, next_route) if can_set_route_response then -- set_train_length_count = S.yards[yard]["state"]["train_length_count"] -- S.yards[yard]["state"] = { status = "moving", current = next_sequence, train_length_count = set_train_length_count } set_route(use_this_signal, next_route) F.print("DIRECT COMMAND current_operation: " .. current_operation .. " next_operation: " .. next_operation) F.print(train_id .. " is heading to " .. next_route .. " through " .. use_this_signal) else F.print(train_id .. " cannot go to " .. next_route .. " at " .. use_this_signal) end end else F.print(atc_command .. " command failed") end else F.print("End of Operations for " .. train_id) end end end F.yard_siding_next_operation = function(yard, train_id, current_sequence) if S.yards[yard]["state"] then if current_sequence == nil then current_sequence = S.yards[yard]["state"]['current'] end local next_sequence = current_sequence + 1 local set_train_length_count = S.yards[yard]["state"]["train_length_count"] local table_count = table.maxn(S.yards[yard]["actions"]) F.print(next_sequence .. "/" .. table_count) S.yards[yard]["state"]["current"] = next_sequence end end F.yard_siding_operations_start = function(yard, train_id, place, current_operation, next_operation, current_split_count) -- F.print("THIS IS " .. place) if atc_arrow then if current_operation == "split_at_engine" then unset_autocouple() -- split_off_locomotive("A0B0") split_at_index(current_split_count, "S0") F.yard_set_route(yard, train_id, atc_command) F.yard_siding_next_operation(yard, train_id) -- elseif current_operation == "reverse" then -- unset_autocouple() -- atc_send("B0 W R S5") elseif next_operation == "split_at_engine" then F.print("MAYBE SPLIT HERE AT " .. place .. " current: " .. current_operation .. " next: " .. next_operation) F.yard_set_route(yard, train_id, atc_command) F.yard_siding_next_operation(yard, train_id) else F.yard_set_route(yard, train_id, atc_command) F.yard_siding_next_operation(yard, train_id) end else if current_split_count == nil then F.print("YARD SIDING " .. place .. " current_operation: " .. current_operation .. " next_operation: " .. next_operation) end if current_operation == "autocouple" then set_autocouple() elseif current_operation == "split_at_engine" then set_autocouple() else unset_autocouple() end if next_operation == "forward" then F.print("at start and the next operation says forward") F.yard_set_route(yard, train_id, atc_command) F.yard_siding_next_operation(yard, train_id) end end end F.yard_siding_operations_end = function(yard, train_id, place, current_operation, next_operation, current_split_count) -- F.print("THIS IS " .. place) if atc_arrow then F.print("YARD SIDING " .. place .. " current_operation: " .. current_operation .. " next_operation: " .. next_operation) if current_operation == "split_at_engine" then -- split_at_index(2, "S0") -- F.yard_set_route(yard, train_id, nil) -- F.yard_siding_next_operation(yard, train_id) unset_autocouple() atc_send("B0 W R S5") -- split_at_index(2, "S0") elseif next_operation == "autocouple" then unset_autocouple() atc_send("B0 W R S5") elseif next_operation == "reverse" then unset_autocouple() atc_send("B0 W R S5") elseif next_operation == "forward" then unset_autocouple() F.yard_set_route(yard, train_id, nil) F.yard_siding_next_operation(yard, train_id) else unset_autocouple() atc_send("B0 W R S5") end else if next_operation == "autocouple" then set_autocouple() end if current_operation == "autocouple" then set_autocouple() end -- if next_operation == "split_at_engine" then -- F.yard_siding_next_operation(yard, train_id) -- end end end F.yard_siding_operations_end_alt = function(yard, train_id, place, current_operation, next_operation, current_split_count) -- F.print("THIS IS " .. place) if atc_arrow then if next_operation == "forward" or next_operation == "split_at_engine" then unset_autocouple() F.yard_set_route(yard, train_id, nil) F.yard_siding_next_operation(yard, train_id) elseif next_operation == "autocouple" then set_autocouple() F.yard_set_route(yard, train_id, nil) F.yard_siding_next_operation(yard, train_id) elseif next_operation == "reverse" then unset_autocouple() atc_send("B0 W R S5") else unset_autocouple() -- atc_send("B0 W R S5") F.print("At " .. place .. " and stopped because the command isn't programmed yet") end end end F.yard_siding_operations = function(yard, train_id, place, current_operation, next_operation, current_split_count) if place == "start" then F.yard_siding_operations_start(yard, train_id, place, current_operation, next_operation, current_split_count) elseif place == "end" then F.yard_siding_operations_end(yard, train_id, place, current_operation, next_operation, current_split_count) elseif place == "end_alt" then F.yard_siding_operations_end_alt(yard, train_id, place, current_operation, next_operation, current_split_count) else F.print("Place for " .. name .. " has not been defined") end end F.yard_siding = function(yard, name, place) if event.train then if not atc_id then return end if F.has_rc("LILSHUNTER", F.get_rc_safe() ) then if S.yards[yard] and S.yards[yard]["state"] and S.yards[yard]["actions"] then train_id = atc_id S.yards[yard]["state"]["train_length_count"] = F.get_train_length_safe() train_length_count = S.yards[yard]["state"]["train_length_count"] status = S.yards[yard]["state"]["status"] current_sequence = S.yards[yard]["state"]["current"] current_operation = S.yards[yard]["actions"][current_sequence]["operation"] current_split_count = S.yards[yard]["actions"][current_sequence]["split_count"] current_split_count = F.get_real_split_count(train_length_count, current_split_count) table_count = table.maxn(S.yards[yard]["actions"]) next_sequence = current_sequence + 1 if next_sequence <= table_count and S.yards[yard]["actions"][next_sequence] then next_route = S.yards[yard]["actions"][next_sequence]["route"] use_this_signal = S.yards[yard]["actions"][next_sequence]["signal"] next_operation = S.yards[yard]["actions"][next_sequence]["operation"] next_split_count = S.yards[yard]["actions"][next_sequence]["split_count"] next_split_count = F.get_real_split_count(train_length_count, next_split_count) F.yard_siding_operations(yard, train_id, place, current_operation, next_operation, current_split_count) else F.print("Went over the table count in F.yard_siding") end else F.yard_siding_basic(yard, name, place) end else F.yard_siding_basic(yard, name, place) end end return end F.yard_run = function(yard, section_id) -- section_id example: "723167" if S.yards[yard] and type(S.yards[yard]) == "table" then section_occuppied_by_table = section_occupancy(section_id) section_occuppied_count = table.maxn(section_occuppied_by_table) if section_occuppied_count == 1 then train_id = section_occuppied_by_table[1] F.print("train_id: " .. train_id) F.yard_set_route(yard, train_id) F.yard_siding_next_operation(yard, train_id) else F.print("HALT! More than one train is in the SHUNT01 section") end else F.print("ERROR: S.yards[yard] needs to be a table") end return end F.reset_trial_setup = function() local yard = "ers_main" if S.yards[yard] then S.yards[yard] = {} F.print(yard .. " has been reset!") end end F.trial_setup = function(type) -- LILSHUNTER local yard = "ers_main" local section_id = "723167" if type == nil then F.print("Please, declare a type") elseif type == "autocouple_1_4" then S.yards[yard] = { ["state"] = { status = "ready", current = 1, train_length_count = 1 }, ["actions"] = { [1] = {route = "SHUNT01", signal = nil, operation = "start"}, [2] = {route = "SIDING01", signal = "SHUNT01_SIGNAL", operation = "autocouple"}, [3] = {route = "HEADSHUNT01", signal = "SIDING01_SIGNAL", operation = "reverse"}, [4] = {route = "SIDING02", signal = "HEADSHUNT01_SIGNAL", operation = "autocouple"}, [5] = {route = "HEADSHUNT01", signal = "SIDING02_SIGNAL", operation = "reverse"}, [6] = {route = "SIDING03", signal = "HEADSHUNT01_SIGNAL", operation = "autocouple"}, [7] = {route = "HEADSHUNT01", signal = "SIDING03_SIGNAL", operation = "reverse"}, [8] = {route = "SIDING04", signal = "HEADSHUNT01_SIGNAL", operation = "autocouple"}, [9] = {route = "HEADSHUNT01", signal = "SIDING04_SIGNAL", operation = "reverse"}, [10] = {route = "SIDING05", signal = "HEADSHUNT01_SIGNAL", operation = "split_at_engine", split_count = "all"}, [11] = {route = "SHUNT01", signal = "SIDING05_SIGNAL", operation = "forward"}, [12] = {route = "SHUNT01", signal = nil, operation = "end"} } } elseif type == "split_train_1_4" then S.yards[yard] = { ["state"] = { status = "ready", current = 1, train_length_count = 1 }, ["actions"] = { [1] = {route = "SHUNT01", signal = nil, operation = "start"}, [2] = {route = "SIDING05", signal = "SHUNT01_SIGNAL", operation = "autocouple"}, [3] = {route = "HEADSHUNT01", signal = "SIDING05_SIGNAL", operation = "reverse"}, [4] = {route = "SIDING04", signal = "HEADSHUNT01_SIGNAL", operation = "split_at_engine", split_count = 1}, [5] = {route = "HEADSHUNT01", signal = "SIDING04_SIGNAL", operation = "reverse"}, [6] = {route = "SIDING03", signal = "HEADSHUNT01_SIGNAL", operation = "split_at_engine", split_count = 1}, [7] = {route = "HEADSHUNT01", signal = "SIDING03_SIGNAL", operation = "reverse"}, [8] = {route = "SIDING02", signal = "HEADSHUNT01_SIGNAL", operation = "split_at_engine", split_count = 1}, [9] = {route = "HEADSHUNT01", signal = "SIDING02_SIGNAL", operation = "reverse"}, [10] = {route = "SIDING01", signal = "HEADSHUNT01_SIGNAL", operation = "split_at_engine", split_count = 1}, [11] = {route = "SHUNT01", signal = "SIDING01_SIGNAL", operation = "reverse"}, [12] = {route = "SHUNT01", signal = nil, operation = "end"} } } elseif type == "loop_test" then S.yards[yard] = { ["state"] = { status = "ready", current = 1, train_length_count = 1 }, ["actions"] = { [1] = {route = "SHUNT01", signal = nil, operation = "start"}, [2] = {route = "SIDING05", signal = "SHUNT01_SIGNAL", operation = "autocouple"}, [3] = {route = "ALTSIDING01", signal = "SIDING05_SIGNAL", operation = "reverse"}, [4] = {route = "SIDING05", signal = "ALTSIDING01_BACK", operation = "forward"}, [5] = {route = "SHUNT01", signal = "SIDING05_SIGNAL", operation = "split_at_engine", split_count = 4}, [6] = {route = "SHUNT01", signal = nil, operation = "end"} } } elseif type == "loop_test1" then S.yards[yard] = { ["state"] = { status = "ready", current = 1, train_length_count = 1 }, ["actions"] = { [1] = {route = "SHUNT01", signal = nil, operation = "start"}, [2] = {route = "SIDING05", signal = "SHUNT01_SIGNAL", operation = "autocouple"}, [3] = {route = "ALTSIDING01", signal = "SIDING05_SIGNAL", operation = "reverse"}, [4] = {route = "SIDING05", signal = "ALTSIDING01_BACK", operation = "forward"}, [5] = {route = "SHUNT01", signal = "SIDING05_SIGNAL", operation = "split_at_engine", split_count = 4}, [6] = {route = nil, signal = nil, operation = "forward"}, [7] = {route = nil, signal = nil, operation = "end"} } } elseif type == "loop_autocouple_1_4" then S.yards[yard] = { ["state"] = { status = "ready", current = 1, train_length_count = 1 }, ["actions"] = { [1] = {route = "SHUNT01", signal = nil, operation = "start"}, [2] = {route = "ALTSIDING01", signal = "SHUNT01_SIGNAL", operation = "forward"}, [3] = {route = "SIDING01", signal = "ALTSIDING01_BACK", operation = "autocouple"}, [4] = {route = "ALTSIDING01", signal = "SIDING01_SIGNAL", operation = "forward"}, [5] = {route = "SIDING02", signal = "ALTSIDING01_BACK", operation = "autocouple"}, [6] = {route = "ALTSIDING01", signal = "SIDING02_SIGNAL", operation = "forward"}, [7] = {route = "SIDING03", signal = "ALTSIDING01_BACK", operation = "autocouple"}, [8] = {route = "ALTSIDING01", signal = "SIDING03_SIGNAL", operation = "forward"}, [9] = {route = "SIDING04", signal = "ALTSIDING01_BACK", operation = "autocouple"}, [10] = {route = nil, signal = nil, operation = "forward"}, [11] = {route = "HEADSHUNT01", signal = "SIDING04_SIGNAL", operation = "reverse"}, [12] = {route = "SIDING05", signal = "HEADSHUNT01_SIGNAL", operation = "forward"}, [13] = {route = "SHUNT01", signal = "SIDING05_SIGNAL", operation = "split_at_engine", split_count = 4}, [14] = {route = nil, signal = nil, operation = "forward"}, [15] = {route = nil, signal = nil, operation = "end"} } } elseif type == "loop_test_old" then S.yards[yard] = { ["state"] = { status = "ready", current = 1, train_length_count = 1 }, ["actions"] = { [1] = {route = "SHUNT01", signal = nil, operation = "start"}, [2] = {route = "ALTSIDING01", signal = "SHUNT01_SIGNAL", operation = "forward"}, [3] = {route = "SIDING01", signal = "ALTSIDING01_BACK", operation = "forward"}, [4] = {route = "ALTSIDING01", signal = "SIDING01_SIGNAL", operation = "forward"}, [5] = {route = "SIDING02", signal = "ALTSIDING01_BACK", operation = "forward"}, [6] = {route = "SHUNT01", signal = "SIDING02_SIGNAL", operation = "forward"}, [7] = {route = "SHUNT01", signal = nil, operation = "end"} } } elseif type == "test" then S.yards[yard] = { ["state"] = { status = "ready", current = 1, train_length_count = 1 }, ["actions"] = { [1] = {route = "SHUNT01", signal = nil, operation = "start"}, [2] = {route = "SIDING05", signal = "SHUNT01_SIGNAL", operation = "autocouple"}, [3] = {route = "ALTSIDING01", signal = "SHUNT01_SIGNAL", operation = "forward"}, [4] = {route = "SIDING01", signal = "ALTSIDING01_BACK", operation = "forward"}, [5] = {route = "ALTSIDING01", signal = "SIDING01_SIGNAL", operation = "split_at_engine", split_count = 1}, [6] = {route = "SIDING02", signal = "ALTSIDING01_BACK", operation = "forward"}, [7] = {route = "SHUNT01", signal = "SIDING02_SIGNAL", operation = "forward"}, [8] = {route = "SHUNT01", signal = nil, operation = "end"} } } else F.print("This type (" .. type .. ") is not defined") end F.yard_run(yard, section_id) end F.delete_train_info = function(train_id) if S.trains[train_id] then S.trains[train_id] = nil F.print("Deleted train id: " .. train_id) end end F.list_trains = function(number_of_displays) if S.trains then if number_of_displays == nil then number_of_displays = F.max_displays end F.clear_main_depot_displays() number_of_displays = number_of_displays + 1 count_keys = 0 trains_table = {} for k in pairs(S.trains) do table.insert(trains_table, k) count_keys = count_keys + 1 end table.sort(trains_table) x = number_of_displays - count_keys for _, k in ipairs(trains_table) do if S.trains[k] then v = S.trains[k] if F.has_rc("LILSHUNTER", v["rc"]) or F.has_rc("LIL", v["rc"]) then F.delete_train_info(v["id"]) else if v["ln"] == nil or v["ln"] == "" then line_number = "" else line_number = "| LN: [" .. v["ln"] .. "]" end if v["rc"] == nil or v["rc"] == "" then rc_display = "" else rc_list = v["rc"] rc_list_cleansed = "" rc_list_unknown = "" rc_list_table = {} if F.has_rc("ERSTAZI", rc_list) and F.has_rc("FREIGHT", rc_list) then rc_list_cleansed = "ERSTAZI FREIGHT |" else rc_list_cleansed = "NO E,F |" end for rc in rc_list:gmatch("[^%s]+") do if rc == "ERSTAZI" or rc == "FREIGHT" then -- leaving for future use do_nothing = true else if F.known_rcs[rc] ~= nil then rc_list_cleansed = rc_list_cleansed .. " " .. rc else rc_list_unknown = rc_list_unknown .. " " .. rc end end end rc_display = "| RC: " .. rc_list_cleansed if not F.isempty(rc_list_unknown) then rc_display = rc_display .. "| *URC*:" .. rc_list_unknown end end if v["cars_count"] == nil or v["cars_count"] == "" then cars_count_display = " Len: 0" else cars_count = tonumber(v["cars_count"]) cars_count_display = " Len: " .. cars_count end message = " ID: " .. v["id"] .. cars_count_display .. rc_display .. line_number if x > 0 then digiline_send("train_display" .. x, message) end F.print(x .. ": " .. message) x = x + 1 end end end else F.print("no trains saved in S.trains") end end F.slow_train_down = function(id) result = atc_send_to_train(id, "B1") if result == false then F.print("Train ID " .. id .. " does not exist") else F.print("Train ID " .. id .. " is slowed down to B1") end end F.train_duration = function(type) if not atc_id then return end local now = os.date("%H:%M:%S") if F.isempty(type) then type = "start" end if not S.train_duration[atc_id] then S.train_duration[atc_id] = { ["train_id"] = atc_id, ["start"] = "", ["end"] = "", ["start_sec"] = "", ["end_sec"] = "", ["diff"] = {} } end if type == "start" then S.train_duration[atc_id]["end"] = nil S.train_duration[atc_id]["end_sec"] = nil end S.train_duration[atc_id][type] = now S.train_duration[atc_id][type .. "_sec"] = os.time() if S.train_duration[atc_id]["start_sec"] ~= nil and S.train_duration[atc_id]["start_sec"] ~= "" and S.train_duration[atc_id]["end_sec"] ~= nil and S.train_duration[atc_id]["end_sec"] ~= "" then if S.train_duration[atc_id]["diff"] == nil then S.train_duration[atc_id]["diff"] = {} end -- Returns the difference, in seconds, from time t1 to time t2 (where the times are values returned by os.time) difference_in_time = os.difftime(S.train_duration[atc_id]["end_sec"], S.train_duration[atc_id]["start_sec"]) table.insert(S.train_duration[atc_id]["diff"], difference_in_time) end end F.train_info = function (passive_name, show_print) local timestart = "" local timeend = "" local time_message = "" local average_duration_message = "" if F.isempty(passive_name) or passive_name == "RESETALL" then train_id_message = "No Train" if passive_name == "RESETALL" then S.train_duration = {} -- Holding off on resetting the whole table of S.trains -- S.trains = {} end else timestart = S.train_duration[atc_id]["start"] timeend = S.train_duration[atc_id]["end"] train_id_message = "Last Train: " .. atc_id end if timestart == nil and timeend == nil then time_message = "Current Time: |" .. os.date("%H:%M:%S") elseif timestart ~= nil and timeend == nil then time_message = "Start: |" .. timestart else time_message = "Time: |" .. timestart .. " to " .. timeend end average_duration_message = "|AVG: " .. math.ceil(F.avg(S.train_duration[atc_id]["diff"])) .. "s" local lcd_message = "" .. train_id_message .. "|" .. time_message .. average_duration_message .. "" digiline_send("lcd", lcd_message) local message = lcd_message .. " | " .. time_message if show_print == true then F.print(message) end end