local def local F = minetest.formspec_escape local ch_core = advtrains.lines.ch_core local S = advtrains.lines.translate --[[ Jednoduchá funkce, která vyhodnotí condition jako podmínku a podle výsledku vrátí buď true_result, nebo false_result. ]] local function ifthenelse(condition, true_result, false_result) if condition then return true_result else return false_result end end -- Singularis-Merge: Emulate certain ch functionality local function prihlasovaci_na_zobrazovaci(prihlasovaci) return prihlasovaci -- no-op. On CH used to colorize the name to reflect the rank of the player end local max_stations = 60 local MODE_NORMAL = 0 -- normální zastávka (výchozí nebo mezilehlá) local MODE_REQUEST_STOP = 1 -- zastávka na znamení (mezilehlá) local MODE_HIDDEN = 2 -- skrytá zastávka (výchozí nebo mezilehlá) local MODE_DISABLED = 3 -- vypnutá zastávka (mezilehlá nebo koncová) local MODE_FINAL = 4 -- koncová zastávka (linka zde jízdu končí) local MODE_FINAL_HIDDEN = 5 -- koncová zastávka skrytá local MODE_FINAL_CONTINUE = 6 -- koncová zastávka (vlak pokračuje jako jiná linka) local color_red = core.get_color_escape_sequence("#ff0000") local color_green = core.get_color_escape_sequence("#00ff00") local cancel_linevar = assert(advtrains.lines.cancel_linevar) local get_last_passages = assert(advtrains.lines.get_last_passages) local get_line_description = assert(advtrains.lines.get_line_description) local linevar_decompose = assert(advtrains.lines.linevar_decompose) local try_get_linevar_def = assert(advtrains.lines.try_get_linevar_def) local show_last_passages_formspec -- forward declaration local function check_rights(pinfo, owner) if pinfo.role == "new" or pinfo.role == "none" then return false end if owner == nil or pinfo.role == "admin" or pinfo.player_name == owner then return true end return false end local function get_stn_from_linevar(linevar) local line, stn = linevar_decompose(linevar) return ifthenelse(line ~= nil, stn, nil) end local function add_linevar(stn, linevar_def) local station = advtrains.lines.stations[stn] if station == nil then return false, "Chybná stanice!" end local linevars = station.linevars if linevars == nil then linevars = {} station.linevars = linevars end if linevars[linevar_def.name] ~= nil then return false, "Nemohu přidat, varianta linky '"..linevar_def.name.."' již existuje." end linevars[linevar_def.name] = linevar_def return true, nil end local function same_stops(stops1, stops2) assert(stops1) assert(stops2) if #stops1 ~= #stops2 then return false end for i, stop in ipairs(stops1) do if stop.stn ~= stops2[i].stn then return false end end return true end local function replace_linevar(stn, linevar_def) local station = advtrains.lines.stations[stn] if station == nil or station.linevars == nil then return false, S("No such station") end local linevar = assert(linevar_def.name) local linevars = station.linevars local old_linevar_def = linevars[linevar] if old_linevar_def == nil then return false, S("Cannot replace, because lineval @1 does not yet exist", linevar) end linevars[linevar] = linevar_def local restart_count = 0 if not same_stops(old_linevar_def.stops, linevar_def.stops) then -- změnily se zastávky, musíme restartovat vlaky: for train_id, train in pairs(advtrains.trains) do local ls = train.line_status if ls ~= nil and ls.linevar == linevar then core.log("action", "Train "..train_id.." restarted from index "..ls.linevar_index.." due to replacement of linevar '"..linevar.."'.") ls.linevar_index = 1 restart_count = restart_count + 1 end end end if restart_count > 0 then return true, S("@1 trains restarted due to changes", restart_count) else return true, nil end end local function delete_linevar(stn, linevar) local station = advtrains.lines.stations[stn] if station == nil or station.linevars == nil then return false, S("No such station") end local linevars = station.linevars if linevars[assert(linevar)] == nil then return false, S("Cannot delete, because lineval @1 does not yet exist", linevar) end linevars[linevar] = nil for train_id, train in pairs(advtrains.trains) do local ls = train.line_status if ls ~= nil and ls.linevar == linevar then core.log("action", "Train "..train_id.." removed from deleted linevar '"..linevar.."'.") cancel_linevar(train) end end return true, nil end 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 selection_index_raw = custom_state.selection_index local selection_index = selection_index_raw or 1 local formspec = { ch_core.formspec_header({formspec_version = 6, size = {20, 16}, auto_background = true}), "label[0.5,0.6;"..S("Line Editor").."]".. "style[s01_pos", } for i = 2, max_stations do table.insert(formspec, string.format(",s%02d_pos", i)) end table.insert(formspec, ";font=mono;font_size=-4]".. "style[rc;font=mono]".. "tablecolumns[color;text,align=right;text;text,align=center;color;text,width=7;color;text]".. "table[0.5,1.25;19,5;linevar;#ffffff,"..S("LINE,ROUTE,VAR.")..",#ffffff,"..S("OWNER")..",#ffffff,STATUS") for _, linevar_def in ipairs(custom_state.linevars) do local lv_line, lv_stn, lv_rc = linevar_decompose(linevar_def.name) local color = ifthenelse(linevar_def.disabled, "#cccccc", "#ffffff") table.insert(formspec, ","..color..","..F(lv_line)..","..F(get_line_description(linevar_def, {first_stop = true, last_stop = true})).. ","..F(lv_rc)..","..ifthenelse(linevar_def.owner == pinfo.player_name, "#00ff00", color)..",") table.insert(formspec, F(prihlasovaci_na_zobrazovaci(linevar_def.owner))) table.insert(formspec, ","..color..",") if linevar_def.disabled then table.insert(formspec, "vypnutá") end end if selection_index_raw ~= nil then table.insert(formspec, ";"..selection_index.."]") else table.insert(formspec, ";]") end if pinfo.role ~= "new" then table.insert(formspec, "button[14.5,0.3;3.5,0.75;create;"..S("New Line...").."]") end local has_rights_to_open_variant = pinfo.role == "admin" or selection_index == 1 or pinfo.player_name == custom_state.linevars[selection_index - 1].owner if selection_index > 1 and has_rights_to_open_variant then table.insert(formspec, "button[10.5,0.3;3.5,0.75;delete;"..S("Delete Line").."]") end table.insert(formspec, "button_exit[18.75,0.3;0.75,0.75;close;X]".. "field[0.5,7;1.25,0.75;line;"..S("Line:")..";"..F(custom_state.line).."]".. "field[2,7;1.5,0.75;rc;"..S("Variant:")..";"..F(custom_state.rc).."]".. "field[3.75,7;3,0.75;train_name;"..S("Dest. Display:")..";"..F(custom_state.train_name).."]") if pinfo.role ~= "admin" then table.insert(formspec, "label[7,6.75;"..S("Owner:").."\n") else table.insert(formspec, "field[7,7;4,0.75;owner;"..S("Owner:")..";") end table.insert(formspec, F(custom_state.owner).."]".. "checkbox[11.25,7.25;disable_linevar;"..S("Disable")..";"..custom_state.disable_linevar.."]".. "field[13.5,7;3,0.75;continues;"..S("Continues:")..";"..F(custom_state.continues).."]") if custom_state.message ~= "" then table.insert(formspec, "label[0.5,8.25;"..F(custom_state.message).."]") end if selection_index > 1 then table.insert(formspec, "button[5,15;4.5,0.75;last_passages;"..S("Last passages").."]".. "tooltip[last_passages;Zobrazí přehled časů několika posledních jízd na dané variantě linky.]") end if has_rights_to_open_variant then table.insert(formspec, "button[10,15;4.5,0.75;save;".. ifthenelse(custom_state.compiled_linevar == nil, S("Verify/Save").."]", S("Save changes").."]")) end table.insert(formspec, "button[15,15.25;4,0.5;reset;"..S("Reset changes").."]") table.insert(formspec, "tooltip[line;".. S("Line designation. Must not be empty. This identifies a certain line.").."]".. "tooltip[rc;"..S("Line variant code. Optional, can be used to identify different variants of a line (e.g. branches).").."]".. "tooltip[train_name;"..S("Optional field, name of the line as used in departure displays and on timetables.").."]".. "tooltip[disable_linevar;"..S("Check to disable the timetable.\nA disabled timetable will not be used for new trains, trains already on the line will finish it.").."]") table.insert(formspec, "container[0,8.75]".. "label[0.5,0.25;"..S("Dep.").."]".. "label[2,0.25;"..S("St.Time").."]".. "label[3.5,0.25;"..S("Station Code").."]".. "label[6.25,0.25;"..S("Mode").."]".. "label[11,0.25;"..S("Track").."]".. "label[12.5,0.25;"..S("Position").."]".. "scrollbaroptions[min=0;max=550;arrows=show]".. "scrollbar[19,0.5;0.5,5.5;vertical;evl_scroll;"..custom_state.evl_scroll.."]".. "scroll_container[0.5,0.5;18.5,5.5;evl_scroll;vertical]".. "box[0,0;20,70;#00808040]") -- box[] = pozadí -- výchozí zastávka: table.insert(formspec, "label[0.1,0.4;0]".. "field[1.5,0;1.25,0.75;s01_wait;;"..F(custom_state.stops[1].wait).."]".. "field[3,0;2.5,0.75;s01_stn;;"..F(custom_state.stops[1].stn).."]".. "dropdown[5.75,0;4.5,0.75;s01_mode;"..S("Normal")..","..S("Hidden (normal)")..";"..custom_state.stops[1].mode..";true]".. "field[10.5,0;1.25,0.75;s01_track;;"..F(custom_state.stops[1].track).."]".. "field[12,0;3,0.75;s01_pos;;"..F(custom_state.stops[1].pos).."]".. "label[15.25,0.4;"..F(custom_state.stops[1].label).."]") -- ostatní zastávky: local y_base, y_scale = 0, 1 for i = 2, max_stations do local stop = custom_state.stops[i] local n if i < 10 then n = "0"..i else n = tostring(i) end local y = string.format("%f", y_base + (i - 1) * y_scale) local y2 = string.format("%f", y_base + (i - 1) * y_scale + 0.4) -- for a label table.insert(formspec, "field[0,"..y..";1.25,0.75;s"..n.."_dep;;"..F(stop.dep).."]".. "field[1.5,"..y..";1.25,0.75;s"..n.."_wait;;"..F(stop.wait).."]".. "field[3,"..y..";2.5,0.75;s"..n.."_stn;;"..F(stop.stn).."]".. "dropdown[5.75,"..y..";4.5,0.75;s"..n.. "_mode;"..S("Normal")..","..S("Request Stop (experimental)")..","..S("Hidden")..","..S("Inactive")..","..S("Terminus")..","..S("Terminus (hidden)")..",".. S("Terminus (continuing)")..";"..stop.mode..";true]".. "field[10.5,"..y..";1.25,0.75;s"..n.."_track;;"..F(stop.track).."]".. "field[12,"..y..";3,0.75;s"..n.."_pos;;"..F(stop.pos).."]".. "label[15.25,"..y2..";"..F(stop.label).."]") end table.insert(formspec, "scroll_container_end[]".. "tooltip[0,0;1.5,1;"..S("Departure: Time (in seconds) after the start of the timetable at which the train departs from this station.\nIt is used to calculate delays. Stations on the line are sorted by their departure time.\nSet this field empty to delete a station from the timetable.").."]".. "tooltip[1.5,0;1.5,1;"..S("Stop time: Minimum time (in seconds) for which the train stops at the station before departing.").."]".. "tooltip[3.5,0;2.75,1;"..S("Station code: The code of the station to stop/pass.").."]".. "tooltip[6.25,0;4.75,1;"..S("Stop mode:\nNormal - Train stops and departs after the stop time\nRequest stop - Train stops when the 'stop request' button is pressed\nHidden - like Normal, but is not shown in passenger timetable\nInactive - passes without stopping\nTerminus - Train stops and ends the timetable operation\nTerminus (hidden) - like Terminus, but will not appear in the passenger timetable\nTerminus (continuing) - Train will continue as timetable configured in the stop rail at the terminus location").."]".. "container_end[]") -- if pinfo.role ~= "new" then return table.concat(formspec) end local mode_from_formspec_map = {MODE_NORMAL, MODE_REQUEST_STOP, MODE_HIDDEN, MODE_DISABLED, MODE_FINAL, MODE_FINAL_HIDDEN, MODE_FINAL_CONTINUE} local mode_to_formspec_map = table.key_value_swap(mode_from_formspec_map) local function mode_to_formspec(i, raw_mode) if i == 1 then return ifthenelse(raw_mode ~= nil and raw_mode == MODE_HIDDEN, 2, 1) elseif raw_mode == nil then return 1 else return mode_to_formspec_map[raw_mode] or 1 end end local function mode_from_formspec(i, fs_mode) if i == 1 then return ifthenelse(fs_mode == 2, MODE_HIDDEN, nil) else local result = mode_from_formspec_map[fs_mode] return ifthenelse(result ~= nil and result ~= MODE_NORMAL, result, nil) end end local function custom_state_set_selection_index(custom_state, new_selection_index) -- this will also refresh stops and resets the changes assert(custom_state.player_name) assert(custom_state.linevars) assert(new_selection_index) local current_linevar = custom_state.linevars[new_selection_index - 1] custom_state.selection_index = new_selection_index or 1 local stops = custom_state.stops if stops == nil then stops = {} custom_state.stops = stops end local linevar_stops if current_linevar ~= nil then linevar_stops = current_linevar.stops else linevar_stops = {} end for i = 1, max_stations do local stop = linevar_stops[i] if stop ~= nil then stops[i] = { dep = tostring(assert(stop.dep)), wait = tostring(stop.wait or 10), stn = assert(stop.stn), mode = mode_to_formspec(i, stop.mode), track = stop.track or "", pos = stop.pos or "", label = "", } else stops[i] = { dep = ifthenelse(i == 1, "0", ""), wait = "10", stn = "", mode = 1, track = "", pos = "", label = "", } end end if current_linevar ~= nil then local lv_line, lv_stn, lv_rc = linevar_decompose(current_linevar.name) custom_state.line = lv_line or "" custom_state.rc = lv_rc or "" custom_state.train_name = current_linevar.train_name or "" custom_state.owner = assert(current_linevar.owner) custom_state.disable_linevar = ifthenelse(current_linevar.disabled, "true", "false") custom_state.continues = current_linevar.continue_line or "" if custom_state.continues ~= "" then custom_state.continues = custom_state.continues.."/"..(current_linevar.continue_rc or "") end else custom_state.line = "" custom_state.rc = "" custom_state.train_name = "" custom_state.owner = custom_state.player_name custom_state.disable_linevar = "false" custom_state.continues = "" end custom_state.owner = prihlasovaci_na_zobrazovaci(custom_state.owner) custom_state.compiled_linevar = nil custom_state.evl_scroll = 0 custom_state.message = "" end local function num_transform(s) local prefix = s:match("^([0-9]+)/") if prefix == nil then return s end return string.format(" %020d%s", tonumber(prefix) or 0, s:sub(#prefix, -1)) end local function linevars_sorter(a, b) return num_transform(a.name) < num_transform(b.name) end local function custom_state_refresh_linevars(custom_state, linevar_to_select) assert(custom_state.player_name) local linevars = {} for _, stdata in pairs(advtrains.lines.stations) do if stdata.linevars ~= nil then for _, linevar_def in pairs(stdata.linevars) do table.insert(linevars, linevar_def) end end end table.sort(linevars, linevars_sorter) custom_state.selection_index = nil custom_state.linevars = linevars custom_state.compiled_linevar = nil if linevar_to_select ~= nil then for i, linevar_def in ipairs(linevars) do if linevar_def.name == linevar_to_select then custom_state_set_selection_index(custom_state, i + 1) return true end end return false end end local function custom_state_compile_linevar(custom_state) local stations = advtrains.lines.stations local line = assert(custom_state.line) local stn = assert(custom_state.stops[1].stn) local rc = assert(custom_state.rc) local train_name = assert(custom_state.train_name) local owner = assert(custom_state.owner) local stops = {} if line == "" then return false, S("Line name must not be empty!") elseif line:find("[/|\\]") then return false, S("Line name must not contain characters '/', '|' or '\\'!") elseif line:len() > 256 then return false, S("Line name must not exceed 256 characters!") elseif stn == "" then return false, S("Starting station code must not be empty!") elseif rc:find("[/|\\]") then return false, S("Routing code must not contain '/', '|' or '\\'!") elseif owner == "" then return false, S("Line owner must not be empty!") elseif train_name:len() > 256 then return false, S("Train name must not exceed 256 characters!") elseif custom_state.continues:len() - custom_state.continues:gsub("/", ""):len() > 1 then return false, S("Field 'Continuation' must contain maximum 1 '/'!") end -- Zkontrolovat zastávky: local errcount = 0 local finalcount = 0 local dep_to_index = {} for i, stop in ipairs(assert(custom_state.stops)) do local good_label stop.label = "" if stop.dep == "" then -- přeskočit elseif not stop.dep:match("^[0-9][0-9]*$") then errcount = errcount + 1 stop.label = color_red..S("Incorrect departure time format!") elseif tonumber(stop.dep) < 0 or tonumber(stop.dep) > 3600 then errcount = errcount + 1 stop.label = color_red..S("Departure time must lie within 0-3600 seconds!") elseif dep_to_index[tonumber(stop.dep)] ~= nil then errcount = errcount + 1 stop.label = color_red..S("Duplicate departure time!") else dep_to_index[tonumber(stop.dep)] = i if stop.stn == "" or stations[stop.stn] == nil or stations[stop.stn].name == nil then errcount = errcount + 1 stop.label = color_red..S("Unknown station code!") elseif stop.stn:find("[/|\\]") then errcount = errcount + 1 stop.label = color_red..S("Station code must not contain '/', '|' or '\\'!") elseif stop.track:len() > 16 then errcount = errcount + 1 stop.label = color_red..S("Line name must not exceed 16 characters!") elseif stop.pos ~= "" and not stop.pos:match("^[-0-9][0-9]*,[-0-9][0-9]*,[-0-9][0-9]*$") then errcount = errcount + 1 stop.label = color_red..S("Incorrect format for stop position!") elseif stop.pos:len() > 22 then errcount = errcount + 1 stop.label = color_red..S("Stop position must not exceed 22 characters!") else -- v pořádku: local new_stop = { stn = stop.stn, dep = tonumber(stop.dep), } local new_mode = mode_from_formspec(i, stop.mode) if new_mode ~= nil then new_stop.mode = new_mode if i > 1 and (new_mode == MODE_FINAL or new_mode == MODE_FINAL_CONTINUE or new_mode == MODE_FINAL_HIDDEN) then finalcount = finalcount + 1 end end if stop.pos ~= "" then new_stop.pos = stop.pos end if stop.track ~= "" then new_stop.track = stop.track end local new_wait = tonumber(stop.wait) if new_wait ~= nil and new_wait == math.floor(new_wait) and new_wait >= 0 and new_wait <= 3600 then new_stop.wait = new_wait end table.insert(stops, new_stop) if stop.stn ~= "" then stop.label = color_green.."= "..assert(stations[stop.stn].name) end end end end if errcount > 0 then return false, S("@1 errors while checking line setup!", errcount) end if finalcount == 0 then return false, S("Line setup must contain at least 1 terminus stop!") end table.sort(stops, function(a, b) return a.dep < b.dep end) local index_vychozi, index_cil for i, stop in ipairs(stops) do local mode = stop.mode or MODE_NORMAL if mode ~= MODE_DISABLED and mode ~= MODE_HIDDEN and mode ~= MODE_FINAL_HIDDEN then if index_vychozi == nil then index_vychozi = i end index_cil = i end if mode == MODE_FINAL or mode == MODE_FINAL_CONTINUE or mode == MODE_FINAL_HIDDEN then break end end custom_state.compiled_linevar = { name = line.."/"..stops[1].stn.."/"..rc, owner = owner, -- ch_core.jmeno_na_prihlasovaci(owner), stops = stops, continue_line = "", continue_rc = "", index_vychozi = index_vychozi, index_cil = index_cil, } if train_name ~= "" then custom_state.compiled_linevar.train_name = train_name end if custom_state.disable_linevar == "true" then custom_state.compiled_linevar.disabled = true end local continues_split = custom_state.continues:find("/") if continues_split == nil then custom_state.compiled_linevar.continue_line = custom_state.continues else custom_state.compiled_linevar.continue_line = custom_state.continues:sub(1, continues_split - 1) custom_state.compiled_linevar.continue_rc = custom_state.continues:sub(continues_split + 1, -1) end return true, nil end local function formspec_callback(custom_state, player, formname, fields) local reload_stations, update_formspec = false, false -- print("DEBUG: "..dump2({custom_state = custom_state, formname = formname, fields = fields})) if fields.quit then return end -- scrollbar: if fields.evl_scroll then local event = core.explode_scrollbar_event(fields.evl_scroll) if event.type == "CHG" then custom_state.evl_scroll = event.value end end -- checkbox: if fields.disable_linevar then custom_state.disable_linevar = fields.disable_linevar end -- dropdowns: for i = 1, max_stations do local id = string.format("s%02d_mode", i) local n = tonumber(fields[id]) if n ~= nil then custom_state.stops[i].mode = n end end -- fields: for _, key in ipairs({"line", "rc", "train_name", "owner", "continues"}) do if fields[key] then custom_state[key] = fields[key] end end for i, stop in ipairs(custom_state.stops) do local prefix = string.format("s%02d_", i) for _, key in ipairs({"dep", "wait", "stn", "track", "pos"}) do local value = fields[prefix..key] if value then stop[key] = value end end end -- selection: if fields.linevar then local event = core.explode_table_event(fields.linevar) if event.type == "CHG" or event.type == "DCL" then custom_state_set_selection_index(custom_state, assert(tonumber(event.row))) update_formspec = true end end -- buttons: if fields.create then custom_state_set_selection_index(custom_state, 1) update_formspec = true elseif fields.reset then custom_state_set_selection_index(custom_state, custom_state.selection_index or 1) update_formspec = true elseif fields.save then local pinfo = ch_core.normalize_player(player) if pinfo.role == "new" or pinfo.role == "none" then core.log("error", "Access violation in line editor caused by '"..pinfo.player_name.."'!") return -- access violation! end if custom_state.compiled_linevar == nil then -- zkontrolovat a skompilovat local success, errmsg = custom_state_compile_linevar(custom_state) if success then -- TODO: zkontrolovat práva a možnost přepsání i zde! custom_state.message = color_green..S("No issues found, the line can now be saved!") else custom_state.message = color_red..S("Error in line setup: ")..(errmsg or S("Unknown reason")) end update_formspec = true else -- pokusit se uložit... custom_state.message = "" local selection_index = custom_state.selection_index or 1 local selected_linevar, selected_linevar_def, selected_linevar_station local to_linevar, to_linevar_def, to_linevar_station local new_linevar, new_linevar_def, new_linevar_station -- NEW: new_linevar_def = custom_state.compiled_linevar new_linevar = new_linevar_def.name new_linevar_station = get_stn_from_linevar(new_linevar) -- SELECTED: if custom_state.selection_index > 1 and custom_state.linevars[selection_index - 1] ~= nil then selected_linevar_def, selected_linevar_station = try_get_linevar_def(custom_state.linevars[selection_index - 1].name) if selected_linevar_def ~= nil then selected_linevar = selected_linevar_def.name end end -- TO OVERWRITE: to_linevar_def, to_linevar_station = try_get_linevar_def(new_linevar) if to_linevar_def ~= nil then to_linevar = to_linevar_def.name end local success, errmsg if selected_linevar == nil then if to_linevar == nil then -- zcela nová varianta core.log("action", "Will add a new linevar '"..new_linevar.."'") success, errmsg = add_linevar(new_linevar_station, new_linevar_def) else -- replace core.log("action", "Will replace an existing linevar '"..new_linevar.."'") success = check_rights(pinfo, to_linevar_def.owner) if success then success, errmsg = replace_linevar(new_linevar_station, new_linevar_def) else errmsg = S("Insufficient permissions to edit '@1'.", to_linevar) end end elseif to_linevar == nil then -- delete and add core.log("action", "Will delete selected linevar '"..selected_linevar.."' and add new linevar '"..new_linevar.."'") success = check_rights(pinfo, selected_linevar_def.owner) if success then success, errmsg = delete_linevar(selected_linevar_station, selected_linevar) if success then success, errmsg = add_linevar(new_linevar_station, new_linevar_def) end else errmsg = S("Insufficient permissions to edit '@1'.", selected_linevar) end elseif selected_linevar ~= to_linevar then -- delete and replace core.log("action", "Will add delete selected linevar '"..selected_linevar.."' and replace existing linevar '"..new_linevar.."'") success = check_rights(pinfo, to_linevar_def.owner) if success then success = check_rights(pinfo, selected_linevar_def.owner) if success then success, errmsg = delete_linevar(selected_linevar_station, selected_linevar) if success then success, errmsg = replace_linevar(new_linevar_station, new_linevar_def) end else errmsg = S("Insufficient permissions to edit '@1'.", selected_linevar) end else errmsg = S("Insufficient permissions to edit '@1'.", to_linevar) end else -- replace core.log("action", "Will replace existing linevar '"..new_linevar.."'") success = check_rights(pinfo, to_linevar_def.owner) if success then success, errmsg = replace_linevar(new_linevar_station, new_linevar_def) else errmsg = S("Insufficient permissions to edit '@1'.", to_linevar) end end if success then custom_state.message = color_green..S("Line '@1' successfully saved!", new_linevar) custom_state_refresh_linevars(custom_state, new_linevar) else custom_state.message = color_red..S("Error in line setup: ")..(errmsg or S("Unknown reason")) end update_formspec = true end elseif fields.delete then local pinfo = ch_core.normalize_player(player) if pinfo.role == "new" or pinfo.role == "none" then core.log("error", "Access violation in line editor caused by '"..pinfo.player_name.."'!") return -- access violation! end local selection_index = custom_state.selection_index or 1 local selected_linevar, selected_linevar_def, selected_linevar_station if selection_index > 1 and custom_state.linevars[selection_index - 1] ~= nil then selected_linevar_def, selected_linevar_station = try_get_linevar_def(custom_state.linevars[selection_index - 1].name) if selected_linevar_def ~= nil then selected_linevar = selected_linevar_def.name end local success, errmsg success = check_rights(pinfo, selected_linevar_def.owner) if success then success, errmsg = delete_linevar(selected_linevar_station, selected_linevar) else errmsg = S("Insufficient permissions to edit '@1'.", selected_linevar) end if success then custom_state.message = S("Line '@1' successfully deleted!", selected_linevar) custom_state_refresh_linevars(custom_state) custom_state_set_selection_index(custom_state, 1) else custom_state.message = S("Deletion failed: ")..(errmsg or S("Unknown reason")) end update_formspec = true end elseif fields.last_passages then local selected_linevar_def = try_get_linevar_def(custom_state.linevars[(custom_state.selection_index or 1) - 1].name) if selected_linevar_def ~= nil then assert(selected_linevar_def.name) show_last_passages_formspec(player, selected_linevar_def, assert(selected_linevar_def.name)) return end end if update_formspec then return get_formspec(custom_state) end end local function show_editor_formspec(player, linevar_to_select) if player == nil then return false end local custom_state = { player_name = assert(player:get_player_name()), evl_scroll = 0, message = "", continues = "", } if not custom_state_refresh_linevars(custom_state, linevar_to_select) then custom_state_set_selection_index(custom_state, 1) end ch_core.show_formspec(player, "advtrains_line_automation:editor_linek", get_formspec(custom_state), formspec_callback, custom_state, {}) end -- make line editor globally available advtrains.lines.open_line_editor = show_editor_formspec local function lp_formspec_callback(custom_state, player, formname, fields) if fields.back then show_editor_formspec(player, custom_state.selected_linevar) elseif fields.update then local selected_linevar_def = try_get_linevar_def(custom_state.selected_linevar) if selected_linevar_def ~= nil then show_last_passages_formspec(player, selected_linevar_def, custom_state.selected_linevar) end end end show_last_passages_formspec = function(player, linevar_def, selected_linevar) local rwt = advtrains.lines.rwt local formspec = { "formspec_version[6]".. "size[20,10]".. "label[0.5,0.6;", S("Last passages of line @1", F(assert(linevar_def.name))), "]".. "tablecolumns[text;text;text,width=5;text,width=5;text,width=5;text,width=5;text,width=5;text,width=5;text,width=5;text,width=5;text,width=5;text,width=5]", "table[0.5,1.25;19,8;jizdy;",S("Code"),",",S("Station"),",1.j.,2.j.,3.j.,4.j.,5.j.,6.j.,7.j.,8.j.,9.j.,10.j." } local passages, stops = get_last_passages(linevar_def) local max_time = {} if passages ~= nil then for j = 1, 10 do max_time[j] = 0 if passages[j] == nil then passages[j] = {} end end -- stání na výchozí zastávce: table.insert(formspec, ",,"..S("At start station:")) for j = 1, 10 do local wait = passages[j].wait if wait ~= nil then table.insert(formspec, ","..wait.." s") else table.insert(formspec, ",-") end end -- odjezd z výchozí zastávky: table.insert(formspec, ","..F(stops[1][1])..","..F(stops[1][2]).." "..S("(departed)")) for j = 1, 10 do local time = passages[j][1] if time ~= nil then table.insert(formspec, ",("..core.formspec_escape(rwt.t_str(time, 1))..")") if rwt.is_before(max_time[j], time) then max_time[j] = time end else table.insert(formspec, ",-") end end -- odjezdy z ostatních zasŧávek: for i = 2, #stops do -- i = index zastávky table.insert(formspec, ","..F(stops[i][1])..","..F(stops[i][2])) for j = 1, 10 do -- j = index jízdy local dep_vych = passages[j][1] local time = passages[j][i] if time ~= nil and dep_vych ~= nil then table.insert(formspec, ","..(rwt.diff(dep_vych, time))) if rwt.is_before(max_time[j], time) then max_time[j] = time end else table.insert(formspec, ",-") end end end table.insert(formspec, ",,"..S("Travelling:")) for i = 1, 10 do if max_time[i] ~= 0 then table.insert(formspec, ",_"..(rwt.diff(passages[i][1], max_time[i])).."_") else table.insert(formspec, ",-") end end end table.insert(formspec, ";]".. "button[13.75,0.3;1.75,0.75;update;"..S("Update").."]".. "button[17.75,0.3;1.75,0.75;back;"..S("Back").."]".. "tooltip[jizdy;"..S("Time data in seconds of railway time").."]") formspec = table.concat(formspec) local custom_state = { player_name = player:get_player_name(), selected_linevar = selected_linevar, } ch_core.show_formspec(player, "advtrains_line_automation:posledni_jizdy", formspec, lp_formspec_callback, custom_state, {}) end def = { -- params = "", description = S("Open line editor"), privs = {railway_operator = true}, func = function(player_name, param) show_editor_formspec(minetest.get_player_by_name(player_name)) end, } core.register_chatcommand("line_editor", def)