diff options
Diffstat (limited to 'advtrains_line_automation/station_announcement.lua')
-rw-r--r-- | advtrains_line_automation/station_announcement.lua | 1579 |
1 files changed, 1579 insertions, 0 deletions
diff --git a/advtrains_line_automation/station_announcement.lua b/advtrains_line_automation/station_announcement.lua new file mode 100644 index 0000000..3f9956c --- /dev/null +++ b/advtrains_line_automation/station_announcement.lua @@ -0,0 +1,1579 @@ +local al = advtrains.lines +local F = core.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 def +local function CF(s) + if s ~= nil then return F(s) else return "" end +end +local has_ch_time = core.get_modpath("ch_time") +local has_signs_api = core.get_modpath("signs_api") +local has_unifieddyes = core.get_modpath("unifieddyes") +local rozhlas_node_name = "advtrains_line_automation:stanicni_rozhlas" + +local RMODE_DEP = 1 +local RMODE_ARR = 2 +local RMODE_BOTH = 3 + +local PAGE_SETUP_1 = 1 +local PAGE_SETUP_2 = 2 +local PAGE_OWNERSHIP = 3 + +local hl_texty = { + { + id = "vcpp", + sample = "Vážení cestující, prosíme pozor!", + default = "", + }, { + id = "tvl", + sample = "{TYPVLAKU}", + }, { + id = "vlk", + sample = "Vlak", + }, { + id = "lnky", + sample = "linky {LINKA}", + }, { + id = "jmvlku", + sample = "{JMVLAKU}", + }, { + id = "zesm", + sample = "ze směru {VYCHOZI}", + }, { + id = "prijnk", + sample = "přijíždí na kolej {KOLEJ}.", + }, { + id = "prisnk", + sample = "bude přistaven na kolej {KOLEJ}.", + }, { + id = "zpoz", + sample = "Vlak má {ZPOZDENI} sekund zpoždění.", + default = "", + }, { + id = "zpozz", + sample = "Vlak má -{ZPOZDENI} sekund zpoždění.", + default = "", + }, { + id = "vkonc", + sample = "Vlak zde jízdu končí.", + }, { + id = "pokrnc", + sample = "Vlak dále pokračuje směr {NASL} a {CIL}", + }, { + id = "pokrc", + sample = "Vlak pokračuje směr {CIL}", + }, { + id = "ozasek", + sample = ", odjezd za {ODJZA} sekund.", + }, { + id = "dek", + sample = "Děkujeme, že používáte naše služby.", + default = "", + } +} +local hl_texty_id_to_idx = function() + local result = {} + for i, def in ipairs(hl_texty) do + local id = assert(def.id) + if result[id] ~= nil then + error("Duplicity: id = "..id.."!") + end + def.fs_sample = F(def.sample) + def.fs_default = F(def.default or def.sample) + result[id] = i + end + return result +end +hl_texty_id_to_idx = hl_texty_id_to_idx() + +local punch_context = {--[[ + [player_name] = { + stn = string, + epos = string, + i = int, + } +]]} + +local function dist2(a, b) + local x, y, z = a.x - b.x, a.y - b.y, a.z - b.z + return x * x + y * y + z * z +end + +local function goa(t, k) -- goa = get or add + local result = t[k] + if result == nil then + result = {} + t[k] = result + end + return result +end + +--[[ + Vrací: + - success = bool + - min = int or nil (pro success == false vždy nil) + - max = int or nil (pro success == false vždy nil) + - align = "left" or "right" or "center" +]] +local function lengths_from_string(s) + if s == "" or s == "-" then + return true, nil, nil + end + local l = #s + s = s:gsub("^ +", "") + local left = #s < l + l = #s + s = s:gsub(" +$", "") + local right = #s < l + local align + if not left then + align = "left" -- mezery vpravo, nebo žádné mezery + elseif right then + align = "center" -- mezery na obou stranách + else + align = "right" -- mezery jen vlevo + end + local n = s:match("^%d+$") + if n ~= nil then + n = assert(tonumber(n)) + if n > 256 then + n = 256 + end + return true, n, n, align + end + local min, max = s:match("^(%d*)-(%d*)$") + if min == nil then + return false, nil, nil, nil -- bad format + end + min, max = tonumber(min), tonumber(max) + if min ~= nil and min > 256 then min = 256 end + if max ~= nil and max > 256 then max = 256 end + if min ~= nil and max ~= nil and min > max then + min = max + end + return true, min, max, align +end + +--[[ (obsolete) +local function lengths_to_string(min, max) + if min == nil then + if max ~= nil then + return "-"..max + else + return "" + end + elseif max == nil then + return min.."-" + elseif min == max then + return tostring(min) + else + return min.."-"..max + end +end +]] + +local alphanum_chars_set = { + ["a"] = true, ["A"] = true, ["á"] = true, ["Á"] = true, ["ä"] = true, ["Ä"] = true, ["b"] = true, ["B"] = true, ["č"] = true, + ["Č"] = true, ["d"] = true, ["D"] = true, ["ď"] = true, ["Ď"] = true, ["e"] = true, ["E"] = true, ["é"] = true, ["É"] = true, + ["ě"] = true, ["Ě"] = true, ["f"] = true, ["F"] = true, ["g"] = true, ["G"] = true, ["h"] = true, ["H"] = true, ["i"] = true, + ["I"] = true, ["í"] = true, ["Í"] = true, ["j"] = true, ["J"] = true, ["k"] = true, ["K"] = true, ["l"] = true, ["L"] = true, + ["ĺ"] = true, ["Ĺ"] = true, ["ľ"] = true, ["Ľ"] = true, ["m"] = true, ["M"] = true, ["n"] = true, ["N"] = true, ["ň"] = true, + ["Ň"] = true, ["o"] = true, ["O"] = true, ["ó"] = true, ["Ó"] = true, ["ô"] = true, ["Ô"] = true, ["p"] = true, ["P"] = true, + ["q"] = true, ["Q"] = true, ["r"] = true, ["R"] = true, ["ŕ"] = true, ["Ŕ"] = true, ["ř"] = true, ["Ř"] = true, ["s"] = true, + ["S"] = true, ["š"] = true, ["Š"] = true, ["t"] = true, ["T"] = true, ["ť"] = true, ["Ť"] = true, ["u"] = true, ["U"] = true, + ["ú"] = true, ["Ú"] = true, ["ů"] = true, ["Ů"] = true, ["v"] = true, ["V"] = true, ["w"] = true, ["W"] = true, ["x"] = true, + ["X"] = true, ["y"] = true, ["Y"] = true, ["ý"] = true, ["Ý"] = true, ["z"] = true, ["Z"] = true, ["ž"] = true, ["Ž"] = true, + ["0"] = true, ["1"] = true, ["2"] = true, ["3"] = true, ["4"] = true, ["5"] = true, ["6"] = true, ["7"] = true, ["8"] = true, + ["9"] = true, +} + +local function dosadit(format, data, defaults) + assert(type(format) == "string") + assert(type(data) == "table") + if defaults == nil then + defaults = {} + end + local result = {} + local i = 1 + local e = 0 + local b = format:find("{", e + 1, true) + while b ~= nil do + if e < b - 1 then + table.insert(result, format:sub(e + 1, b - 1)) + end + e = format:find("}", b + 1, true) + if e == nil then + core.log("warning", "[advtrains_line_automation] dosadit(): invalid format: <"..format..">") + table.insert(result, format:sub(b, -1)) + break + end + local tag = format:sub(b + 1, e - 1) + local tag_name = tag + local tagfmt, tagalt = "" + local b2 = tag:find("[:|]") + if b2 == nil then + tag_name, tagfmt = tag, "" + else + tag_name = tag:sub(1, b2 - 1) + repeat + local e2 = tag:find("[:|]", b2 + 1) or (#tag + 1) + local c = tag:sub(b2, b2) + if c == ":" then + tagfmt = tag:sub(b2 + 1, e2 - 1) + elseif c == "|" then + tagalt = tag:sub(b2 + 1, e2 - 1) + end + b2 = e2 + until b2 >= #tag + end + local min, max, align + if tagfmt ~= "" then + local success + success, min, max, align = lengths_from_string(tagfmt) + end + tag = tag_name + if tag:len() < 4 and ch_core.utf8_length(tag) == 1 and alphanum_chars_set[tag] == nil then + -- speciální případ: zopakovat znak alespoň min-krát + if min ~= nil then + table.insert(result, string.rep(tag, min)) + else + table.insert(result, tag) + end + else + local value = data[tag] or tagalt or defaults[tag] or "ERR" + local len = ch_core.utf8_length(value) + if min ~= nil and len < min then + -- řetězec je kratší než minimum => prodloužit + local missing = min - len + if align == "left" then + table.insert(result, value) + table.insert(result, string.rep(" ", missing)) + elseif align == "right" then + table.insert(result, string.rep(" ", missing)) + table.insert(result, value) + else + table.insert(result, string.rep(" ", math.floor(missing / 2))) + table.insert(result, value) + table.insert(result, string.rep(" ", missing - math.floor(missing / 2))) + end + elseif max ~= nil and len > max then + -- řetězec je delší než maximum => oříznout + if align == "left" then + local pos = assert(ch_core.utf8_seek(value, 1, max)) + table.insert(result, value:sub(1, pos - 1)) + elseif align == "right" then + local pos = assert(ch_core.utf8_seek(value, 1, len - max)) + table.insert(result, value:sub(pos, -1)) + else + local overflow = len - max + local half = math.floor(overflow / 2) + local pos1 = assert(ch_core.utf8_seek(value, 1, half)) + local pos2 = (ch_core.utf8_seek(value, pos1, len - overflow) or 0) - 1 + table.insert(result, value:sub(pos1, pos2)) + end + else + -- řetězec odpovídá + table.insert(result, value) + end + end + b = format:find("{", e + 1, true) + end + table.insert(result, format:sub(e + 1, -1)) + return table.concat(result) +end + +-- Vrátí neuspořádaný seznam čísel řádků, které musejí být zformátovány pro daný formátovací řetězec. +local function ktere_radky(s, empty_as_string) + local set = {} + local list = {} + for match in s:gmatch("{[1-9][:|}]") do + local n = tonumber(match:sub(2,2)) + if n ~= nil and not set[n] then + set[n] = true + table.insert(list, n) + end + end + if list[1] == nil and empty_as_string then + return "" + else + return list + end +end + +local function sestavit_hlaseni(settings, settings_override, data, defaults) + local parts = {} + local function a(s) + table.insert(parts, s) + end + local function t(id) + if id == nil then + return "" + end + local key = "tx_"..id + local result = settings_override[key] or settings[key] + if result == nil then + local def = assert(hl_texty[hl_texty_id_to_idx[id]]) + result = assert(def.default or def.sample) + end + return result + end + assert(settings) + if settings_override == nil then + settings_override = {} + end + assert(data) + a(t("vcpp")) + a("{SEP}") + a(t(ifthenelse(data.TYPVLAKU ~= nil, "tvl", "vlk"))) + a("{SEP}") + if data.LINKA ~= nil then + a(t("lnky")) + a("{SEP}") + end + if data.VYCHOZI ~= nil then + a(t("zesm")) + a("{SEP}") + a(t("prijnk")) + else + a(t("prisnk")) + end + a("{SEP}") + if data.typ_zpozdeni == "+" then + a(t("zpoz")) + a("{SEP}") + elseif data.typ_zpozdeni == "-" then + a(t("zpozz")) + a("{SEP}") + end + if not data.CIL then + a(t("vkonc")) + elseif data.NASL then + a(t("pokrnc")) + else + a(t("pokrc")) + end + if data.ODJZA then + a(t("ozasek")) + else + a(".") + end + a("{SEP}") + a(t("dek")) + data = table.copy(data) + data.SEP = "{SEP}" + local s = table.concat(parts) + s = assert(dosadit(s, data, defaults)) + s = s:gsub(" *{SEP} *", "{SEP}") + while true do + t = s:gsub("{SEP}{SEP}", "{SEP}") + if t:len() == s:len() then + break + end + s = t + end + s = s:gsub("^{SEP}", "") + s = s:gsub("{SEP}$", "") + s = s:gsub("{SEP}", " ") + return s +end + +local function get_or_add_anns(stn) + local station = advtrains.lines.stations[stn] + if station == nil then + return nil -- dopravna neexistuje! + end + local anns = station.anns + if anns == nil then + anns = {} + station.anns = anns + end + return anns +end + +local cedule_default_settings = { + empty = "{-:5}", + fs = "", + pos = vector.zero(), + row = "{LINKA: 3} za {ODJZA: 2-3} s", + text = "{ZDE} - odjezdy\n{1}\n{2}", + text_rtf = {1, 2}, +} + +local function init_ann_data(stn, epos) + local anns = get_or_add_anns(stn) + if anns == nil then + return + end + local result = { + cedule = { + table.copy(cedule_default_settings), table.copy(cedule_default_settings), + table.copy(cedule_default_settings), table.copy(cedule_default_settings)}, + chat_dosah = 50, + fmt_delay = "{}", + fmt_negdelay = "-{}", + fmt_nodelay = "", + fn_firstupper = false, + fs_koleje = "", + koleje = "", + owner = "", + version = 3, + } + anns[epos] = result + return result +end + +local function get_ann_data(stn, epos, make_copy) + local anns = get_or_add_anns(stn) + if anns == nil then + core.log("error", "get_ann_data() called on non-existent stn '"..tostring(stn).."'!") + return nil + end + local ann = assert(anns[epos] or init_ann_data(stn, epos)) + if make_copy then + ann = table.copy(ann) + local cedule = {} + for i, v in ipairs(ann.cedule) do + cedule[i] = table.copy(v) + end + ann.cedule = cedule + end + return ann +end + +local function set_ann_data(stn, epos, data) + local anns = get_or_add_anns(stn) + if anns == nil then + return false + end + local ann = anns[epos] + if ann ~= nil then + for k, v in pairs(data) do + ann[k] = v + end + else + anns[epos] = table.copy(data) + end + return true +end + +local function attach_sign(stn, epos, i, sign_pos) + -- zkontrolovat rozhlas: + local rozhl_pos = advtrains.decode_pos(epos) + core.load_area(rozhl_pos) + local rozhl_node = core.get_node(rozhl_pos) + if rozhl_node.name ~= rozhlas_node_name then + return false, "Staniční rozhlas se nenachází na očekávané pozici." + end + local rozhl_meta = core.get_meta(rozhl_pos) + if rozhl_meta:get_string("stn") ~= stn then + return false, "Staniční rozhlas přísluší k jiné dopravně." -- vnitřní chyba! + end + local data = get_ann_data(stn, epos, false) + if data == nil then + return false, "Data staničního rozhlasu nebyla nalezena." + end + + -- zkontrolovat ceduli: + core.load_area(sign_pos) + local sign_node = core.get_node_or_nil(sign_pos) + if sign_node == nil or core.get_item_group(sign_node.name, "display_api") == 0 then + return false, "Toto není podporovaná cedule." + end + + -- zkontrolovat vzdálenost: + if vector.distance(rozhl_pos, sign_pos) > 1024 then + return false, "Cedule je příliš daleko. Vzdálenost může být max. 1024 metrů." + end + + -- zkontrolovat zadání: + local cedule = data.cedule[i] + if cedule == nil then + return false, "Chybný index." + end + + -- připojit: + local s = string.format("%d,%d,%d", sign_pos.x, sign_pos.y, sign_pos.z) + local fs = F(s) + cedule.fs = fs + cedule.pos = sign_pos + return true, "Cedule úspěšně připojena ke staničnímu rozhlasu." +end + +local function detach_sign(stn, epos, i) + -- zkontrolovat rozhlas: + local rozhl_pos = advtrains.decode_pos(epos) + core.load_area(rozhl_pos) + local rozhl_node = core.get_node(rozhl_pos) + if rozhl_node.name ~= rozhlas_node_name then + return false, "Staniční rozhlas se nenachází na očekávané pozici." + end + local rozhl_meta = core.get_meta(rozhl_pos) + if rozhl_meta:get_string("stn") ~= stn then + return false, "Staniční rozhlas přísluší k jiné dopravně." -- vnitřní chyba! + end + local data = get_ann_data(stn, epos, false) + if data == nil then + return false, "Data staničního rozhlasu nebyla nalezena." + end + + -- zkontrolovat zadání: + local cedule = data.cedule[i] + if cedule == nil then + return false, "Chybný index." + end + + if cedule.fs == "" then + return false, "Cedule není připojena." + end + + -- odpojit: + cedule.fs = "" + cedule.pos = vector.zero() + return true, "Cedule úspěšně odpojena." +end + + +local function init_formspec_callback(custom_state, player, formname, fields) + local player_name = player:get_player_name() + local pos = custom_state.pos + local node = core.get_node(pos) + if node.name ~= rozhlas_node_name then + core.chat_send_player(player_name, "CHYBA: staniční rozhlas nenalezen!") + return + end + if not core.check_player_privs(player, "railway_operator") then + core.chat_send_player(player_name, "*** K instalaci staničního rozhlasu je nutné právo railway_operator!") + return + end + if fields.dopravna then + local event = core.explode_textlist_event(fields.dopravna) + local new_index = tonumber(event.index) + if new_index ~= nil and custom_state.list[new_index] ~= nil then + custom_state.selection_index = new_index + end + if event.type == "DCL" then + fields.zvolit_dopravnu = "true" + end + end + if fields.zvolit_dopravnu and custom_state.selection_index ~= nil then + local stn = assert(custom_state.list[custom_state.selection_index].stn) + local stdata = advtrains.lines.stations[stn] + if stdata ~= nil then + local meta = core.get_meta(pos) + meta:set_string("infotext", "staniční rozhlas ("..(stdata.name or "???")..")") + meta:set_string("owner", player_name) + meta:set_string("stn", stn) + init_ann_data(stn, custom_state.epos) + core.chat_send_player(player_name, "*** Úspěšně nastaveno.") + end + end +end + +local function get_setup_formspec(custom_state) + local player_name = assert(custom_state.player_name) + local page = assert(custom_state.page) + local stations = assert(custom_state.stations) + local stn = custom_state.stn + local data = custom_state.data + + local formspec = { + "formspec_version[6]".. + "size[15,16.5]".. + -- "style_type[textarea;font=mono]".. + "tabheader[0,0;0.75;tab;Nastavení 1,Nastavení 2", + ifthenelse(custom_state.is_admin, ",Vlastnictví;", ";"), + custom_state.page..";false;true]".. + "button_exit[14,0.25;0.75,0.75;close;X]".. + "item_image[0.5,0.5;1,1;"..rozhlas_node_name.."]".. + "label[1.75,1;staniční rozhlas]".. + "label[9,0.75;vlastník/ice:\n", + ch_core.prihlasovaci_na_zobrazovaci(custom_state.owner), + "]", + } + local function a(x) + if type(x) == "table" then + for _, s in ipairs(x) do + table.insert(formspec, s) + end + else + table.insert(formspec, x) + end + end + if page == PAGE_SETUP_1 then + a( "container[0.5,1.5]".. + "label[0,0.5;dopravna:]".. + "dropdown[1.75,0.2;5,0.6;dopravna;") + for i, station in ipairs(stations) do + a(ifthenelse(i ~= 1, ",", "")..F(station.stn).." | "..F(station.name)) + end + a{";"..custom_state.station_index..";true]".. + "label[7,0.5;omezit jen na koleje:]".. + "field[10,0.2;4,0.6;koleje;;", + data.fs_koleje or "", + "]label[0,1.25;režim:]".. + "dropdown[1.75,1;3,0.6;rmode;odjezdy,příjezdy,odjezdy i příjezdy;", + tostring(data.rmode), + ";true]container_end[]", + -- ---- + "container[0.5,3.25]".. + "checkbox[0,0.25;fn_firstupper;první písmeno řádky odjezdu vždy velké;", + ifthenelse(ifthenelse(custom_state.fn_firstupper ~= nil, custom_state.fn_firstupper, data.fn_firstupper), "true", "false"), + "]field[0,1;3.25,0.75;fmt_nodelay;bez zpoždění;", F(data.fmt_nodelay or ""), "]".. + "field[4,1;3.25,0.75;fmt_delay;zpoždění ({} = číslo);", F(data.fmt_delay or "{}"), "]".. + "field[8,1;3.25,0.75;fmt_negdelay;záp.zpoždění ({} = číslo);", F(data.fmt_negdelay or "-{}"), "]".. + "tooltip[fmt_nodelay;Text pro značku {ZPOZDENI} v případě\\, že vlak jede bez zpoždění.]".. + "tooltip[fmt_delay;Formát pro značku {ZPOZDENI} v případě\\, že vlak má (kladné) zpoždění.\n".. + "Značka {} se nahradí počtem sekund zpoždění.]".. + "tooltip[fmt_negdelay;Formát pro značku {ZPOZDENI} v případě\\, že vlak má záporné zpoždění.\n".. + "Značka {} se nahradí absolutní hodnotou počtu sekund záporného zpoždění.]".. + "container_end[]".. + "container[0.5,10.5]".. + "box[0,0.15;14,0.05;#000000FF]"} + --[[ + -- hlášení do četu (zatím neimplementováno): + a{ "label[7,0.5;dosah hlášení v četu \\[m\\] (0=vyp):]".. + "field[11.5,0.25;2,0.5;chat_dosah;;", + tostring(data.chat_dosah or "50"), + "]".. + "tooltip[chat_dosah;Dosah je současně limitován doslechem jednotlivých hráčských postav.]".. + "label[0,0.5;texty pro hlášení příjezdu/přistavení vlaku v četu:]".. + "tablecolumns[text;text]".. + "table[0,0.75;14,2;texty;"} + for _, def in ipairs(hl_texty) do + local id = "tx_"..def.id + a(def.fs_sample) + a(",") + a(F(data[id] or def.default or def.sample)) + a(",") + end + formspec[#formspec] = ";"..(custom_state.tx_index or "").."]" + a("label[0.1,3.125;text:]".."field[0.75,2.75;10,0.75;preklad;;") + if custom_state.tx_index ~= nil then + local def = assert(hl_texty[custom_state.tx_index]) + local id = "tx_"..def.id + local s = data[id] + if s ~= nil then + a(F(s)) + else + a(def.fs_default) + end + end + a( "]".. + "button[11,2.75;3,0.75;preklad_set;nastavit]".. + "tooltip[preklad;V levém sloupci tabulky jsou vzorové texty\\, v pravém sloupci jsou texty\\,\n".. + "které budou na jejich místě použity pro tento staniční rozhlas (ty můžete měnit).]".. + "textarea[0,3.5;14,1;;;příklad: ") + local hlaseni = sestavit_hlaseni(data, custom_state, { + LINKA = "S1", + VYCHOZI = "Praha hl. n.", + typ_zpozdeni = "+", + CIL = "Bratislava hl. st.", + NASL = "Pardubice hl. n.", + ODJZA = "60", + ZPOZDENI = "13", + JMVLAKU = "Testovací expres", + KOLEJ = "A", + }) + a(F(hlaseni)) + a("]") + ]] + a("container_end[]"--[[.. + -- ---- + "container[0.5,9.25]".. + "label[0,0.25;Formáty řádků ({1}, {2} atd.):]".. + "container_end[]" ]] + ) + a("button[0.5,15;14,1;btn_save;Uložit]") + elseif page == PAGE_SETUP_2 then + a( "textarea[0.5,2;14,2;;;"..F("Pro nápovědu a použitou syntaxi viz wiki Českého hvozdu (článek „Staniční rozhlas“).").."]".. + "container[0.5,4]") + for i = 1, 4 do + local cedule = data.cedule[i] + local s = tostring(i) + a{ "container[0,", string.format("%f", 2.5 * (i - 1)), + "]label[0,0.3;cedule ", s, ":]".. + "field[0,0.9;9.75,0.75;fmt_cedule", s, "_row;formát řádky / prázdný řádek:;", + F(cedule.row), + "]field[0,1.75;9.75,0.75;fmt_cedule", s, "_empty;;", F(cedule.empty), + "]textarea[10,0.5;4,2;fmt_cedule", s, ";;"..F(cedule.text), + "]field[2,0;4.5,0.5;pos_cedule", s, ";;", cedule.fs, + "]button_exit[10,0;3,0.5;zam_cedule", s, + ";zaměřit...]button[6.75,0;3,0.5;", + ifthenelse(cedule.fs ~= "", "odp_cedule"..s..";odpojit", "pri_cedule"..s..";připojit"), + "]container_end[]", + } + end + a{ "container_end[]".. + "label[0.5,14.5;", CF(custom_state.message), "]".. + "button[0.5,15;14,1;btn_save;Uložit]", + } + elseif custom_state.is_admin and page == PAGE_OWNERSHIP then + a{ + "field[0.5,2.5;5,0.75;owner;vlastník/ice:;", + ch_core.prihlasovaci_na_zobrazovaci(custom_state.owner), + "]button[5.75,2.5;3,0.75;set_owner;nastavit]".. + "label[0.5,13;", + CF(custom_state.message), + "]button_exit[0.5,15;14,1;close2;zavřít]", + } + end + return table.concat(formspec) +end + +local function setup_formspec_callback(custom_state, player, formname, fields) + assert(player:get_player_name() == custom_state.player_name) + local node = core.get_node(custom_state.pos) + if node.name ~= rozhlas_node_name then + return + end + local is_admin = custom_state.is_admin + local page = custom_state.page + local stn = custom_state.stn + local data = custom_state.data + + if page == PAGE_SETUP_1 then + if + fields.dopravna and + fields.dopravna ~= tostring(custom_state.station_index) and + tonumber(fields.dopravna) ~= nil and + custom_state.stations[tonumber(fields.dopravna)] ~= nil + then + -- přepnout dopravnu + custom_state.station_index = tonumber(fields.dopravna) + end + if fields.rmode then + local new_rmode = tonumber(fields.rmode) + if new_rmode ~= nil and new_rmode ~= data.rmode then + data.rmode = new_rmode + end + end + + -- zaškrtávací pole: + if fields.fn_firstupper then + data.fn_firstupper = ifthenelse(fields.fn_firstupper == "true", true, false) + end + + -- koleje: + if fields.koleje and F(fields.koleje) ~= data.fs_koleje then + local parts = string.split(fields.koleje, ",", false) + local list, set = {}, {} + for _, part in ipairs(parts) do + if not set[part] then + set[part] = true + table.insert(list, part) + end + end + if #list == 0 then + -- všechny koleje + data.fs_koleje = "" + data.koleje = "" + elseif #list == 1 then + data.fs_koleje = F(list[1]) + data.koleje = list[1] + else + table.sort(list, function(a, b) return a < b end) + data.fs_koleje = F(table.concat(list, ",")) + data.koleje = set + end + end + if fields.fmt_delay then + data.fmt_delay = fields.fmt_delay + end + if fields.fmt_nodelay then + data.fmt_nodelay = fields.fmt_nodelay + end + if fields.fmt_negdelay then + data.fmt_negdelay = fields.fmt_negdelay + end + + -- texty + if fields.texty then + local event = core.explode_table_event(fields.texty) + if (event.type == "CHG" or event.type == "DCL") and event.row ~= custom_state.tx_index and hl_texty[event.row] ~= nil then + custom_state.tx_index = event.row + end + end + + if fields.preklad_set and custom_state.tx_index then + local def = assert(hl_texty[custom_state.tx_index]) + custom_state.data["tx_"..def.id] = assert(fields.preklad) + return get_setup_formspec(custom_state) + end + if fields.chat_dosah and tonumber(fields.chat_dosah) ~= nil then + local new_dosah = tonumber(fields.chat_dosah) + if new_dosah ~= nil and new_dosah == math.floor(new_dosah) and new_dosah >= 0 and new_dosah < 1024 then + custom_state.data.chat_dosah = new_dosah + end + end + + -- uložit? + if fields.btn_save then + local new_stn = custom_state.stations[custom_state.station_index].stn + if new_stn ~= stn then + -- přesunout rozhlas na jinou dopravnu + local meta = assert(core.get_meta(custom_state.pos)) + local old_anns = get_or_add_anns(stn) + local new_anns = get_or_add_anns(new_stn) + if old_anns ~= nil and new_anns ~= nil then + local epos = custom_state.epos + new_anns[epos] = old_anns[epos] + old_anns[epos] = nil + meta:set_string("stn", new_stn) + stn = new_stn + custom_state.stn = new_stn + end + end + set_ann_data(stn, custom_state.epos, data) + custom_state.data = get_ann_data(stn, custom_state.epos, true) + -- update infotext: + local meta = core.get_meta(custom_state.pos) + local station_name = al.get_station_name(meta:get_string("stn")) + local koleje = custom_state.data.fs_koleje + if koleje ~= "" then + koleje = " ["..koleje:gsub("\\", "").."]" + end + meta:set_string("infotext", "staniční rozhlas\n"..station_name..koleje) + end + elseif page == PAGE_SETUP_2 then + -- update fields: + for i = 1, 4 do + local cedule = data.cedule[i] + local s = fields["fmt_cedule"..i] + if s ~= nil then + cedule.text = s + cedule.text_rtf = ktere_radky(s, true) + end + s = fields["fmt_cedule"..i.."_row"] + if s ~= nil then + cedule.row = s + end + s = fields["fmt_cedule"..i.."_empty"] + if s ~= nil then + cedule.empty = s + end + end + if fields.btn_save then + local new_cedule = {} + for i = 1, 4 do + new_cedule[i] = table.copy(data.cedule[i]) + end + get_ann_data(stn, custom_state.epos, false).cedule = new_cedule + return get_setup_formspec(custom_state) + else + for i = 1, 4 do + if fields["pri_cedule"..i] then + -- připojit ceduli: + local pos_cedule_str = fields["pos_cedule"..i] + local x, y, z = pos_cedule_str:match("^(-?%d+),(-?%d+),(-?%d+)$") + if x == nil or y == nil or z == nil then + custom_state.message = "Chybný formát pozice: "..pos_cedule_str + return get_setup_formspec(custom_state) + end + local pos_cedule = vector.new(tonumber(x), tonumber(y), tonumber(z)) + local success, message = attach_sign(stn, custom_state.epos, i, pos_cedule) + if success then + local current_data = get_ann_data(stn, custom_state.epos, true) + if current_data ~= nil then + custom_state.data = current_data + end + custom_state.message = "Cedule úspěšně připojena." + else + custom_state.message = "CHYBA: "..message + end + return get_setup_formspec(custom_state) + end + if fields["odp_cedule"..i] then + local success, message = detach_sign(stn, custom_state.epos, i) + if success then + local current_data = get_ann_data(stn, custom_state.epos, true) + if current_data ~= nil then + custom_state.data = current_data + end + custom_state.message = "Cedule úspěšně odpojena." + else + custom_state.message = "CHYBA: "..message + end + return get_setup_formspec(custom_state) + end + if fields["zam_cedule"..i] then + local player_name = player:get_player_name() + local stack = player:get_wielded_item() + if stack:is_empty() then + player:set_wielded_item("advtrains_line_automation:sign_selector") + core.chat_send_player(player_name, "*** Levým klikem vyberte ceduli k připojení...") + else + player:get_inventory():add_item("main", "advtrains_line_automation:sign_selector") + core.chat_send_player(player_name, "*** Levým klikem výběrovým nástrojem vyberte ceduli k připojení...") + end + punch_context[player_name] = {stn = assert(custom_state.stn), epos = custom_state.epos, i = i} + return + end + end + end + elseif page == PAGE_OWNERSHIP then + if is_admin and fields.set_owner then + local new_owner = ch_core.jmeno_na_existujici_prihlasovaci(fields.owner or "") + if new_owner == nil then + custom_state.message = "Postava '"..(fields.owner or "").."' neexistuje!" + else + local ann_data = assert(get_ann_data(stn, custom_state.epos, false)) + ann_data.owner = new_owner + core.load_area(custom_state.pos) + local meta = core.get_meta(custom_state.pos) + meta:set_string("owner", new_owner) + custom_state.owner = new_owner + end + return get_setup_formspec(custom_state) + end + end + if fields.tab then + -- přepnout stránku + local new_tab = tonumber(fields.tab) + if new_tab ~= nil and new_tab ~= page and ( + new_tab == PAGE_SETUP_1 or new_tab == PAGE_SETUP_2 or (is_admin and new_tab == PAGE_OWNERSHIP) + ) then + custom_state.page = new_tab + custom_state.message = "" -- smazat zprávu + end + return get_setup_formspec(custom_state) + end + if not fields.quit then + return get_setup_formspec(custom_state) + end +end + +local function fill(line, prefix, rwtime_now, rwtime_value) + if rwtime_value == nil then + return + end + local secs = math.ceil((rwtime_value - rwtime_now) / 5) * 5 + if secs < 0 then + secs = -secs + line[prefix.."_Z"] = "-" + end + local n_s = secs % 60 + local n_m = (secs - n_s) / 60 + local s = tostring(n_s) + local m = tostring(n_m) + line[prefix] = tostring(secs) + line[prefix.."_M"] = m + line[prefix.."_S"] = s + if n_m < 10 then + line[prefix.."_MM"] = "0"..m + else + line[prefix.."_MM"] = m + end + if n_s < 10 then + line[prefix.."_SS"] = "0"..s + else + line[prefix.."_SS"] = s + end +end + +--[[ + stn -- kód dopravny, jejíž příjezdy/odjezdy se budou zapisovat na cedule + epos -- kódovaná pozice st. rozhlasu (pro načtení dat) + signs -- (volitelný) seznam až 4 pozic cedulí, které se budou aktualizovat + records -- viz níže + rwtime -- aktuální žel. čas (číselná forma) + --- + records je tabulka záznamů z al.predict_train(), doplněných o následující pole: + start = string or nil, -- název výchozí zastávky, pokud vlak odněkud přijíždí, jinak "" + destination = string, -- název cílové zastávky, pokud vlak někam pokračuje, jinak "" + prev_stop = string, -- název předchozí zastávky, pokud vlak odněkud přijíždí a pokud jde o jinou zastávku než 'start', jinak "" + next_stop = string, -- název násl. zast., pokud vlak pokračuje a pokud jde o jinou zastávku než 'destination', jinak "" + last_pos = string, -- název poslední známé polohy vlaku, nebo "" + -- + stn = string, track = string, delay = int, + stdata = table or nil, + dep = int or nil, dep_linevar_def = table or nil, dep_index = int or nil, + arr = int or nil, arr_linevar_def = table or nil, arr_index = int or nil, +]] + +local function update_ann(stn, epos, signs, records, rwtime) + local ann = get_ann_data(stn, epos) + if ann == nil then + core.log("error", "update_ann() called for "..stn.."/"..epos..", but ann is nil!") + return + end + local tracks + local any_line = { + ZDE = al.get_station_name(stn), + } + if ann.fs_koleje ~= "" then + any_line.KOLEJE = ann.fs_koleje:gsub("\\", "") + tracks = ann.koleje + if tracks ~= nil and type(tracks) ~= "table" then + if tracks == "" then + tracks = nil + else + tracks = {[tracks] = true} + end + end + end + if has_ch_time then + local cas = ch_time.aktualni_cas() + any_line.HH = string.format("%02d", cas.hodina) + any_line.MM = string.format("%02d", cas.minuta) + any_line.SS = string.format("%02d", cas.sekunda) + end + local lines = {} + for _, record in ipairs(records) do + assert(record.start ~= nil) + assert(record.destination ~= nil) + assert(record.prev_stop ~= nil) + assert(record.next_stop ~= nil) + assert(record.last_pos ~= nil) + if + (tracks == nil or tracks[record.track]) and ( + (ann.rmode == RMODE_ARR and record.arr ~= nil) or + (ann.rmode == RMODE_DEP and record.dep ~= nil) or + (ann.rmode == RMODE_BOTH and (record.arr ~= nil or record.dep ~= nil)) + ) + then + local linevar_def, index + if record.dep ~= nil then + linevar_def, index = record.dep_linevar_def, record.dep_index + else + linevar_def, index = record.arr_linevar_def, record.arr_index + end + local stops = linevar_def.stops + local line = setmetatable({}, {__index = any_line}) + line.LINKA = advtrains.lines.linevar_decompose(linevar_def.name) + assert(line.LINKA) + if record.start ~= "" then + line.VYCHOZI = record.start + end + if record.destination ~= "" then + line.CIL = record.destination + end + if record.track ~= "" then + line.KOLEJ = record.track + end + fill(line, "PRIJZA", rwtime, record.arr) + fill(line, "ODJZA", rwtime, record.dep) + local abs_delay = math.abs(record.delay) + if abs_delay < 5 then + line.ZPOZDENI = ann.fmt_nodelay or "" + else + line.ZPOZDENI = dosadit( + ifthenelse(record.delay > 0, ann.fmt_delay or "{}", ann.fmt_negdelay or "-{}"), + {[""] = tostring(5 * math.ceil(abs_delay / 5))} + ) + end + -- PREDCH + if record.prev_stop ~= "" then + line.PREDCH = record.prev_stop + end + -- NASL + if record.next_stop ~= "" then + line.NASL = record.next_stop + end + -- POLOHA + if record.last_pos ~= "" then + line.POLOHA = record.last_pos + end + -- JMVLAKU + if linevar_def.train_name ~= nil then + line.JMVLAKU = linevar_def.train_name + end + -- TYP + line.TYP = "Os" + -- TYPVLAKU + line.TYPVLAKU = "osobní vlak" + table.insert(lines, line) + end + end + if signs ~= nil then + local empty_table = {} + for i = 1, 4 do + local cedule = ann.cedule[i] + local sign_pos = signs[i] + if sign_pos ~= nil and core.compare_block_status(sign_pos, "active") then + local formatted_lines = setmetatable({}, {__index = any_line}) + if type(cedule.text_rtf) == "table" then + for _, i_row in ipairs(cedule.text_rtf) do + if lines[i_row] == nil then + -- prázdný řádek + formatted_lines[tostring(i_row)] = dosadit(cedule.empty, empty_table) + else + -- řádek odjezdu + local s = dosadit(cedule.row, lines[i_row]) + if s ~= "" and ann.fn_firstupper then + local l = ch_core.utf8_seek(s, 1, 1) + if l == nil then + s = ch_core.na_velka_pismena(s) + else + local c = s:sub(1, l - 1) + local uc = ch_core.na_velka_pismena(c) + if uc ~= c then + s = uc..s:sub(l, -1) + end + end + end + formatted_lines[tostring(i_row)] = s + end + end + end + local s = dosadit(cedule.text, formatted_lines) + if has_signs_api then + signs_api.set_display_text(sign_pos, s) + end + end + end + end +end + +local globalstep_time = -5 +local first_run = true + +local function first_globalstep() + for stn, stdata in pairs(advtrains.lines.stations) do + local anns = stdata.anns + if stdata.anns ~= nil then + for rozh_epos, ann in pairs(stdata.anns) do + if ann.version < 2 then + -- upgrade version 1 to version 2: + ann.rmode = RMODE_DEP + ann.version = 2 + end + if ann.version < 3 then + local pos = advtrains.decode_pos(rozh_epos) + core.load_area(pos) + local meta = core.get_meta(pos) + ann.owner = meta:get_string("owner") + core.log("action", "strozhlas at position "..core.pos_to_string(pos).." upgraded to metadata version 3 (owner "..ann.owner..")") + ann.version = 3 + end + end + end + end +end + +local function get_start_by_linevar_def(cache, linevar_def) + local result = cache[linevar_def.name] + if result == nil then + result = al.get_line_description(linevar_def, {first_stop = true, last_stop = false, last_stop_prefix = ""}) + if result == "???" then + result = "" + end + cache[linevar_def.name] = result + end + return result +end + +local function get_destination_by_linevar_def(cache, linevar_def) + local result = cache[linevar_def.name] + if result == nil then + result = al.get_line_description(linevar_def, {first_stop = false, last_stop = true, last_stop_prefix = ""}) + if result == "???" then + result = "" + end + cache[linevar_def.name] = result + end + return result +end + +local function get_name_by_stn(cache, stn, alt) + local result = cache[stn] + if result == nil then + result = al.get_station_name(stn) + if result == "???" then + result = "" + end + cache[stn] = result + end + if result == "" then + return alt + else + return result + end +end + +local function globalstep(dtime) + globalstep_time = globalstep_time + dtime + if globalstep_time < 0 then + return + end + globalstep_time = globalstep_time - 5 + + if first_run then + first_run = false + return first_globalstep() + end + + local rwtime = rwt.to_secs(rwt.get_time()) + local rwtime_limit = rwtime + 3600 + -- Shromáždit rozhlasy: + local subscriptions = {--[[ + [stn] = {{ + rozh_pos = vector, + rozh_epos = string, + rozh_def = table, + signs = {[1..4] = vector or nil} or nil, + }...} + ]]} + local signs = {} + for stn, stdata in pairs(advtrains.lines.stations) do + local anns = stdata.anns + if stdata.anns ~= nil then + for rozh_epos, ann in pairs(stdata.anns) do + local rozh_pos = advtrains.decode_pos(rozh_epos) + local is_admin = core.check_player_privs(assert(ann.owner), "protection_bypass") + local signs_count = 0 + for i = 1, 4 do + local cedule = assert(ann.cedule[i]) + local s = cedule.fs + if s ~= nil and s ~= "" then + local sign_pos = assert(cedule.pos) + if core.compare_block_status(sign_pos, "active") then + signs[i] = sign_pos + signs_count = signs_count + 1 + if not is_admin then + local sign_meta = core.get_meta(sign_pos) + local sign_owner = sign_meta:get_string("owner") + if sign_meta:get_int("access_level") ~= 1 and sign_owner ~= "" and ann.owner ~= sign_owner then + -- unauthorized access to the sign + core.log("warning", "Station announcement "..core.pos_to_string(rozh_pos).." owned by '".. + ann.owner.."' cannot write to sign at "..core.pos_to_string(sign_pos).." owned by '".. + sign_owner.."'! Access denied.") + signs[i] = nil + signs_count = signs_count - 1 + end + end + end + end + end + if signs_count > 0 then + -- nějaké cedule jsou aktivní + table.insert(goa(subscriptions, stn), {rozh_pos = rozh_pos, rozh_epos = rozh_epos, rozh_def = ann, signs = signs}) + signs = {} + elseif core.compare_block_status(rozh_pos, "active") then + -- cedule nejsou aktivní, ale rozhlas ano + table.insert(goa(subscriptions, stn), {rozh_pos = rozh_pos, rozh_epos = rozh_epos, rozh_def = ann}) + end + end + end + end + + -- Shromáždit vlaky: + local by_stn = {} + for stn, _ in pairs(subscriptions) do + by_stn[stn] = {} + end + local start_by_linevar = {} + local destination_by_linevar = {} + local name_by_stn = {} + + for _, train in pairs(advtrains.trains) do + local ls, linevar_def = al.get_line_status(train) + if linevar_def ~= nil then + local prediction = al.predict_train(ls, linevar_def, rwtime, true) + local last_pos = al.get_last_pos_station_name(ls) or "" + for i, record in ipairs(prediction) do + local records = by_stn[record.stn] + if + records ~= nil and + (record.dep ~= nil or record.arr ~= nil) and + (record.dep == nil or record.dep < rwtime_limit) and + (record.arr == nil or record.arr < rwtime_limit) + then + -- nutno doplnit: start, destination, prev_stop, next_stop, last_pos + record.last_pos = last_pos -- název poslední dopravny, kde byl vlak spatřen + if record.final and record.arr ~= nil and record.dep ~= nil and record.arr_linevar_def.name ~= record.dep_linevar_def.name then + -- změna linky => rozdělit na příjezd a odjezd + local record2 = table.copy(record) + record2.dep = nil + record2.dep_linevar_def = nil + record2.dep_index = nil + record2.start = get_start_by_linevar_def(start_by_linevar, record.arr_linevar_def) + local other_index, other_data = al.get_prev_stop(record.arr_linevar_def, record.arr_index, false) + if other_index ~= nil then + record2.prev_stop = get_name_by_stn(name_by_stn, other_data.stn, "") + end + record2.next_stop = "" + record2.destination = get_destination_by_linevar_def(destination_by_linevar, record.arr_linevar_def) + table.insert(records, record2) + record.arr = nil + record.arr_linevar_def = nil + record.arr_index = nil + record.start = get_start_by_linevar_def(start_by_linevar, record.dep_linevar_def) + record.prev_stop = "" + other_index, other_data = al.get_next_stop(record.dep_linevar_def, record.dep_index, false) + if other_index ~= nil then + record.next_stop = get_name_by_stn(name_by_stn, other_data.stn, "") + end + record.destination = get_destination_by_linevar_def(destination_by_linevar, record.dep_linevar_def) + table.insert(records, record) + elseif record.dep ~= nil then + -- odjezd nebo příjezd/odjezd (ale na stejné lince!) + local linevar_def = record.dep_linevar_def + local index = record.dep_index + record.start = get_start_by_linevar_def(start_by_linevar, linevar_def) + record.destination = get_destination_by_linevar_def(destination_by_linevar, linevar_def) + record.prev_stop = "" + record.next_stop = "" + local other_index, other_data + if record.arr ~= nil then + other_index, other_data = al.get_prev_stop(linevar_def, index, false) + if other_index ~= nil then + record.prev_stop = get_name_by_stn(name_by_stn, other_data.stn, "") + end + end + other_index, other_data = al.get_next_stop(linevar_def, index, false) + if other_index ~= nil then + record.next_stop = get_name_by_stn(name_by_stn, other_data.stn, "") + end + record.destination = get_destination_by_linevar_def(destination_by_linevar, linevar_def) + table.insert(records, record) + elseif record.arr ~= nil then + -- jen příjezd + local linevar_def = record.arr_linevar_def + local index = record.arr_index + record.start = get_start_by_linevar_def(start_by_linevar, linevar_def) + local other_index, other_data = al.get_prev_stop(linevar_def, index, false) + if other_index ~= nil then + record.prev_stop = get_name_by_stn(name_by_stn, other_data.stn, "") + else + record.prev_stop = "" + end + record.next_stop = "" + record.destination = get_destination_by_linevar_def(destination_by_linevar, linevar_def) + table.insert(records, record) + end + end + end + end + end + + -- Aktualizovat rozhlasy: + for stn, records in pairs(by_stn) do + local deps = records + local arrs = table.copy(records) + table.sort(deps, function(a, b) + return assert(a.dep or a.arr) < assert(b.dep or b.arr) + end) + table.sort(arrs, function(a, b) + return (a.arr or 1.0e+100) < (b.arr or 1.0e+100) + end) + for i = #arrs, 1, -1 do + if arrs[i].arr == nil then + arrs[i] = nil -- ponechat jen příjezdy v rámci nejbližší hodiny + end + end + for _, ann in ipairs(subscriptions[stn]) do + if ann.rmode ~= RMODE_ARR then + update_ann(assert(stn), assert(ann.rozh_epos), ann.signs, deps, rwtime) + else + update_ann(assert(stn), assert(ann.rozh_epos), ann.signs, arrs, rwtime) + end + end + end +end + +core.register_globalstep(globalstep) + +local function can_dig(pos, player) + if player ~= nil and core.is_player(player) then + local owner = core.get_meta(pos):get_string("owner") + local player_name = player:get_player_name() + return owner == "" or owner == player_name or core.check_player_privs(player_name, "protection_bypass") + end + return false +end + +local function on_construct(pos) + local meta = core.get_meta(pos) + meta:set_string("infotext", "staniční rozhlas") +end + +local function on_destruct(pos) + local meta = core.get_meta(pos) + local stn = meta:get_string("stn") + if stn ~= "" then + local epos = advtrains.encode_pos(pos) + local stdata = advtrains.lines.stations[stn] + if stdata ~= nil then + (stdata.anns or {})[epos] = nil -- odstranit data staničního rozhlasu + end + end +end + +local function on_dig(pos, node, digger) + -- TODO? + -- return core.node_dig(pos, node, digger) + if not can_dig(pos, digger) then + return false + end + if has_unifieddyes then + return unifieddyes.on_dig(pos, node, digger) + else + return core.node_dig(pos, node, digger) + end +end + +local function on_rightclick(pos, node, clicker, itemstack, pointed_thing) + if clicker == nil or not clicker:is_player() then + return + end + local player_name = assert(clicker:get_player_name()) + local meta = core.get_meta(pos) + local owner = meta:get_string("owner") + local stn = meta:get_string("stn") + local epos = advtrains.encode_pos(pos) + local stdata = advtrains.lines.stations[stn] + if owner == "" or stn == "" or stdata == nil or stdata.anns == nil or stdata.anns[epos] == nil then + if not core.check_player_privs(clicker, "railway_operator") then + core.chat_send_player(player_name, "*** K instalaci staničního rozhlasu je nutné právo railway_operator!") + return + end + local limit = 256 * 256 + local stations = advtrains.lines.load_stations_for_formspec() + local list = {} + for i, station_data in ipairs(stations) do + local d2 = limit + for _, stop in ipairs(station_data.tracks) do + local d2new = dist2(pos, stop.pos) + if d2new < d2 then + d2 = d2new + end + end + if d2 < limit then + table.insert(list, { + stn = assert(station_data.stn), + name = assert(station_data.name), + distance = math.floor(math.sqrt(d2)), + }) + end + end + table.sort(list, function(a, b) return a.distance < b.distance end) + local custom_state = { + pos = pos, + epos = advtrains.encode_pos(pos), + list = list, + } + local formspec = { + "formspec_version[6]".. + "size[15,8]".. + "button_exit[14,0.25;0.75,0.75;close;X]".. + "item_image[0.5,0.5;1,1;"..rozhlas_node_name.."]".. + "label[1.75,1;staniční rozhlas]".. + "label[0.5,2.25;vyberte dopravnu:]".. + "button_exit[0.5,6.75;14,1;zvolit_dopravnu;Zvolit]".. + "textlist[0.5,2.5;14,4;dopravna;", + } + if #list > 0 then + for i, candidate in ipairs(list) do + if i ~= 1 then + table.insert(formspec, ",") + end + table.insert(formspec, F(candidate.stn.." | "..candidate.name.." ("..candidate.distance.." m)")) + end + custom_state.selection_index = 1 + table.insert(formspec, ";1]") + else + table.insert(formspec, ";]") + end + ch_core.show_formspec(clicker, "advtrains_line_automation:init_rozhlas", table.concat(formspec), init_formspec_callback, custom_state, {}) + return + end + if player_name ~= owner and not core.check_player_privs(player_name, "protection_bypass") then -- train_admin? + core.chat_send_player(player_name, "Nemáte oprávnění nastavovat tento staniční rozhlas!") + return + end + local stations = advtrains.lines.load_stations_for_formspec() + local selection_index + for i, station in ipairs(stations) do + if station.stn == stn then + selection_index = i + break + end + end + if selection_index == nil then + core.log("error", "Cannot determine selection index for the station '"..stn.."' in the list of stations!") + core.chat_send_player(player_name, "CHYBA: Vnitřní chyba: dopravna nenalezena ve výpisu!") + return + end + local custom_state = { + player_name = player_name, + is_admin = ch_core.get_player_role(player_name) == "admin", + pos = pos, + epos = epos, + owner = owner, + stn = assert(stn), -- kam byl staniční rozhlas dosud přiřazen + stations = stations, -- pro dropdown[] + station_index = selection_index, -- pro dropdown[] + data = assert(get_ann_data(stn, epos, true)), + page = PAGE_SETUP_1, + } + ch_core.show_formspec(clicker, "advtrains_line_automation:rozhlas", get_setup_formspec(custom_state), + setup_formspec_callback, custom_state, {}) +end + +local function selector_on_use(itemstack, user, pointed_thing) + if pointed_thing.type ~= "node" then + return + end + if user ~= nil then + local player_name = user:get_player_name() + local pc = punch_context[player_name] + if pc ~= nil then + local success, message = attach_sign(assert(pc.stn), assert(pc.epos), assert(pc.i), assert(pointed_thing.under)) + if not success then + message = message.." Zaměřování bude zrušeno." + end + core.chat_send_player(player_name, message) + end + end + return ItemStack() +end + +local box = { + type = "fixed", + fixed = { + {-0.125, 0.125, 0.25, 0.125, 0.5, 0.5}, + {-0.25, 0.05, 0, 0.25, 0.45, 0.25}, + }, +} + +def = { + description = "staniční rozhlas", + tiles = {{name = "default_steel_block.png", backface_culling = true}}, + drawtype = "mesh", + mesh = "advtrains_tuber.obj", + paramtype = "light", + paramtype2 = "4dir", + selection_box = box, + collision_box = box, + groups = {oddly_breakable_by_hand = 3, ud_param2_colorable = 1}, + sounds = default.node_sound_metal_defaults(), + can_dig = can_dig, + on_dig = on_dig, + on_construct = on_construct, + on_destruct = on_destruct, + on_rightclick = on_rightclick, +} +if has_unifieddyes then + def.paramtype2 = "color4dir" + def.palette = "unifieddyes_palette_color4dir.png" +end +core.register_node(rozhlas_node_name, def) + +def = { + description = "levým klikem zvolte ceduli pro připojení", + groups = {not_in_creative_inventory = 1, tool = 1}, + inventory_image = "[combine:16x16:7,0=blank.png\\^[noalpha\\^[resize\\:2x16:0,7=blank.png\\^[noalpha\\^[resize\\:16x2", + wield_image = "blank.png", + on_use = selector_on_use, +} + +core.register_tool("advtrains_line_automation:sign_selector", def) + +core.register_craft({ + output = rozhlas_node_name, + recipe = { + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + {"default:steel_ingot", "mesecons_noteblock:noteblock", "default:steel_ingot"}, + {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, + }, +}) |