diff options
author | Singularis <singularis@volny.cz> | 2025-01-20 17:48:28 +0100 |
---|---|---|
committer | orwell <orwell@bleipb.de> | 2025-05-27 20:22:01 +0200 |
commit | d49e6ad23c66e8a2a9be3b1fb9f0527617a257d6 (patch) | |
tree | 41da083cdf1262052e3955341050138666e31890 | |
parent | 8965b1115473346df8aa80bc2c3d61eab3509d62 (diff) | |
download | advtrains-d49e6ad23c66e8a2a9be3b1fb9f0527617a257d6.tar.gz advtrains-d49e6ad23c66e8a2a9be3b1fb9f0527617a257d6.tar.bz2 advtrains-d49e6ad23c66e8a2a9be3b1fb9f0527617a257d6.zip |
[advtrains_line_automation] vývoj staničního rozhlasu
- [home_workshop_misc] drobná oprava
-rw-r--r-- | advtrains_line_automation/init.lua | 2 | ||||
-rw-r--r-- | advtrains_line_automation/line_functions.lua | 115 | ||||
-rw-r--r-- | advtrains_line_automation/mod.conf | 4 | ||||
-rw-r--r-- | advtrains_line_automation/models/advtrains_tuber.obj | 152 | ||||
-rw-r--r-- | advtrains_line_automation/models/license.txt | 5 | ||||
-rw-r--r-- | advtrains_line_automation/station_announcement.lua | 748 | ||||
-rw-r--r-- | advtrains_line_automation/structs.md | 39 |
7 files changed, 990 insertions, 75 deletions
diff --git a/advtrains_line_automation/init.lua b/advtrains_line_automation/init.lua index 2d4a97e..fbf1d8d 100644 --- a/advtrains_line_automation/init.lua +++ b/advtrains_line_automation/init.lua @@ -24,7 +24,7 @@ dofile(modpath.."line_editor.lua") dofile(modpath.."scheduler.lua") dofile(modpath.."station_editor.lua") dofile(modpath.."stoprail.lua") --- dofile(modpath.."station_announcement.lua") +dofile(modpath.."station_announcement.lua") function advtrains.lines.load(data) if data then diff --git a/advtrains_line_automation/line_functions.lua b/advtrains_line_automation/line_functions.lua index 0a4e6d2..6f60ab5 100644 --- a/advtrains_line_automation/line_functions.lua +++ b/advtrains_line_automation/line_functions.lua @@ -59,6 +59,7 @@ local function get_station_name(stn) return "???" end end +al.get_station_name = get_station_name local function na_velka_pismena(s) local l = #s @@ -130,6 +131,7 @@ local function get_first_last_stations(linevar_def) end end end + print("get_first_last_stations(): "..dump2({i_first = i_first, i_last = i_last, i_firstx = i_firstx, i_lastx = i_lastx, stops = stops})) if i_first ~= nil and i_last ~= nil then return stops[i_first].stn, stops[i_last].stn elseif i_firstx ~= nil and i_lastx ~= nil then @@ -299,11 +301,31 @@ end --[[ Vrací: + a) index, stop_data -- pokud byla vyhovující předchozí zastávka nalezena + b) nil, nil -- pokud nalezena nebyla +]] +function al.get_prev_stop(linevar_def, current_index, allow_hidden_stops) + local stops = assert(linevar_def.stops) + assert(current_index) + if current_index > 1 then + for i = current_index - 1, 1, -1 do + local mode = stops[i].mode + if mode == nil or (mode ~= MODE_DISABLED and ((mode ~= MODE_HIDDEN and mode ~= MODE_FINAL_HIDDEN) or allow_hidden_stops)) then + return i, stops[i] + end + end + end + return nil, nil +end + +--[[ + Vrací: a) index, stop_data -- pokud byla vyhovující další zastávka nalezena b) nil, nil -- pokud nalezena nebyla ]] function al.get_next_stop(linevar_def, current_index, allow_hidden_stops) local stops = assert(linevar_def.stops) + assert(current_index) if current_index < #stops then for i = current_index + 1, #stops do local mode = stops[i].mode @@ -321,16 +343,22 @@ end b) nil, nil -- pokud nalezena nebyla ]] function al.get_terminus(linevar_def, current_index, allow_hidden_stops) + print("DEBUG: get_terminus() called: "..dump2({linevar_def, current_index, allow_hidden_stops})) local stops = assert(linevar_def.stops) + local r_i, r_stop if current_index < #stops then for i = current_index + 1, #stops do - local mode = stops[i].mode - if mode ~= nil and (mode == MODE_FINAL or mode == MODE_FINAL_CONTINUE or (mode == MODE_FINAL_HIDDEN and allow_hidden_stops)) then - return i, stops[i] + local mode = stops[i].mode or MODE_NORMAL + print("DEBUG: stop mode at index "..i.." is "..(mode or MODE_NORMAL)) + if mode ~= MODE_DISABLED and ((mode ~= MODE_HIDDEN and mode ~= MODE_FINAL_HIDDEN) or allow_hidden_stops) then + r_i, r_stop = i, stops[i] + end + if mode == MODE_FINAL or mode == MODE_FINAL_CONTINUE or mode == MODE_FINAL_HIDDEN then + break end end end - return nil, nil + return r_i, r_stop end --[[ @@ -929,6 +957,15 @@ local function get_last_pos(line_status) return result end +function al.get_last_pos_station_name(line_status) + local result = get_last_pos(line_status) + if result.type ~= "none" then + return get_station_name(result.last_pos.stn) + else + return nil + end +end + local function get_train_position(line_status, linevar_def, rwtime) if line_status ~= nil then local last_pos_info = get_last_pos(line_status) @@ -948,6 +985,76 @@ local function get_train_position(line_status, linevar_def, rwtime) return "???" end +--[[ + Zadaný vlak musí být linkový. + Vrací: + {stn = string, track = string, stdata = table or nil, dep = int or nil, arr = int or nil, delay = int} +]] +function al.predict_train(line_status, linevar_def, rwtime) + assert(line_status) + assert(linevar_def) + local stops = linevar_def.stops + local result = {} + local index = assert(line_status.linevar_index) + if rwtime == nil then + rwtime = rwt.to_secs(rwt.get_time()) + end + local delay_desc = al.get_delay_description(line_status, linevar_def, rwtime) + local delay + if delay_desc.has_delay then + delay = delay_desc.delay + else + delay = 0 + end + if line_status.standing_at ~= nil then + -- vlak stojí na zastávce + local stop = assert(stops[index]) + local stdata = advtrains.lines.stations[stop.stn] + table.insert(result, { + stn = line_status.linevar_last_stn, + track = stop.track or "", + stdata = stdata, + dep = assert(line_status.linevar_last_dep), + -- arr = nil, + delay = delay, + index = index, + hidden = stop.mode == MODE_HIDDEN + }) + end + index = index + 1 + while stops[index] ~= nil do + local stop = stops[index] + local stdata = advtrains.lines.stations[stop.stn] + if stop.mode == MODE_FINAL or stop.mode == MODE_FINAL_CONTINUE or stop.mode == MODE_FINAL_HIDDEN then + -- koncová zastávka + table.insert(result, { + stn = assert(stop.stn), + track = stop.track or "", + stdata = stdata, + arr = line_status.linevar_dep + stop.dep + delay, + delay = delay, + index = index, + hidden = stop.mode == MODE_FINAL_HIDDEN, + }) + break + elseif stop.mode ~= MODE_DISABLED then + -- mezilehlá zastávka + table.insert(result, { + stn = assert(stop.stn), + track = stop.track or "", + stdata = stdata, + arr = line_status.linevar_dep + stop.dep + delay, -- TODO... + dep = line_status.linevar_dep + stop.dep + delay, + delay = delay, + index = index, + hidden = stop.mode == MODE_HIDDEN, + }) + end + index = index + 1 + end + return result +end + local function vlaky(param, past_trains_too) local result = {} if param:match("/") then diff --git a/advtrains_line_automation/mod.conf b/advtrains_line_automation/mod.conf index 9d6e9e8..eeae5a2 100644 --- a/advtrains_line_automation/mod.conf +++ b/advtrains_line_automation/mod.conf @@ -3,5 +3,5 @@ title=Advanced Trains Line Automation description=Tools for automatic train lines author=orwell96 -depends=advtrains_interlocking -optional_depends=advtrains_train_track,ch_time +depends=advtrains_interlocking,default +optional_depends=advtrains_train_track,ch_time,signs_api,unifieddyes diff --git a/advtrains_line_automation/models/advtrains_tuber.obj b/advtrains_line_automation/models/advtrains_tuber.obj new file mode 100644 index 0000000..25bc6dc --- /dev/null +++ b/advtrains_line_automation/models/advtrains_tuber.obj @@ -0,0 +1,152 @@ +# Blender v2.76 (sub 0) OBJ File: 'dark_tuber.blend' +# www.blender.org +mtllib underch_dark_tuber.mtl +o Cube +v 0.136329 -0.157988 0.702133 +v 0.136329 0.157988 0.702133 +v -0.136329 0.157988 0.702133 +v -0.136329 -0.157988 0.702133 +v 0.368861 -0.368861 -0.337695 +v 0.368861 0.368862 -0.466279 +v -0.381520 0.360664 -0.354918 +v -0.368861 -0.368861 -0.057503 +v 0.223277 -0.225624 0.028756 +v 0.216947 0.221525 0.018022 +v -0.262021 0.200536 -0.023957 +v -0.229606 -0.229722 0.156757 +v 0.100830 -0.108796 0.403707 +v 0.100830 0.108796 0.432070 +v -0.117708 0.097867 0.380743 +v -0.100830 -0.108796 0.439469 +v 0.264026 -0.267600 0.054980 +v 0.264026 0.267600 -0.003499 +v -0.264026 0.267600 0.054980 +v -0.264026 -0.267600 0.211890 +v 0.000000 -0.157988 0.702133 +v 0.000000 -0.461012 -0.167161 +v 0.000000 -0.263640 0.098449 +v 0.000000 -0.131624 0.421588 +v 0.000000 -0.316408 0.141084 +v -0.000000 0.157988 0.702133 +v -0.006330 0.456914 -0.441037 +v -0.025702 0.246997 -0.008661 +v -0.008439 0.126160 0.406407 +v -0.000000 0.316408 0.018092 +v -0.136329 -0.000000 0.702133 +v -0.467342 -0.004099 -0.175772 +v -0.286994 -0.016643 0.063482 +v -0.128968 -0.005465 0.410106 +v -0.312834 -0.000000 0.141084 +v 0.136329 0.000000 0.702133 +v 0.461012 0.000000 -0.432425 +v 0.261292 0.000000 0.026307 +v 0.120528 0.000000 0.417888 +v 0.312834 0.000000 0.018092 +vt 1.000000 1.000000 +vt 0.937500 1.000000 +vt 0.875000 1.000000 +vt 0.875000 0.937500 +vt 0.875000 0.875000 +vt 0.937500 0.875000 +vt 1.000000 0.875000 +vt 1.000000 0.937500 +vt 0.750000 1.000000 +vt 0.750000 0.500000 +vt 0.875000 0.500000 +vt 0.625000 0.500000 +vt 0.625000 1.000000 +vt 0.500000 1.000000 +vt 0.500000 0.500000 +vt 0.375000 0.500000 +vt 0.375000 1.000000 +vt 0.250000 1.000000 +vt 0.250000 0.500000 +vt 0.125000 0.500000 +vt 0.125000 1.000000 +vt -0.000000 1.000000 +vt 0.000000 0.500000 +vt 0.875000 -0.000000 +vt 1.000000 0.000000 +vt 1.000000 0.500000 +vt 1.000000 0.750000 +vt 1.000000 0.812500 +vt 0.875000 0.812500 +vt 0.875000 0.750000 +vt 0.937500 0.750000 +vt 0.125000 -0.000000 +vt -0.000000 -0.000000 +vt 0.375000 -0.000000 +vt 0.250000 -0.000000 +vt 0.625000 0.000000 +vt 0.500000 -0.000000 +vt 0.750000 0.000000 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +vn 0.3128 0.0000 0.0181 +usemtl Material +s off +f 1/1/1 36/2/1 2/3/1 26/4/1 3/5/1 31/6/1 4/7/1 21/8/1 +f 32/3/2 7/9/2 11/10/2 33/11/2 +f 40/12/3 37/13/3 6/14/3 18/15/3 +f 30/16/4 27/17/4 7/18/4 19/19/4 +f 35/20/5 32/21/5 8/22/5 20/23/5 +f 25/11/6 21/24/6 4/25/6 20/26/6 +f 22/21/7 8/22/7 12/23/7 23/20/7 +f 27/13/8 6/14/8 10/15/8 28/12/8 +f 37/17/9 5/18/9 9/19/9 38/16/9 +f 13/27/10 24/28/10 16/7/10 34/6/10 15/5/10 29/29/10 14/30/10 39/31/10 +f 22/3/11 25/11/11 20/26/11 8/1/11 +f 31/32/12 35/20/12 20/23/12 4/33/12 +f 26/34/13 30/16/13 19/19/13 3/35/13 +f 36/36/14 40/12/14 18/15/14 2/37/14 +f 28/12/15 10/15/15 14/37/15 29/36/15 +f 38/16/16 9/19/16 13/35/16 39/34/16 +f 33/11/17 11/10/17 15/38/17 34/24/17 +f 23/20/18 12/23/18 16/33/18 24/32/18 +f 9/19/19 23/20/19 24/32/19 13/35/19 +f 5/9/20 17/10/20 25/11/20 22/3/20 +f 5/18/21 22/21/21 23/20/21 9/19/21 +f 17/10/22 1/38/22 21/24/22 25/11/22 +f 11/10/23 28/12/23 29/36/23 15/38/23 +f 2/37/24 18/15/24 30/16/24 26/34/24 +f 7/9/25 27/13/25 28/12/25 11/10/25 +f 18/15/26 6/14/26 27/17/26 30/16/26 +f 12/26/27 33/11/27 34/24/27 16/25/27 +f 3/35/28 19/19/28 35/20/28 31/32/28 +f 19/19/29 7/18/29 32/21/29 35/20/29 +f 8/1/30 32/3/30 33/11/30 12/26/30 +f 10/15/31 38/16/31 39/34/31 14/37/31 +f 1/38/32 17/10/32 40/12/32 36/36/32 +f 6/14/33 37/17/33 38/16/33 10/15/33 +f 17/10/34 5/9/34 37/13/34 40/12/34 diff --git a/advtrains_line_automation/models/license.txt b/advtrains_line_automation/models/license.txt new file mode 100644 index 0000000..dae06a8 --- /dev/null +++ b/advtrains_line_automation/models/license.txt @@ -0,0 +1,5 @@ +advtrains_tuber.obj + Author: Hume2 + Source: https://gitlab.com/h2mm/underch underch_dark_tuber.obj (Underground Challenge) + Modified (rotated) + License: CC0 diff --git a/advtrains_line_automation/station_announcement.lua b/advtrains_line_automation/station_announcement.lua index c20fa3c..ef4fc01 100644 --- a/advtrains_line_automation/station_announcement.lua +++ b/advtrains_line_automation/station_announcement.lua @@ -1,6 +1,14 @@ -local def +local al = advtrains.lines local F = core.formspec_escape local ifthenelse = assert(ch_core.ifthenelse) +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_signs_api = core.get_modpath("signs_api") +local has_unifieddyes = core.get_modpath("unifieddyes") +local rozhlas_node_name = "advtrains_line_automation:stanicni_rozhlas_experimental" local PAGE_SETUP_1 = 1 local PAGE_SETUP_2 = 2 @@ -75,32 +83,64 @@ local hl_texty_id_to_idx = function() 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 + return true, n, n, align end local min, max = s:match("^(%d*)-(%d*)$") if min == nil then - return false, nil, nil -- bad format + return false, nil, nil, nil -- bad format end min, max = tonumber(min), tonumber(max) if min ~= nil and min > 256 then min = 256 end @@ -108,9 +148,10 @@ local function lengths_from_string(s) if min ~= nil and max ~= nil and min > max then min = max end - return true, min, max + return true, min, max, align end +--[[ (obsolete) local function lengths_to_string(min, max) if min == nil then if max ~= nil then @@ -126,6 +167,7 @@ local function lengths_to_string(min, max) return min.."-"..max end end +]] local alphanum_chars_set = { ["a"] = true, ["A"] = true, ["á"] = true, ["Á"] = true, ["ä"] = true, ["Ä"] = true, ["b"] = true, ["B"] = true, ["č"] = true, @@ -163,22 +205,32 @@ local function dosadit(format, data, defaults) break end local tag = format:sub(b + 1, e - 1) + local tag_name = tag local tagfmt, tagalt = "" - local j = tag:find("|", 1, true) - if j ~= nil then - tagalt = tag:sub(j + 1, -1) - tag = tag:sub(1, j - 1) - end - j = tag:find(":", 1, true) - if j ~= nil then - tagfmt = tag:sub(j + 1, -1) - tag = tag:sub(1, j - 1) + 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) + print("DEBUG: b2 == "..b2.." e2 = "..e2.." #tag = "..#tag) + 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 + local min, max, align if tagfmt ~= "" then local success - success, min, max = lengths_from_string(tagfmt) + success, min, max, align = lengths_from_string(tagfmt) end + tag = tag_name + -- print("DEBUG: tag("..tag..") tagname("..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 @@ -190,20 +242,59 @@ local function dosadit(format, data, defaults) 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 - table.insert(result, value) - table.insert(result, string.rep(" ", min - len)) + -- ř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))) + print("DEBUG: value \""..value.."\" align(center) min("..min..") => \""..string.rep(" ", math.floor(missing / 2))..value..string.rep(" ", missing - math.floor(missing / 2)).."\"") + end elseif max ~= nil and len > max then - table.insert(result, ch_core.utf8_truncate_right(value, max)) + -- ř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)) + print("DEBUG: value \""..value.."\" align(left) max("..max..") => \""..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)) + print("DEBUG: value \""..value.."\" align(right) max("..max..") => \""..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)) + print("DEBUG: value \""..value.."\" align(center) max("..max..") => \""..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)) + print("DEBUG: result: "..dump2(result)) return table.concat(result) end +-- DEBUG: +local dosadit_inner = dosadit +dosadit = function(format, data, defaults) + local result = dosadit_inner(format, data, defaults) + print("DEBUG: dosadit(): "..dump2({format = format, data = data, defaults = defaults, result = result})) + return result +end +-- ------------------ + local function sestavit_hlaseni(settings, settings_override, data, defaults) local parts = {} local function a(s) @@ -216,7 +307,7 @@ local function sestavit_hlaseni(settings, settings_override, data, defaults) local key = "tx_"..id local result = settings_override[key] or settings[key] if result == nil then - local def = assert(hl_texty_id_to_idx[id]) + local def = assert(hl_texty[hl_texty_id_to_idx[id]]) result = assert(def.default or def.sample) end return result @@ -236,6 +327,7 @@ local function sestavit_hlaseni(settings, settings_override, data, defaults) end if data.VYCHOZI ~= nil then a(t("zesm")) + a("{SEP}") a(t("prijnk")) else a(t("prisnk")) @@ -276,6 +368,7 @@ local function sestavit_hlaseni(settings, settings_override, data, defaults) end s = s:gsub("^{SEP}", "") s = s:gsub("{SEP}$", "") + s = s:gsub("{SEP}", " ") return s end @@ -292,15 +385,35 @@ local function get_or_add_anns(stn) return anns end -local function get_ann_data(stn, epos, make_copy) +local function init_ann_data(stn, epos) local anns = get_or_add_anns(stn) if anns == nil then - return {} + return end - local ann = anns[epos] - if ann == nil then - return {} + local result = { + chat_dosah = 50, + fmt_cedule1 = "", fmt_cedule2 = "", fmt_cedule3 = "", fmt_cedule4 = "", + fmt_negdelay = "-{}", + fmt_prradek = {""}, + fmt_radek = {""}, + fn_firstupper = false, + fs_koleje = "", + koleje = "", + pos_cedule1_fs = "", pos_cedule2_fs = "", pos_cedule3_fs = "", pos_cedule4_fs = "", + pos_cedule1_pos = vector.zero(), pos_cedule2_pos = vector.zero(), pos_cedule3_pos = vector.zero(), pos_cedule4_pos = vector.zero(), + version = 1, + } + 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 return table.copy(ann) else @@ -325,11 +438,90 @@ local function set_ann_data(stn, epos, data) 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) + 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í: + if i < 1 or i > 4 then + return false, "Chybný index." + end + + -- připojit: + local s = string.format("%d,%d,%d", sign_pos.x, sign_pos.y, sign_pos.z) + set_ann_data(stn, epos, { + ["pos_cedule"..i.."_fs"] = F(s), + ["pos_cedule"..i.."_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) + if data == nil then + return false, "Data staničního rozhlasu nebyla nalezena." + end + + -- zkontrolovat zadání: + if i < 1 or i > 4 then + return false, "Chybný index." + end + + local key = "pos_cedule"..i.."_fs" + if data[key] == nil or data[key] == "" then + return false, "Cedule není připojena." + end + + -- odpojit: + set_ann_data(stn, epos, { + [key.."_fs"] = "", + [key.."_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 ~= "advtrains_line_automation:stanicni_rozhlas" then + if node.name ~= rozhlas_node_name then core.chat_send_player(player_name, "CHYBA: staniční rozhlas nenalezen!") return end @@ -356,12 +548,7 @@ local function init_formspec_callback(custom_state, player, formname, fields) meta:set_string("infotext", "staniční rozhlas ("..(stdata.name or "???")..")") meta:set_string("owner", player_name) meta:set_string("stn", stn) - local anns = stdata.anns - if anns == nil then - anns = {} - stdata.anns = anns - end - anns[custom_state.epos] = {} + init_ann_data(stn, custom_state.epos) core.chat_send_player(player_name, "*** Úspěšně nastaveno.") print("DEBUG: D") end @@ -370,7 +557,6 @@ end local function get_setup_formspec(custom_state) local player_name = assert(custom_state.player_name) - local is_admin = assert(custom_state.is_admin) local page = assert(custom_state.page) local stations = assert(custom_state.stations) local stn = custom_state.stn @@ -381,11 +567,11 @@ local function get_setup_formspec(custom_state) "size[15,16.5]".. -- "style_type[textarea;font=mono]".. "tabheader[0,0;0.75;tab;Nastavení 1,Nastavení 2,Import/export nastavení,Nápověda", - ifthenelse(is_admin, ",Vlastnictví;", ";"), + 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;advtrains_line_automation:stanicni_rozhlas]".. - "label[1.75,1;staniční rozhlas]".. + "item_image[0.5,0.5;1,1;"..rozhlas_node_name.."]".. + "label[1.75,1;staniční rozhlas (experimentální)]".. "label[9,0.75;vlastník/ice:\n", ch_core.prihlasovaci_na_zobrazovaci(custom_state.owner), "]", @@ -413,7 +599,7 @@ local function get_setup_formspec(custom_state) "]container_end[]", -- ---- "container[0.5,2.75]".. - "label[0,0.25;Formátování na cedule ({1}, {2} atd.):]".. + "label[0,0.25;Formátování na cedule:]".. "checkbox[5.5,0.25;fn_firstupper;první písmeno řádky vždy velké;", ifthenelse(ifthenelse(custom_state.fn_firstupper ~= nil, custom_state.fn_firstupper, data.fn_firstupper), "true", "false"), "]textarea[0,1;13.25,1.5;fmt_radek;formát řádků s odjezdem:;", @@ -432,24 +618,28 @@ local function get_setup_formspec(custom_state) "a poslední se použije i pro všechny následující.]".. "container_end[]".. "container[0.5,7.5]".. - "label[0,0;formát záp. zpoždění (lze {}):]".. - - "field[0,0.25;3.25,0.75;fmt_negdelay;formát záp. zpoždění (lze {}):;", - F(data.fmt_negdelay or "-{}"), - "tooltip[fmt_negdelay;Formát v tomto poli se použije pro záporné zpoždění.\n".. - "Značka {} se nahradí absolutní hodnotou záporného zpoždění.]".. + "field[0,0.25;3.25,0.75;fmt_nodelay;bez zpoždění;", F(data.fmt_nodelay or ""), "]".. + "field[4,0.25;3.25,0.75;fmt_delay;zpoždění ({} = číslo);", F(data.fmt_delay or "{}"), "]".. + "field[8,0.25;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í.".. + "Značka {} se nahradí absolutní hodnotou počtu sekund záporného zpoždění.]".. "textarea[0,1;13.25,2;;;", - F("Značky, které můžete použít ve formátu řádků s odjezdem: {LINKA}, {VYCHOZI}, {CIL}, {KOLEJ}, {PRIJZA}, {ODJZA}, ".. - "{ZPOZDENI}, {PREDCH}, {NASL}, {JMVLAKU}, {TYP}, {TYPVLAKU}. ".. - "Příklady stanovení délky: {LINKA:4} (pevná délka), {LINKA:4-} (min. délka), {LINKA:-4} (max. délka), {LINKA:2-4} ".. - "(délka v rozmezí). Příklady náhradního textu: {LINKA|-}, {LINKA:3|-}. Zopakování symbolu (symbol nesmí být písmeno, ".. - "číslice, {, }, : ani |, lze použít i ve formátu prázdných řádků: {.:7}, { :4}.)"), + F("Podporované značky: {LINKA}, {VYCHOZI}, {CIL}, {KOLEJ}, {PRIJZA}, {ODJZA}, ".. + "{ZPOZDENI}, {PREDCH}, {NASL}, {POLOHA}, {JMVLAKU}, {TYP}, {TYPVLAKU}.\n".. + "Formátovací specifikace: {LINKA:4} (pevná délka), {LINKA:4-} (min. délka), {LINKA:-4} (max. délka), {LINKA:2-4} ".. + "(délka v rozmezí).\nNáhradní text: {LINKA|-}, {LINKA:3|není}.\nZopakování symbolu (symbol nesmí být písmeno, ".. + "číslice, {, }, : ani |, symbol může být mezera, lze použít i ve formátu prázdných řádků: {.:7}, { :4}.)"), "]container_end[]".. "container[0.5,10.5]".. - "box[0,0.15;14,0.05;#000000FF]".. - "label[7,0.5;dosah hlášení v četu \\[m\\] (0=vyp):]".. + "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(custom_state.chat_dosah or data.chat_dosah or "50"), + 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:]".. @@ -459,7 +649,7 @@ local function get_setup_formspec(custom_state) local id = "tx_"..def.id a(def.fs_sample) a(",") - a(F(custom_state[id] or data[id] or def.default or def.sample)) + a(F(data[id] or def.default or def.sample)) a(",") end formspec[#formspec] = ";"..(custom_state.tx_index or "").."]" @@ -467,7 +657,7 @@ local function get_setup_formspec(custom_state) if custom_state.tx_index ~= nil then local def = assert(hl_texty[custom_state.tx_index]) local id = "tx_"..def.id - local s = custom_state[id] or data[id] + local s = data[id] if s ~= nil then a(F(s)) else @@ -491,7 +681,9 @@ local function get_setup_formspec(custom_state) KOLEJ = "A", }) a(F(hlaseni)) - a("]container_end[]"--[[.. + a("]") + ]] + a("container_end[]"--[[.. -- ---- "container[0.5,9.25]".. "label[0,0.25;Formáty řádků ({1}, {2} atd.):]".. @@ -499,9 +691,43 @@ local function get_setup_formspec(custom_state) ) a("button[0.5,15;14,1;btn_save;Uložit]") elseif page == PAGE_SETUP_2 then + for i = 1, 4 do + local s = tostring(i) + local fs_pos_cedule = data["pos_cedule"..s.."_fs"] or "" + a{ "container[0.5,"..(2 * i - 2 + 6).."]".. + "textarea[0,0.5;13.25,1.5;fmt_cedule", s, ";cedule ", s, ":;", + CF(data["fmt_cedule"..s]), + "]field[2,0;4.5,0.5;pos_cedule", s, ";;", + fs_pos_cedule or "", + "]button[6.75,0;3,0.5;", + ifthenelse(fs_pos_cedule ~= "", "odp_cedule"..s..";odpojit", "pri_cedule"..s..";připojit"), + "]button_exit[10,0;3,0.5;zam_cedule", s, ";zaměřit...]".. + "container_end[]", + } + end + a{"label[0.5,14.5;", CF(custom_state.message), + "]button[0.5,15;14,1;btn_save;Uložit]"} elseif page == PAGE_IMPORT then + a{ + "textarea[0.5,2.5;14,10;nastaveni;nastavení ve formátu JSON:;", + -- CF(core.write_json(data, true)), + "(Zatím neimplementováno)", + "]label[0.5,13;", + CF(custom_state.message), + "]".. -- "button[0.5,13.5;14,1;importovat;importovat zadané nastavení a uložit]".. + "button_exit[0.5,15;14,1;close2;zavřít]", + } + elseif page == PAGE_HELP then - elseif is_admin and page == PAGE_OWNERSHIP then + 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 @@ -509,6 +735,10 @@ end local function setup_formspec_callback(custom_state, player, formname, fields) print("DEBUG: setup_formspec_callback(): "..dump2({custom_state = custom_state, fields = fields, player_name = custom_state.player_name})) 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 @@ -540,9 +770,24 @@ local function setup_formspec_callback(custom_state, player, formname, fields) table.insert(list, part) end end - table.sort(list, function(a, b) return a < b end) - data.koleje = set - data.fs_koleje = F(table.concat(list, ",")) + 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 @@ -559,18 +804,39 @@ local function setup_formspec_callback(custom_state, player, formname, fields) end 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 - print("DEBUG: rozhlas moved from "..stn.." to "..new_stn) + meta:set_string("stn", new_stn) stn = new_stn custom_state.stn = new_stn end @@ -578,11 +844,82 @@ local function setup_formspec_callback(custom_state, player, formname, fields) set_ann_data(stn, custom_state.epos, data) end elseif page == PAGE_SETUP_2 then + if fields.btn_save then + for i = 1, 4 do + data["fmt_cedule"..i] = assert(fields["fmt_cedule"..i]) + end + set_ann_data(stn, custom_state.epos, data) + 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) + 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) + 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_IMPORT then + if fields.importovat then + local s = assert(fields.nastaveni) + -- TODO + end elseif page == PAGE_HELP then + -- nic elseif page == PAGE_OWNERSHIP then - if is_admin then - -- TODO + 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 + 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 @@ -593,6 +930,7 @@ local function setup_formspec_callback(custom_state, player, formname, fields) (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 @@ -601,6 +939,229 @@ local function setup_formspec_callback(custom_state, player, formname, fields) end end +local debug_counter = 0 + +local function update_ann(stn, epos, signs, deps, rwtime) + print("DEBUG: update_ann(): "..dump2({stn = stn, epos = epos, signs = signs, deps = deps, rwtime = 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 = ann.koleje + if tracks ~= nil and type(tracks) ~= "table" then + if tracks == "" then + tracks = nil + else + tracks = {[tracks] = true} + end + end + -- print("DEBUG: "..dump2({tracks = tracks})) + local lines = {} + -- update_ann(assert(stn), assert(ann.rozh_epos), signs, deps) + for _, dep in ipairs(deps) do + if (tracks == nil or tracks[dep.track]) and (dep.dep == nil or dep.dep > rwtime) then + local linevar_def = dep.linevar_def + local stops = linevar_def.stops + local line = {} + line.LINKA = linevar_def.line or "" + line.VYCHOZI = al.get_line_description(linevar_def, {line_number = false, first_stop = true, last_stop = false}) + line.CIL = dep.destination + print("DEBUG: CIL = '"..line.CIL.."'") + if dep.track ~= "" then + line.KOLEJ = dep.track + end + if dep.arr ~= nil then + line.PRIJZA = math.ceil((dep.arr - rwtime) / 5) * 5 + end + if dep.dep ~= nil then + line.ODJZA = math.ceil((dep.dep - rwtime) / 5) * 5 + end + local abs_delay = math.abs(dep.delay) + if abs_delay < 5 then + line.ZPOZDENI = ann.fmt_nodelay or "" + else + line.ZPOZDENI = dosadit( + ifthenelse(dep.delay > 0, ann.fmt_delay or "{}", ann.fmt_negdelay or "-{}"), + {[""] = tostring(5 * math.ceil(abs_delay / 5))} + ) + end + -- PREDCH + if dep.prev_stop ~= nil then + line.PREDCH = dep.prev_stop + end + -- NASL + if dep.next_stop ~= nil then + line.NASL = dep.next_stop + end + -- POLOHA + if dep.last_pos ~= nil then + line.POLOHA = dep.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" + debug_counter = debug_counter + 1 + line.POCITADLO = tostring(debug_counter) + -- print("DEBUG: line filled: "..dump2({line = line})) + table.insert(lines, line) + end + end + local full_fmt, empty_fmt = ann.fmt_radek[1] or "", ann.fmt_prradek[1] or "" + local formatted_lines = {} + for i = 1, 9 do + if i > 1 then + if ann.fmt_radek[i] ~= nil then + full_fmt = ann.fmt_radek[i] + end + if ann.fmt_prradek[i] ~= nil then + empty_fmt = ann.fmt_prradek[i] + end + end + local s + if lines[i] ~= nil then + s = dosadit(full_fmt, lines[i]) + else + s = dosadit(empty_fmt, {}) + end + 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)] = s + end + --[[print("DEBUG: formatted lines: "..dump2({formatted_lines = formatted_lines, fmt_radek = ann.fmt_radek, fmt_prradek = ann.fmt_prradek, + full_fmt = full_fmt, empty_fmt = empty_fmt}))]] + if signs ~= nil then + for i = 1, 4 do + local sign_pos = signs[i] + if sign_pos ~= nil and core.compare_block_status(sign_pos, "active") then + local s = dosadit(ann["fmt_cedule"..i] or "", 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 function globalstep(dtime) + globalstep_time = globalstep_time + dtime + if globalstep_time < 0 then + return + end + print("DEBUG: globalstep...") + globalstep_time = globalstep_time - 5 + + local rwtime = rwt.to_secs(rwt.get_time()) + -- 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 signs_count = 0 + for i = 1, 4 do + local s = ann["pos_cedule"..i.."_fs"] + if s ~= nil and s ~= "" then + local sign_pos = assert(ann["pos_cedule"..i.."_pos"]) + if core.compare_block_status(sign_pos, "active") then + signs[i] = sign_pos + signs_count = signs_count + 1 + end + end + end + if signs_count > 0 then + -- nějaké cedule jsou aktivní + -- print("DEBUG: - "..rozh_epos.." : added ("..stn.."), because has "..signs_count.." active signs") + 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 + print("DEBUG: - "..rozh_epos.." : added ("..stn.."), because is active") + table.insert(goa(subscriptions, stn), {rozh_pos = rozh_pos, rozh_epos = rozh_epos, rozh_def = ann}) + end + end + else + -- print("DEBUG: - "..stn.." not added (anns: "..ifthenelse(stdata.anns == nil, "nil", "non-nil")..")") + end + end + + -- Shromáždit vlaky: + local deps_by_stn = {} + for stn, _ in pairs(subscriptions) do + deps_by_stn[stn] = {} + end + 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) + local last_pos = al.get_last_pos_station_name(ls) + local destination = "???" + for i = #prediction, 1, -1 do + local p = prediction[i] + if not p.hidden then + destination = al.get_station_name(p.stn) + break + end + end + for _, record in ipairs(prediction) do + local deps = deps_by_stn[record.stn] + if deps ~= nil and record.dep ~= nil then + local record_index = assert(record.index) + local other_index, other_data = al.get_prev_stop(linevar_def, record_index, false) + if other_index ~= nil then + record.prev_stop = al.get_station_name(other_data.stn) + end + other_index, other_data = al.get_next_stop(linevar_def, record_index, false) + if other_index ~= nil then + record.next_stop = al.get_station_name(other_data.stn) + end + record.last_pos = last_pos -- název poslední dopravny, kde byl vlak spatřen + record.linevar = linevar_def.name + record.linevar_def = linevar_def + record.destination = destination + table.insert(deps, record) + end + end + end + end + + -- Aktualizovat rozhlasy: + for stn, deps in pairs(deps_by_stn) do + table.sort(deps, function(a, b) return assert(a.dep) < assert(b.dep) end) + for _, ann in ipairs(subscriptions[stn]) do + update_ann(assert(stn), assert(ann.rozh_epos), ann.signs, deps, rwtime) + 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") @@ -629,7 +1190,12 @@ end local function on_dig(pos, node, digger) -- TODO? - return core.node_dig(pos, node, digger) + -- return core.node_dig(pos, node, digger) + 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) @@ -675,7 +1241,7 @@ local function on_rightclick(pos, node, clicker, itemstack, pointed_thing) "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;advtrains_line_automation:stanicni_rozhlas]".. + "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]".. @@ -688,6 +1254,7 @@ local function on_rightclick(pos, node, clicker, itemstack, pointed_thing) 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, ";]") @@ -703,6 +1270,7 @@ local function on_rightclick(pos, node, clicker, itemstack, pointed_thing) local stdata = advtrains.lines.stations[stn] if stdata == nil or stdata.anns == nil or stdata.anns[epos] == nil then core.chat_send_player(player_name, "CHYBA: data dopravny nenalezena!") + print("DEBUG: stn = <"..stn..">") return end local stations = advtrains.lines.load_stations_for_formspec() @@ -734,16 +1302,62 @@ local function on_rightclick(pos, node, clicker, itemstack, pointed_thing) 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.25, -0.25, 0, 0.25, 0.25, 0.5}, + {-0.5, -0.4, -0.25, 0.5, 0.4, 0}, + }, +} + def = { - description = "staniční rozhlas", - tiles = {{name = "blank.png^[noalpha"}}, -- TODO - drawtype = "normal", + description = "staniční rozhlas [EXPERIMENTÁLNÍ]", + tiles = {{name = "default_steel_block.png", backface_culling = true}}, + drawtype = "mesh", + mesh = "advtrains_tuber.obj", paramtype = "light", - paramtype2 = "facedir", -- TODO: => colorfacedir + paramtype2 = "4dir", + selection_box = box, + collision_box = box, + groups = {oddly_breakable_by_hand = 3, ud_param2_colorable = 1, experimental = 1}, -- TODO + 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, } -core.register_node("advtrains_line_automation:stanicni_rozhlas", def) +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) + diff --git a/advtrains_line_automation/structs.md b/advtrains_line_automation/structs.md index 9b8d27d..cffb940 100644 --- a/advtrains_line_automation/structs.md +++ b/advtrains_line_automation/structs.md @@ -102,7 +102,44 @@ station = { }, anns = { -- staniční rozhlasy [encoded_pos] = { - ... + -- dosah zpráv v četu (>= 0, nil znamená 50): + chat_dosah = int or nil, + + -- formát jednotlivých cedulí, může používat značky {1} až {9} a může mít víc řádků + fmt_cedule[1234] = string or nil, + + -- formát pro záporné zpoždění; nil znamená "-{}" + fmt_negdelay = string or nil, + + -- pole formátů pro prázdné řádky (vždy obsahuje alespoň prvek [1]) + fmt_prradek = {string...} or nil, + + -- pole formátů pro řádky s odjezdy (vždy obsahuje alespoň prvek [1]) + fmt_radek = {string...} or nil, + + -- udává, zda na cedulích bude první znak každého řádku převeden na velké písmeno: + fn_firstupper = bool, + + -- obsah pole "koleje" zformátovaný pro použití ve formspecu; prázdný řetězec "" znamená, že st. rozhlas platí pro všechny koleje + -- a na .koleje pak nezáleží + fs_koleje = string or nil, + + -- pokud st. rozhlas není omezený na určité koleje, nil nebo "" + -- je-li omezen na jednu konkrétní kolej, pak jde o název této koleje + -- je-li omezen na více kolejí, pak jde o množinu indexovanou označeními kolejí + koleje = {[string] = true, ...} or string or nil, + + -- pozice připojených cedulí ve tvaru pro použití ve formspecu, nebo "", pokud daná cedule není připojená + pos_cedule[1234]_fs = string or nil, + + -- pozice připojených cedulí ve formě vektoru + pos_cedule[1234]_pos = vector or nil, + + -- číslo verze systému staničního rozhlasu (pro detekci zastaralých rozhlasů) + version = int, + + -- řetězce pro formátování hlášení v četu; nemusí být uvedeny všechny, nil znamená použít výchozí text + tx_* = string or nil, } } } |