diff options
Diffstat (limited to 'advtrains_line_automation/station_editor.lua')
-rw-r--r-- | advtrains_line_automation/station_editor.lua | 1054 |
1 files changed, 1054 insertions, 0 deletions
diff --git a/advtrains_line_automation/station_editor.lua b/advtrains_line_automation/station_editor.lua new file mode 100644 index 0000000..ceeeffe --- /dev/null +++ b/advtrains_line_automation/station_editor.lua @@ -0,0 +1,1054 @@ +local def +local F = minetest.formspec_escape +local ifthenelse = function(cond, a, b) if cond then return a else return b end end +local rwt = assert(advtrains.lines.rwt) + +local function load_stations() + local result = {} + local by_stn = {} + local all_lines_set = {["*"] = true} + local lines_set = {} + for stn, data in pairs(advtrains.lines.stations) do + local new_station = { + stn = stn, + name = data.name or "", + owner = data.owner or "", + tracks = {}, + } + by_stn[stn] = new_station + lines_set[stn] = {} + table.insert(result, new_station) + end + for epos, data in pairs(advtrains.lines.stops) do + if data.stn ~= nil and data.stn ~= "" and by_stn[data.stn] ~= nil then + local st = by_stn[data.stn] + local new_track = { + epos = epos, + pos = assert(advtrains.decode_pos(epos)), + track = data.track or "", + } + table.insert(st.tracks, new_track) + local ars = data.ars + if ars ~= nil then + if ars.default then + lines_set[data.stn] = all_lines_set + else + local set = lines_set[data.stn] + for _, rule in ipairs(ars) do + if not rule.n and rule.ln ~= nil then + set[rule.ln] = true + end + end + end + end + end + end + for _, st in ipairs(result) do + local set = lines_set[st.stn] + if set["*"] then + st.lines = {"*"} + else + local lines = {} + for line, _ in pairs(set) do + table.insert(lines, line) + end + table.sort(lines) + st.lines = lines + end + end + table.sort(result, function(a, b) return a.stn < b.stn end) + return result +end + +advtrains.lines.load_stations_for_formspec = load_stations + +local function station_distance(player_pos, st) + if st.tracks[1] == nil then + return -- no tracks + end + local distance = vector.distance(player_pos, st.tracks[1].pos) + for i = 2, #st.tracks do + local d2 = vector.distance(player_pos, st.tracks[i].pos) + if d2 < distance then + distance = d2 + end + end + return distance +end + +local function station_distance_s(player_pos, st) + local result = station_distance(player_pos, st) + if result ~= nil then + return string.format("%d m", result) + else + return "" + end +end + + +local function filter_all() + return true +end + +local function filter_mine(a, player_info) + return a.owner == player_info.name +end + +local function sort_by_distance(a, b, player_info) + return (station_distance(player_info.pos, a) or 1.0e+20) < (station_distance(player_info.pos, b) or 1.0e+20) +end + +local function sort_by_stn(a, b) + return tostring(a.stn) < tostring(b.stn) +end + +local function sort_by_name(a, b) + local a_key, b_key = ch_core.utf8_radici_klic(a.name, false), ch_core.utf8_radici_klic(b.name, false) + if a_key ~= b_key then + return a_key < b_key + else + return sort_by_stn(a, b) + end +end + +local filters = { + { + description = "od nejbližší", + -- filter = filter_all, + sorter = sort_by_distance, + }, + { + description = "podle kódu A-Z", + -- filter = filter_all, + sorter = sort_by_stn, + }, + { + description = "podle názvu A-Z", + -- filter = filter_all, + sorter = sort_by_name, + }, + { + description = "moje (podle kódu A-Z)", + filter = filter_mine, + sorter = sort_by_stn, + }, + { + description = "moje (podle názvu A-Z)", + filter = filter_mine, + sorter = sort_by_name, + }, + { + description = "moje (od nejbližší)", + filter = filter_mine, + sorter = sort_by_distance, + }, +} + + +local function get_formspec(custom_state) + local pinfo = ch_core.normalize_player(assert(custom_state.player_name)) + if pinfo.player == nil then + minetest.log("error", "Expected player not in game!") + return "" + end + local player_info = { + name = assert(custom_state.player_name), + pos = assert(custom_state.player_pos), + } + + local stations = custom_state.stations + if stations == nil then + local filter = filters[custom_state.active_filter] + local filter_func = filter.filter or filter_all + local sorter_func = filter.sorter + stations = {} + for _, st in ipairs(load_stations()) do + if filter_func(st, player_info) then + table.insert(stations, st) + end + end + table.sort(stations, function(a, b) return sorter_func(a, b, player_info) end) + custom_state.stations = stations + if custom_state.selection_index ~= nil and custom_state.selection_index > #stations + 1 then + custom_state.selection_index = nil + end + end + + local selection_index = custom_state.selection_index + local formspec = { + ch_core.formspec_header({formspec_version = 6, size = {20, 10}, auto_background = true}), + "label[0.5,0.6;Editor dopraven]", + } + + table.insert(formspec, "tablecolumns[image,".. + "0=ch_core_empty.png,".. + "1=basic_materials_padlock.png\\^[resize:16x16".. + ";text;text,width=25;color,span=1;text,width=7;text;text]".. + "table[0.5,1.25;19,5;dopravna;0,KÓD,NÁZEV,#ffffff,SPRAVUJE,VZDÁLENOST,INFO") + for _, st in ipairs(stations) do + local n_tracks = #st.tracks + table.insert(formspec, ",0,"..F(st.stn)..","..F(st.name)..",#ffffff,"..F(ch_core.prihlasovaci_na_zobrazovaci(st.owner))..",".. + F(station_distance_s(custom_state.player_pos, st))..","..n_tracks.." kolej") + if n_tracks < 1 or n_tracks > 4 then + table.insert(formspec, "í") + elseif n_tracks ~= 1 then + table.insert(formspec, "e") + end + if n_tracks > 0 then + table.insert(formspec, "\\, linky " ..F(table.concat(st.lines, ","))) + end + end + table.insert(formspec, ";"..(selection_index or "").."]") + + -- rozbalovací pole s volbou filtru a řazení + table.insert(formspec, "dropdown[8,0.3;7,0.6;filter;"..F(assert(filters[1].description))) + for i = 2, #filters do + table.insert(formspec, ","..F(filters[i].description)) + end + table.insert(formspec, ";"..custom_state.active_filter..";true]") + + table.insert(formspec, "button_exit[18.75,0.3;0.75,0.75;close;X]") + + local st = selection_index ~= nil and stations[selection_index - 1] + local stn, nazev, spravuje + if st then + stn = F(st.stn) + nazev = F(st.name) + spravuje = F(ch_core.prihlasovaci_na_zobrazovaci(st.owner)) + else + stn, nazev, spravuje = "", "", F(pinfo.viewname) + end + table.insert(formspec, + "field[0.5,7;2.5,0.75;stn;kód:;"..stn.."]".. + "field[3.25,7;7,0.75;name;název:;"..nazev.."]".. + ifthenelse(pinfo.role == "admin", "field[10.5,7;4,0.75;owner;spravuje:;", "label[10.5,6.75;spravuje:\n").. + spravuje.."]") + if pinfo.role ~= "new" then + table.insert(formspec, "button[0.5,8;4.5,0.75;vytvorit;vytvořit novou]".. + "button[10,8;4.5,0.75;jrad;jízdní řády...]") + if st and (pinfo.role == "admin" or st.owner == pinfo.player_name) then + table.insert(formspec, "button[5.25,8;4.5,0.75;ulozit;uložit změny]") + if st.tracks[1] == nil then + table.insert(formspec, "button[15.25,8;3,0.75;smazat;smazat]") + end + if custom_state.linevars[1] ~= nil then + table.insert(formspec, "label[0.5,9.4;přiřadit kolej]".. + "field[2.75,9.1;1,0.6;kolej;;]".. + "label[3.9,9.4;lince]".. + "dropdown[5,9.1;5,0.6;klinevar;") + for i, lvar in ipairs(custom_state.linevars) do + if i ~= 1 then + table.insert(formspec, ",") + end + table.insert(formspec, F(lvar.linevar.." | "..lvar.dep.." "..stn.." ["..lvar.track.."]")) + end + table.insert(formspec, ";"..custom_state.current_linevar..";true]".. + "button[10.25,9;4.25,0.75;priradit_kolej;přiřadit]".. + "tooltip[klinevar;") + table.insert(formspec, F("Vysvětlení formátu:\n<linka>/<kód vých.dop.>/<sm.kód> | <odjezd> <kód dop.> [<stávající kolej>]")) + table.insert(formspec, "]") + end + end + end + if st and st.tracks[1] ~= nil then + table.insert(formspec, "textarea[14.75,7;4.75,2.5;;pozice kolejí:;"..F(minetest.pos_to_string(st.tracks[1].pos))) + for i = 2, #st.tracks do + table.insert(formspec, "\n"..F(minetest.pos_to_string(st.tracks[i].pos))) + end + table.insert(formspec, "]") + end + return table.concat(formspec) +end + +local function formspec_callback(custom_state, player, formname, fields) + local update_formspec = false + if fields.vytvorit then + local new_stn, new_name, new_owner = fields.stn, fields.name or "", fields.owner + local pinfo = ch_core.normalize_player(player) + if pinfo.role ~= "admin" or new_owner == nil or new_owner == "" then + new_owner = pinfo.player_name + else + new_owner = ch_core.jmeno_na_prihlasovaci(new_owner) + end + if new_stn == nil or new_stn == "" then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: kód nesmí být prázdný!") + return + end + local als = advtrains.lines.stations + if als[new_stn] ~= nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: zastávka s kódem "..new_stn.." již existuje!") + return + end + als[new_stn] = {name = assert(new_name), owner = assert(new_owner)} + custom_state.stations = nil + update_formspec = true + ch_core.systemovy_kanal(custom_state.player_name, "Dopravna úspěšně vytvořena.") + elseif fields.ulozit then + local new_stn, new_name, new_owner = fields.stn, fields.name or "", fields.owner + local pinfo = ch_core.normalize_player(player) + local st = custom_state.stations[(custom_state.selection_index or 0) - 1] + if st == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: není vybrána žádná zastávka!") + return + end + local change_stn, change_name = st.stn ~= new_stn, st.name ~= new_name + local change_owner = pinfo.role == "admin" and fields.owner ~= nil and fields.owner ~= "" and + ch_core.jmeno_na_prihlasovaci(fields.owner) ~= st.owner + if not change_stn and not change_name and not change_owner then + ch_core.systemovy_kanal(custom_state.player_name, "Nic nezměněno.") + return + end + local t = advtrains.lines.stations[st.stn] + if t == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: zastávka k úpravě nebyla nalezena! Toto je pravděpodobně vnitřní chyba editoru.") + return + end + if change_stn then + -- zkontrolovat, že cílový kód je volný + if advtrains.lines.stations[new_stn] ~= nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: zastávka s kódem "..new_stn.." již existuje!") + return + end + end + if change_owner then + t.owner = ch_core.jmeno_na_prihlasovaci(fields.owner) + ch_core.systemovy_kanal(custom_state.player_name, "Správa zastávky změněna.") + end + if change_name then + t.name = new_name + ch_core.systemovy_kanal(custom_state.player_name, "Jmeno zastávky změněno.") + end + if change_stn then + advtrains.lines.stations[new_stn] = t + local stops = advtrains.lines.stops + local count = 0 + for _, trackinfo in ipairs(st.tracks) do + local stop = stops[trackinfo.epos] + if stop == nil then + minetest.log("error", "Expected track at position "..trackinfo.epos.." not found!") + elseif stop.stn ~= st.stn then + minetest.log("error", "Track at position "..trackinfo.epos.." has unexpected stn '"..tostring(stop.stn).."' instead of '"..st.stn.."'!") + else + stop.stn = new_stn + count = count + 1 + end + end + advtrains.lines.stations[st.stn] = nil + ch_core.systemovy_kanal(custom_state.player_name, "Kód zastávky změněn, "..count.." bloků kolejí aktualizováno.") + end + custom_state.stations = nil + update_formspec = true + elseif fields.smazat then + local pinfo = ch_core.normalize_player(player) + local st = custom_state.stations[(custom_state.selection_index or 0) - 1] + if st == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: není vybrána žádná zastávka!") + return + end + if st.tracks[1] ~= nil then + ch_core.systemovy_kanal(custom_state.player_name, "Nelze smazat zastávku, k níž jsou přiřazeny koleje!") + return + end + local t = advtrains.lines.stations[st.stn] + if t == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: zastávka k úpravě nebyla nalezena! Toto je pravděpodobně vnitřní chyba editoru.") + return + end + advtrains.lines.stations[st.stn] = nil + ch_core.systemovy_kanal(custom_state.player_name, "Zastávka úspěšně smazána.") + custom_state.stations = nil + update_formspec = true + elseif fields.jrad then + local st = custom_state.stations[(custom_state.selection_index or 0) - 1] + if st == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: není vybrána žádná zastávka!") + return + end + advtrains.lines.show_jr_formspec(player, nil, assert(st.stn)) + return + elseif fields.priradit_kolej then + local st = custom_state.stations[(custom_state.selection_index or 0) - 1] + if st == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: není vybrána žádná zastávka!") + return + end + local linevar_to_change = custom_state.linevars[custom_state.current_linevar] + if linevar_to_change == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: vnitřní chyba 1!") + return + end + local linevar_def = advtrains.lines.try_get_linevar_def(linevar_to_change.linevar, linevar_to_change.stn) + if linevar_def == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: vnitřní chyba 2!") + return + end + local stop = linevar_def.stops[linevar_to_change.linevar_index] + if stop == nil then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: vnitřní chyba 3!") + return + end + if stop.stn ~= st.stn then + ch_core.systemovy_kanal(custom_state.player_name, "CHYBA: vnitřní chyba 4!") + return + end + stop.track = tostring(fields.kolej) + linevar_to_change.track = stop.track + ch_core.systemovy_kanal(custom_state.player_name, "Přiřazená kolej úspěšně nastavena.") + update_formspec = true + elseif fields.quit then + return + end + + if fields.dopravna then + local event = minetest.explode_table_event(fields.dopravna) + if event.type == "CHG" then + custom_state.selection_index = ifthenelse(event.row > 1, event.row, nil) + local st = custom_state.stations[(custom_state.selection_index or 0) - 1] + local new_linevars = {} + custom_state.linevars = new_linevars + custom_state.current_linevar = 1 + if st ~= nil then + for _, r in ipairs(advtrains.lines.get_linevars_by_station(st.stn)) do + local line, stn = advtrains.lines.linevar_decompose(r.linevar) + for _, i in ipairs(r.indices) do + local stop = r.linevar_def.stops[i] + table.insert(new_linevars, { + stn = stn, + linevar = r.linevar, + linevar_index = i, + dep = assert(stop.dep), + track = stop.track or "", + }) + end + end + end + update_formspec = true + end + end + + if fields.klinevar then + local n = tonumber(fields.klinevar) + if n ~= nil and custom_state.linevars[n] ~= nil then + custom_state.current_linevar = n + end + end + + -- filter (must be the last) + if fields.filter then + local new_filter = tonumber(fields.filter) + if filters[new_filter] ~= nil and new_filter ~= custom_state.active_filter then + custom_state.active_filter = new_filter + custom_state.stations = nil + update_formspec = true + end + end + if update_formspec then + return get_formspec(custom_state) + end +end + +local function show_formspec(player) + + local custom_state = { + player_name = assert(player:get_player_name()), + player_pos = vector.round(player:get_pos()), + active_filter = 1, + -- selection_index = nil, + linevars = {--[[ + {stn = string, linevar = string, linevar_index = int, track = string}... + ]]}, + current_linevar = 1, + } + -- ch_core.show_formspec(player_or_player_name, formname, formspec, formspec_callback, custom_state, options) + ch_core.show_formspec(player, "advtrains_line_automation:editor_dopraven", get_formspec(custom_state), formspec_callback, custom_state, {}) +end + +advtrains.lines.open_station_editor = show_formspec + +def = { + -- params = "", + description = "Otevře editor dopraven (stanic, zastávek a odboček)", + privs = {}, + func = function(player_name, param) show_formspec(minetest.get_player_by_name(player_name)) end, +} +core.register_chatcommand("zastavky", def) +core.register_chatcommand("zastávky", def) + + +-- Jízdní řád + +--[[ + custom_state = { + pos = vector or nil, -- node position (will use metadata to determine the owner) + player_name = string, -- player to whom the formspec is to be shown (will use this to determine privs) + stn = int, -- station selection from stns + stns = { + {stn = "", fs = "(vyberte dopravnu)", name_fs = ""}, + {stn = string, fs = string, name_fs = string}... + }, -- the list of stations to select from; the first must be "", which means no station + track = int, -- selection of track from "tracks" list + tracks = {"", string...}, -- the list of tracks to select from; the first must be "", which means all tracks + linevar = int, + linevars = {{ + stn = string, -- station from linevar + linevar = string, -- linevar + line_fs = string, -- line for formspec + target_fs = string, -- terminus name for formspec + track_fs = string, -- track info for formspec ("" if not available) + status_fs = string, -- line status for formspec (including color column) + train_name_fs = string, -- train name for formspec ("" if not available) + linevar_index = int, -- index of the selected station (stn) in linevar_def.stops of this linevar + }...}, + stop = int, + stops = {{ + stn = string, + name_fs = string, + track_fs = string, + dep = int, + wait = int, + linevar_index = int, -- index of this stop in linevar_def.stops + }...}, + message = string, -- message for label[] on the bottom; "" to disable + } +]] + +local all_stations_record = {stn = "", fs = F("(vyberte dopravnu)"), name_fs = ""} +local is_visible_mode = assert(advtrains.lines.is_visible_mode) + +-- refresh custom_state.stops according to custom_state.linevar +local function jr_refresh_stops(custom_state, stn_to_select) + if stn_to_select == "" then + stn_to_select = nil + end + local linevar_info = custom_state.linevars[custom_state.linevar] + local index_to_select = 0 + local result = {} + if linevar_info ~= nil then + local linevar_def = advtrains.lines.try_get_linevar_def(linevar_info.linevar, linevar_info.stn) + if linevar_def == nil then + -- invalid linevar => no stops + core.log("error", "Player "..custom_state.player_name.." selected invalid linevar "..linevars[linevar].linevar.."!") + else + local stops = linevar_def.stops + for linevar_index, stop_data in ipairs(linevar_def.stops) do + if is_visible_mode(stop_data.mode) then + local r = { + stn = assert(stop_data.stn), + name_fs = F(advtrains.lines.get_station_name(stop_data.stn)), + track_fs = stop_data.track or "", + dep = stop_data.dep, + wait = stop_data.wait or 10, + linevar_index = linevar_index, + } + if r.track_fs ~= "" then + r.track_fs = F("["..r.track_fs.."]") + end + table.insert(result, r) + if stn_to_select ~= nil and index_to_select == 0 and r.stn == stn_to_select then + index_to_select = #result -- stop selected + end + end + end + end + end + if index_to_select == 0 and result[1] ~= nil then + index_to_select = 1 + end + custom_state.stop = index_to_select + custom_state.stops = result + custom_state.message = "" +end + +local function get_all_linevars() + local result = {} + local empty_table = {} + local trains_by_linevar = advtrains.lines.get_trains_by_linevar() + for stn, stdata in pairs(advtrains.lines.stations) do + for linevar, linevar_def in pairs(stdata.linevars or empty_table) do + local line, stn = advtrains.lines.linevar_decompose(linevar) + local target_fs = F(advtrains.lines.get_line_description(linevar_def, {line_number = false, last_stop = true, last_stop_prefix = "", + last_stop_uppercase = false, train_name = false})) + local status_fs + if trains_by_linevar[linevar] ~= nil then + status_fs = "#00ff00,v provozu" + else + status_fs = "#999999,neznámý" + end + table.insert(result, { + stn = stn, + linevar = linevar, + line_fs = F(line), + target_fs = target_fs, + track_fs = "", + status_fs = status_fs, + train_name_fs = F(linevar_def.train_name or ""), + linevar_index = 1, + }) + end + end + table.sort(result, function(a, b) return a.linevar < b.linevar end) + return result +end + +--[[ + stn_filter = string, + track_filter = string or nil, +]] +local function get_linevars_by_filter(stn_filter, track_filter) + local result = {} + local empty_table = {} + local line_description_options = {line_number = false, last_stop = true, last_stop_prefix = "", last_stop_uppercase = false, train_name = false} + local trains_by_linevar = advtrains.lines.get_trains_by_linevar() + assert(stn_filter) + if track_filter == "" then + track_filter = nil + end + for stn, stdata in pairs(advtrains.lines.stations) do + for linevar, linevar_def in pairs(stdata.linevars or empty_table) do + local last_stop_index = advtrains.lines.get_last_stop(linevar_def, false) + if last_stop_index ~= nil then + for linevar_index = 1, last_stop_index - 1 do -- NOTE: the last visible station is intentionally ignored here! + local stop_data = linevar_def.stops[linevar_index] + local initialized = false + local line, stn, line_fs, target_fs, status_fs + if + stop_data.stn == stn_filter and + is_visible_mode(stop_data.mode) and + (track_filter == nil or track_filter == stop_data.track) + then + if not initialized then + initialized = true + line, stn = advtrains.lines.linevar_decompose(linevar) + line_fs = F(line) + target_fs = F(advtrains.lines.get_line_description(linevar_def, line_description_options)) + if trains_by_linevar[linevar] ~= nil then + status_fs = "#00ff00,v provozu" + else + status_fs = "#999999,neznámý" + end + end + local track_fs = stop_data.track + if track_fs == nil or track_fs == "" then + track_fs = "" + else + track_fs = F("["..track_fs.."]") + end + table.insert(result, { + stn = stn, + linevar = linevar, + line_fs = line_fs, + target_fs = target_fs, + track_fs = track_fs, + status_fs = status_fs, + train_name_fs = F(linevar_def.train_name or ""), + linevar_index = assert(linevar_index), + }) + end + end + end + end + end + table.sort(result, function(a, b) + if a.linevar ~= b.linevar then + return a.linevar < b.linevar + else + return a.linevar_index < b.linevar_index + end + end) + return result +end + +local function is_jr_node_name(name) + return core.get_item_group(name, "ch_jrad") ~= 0 +end + +-- refresh custom_state.linevars according to custom_state.stn and custom_state.track +local function jr_refresh_linevars(custom_state, linevar_to_select, linevar_index_to_select) + if linevar_to_select == "" then + linevar_to_select = nil + end + assert(linevar_index_to_select == nil or type(linevar_index_to_select) == "number") + local stn = assert(custom_state.stn) + local stn_info = assert(custom_state.stns[stn]) + local track = assert(custom_state.track) + local tracks = assert(custom_state.tracks) + + local new_linevars + if stn_info.stn == "" then + new_linevars = get_all_linevars() + else + new_linevars = get_linevars_by_filter(stn_info.stn, assert(tracks[track])) + end + local index_to_select = 1 + if linevar_to_select ~= nil then + for i, r in ipairs(new_linevars) do + if r.linevar == linevar_to_select and (linevar_index_to_select == nil or r.linevar_index == linevar_index_to_select) then + index_to_select = i + break + end + end + end + if new_linevars[index_to_select] == nil then + index_to_select = 0 + end + custom_state.linevars = new_linevars + custom_state.linevar = index_to_select + custom_state.message = "" + + local pos = custom_state.pos + if pos ~= nil and is_jr_node_name(core.get_node(pos).name) then + local meta = core.get_meta(pos) + meta:set_string("stn", custom_state.stns[custom_state.stn].stn) + meta:set_string("track", custom_state.tracks[custom_state.track]) + local infotext = {"jízdní řád\n"} + if stn_info.stn == "" then + table.insert(infotext, "<všechny linky>") + else + table.insert(infotext, advtrains.lines.get_station_name(stn_info.stn)) + if custom_state.tracks[custom_state.track] ~= "" then + table.insert(infotext, " ["..custom_state.tracks[custom_state.track].."]") + end + end + if new_linevars[1] ~= nil then + local prefix = "\n" + local set = {[""] = true} + for _, linevar_info in ipairs(new_linevars) do + local line = advtrains.lines.linevar_decompose(linevar_info.linevar) + if not set[line] then + set[line] = true + table.insert(infotext, prefix.."["..line.."]") + prefix = " " + end + end + end + meta:set_string("infotext", table.concat(infotext)) + end +end + +-- refresh custom_state.tracks according to custom_state.stn +-- and selects a specified track, if available +local function jr_refresh_tracks(custom_state, track_to_select) + if track_to_select == "" then + track_to_select = nil + end + local result = {""} + local index_to_select = 1 + local current_stn = custom_state.stns[custom_state.stn].stn + if current_stn ~= "" and advtrains.lines.stations[current_stn] ~= nil then + local track_set = {[""] = true} + -- search for tracks: + for epos, stdata in pairs(advtrains.lines.stops) do + if stdata.stn == current_stn and stdata.track ~= nil and not track_set[stdata.track] then + track_set[stdata.track] = true + table.insert(result, tostring(stdata.track)) + end + end + if #result > 1 then + table.sort(result) + assert(result[1] == "") + if track_to_select ~= nil then + for i, track in ipairs(result) do + if track_to_select == track then + index_to_select = i + end + end + end + end + end + custom_state.tracks = result + custom_state.track = index_to_select + custom_state.message = "" +end + +--[[ + -- will refresh custom_state.stns[] and (optionally) select a wanted station if it's on the list, + -- otherwise the default 'select station' option will be chosen + custom_state = table, + stn_to_select = string or nil, +]] +local function jr_refresh_stns(custom_state, stn_to_select) + if stn_to_select == "" then + stn_to_select = nil + end + local result = {all_stations_record} + local index_to_select = 1 + for i, st in ipairs(load_stations()) do + result[1 + i] = { + stn = assert(st.stn), + fs = F(st.stn.." | "..st.name), + name_fs = F(st.name), + } + if stn_to_select ~= nil and st.stn == stn_to_select then + index_to_select = 1 + i + end + end + custom_state.stns = result + custom_state.stn = index_to_select + custom_state.message = "" +end + +-- will refresh a departure message according to linevar + stop +local function jr_refresh_departure(custom_state) + local linevar_info = custom_state.linevars[custom_state.linevar] + local stop_info = custom_state.stops[custom_state.stop] + if linevar_info == nil or stop_info == nil then + custom_state.message = "" + return + end + local linevar_def = advtrains.lines.try_get_linevar_def(linevar_info.linevar) + if linevar_def == nil then + custom_state.message = "" + return + end + local rwtime = rwt.to_secs(rwt.get_time()) + local prediction = advtrains.lines.predict_station_departures(linevar_def, assert(stop_info.linevar_index), rwtime) + if #prediction == 0 then + custom_state.message = "v nejbližší době nenalezeny žádné odjezdy zvolené linky" + return + end + local deps = {} + for i, pred in ipairs(prediction) do + deps[i] = tostring(pred.dep - rwtime) + end + custom_state.message = "nejbližší odjezdy zvolené linky za: "..table.concat(deps, ", ").." s" +end + +local function get_jr_formspec(custom_state) + local formspec = { + ch_core.formspec_header({ + formspec_version = 6, + size = {20, 12}, + auto_background = true, + }) + } + local access_level = "player" -- player | owner | admin + local node_owner + if custom_state.pos ~= nil then + node_owner = core.get_meta(custom_state.pos):get_string("owner") + if node_owner == "" then + node_owner = nil + end + end + local stn, stn_owner + if custom_state.stn > 1 and custom_state.stns[custom_state.stn] ~= nil then + stn_owner = (advtrains.lines.stations[custom_state.stns[custom_state.stn].stn] or {}).owner -- may be nil + end + + if not custom_state.force_unprivileged then + if ch_core.get_player_role(custom_state.player_name) == "admin" then + access_level = "admin" + elseif custom_state.player_name == node_owner or custom_state.player_name == stn_owner then + access_level = "owner" + end + end + + if node_owner ~= nil then + if access_level ~= "player" then + -- admin or owner: + table.insert(formspec, "label[0.5,0.6;Jízdní řády]".. + "dropdown[5,0.3;10,0.6;dopravna;") + for i, r in ipairs(custom_state.stns) do + table.insert(formspec, ifthenelse(i == 1, r.fs, ","..r.fs)) + end + table.insert(formspec, ";"..custom_state.stn..";true]".. + "dropdown[15.25,0.3;3.5,0.6;kolej;") + for i, r in ipairs(custom_state.tracks) do + if i == 1 then + table.insert(formspec, "(všechny koleje)") + else + table.insert(formspec, ","..F(r)) + end + end + table.insert(formspec, ";"..custom_state.track..";true]") + else + -- player (including 'new' players) + local stn_info = custom_state.stns[custom_state.stn] + if stn_info.stn == "" then + table.insert(formspec, "label[0.5,0.6;Jízdní řády (všechny linky)]") + else + local track = custom_state.tracks[custom_state.track] + if track ~= "" then + track = F(" ["..track.."]") + end + table.insert(formspec, "label[0.5,0.6;"..F("Jízdní řády: ")..stn_info.name_fs..track.."]") + end + end + if access_level ~= "admin" then + -- player/owner + table.insert(formspec, "label[0.5,1.65;vlastník/ice j. řádu: ") + table.insert(formspec, ch_core.prihlasovaci_na_zobrazovaci(node_owner)) + if stn_owner ~= nil then + table.insert(formspec, " | dopravnu spravuje: ") + table.insert(formspec, ch_core.prihlasovaci_na_zobrazovaci(stn_owner)) + end + table.insert(formspec, "]") + else + -- admin only + table.insert(formspec, "label[0.5,1.65;vlastník/ice:]".. + "field[2.75,1.25;5,0.75;owner;;") + table.insert(formspec, ch_core.prihlasovaci_na_zobrazovaci(node_owner)) + table.insert(formspec, "]button[8,1.25;3,0.75;setowner;nastavit]") + if stn_owner ~= nil then + table.insert(formspec, "label[11.25,1.65;dopravnu spravuje: "..ch_core.prihlasovaci_na_zobrazovaci(stn_owner).."]") + end + end + else + table.insert(formspec, "label[0.5,0.6;Příruční jízdní řády (všechny linky)]") + end + + table.insert(formspec, "tablecolumns[text,align=right,tooltip=linka;text,width=12,tooltip=cíl;text,tooltip=kolej;color,span=1;text,tooltip=stav;color,span=1;text,tooltip=jméno vlaku]".. + "table[0.5,2.25;11,5;linka;") + for i, r in ipairs(custom_state.linevars) do + if i > 1 then + table.insert(formspec, ",") + end + table.insert(formspec, r.line_fs..","..r.target_fs..","..r.track_fs..","..r.status_fs..",#cccccc,"..r.train_name_fs) + end + table.insert(formspec, ifthenelse(custom_state.linevar > 0, ";"..custom_state.linevar.."]", ";]")) + table.insert(formspec, "tablecolumns[text,align=right;text;text]".. + "table[12.5,2.25;7,8.75;zastavka;") + if custom_state.stops[1] ~= nil then + local selected_stop_index = custom_state.stop + if custom_state.stops[selected_stop_index] == nil then + selected_stop_index = 1 + end + local base_dep + for i, r in ipairs(custom_state.stops) do + if i > 1 then + table.insert(formspec, ",") + end + if i >= selected_stop_index then + if i == selected_stop_index then + base_dep = assert(r.dep) + table.insert(formspec, "0,") + else + table.insert(formspec, (r.dep - base_dep)..",") + end + else + table.insert(formspec, " ,") + end + table.insert(formspec, r.name_fs..","..r.track_fs) + end + table.insert(formspec, ";"..selected_stop_index.."]") + else + table.insert(formspec, ";]") -- empty list + end + table.insert(formspec, "button_exit[18.75,0.3;0.75,0.75;close;X]") + if custom_state.message ~= "" then + table.insert(formspec, "label[5.25,11.35;"..F(custom_state.message).."]") + end + table.insert(formspec, "button[0.5,11;4.5,0.75;refresh;zjistit nejbližší odjezdy...]") + return table.concat(formspec) +end + +local function jr_formspec_callback(custom_state, player, formname, fields) + if fields.dopravna then + local new_stn = tonumber(fields.dopravna) + if new_stn ~= nil and new_stn ~= custom_state.stn and custom_state.stns[new_stn] ~= nil then + custom_state.stn = new_stn + local current_track = custom_state.tracks[custom_state.track] or "" + local current_linevar_info = custom_state.linevars[custom_state.linevar] + jr_refresh_tracks(custom_state, current_track) + if current_linevar_info ~= nil then + jr_refresh_linevars(custom_state, current_linevar_info.linevar, current_linevar_info.linevar_index) + else + jr_refresh_linevars(custom_state) + end + jr_refresh_stops(custom_state, custom_state.stns[new_stn].stn) + jr_refresh_departure(custom_state) + return get_jr_formspec(custom_state) + end + end + if fields.kolej then + local new_track = tonumber(fields.kolej) + if new_track ~= nil and new_track ~= custom_state.track and custom_state.tracks[new_track] ~= nil then + custom_state.track = new_track + local current_linevar_info = custom_state.linevars[custom_state.linevar] + if current_linevar_info ~= nil then + jr_refresh_linevars(custom_state, current_linevar_info.linevar, current_linevar_info.linevar_index) + else + jr_refresh_linevars(custom_state) + end + jr_refresh_stops(custom_state, custom_state.stns[custom_state.stn].stn) + jr_refresh_departure(custom_state) + return get_jr_formspec(custom_state) + end + end + if fields.setowner and custom_state.pos ~= nil and is_jr_node_name(core.get_node(custom_state.pos).name) then + local meta = core.get_meta(custom_state.pos) + local jm = ch_core.jmeno_na_existujici_prihlasovaci(fields.owner) + if jm ~= nil then + meta:set_string("owner", jm) + else + core.chat_send_player(custom_state.player_name, "*** Postava '"..fields.owner.."' neexistuje!") + end + return get_jr_formspec(custom_state) + end + if fields.linka then + local event = core.explode_table_event(fields.linka) + local new_line + if event.type == "CHG" or event.type == "DCL" then + new_line = tonumber(event.row) + end + if new_line ~= nil and new_line ~= custom_state.linevar then + local new_linevar_info = custom_state.linevars[new_line] + if new_linevar_info ~= nil then + jr_refresh_linevars(custom_state, new_linevar_info.linevar, new_linevar_info.linevar_index) + else + jr_refresh_linevars(custom_state) + end + jr_refresh_stops(custom_state, custom_state.stns[custom_state.stn].stn) + jr_refresh_departure(custom_state) + return get_jr_formspec(custom_state) + end + end + if fields.zastavka then + local event = core.explode_table_event(fields.zastavka) + if event.type == "CHG" or event.type == "DCL" then + local new_stop = tonumber(event.row) + if new_stop ~= nil and new_stop ~= custom_state.stop and custom_state.stops[new_stop] ~= nil then + custom_state.stop = new_stop + if event.type == "DCL" then + jr_refresh_departure(custom_state) + end + return get_jr_formspec(custom_state) + end + end + end + if fields.refresh then + jr_refresh_departure(custom_state) + return get_jr_formspec(custom_state) + end +end + +function advtrains.lines.show_jr_formspec(player, pos, stn, track, linevar, stop_stn, force_unprivileged) + assert(core.is_player(player)) + local custom_state = { + player_name = player:get_player_name(), + stn = 1, + stns = {all_stations_record}, + track = 1, + tracks = {""}, + linevar = 0, + linevars = {}, + stop = 0, + stops = {}, + message = "", + force_unprivileged = force_unprivileged, + } + if pos ~= nil then + custom_state.pos = pos + end + jr_refresh_stns(custom_state, stn) + jr_refresh_tracks(custom_state, track) + jr_refresh_linevars(custom_state, linevar) + if stop_stn == nil then + stop_stn = custom_state.stns[custom_state.stn].stn + end + jr_refresh_stops(custom_state, stop_stn) + jr_refresh_departure(custom_state) + + -- show formspec: + return ch_core.show_formspec(player, "advtrains_line_automation:jizdni_rad", + get_jr_formspec(custom_state), jr_formspec_callback, custom_state, {}) +end |