aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authororwell <orwell@bleipb.de>2025-05-27 21:03:14 +0200
committerorwell <orwell@bleipb.de>2025-05-27 21:03:14 +0200
commit8506dd2825b715293138976a5ad1fa11a46206a7 (patch)
tree1f48c1dc03c3bbc6ed6762bd04d10e543a3a580c
parent2a9891577c1b00068cc4ec858c7dc6c5196f0a2b (diff)
parentadc01a0bba29b40278e45c50caa954c435374f7b (diff)
downloadadvtrains-8506dd2825b715293138976a5ad1fa11a46206a7.tar.gz
advtrains-8506dd2825b715293138976a5ad1fa11a46206a7.tar.bz2
advtrains-8506dd2825b715293138976a5ad1fa11a46206a7.zip
Merge branch 'master' into cesky-hvozd
Throw away most of the changes in everything except line_automation. Merge line_automation changes between CH and master
-rw-r--r--advtrains/helpers.lua66
-rw-r--r--advtrains/init.lua93
l---------advtrains/locale/README.md1
-rw-r--r--advtrains/po/README.md70
-rw-r--r--advtrains/po/advtrains.pot957
-rw-r--r--advtrains/po/de.po1071
-rw-r--r--advtrains/po/fr.po1084
-rwxr-xr-xadvtrains/po/update-translations.sh29
-rw-r--r--advtrains/po/zh_CN.po1043
-rw-r--r--advtrains/po/zh_TW.po1043
-rw-r--r--advtrains/poconvert.lua185
-rw-r--r--advtrains/protection.lua25
-rw-r--r--advtrains/signals.lua74
-rw-r--r--advtrains/track_reg_helper.lua79
-rw-r--r--advtrains/tracks.lua546
-rw-r--r--advtrains/wagons.lua259
-rw-r--r--advtrains_interlocking/ars.lua296
-rw-r--r--advtrains_interlocking/database.lua10
-rw-r--r--advtrains_interlocking/init.lua4
-rw-r--r--advtrains_interlocking/route_prog.lua96
-rw-r--r--advtrains_interlocking/route_ui.lua58
-rw-r--r--advtrains_interlocking/routesetting.lua85
-rw-r--r--advtrains_interlocking/signal_api.lua2
-rw-r--r--advtrains_interlocking/signal_aspect_ui.lua42
-rw-r--r--advtrains_interlocking/smartroute.lua41
-rw-r--r--advtrains_interlocking/tcb_ts_ui.lua266
-rw-r--r--advtrains_interlocking/tool.lua31
-rw-r--r--advtrains_line_automation/init.lua2
-rw-r--r--advtrains_line_automation/scheduler.lua2
-rw-r--r--advtrains_line_automation/stoprail.lua19
-rwxr-xr-xadvtrains_luaautomation/README.md466
-rw-r--r--advtrains_luaautomation/active_common.lua206
-rw-r--r--advtrains_luaautomation/atc_rail.lua291
-rwxr-xr-xadvtrains_luaautomation/environment.lua399
-rw-r--r--advtrains_luaautomation/init.lua120
-rw-r--r--advtrains_luaautomation/mesecon_controller.lua260
-rw-r--r--advtrains_luaautomation/operation_panel.lua29
-rw-r--r--advtrains_luaautomation/pcnaming.lua93
-rw-r--r--advtrains_luaautomation/recipes.lua27
-rw-r--r--advtrains_luaautomation/settingtypes.txt2
-rw-r--r--advtrains_signals_japan/.gitignore1
-rw-r--r--advtrains_signals_japan/init.lua474
-rw-r--r--advtrains_signals_japan/mod.conf6
-rw-r--r--advtrains_signals_japan/textures/advtrains_signals_japan_mast.pngbin0 -> 180 bytes
-rw-r--r--advtrains_signals_ks/init.lua264
-rw-r--r--advtrains_signals_ks/textures/advtrains_signals_ks_mast.pngbin201 -> 180 bytes
-rw-r--r--advtrains_signals_muc_ubahn/init.lua116
-rw-r--r--advtrains_signals_muc_ubahn/mod.conf5
-rw-r--r--advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_l.obj2137
-rw-r--r--advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_r.obj2137
-rw-r--r--advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_t.mtl12
-rw-r--r--advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_t.obj2138
-rw-r--r--advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp0.pngbin0 -> 4991 bytes
-rw-r--r--advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp1.pngbin0 -> 4985 bytes
-rw-r--r--advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp2.pngbin0 -> 5048 bytes
-rw-r--r--advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp3.pngbin0 -> 4984 bytes
-rwxr-xr-xadvtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_template.pngbin0 -> 5395 bytes
-rw-r--r--advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_vr0.pngbin0 -> 5055 bytes
-rw-r--r--advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_vr1.pngbin0 -> 5047 bytes
-rw-r--r--advtrains_trackmap/mod.conf2
-rw-r--r--advtrains_trackmap/viewer.lua24
-rw-r--r--advtrains_train_track/init.lua267
-rw-r--r--assets/mm_trains_bvbg.pngbin0 -> 31081 bytes
-rw-r--r--assets/muc_ubahn_uvs.pngbin0 -> 93694 bytes
-rw-r--r--assets/signal_wall.blend1bin0 -> 602788 bytes
-rw-r--r--assets/signal_wall_ceiling_muc_ubahn.blendbin0 -> 603780 bytes
-rw-r--r--assets/signal_wall_muc_ubahn.blendbin0 -> 603780 bytes
67 files changed, 15597 insertions, 1458 deletions
diff --git a/advtrains/helpers.lua b/advtrains/helpers.lua
index 6f5d1eb..e58625f 100644
--- a/advtrains/helpers.lua
+++ b/advtrains/helpers.lua
@@ -236,11 +236,10 @@ function advtrains.is_damage_enabled(name)
if not name then
error("advtrains.is_damage_enabled() called without name parameter!")
end
- return not minetest.check_player_privs(name, "train_ghost")
- --[[ if minetest.check_player_privs(name, "train_admin") then
+ if minetest.check_player_privs(name, "train_admin") then
return false
end
- return minetest.settings:get_bool("enable_damage") ]]
+ return minetest.settings:get_bool("enable_damage")
end
function advtrains.ms_to_kmh(speed)
@@ -472,11 +471,16 @@ function advtrains.position_in_range(pos, range)
return false
end
---[[
local active_node_range = tonumber(minetest.settings:get("active_block_range"))*16 + 16
-- Function to check whether node at position(pos) is "loaded"/"active"
-- That is, whether it is within the active_block_range to a player
-if minetest.is_block_active then -- define function differently whether minetest.is_block_active is available or not
+if core.compare_block_status then
+ -- latest API
+ function advtrains.is_node_loaded(pos)
+ return core.compare_block_status(pos, "active")
+ end
+elseif minetest.is_block_active then -- define function differently whether minetest.is_block_active is available or not
+ -- API added by my PR but later superseded by the above and now removed
advtrains.is_node_loaded = minetest.is_block_active
else
function advtrains.is_node_loaded(pos)
@@ -485,58 +489,6 @@ else
end
end
end
-]]
-function advtrains.is_node_loaded(pos)
- return minetest.compare_block_status(pos, "loaded") -- loaded, or active?
-end
-
-local variants = {
- {"0", 0},
- {"30", 0},
- {"45", 0},
- {"60", 0},
- {"0", 1},
- {"30", 1},
- {"45", 1},
- {"60", 1},
- {"0", 2},
- {"30", 2},
- {"45", 2},
- {"60", 2},
- {"0", 3},
- {"30", 3},
- {"45", 3},
- {"60", 3},
- {"0", 0},
- {"30", 0},
- {"45", 0},
- {"60", 0},
-}
-
-function advtrains.after_place_signal(pos, placer, itemstack, pointed_thing)
- if not minetest.is_player(placer) then return end
- local name = itemstack:get_name()
- if not name:match("_0$") then return end
- local rn = minetest.registered_nodes
- local prefix = name:sub(1, -2)
- if not (rn[prefix.."30"] and rn[prefix.."45"] and rn[prefix.."60"]) then return end
- local variant = math.floor(placer:get_look_horizontal() * -8 / math.pi + 16.25) % 16
- local n = variants[variant + 1]
- if n == nil then return end
- local node = advtrains.ndb.get_node(pos)
- if node.name ~= name then return end
- node.name = prefix..n[1]
- node.param2 = n[2]
- advtrains.ndb.swap_node(pos, node)
-end
-
-function advtrains.yaw_equals(yaw1, yaw2)
- if yaw1 ~= nil and yaw2 ~= nil then
- return math.abs(yaw2 - yaw1) < 1.0e-9
- else
- return yaw1 == yaw2
- end
-end
-- TrackIterator interface --
diff --git a/advtrains/init.lua b/advtrains/init.lua
index 9019571..91b2b58 100644
--- a/advtrains/init.lua
+++ b/advtrains/init.lua
@@ -1,3 +1,4 @@
+
--[[
Advanced Trains - Minetest Mod
@@ -21,9 +22,6 @@ Copyright (C) 2016-2020 Moritz Blei (orwell96) and contributors
local lot = os.clock()
minetest.log("action", "[advtrains] Loading...")
-local has_itrainmap = minetest.get_modpath("advtrains_itrainmap")
-local has_luaautomation = minetest.get_modpath("advtrains_luaautomation")
-
-- There is no need to support 0.4.x anymore given that the compatitability with it is already broken by 1bb1d825f46af3562554c12fba35a31b9f7973ff
attrans = minetest.get_translator ("advtrains")
function attrans_formspec(...)
@@ -75,7 +73,7 @@ end
local no_action=false
local function reload_saves()
- atwarn("Restoring saved state in 1 second...")
+ atwarn(S("Restoring saved state in 1 second..."))
no_action=true
advtrains.lock_path_inval = false
--read last save state and continue, as if server was restarted
@@ -86,7 +84,7 @@ local function reload_saves()
end
minetest.after(1, function()
advtrains.load()
- atwarn("Reload successful!")
+ atwarn(S("Reload successful!"))
advtrains.ndb.restore_all()
end)
end
@@ -155,6 +153,7 @@ end
atwarn=function(t, ...)
local text=advtrains.print_concat_table({t, ...})
minetest.log("warning", "[advtrains]"..text)
+ minetest.chat_send_all("[advtrains] -!- "..text)
end
sid=function(id) if id then return string.sub(id, -6) end end
@@ -163,6 +162,7 @@ sid=function(id) if id then return string.sub(id, -6) end end
atdebug=function(t, ...)
local text=advtrains.print_concat_table({t, ...})
minetest.log("action", "[advtrains]"..text)
+ minetest.chat_send_all("[advtrains]"..text)
end
if minetest.settings:get_bool("advtrains_enable_debugging") then
@@ -184,7 +184,7 @@ function assertt(var, typ)
end
end
-dofile(advtrains.modpath.."/helpers.lua");
+dofile(advtrains.modpath.."/helpers.lua")
--dofile(advtrains.modpath.."/debugitems.lua");
advtrains.meseconrules =
@@ -204,6 +204,8 @@ advtrains.meseconrules =
advtrains.fpath=minetest.get_worldpath().."/advtrains"
+advtrains.poconvert = dofile(advtrains.modpath.."/poconvert.lua")
+advtrains.poconvert.from_flat("advtrains")
attrans = minetest.get_translator("advtrains")
advtrains.speed = dofile(advtrains.modpath.."/speed.lua")
@@ -233,7 +235,7 @@ dofile(advtrains.modpath.."/craft_items.lua")
dofile(advtrains.modpath.."/log.lua")
dofile(advtrains.modpath.."/passive.lua")
-if minetest.get_modpath("mesecons") then
+if mesecon then
dofile(advtrains.modpath.."/p_mesecon_iface.lua")
end
@@ -347,7 +349,7 @@ function advtrains.avt_load()
end
end
for wid, _ in pairs(todel) do
- atwarn("Removing unused wagon", wid, "from wagon_save table.")
+ atwarn(S("Removing unused wagon"), wid, S("from wagon_save table."))
advtrains.wagon_save[wid]=nil
end
else
@@ -412,7 +414,7 @@ function advtrains.load_version_4()
end
end
for wid, _ in pairs(todel) do
- atwarn("Removing unused wagon", wid, "from wagon_save table.")
+ atwarn(S("Removing unused wagon"), wid, S("from wagon_save table."))
advtrains.wagon_save[wid]=nil
end
end
@@ -446,7 +448,7 @@ function advtrains.load_version_4()
end
--== load luaatc ==
- if has_luaautomation and atlatc then
+ if atlatc then
local la_save = serialize_lib.load_atomic(advtrains.fpath.."_atlatc.ls")
if la_save then
atlatc.load(la_save)
@@ -495,12 +497,12 @@ advtrains.avt_save = function(remove_players_from_wagons)
"text_outside", "text_inside", "line", "routingcode",
"il_sections", "speed_restriction", "speed_restrictions_t", "is_shunt",
"path_ori_cp", "autocouple", "atc_wait_autocouple", "ars_disable",
- "staticdata", "line_status",
+ "staticdata",
})
--then save it
tmp_trains[id]=v
else
- atwarn("Train",id,"had no wagons left because of some bug. It is being deleted. Wave it goodbye!")
+ atwarn(S("Train"),id,S("had no wagons left because of some bug. It is being deleted. Wave it goodbye!"))
advtrains.remove_train(id)
end
end
@@ -551,7 +553,7 @@ advtrains.avt_save = function(remove_players_from_wagons)
-- save of luaatc
local la_save
- if has_luaautomation and atlatc then
+ if atlatc then
la_save = atlatc.save()
end
@@ -581,7 +583,7 @@ advtrains.avt_save = function(remove_players_from_wagons)
local succ, err = serialize_lib.save_atomic_multiple(parts_table, advtrains.fpath.."_", callbacks_table)
if not succ then
- atwarn("Saving failed: "..err)
+ atwarn(S("Saving failed: ")..err)
else
-- store version
advtrains.save_component(4, "version")
@@ -636,10 +638,10 @@ minetest.register_globalstep(function(dtime_mt)
end
advtrains.mainloop_trainlogic(dtime,advtrains.mainloop_runcnt)
- if has_itrainmap and advtrains_itm_mainloop then
+ if advtrains_itm_mainloop then
advtrains_itm_mainloop(dtime)
end
- if has_luaautomation and atlatc then
+ if atlatc then
--atlatc.mainloop_stepcode(dtime)
atlatc.interrupt.mainloop(dtime)
end
@@ -668,10 +670,10 @@ end)
-- first time called in main loop (after the init phase) because luaautomation has to initialize first.
function advtrains.load()
advtrains.avt_load() --loading advtrains. includes ndb at advtrains.ndb.load_data()
- --if minetest.get_modpath("advtrains_luaautomation") and atlatc then
+ --if atlatc then
-- atlatc.load() --includes interrupts
--end == No longer loading here. Now part of avt_save() legacy loading.
- if has_itrainmap and advtrains_itm_init then
+ if advtrains_itm_init then
advtrains_itm_init()
end
init_load=true
@@ -684,7 +686,7 @@ end
function advtrains.save(remove_players_from_wagons)
if not init_load then
--wait... we haven't loaded yet?!
- atwarn("Instructed to save() but load() was never called!")
+ atwarn(S("Instructed to save() but load() was never called!"))
return
end
@@ -700,22 +702,12 @@ function advtrains.save(remove_players_from_wagons)
return
end
- local rwtime
- if advtrains.lines ~= nil and advtrains.lines.rwt ~= nil then
- local rwt = advtrains.lines.rwt
- rwtime = rwt.to_string(rwt.get_time())
- end
-
local t1 = os.clock()
advtrains.avt_save(remove_players_from_wagons) --saving advtrains. includes ndb at advtrains.ndb.save_data()
- if has_luaautomation and atlatc then
+ if atlatc then
atlatc.save()
end
- local message = "Saved advtrains save files, took "..tostring(math.floor((os.clock()-t1) * 1000)).."ms"
- if rwtime ~= nil then
- message = message.." rwtime="..rwtime
- end
- atlog(message)
+ atlog("Saved advtrains save files, took",math.floor((os.clock()-t1) * 1000),"ms")
-- Cleanup actions
--TODO very simple yet hacky workaround for the "green signals" bug
@@ -723,7 +715,7 @@ function advtrains.save(remove_players_from_wagons)
end
minetest.register_on_shutdown(function()
if within_mainstep then
- atwarn("Crash during advtrains main step - skipping the shutdown save operation to not save inconsistent data!")
+ atwarn(S("Crash during advtrains main step - skipping the shutdown save operation to not save inconsistent data!"))
else
advtrains.save()
end
@@ -735,10 +727,10 @@ end)
minetest.register_chatcommand("at_empty_seats",
{
params = "", -- Short parameter description
- description = attrans("Detach all players, especially the offline ones, from all trains. Use only when no one serious is on a train."), -- Full description
+ description = S("Detach all players, especially the offline ones, from all trains. Use only when no one serious is on a train."), -- Full description
privs = {train_operator=true, server=true}, -- Require the "privs" privilege to run
func = function(name, param)
- atwarn("Data is being saved. While saving, advtrains will remove the players from trains. Save files will be reloaded afterwards!")
+ atwarn(S("Data is being saved. While saving, advtrains will remove the players from trains. Save files will be reloaded afterwards!"))
advtrains.save(true)
reload_saves()
end,
@@ -747,60 +739,60 @@ minetest.register_chatcommand("at_empty_seats",
minetest.register_chatcommand("at_reroute",
{
params = "",
- description = attrans("Delete all train routes, force them to recalculate"),
+ description = S("Delete all train routes, force them to recalculate"),
privs = {train_operator=true}, -- Only train operator is required, since this is relatively safe.
func = function(name, param)
advtrains.invalidate_all_paths()
- return true, "Successfully invalidated train routes"
+ return true, S("Successfully invalidated train routes")
end,
})
minetest.register_chatcommand("at_whereis",
{
- params = attrans("<train id>"),
- description = attrans("Returns the position of the train with the given id"),
+ params = "<train id>",
+ description = S("Returns the position of the train with the given id"),
privs = {train_operator = true},
func = function(name,param)
local train = advtrains.trains[param]
if not train or not train.last_pos then
- return false, "Train "..param.." does not exist or is invalid"
+ return false, S("Train ")..param..S(" does not exist or is invalid")
else
- return true, "Train "..param.." is at "..minetest.pos_to_string(train.last_pos)
+ return true, S("Train ")..param..S(" is at ")..minetest.pos_to_string(train.last_pos)
end
end,
})
minetest.register_chatcommand("at_tp",
{
params = "<train id>",
- description = attrans("Teleports you to the position of the train with the given id"),
+ description = S("Teleports you to the position of the train with the given id"),
privs = {train_operator = true, teleport = true},
func = function(name,param)
local train = advtrains.trains[param]
if not train or not train.last_pos then
- return false, "Train "..param.." does not exist or is invalid"
+ return false, S("Train ")..param..S(" does not exist or is invalid")
else
minetest.get_player_by_name(name):set_pos(train.last_pos)
- return true, "Teleporting to train "..param
+ return true, S("Teleporting to train ")..param
end
end,
})
minetest.register_chatcommand("at_disable_step",
{
params = "<yes/no>",
- description = attrans("Disable the advtrains globalstep temporarily"),
+ description = S("Disable the advtrains globalstep temporarily"),
privs = {server=true},
func = function(name, param)
if minetest.is_yes(param) then
-- disable everything, and turn off saving
no_action = true;
- atwarn("The advtrains globalstep has been disabled. Trains are not moving, and no data is saved! Run '/at_disable_step no' to enable again!")
- return true, "Disabled advtrains successfully"
+ atwarn(S("The advtrains globalstep has been disabled. Trains are not moving, and no data is saved! Run '/at_disable_step no' to enable again!"))
+ return true, S("Disabled advtrains successfully")
elseif no_action then
- atwarn("Re-enabling advtrains globalstep...")
+ atwarn(S("Re-enabling advtrains globalstep..."))
reload_saves()
return true
else
- return false, "Advtrains is already running normally!"
+ return false, S("Advtrains is already running normally!")
end
end,
})
@@ -808,10 +800,10 @@ minetest.register_chatcommand("at_disable_step",
minetest.register_chatcommand("at_status",
{
params = "",
- description = attrans("Print advtrains status info"),
+ description = S("Print advtrains status info"),
privs = {train_operator = true},
func = function(name, param)
- return true, advtrains.print_concat_table({"Advtrains Status: no_action",no_action,"slowdown",advtrains.global_slowdown,"(log",math.log(advtrains.global_slowdown),")"})
+ return true, advtrains.print_concat_table({S("Advtrains Status: no_action"),no_action,S("slowdown"),advtrains.global_slowdown,S("(log"),math.log(advtrains.global_slowdown),")"})
end,
})
@@ -822,3 +814,4 @@ end
local tot=(os.clock()-lot)*1000
minetest.log("action", "[advtrains] Loaded in "..tot.."ms")
+
diff --git a/advtrains/locale/README.md b/advtrains/locale/README.md
new file mode 120000
index 0000000..61e473c
--- /dev/null
+++ b/advtrains/locale/README.md
@@ -0,0 +1 @@
+../po/README.md \ No newline at end of file
diff --git a/advtrains/po/README.md b/advtrains/po/README.md
new file mode 100644
index 0000000..3e94682
--- /dev/null
+++ b/advtrains/po/README.md
@@ -0,0 +1,70 @@
+# Translations
+Please read this document before working on any translations.
+
+Unlike many other mods, Advtrains uses `.po` files for localization,
+which are then automatically converted to `.tr` files when the mod is
+loaded. Therefore, please submit patches that edit the `.po` files.
+
+## Getting Started
+The translation files can be edited like any other `.po` file.
+
+If the translation file for your language does not exist, create it by
+copying `template.txt` to `advtrains.XX.tr`, where `XX` is replaced by
+the language code.
+
+Feel free to use the [discussion mailing list][srht-discuss] if you
+have any questions regarding localization.
+
+You can share your `.po` file directly or [as a patch][gsm] to the [dev
+mailing list][srht-devel]. The latter is encouraged, but, unlike code
+changes, translation files sent directly are also accepted.
+
+[tr-format]: https://minetest.gitlab.io/minetest/translations/#translation-file-format
+[srht-discuss]: https://lists.sr.ht/~gpcf/advtrains-discuss
+[srht-devel]: https://lists.sr.ht/~gpcf/advtrains-devel
+[gsm]: https://git-send-email.io
+
+## Translation Notes
+* Translations should be consistent. You can use other entries or the
+translations in Minetest as a reference.
+* Translations do not have to fully correspond to the original text -
+they only need to provide the same information. In particular,
+translations do not need to have the same linguistical structure as the
+original text.
+* Replacement sequences (`@1`, `@2`, etc) should not be translated.
+* Certain abbreviations or names, such as "Ks" or "Zs 3", should
+generally not be translated.
+
+### (de) German
+* Verwenden Sie die neue Rechtschreibung und die Sie-Form.
+* Mit der deutschen Tastaturbelegung unter Linux können die
+Anführungszeichen „“ mit AltGr-V bzw. AltGr-B eingegeben werden.
+
+### (zh) Chinese
+(This section is written in English to avoid writing the note twice or
+using only one of the variants, as most of this section applies to both
+the traditional and simplified variants.)
+
+* Please use the 「」 quotation marks for Traditional Chinese and “”
+for Simplified Chinese.
+* Please use the fullwidth variants of: , 、 。 ? ! : ;
+* Please use the halfwidth variants of: ( ) [ ] / \ |
+* Please do not leave any space between Han characters (including
+fullwidth punctuation marks).
+* Please leave a space between Han characters (excluding fullwidth
+punctuation marks) and characters from other scripts (including
+halfwidth punctuation marks). However, do not leave any space between
+Han characters and Arabic numerals.
+
+## Notes for developers
+* The `update-translations.sh` script can be used to update the
+translation files. However, please make sure to install the
+`basic_trains` mod before running the script.
+* Please make sure that the first argument to `S` (or `attrans`) _only_
+includes string literals without formatting or concatenation. This is
+unfortunately a limitation of the `xgettext` utility.
+* Avoid word-by-word translations.
+* Avoid manipulating translated strings (except for concatenation). Use
+server-side translations if you have to modify the text sent to users.
+* Avoid truncating strings unless multibyte characters are handled
+properly.
diff --git a/advtrains/po/advtrains.pot b/advtrains/po/advtrains.pot
new file mode 100644
index 0000000..cd6ea75
--- /dev/null
+++ b/advtrains/po/advtrains.pot
@@ -0,0 +1,957 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the advtrains package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: advtrains\n"
+"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n"
+"POT-Creation-Date: 2025-03-25 15:40+0100\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: advtrains/atc.lua
+msgid "Unconfigured ATC controller"
+msgstr ""
+
+#: advtrains/atc.lua
+msgid ""
+"ATC controller, mode @1\n"
+"Command: @2"
+msgstr ""
+
+#: advtrains/atc.lua
+msgid "Command"
+msgstr ""
+
+#: advtrains/atc.lua
+msgid "Command (on)"
+msgstr ""
+
+#: advtrains/atc.lua
+msgid "Digiline channel"
+msgstr ""
+
+#: advtrains/atc.lua advtrains/wagons.lua
+#: advtrains_line_automation/stoprail.lua
+#: advtrains_luaautomation/active_common.lua
+msgid "Save"
+msgstr ""
+
+#: advtrains/atc.lua
+msgid "ATC Reverse command warning: didn't reverse train, train moving."
+msgstr ""
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: doors are closed."
+msgstr ""
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: train moving."
+msgstr ""
+
+#: advtrains/atc.lua
+msgid "ATC command syntax error: I statement not closed: @1"
+msgstr ""
+
+#: advtrains/atc.lua
+msgid "ATC command parse error: Unknown command: @1"
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid ""
+"Train copy/paste tool\n"
+"\n"
+"Left-click: copy train\n"
+"Right-click: paste train"
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "You do not have the @1 privilege."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "The track you are trying to place the wagon on is not long enough."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Paste failed."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "The clipboard is empty."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "Back of train would end up off track, cancelling."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "No such lua entity."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "No such wagon: @1."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "No such train: @1."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Copy failed."
+msgstr ""
+
+#: advtrains/copytool.lua
+msgid "Train copied."
+msgstr ""
+
+#: advtrains/couple.lua
+msgid "Buffer and Chain Coupler"
+msgstr ""
+
+#: advtrains/couple.lua
+msgid "Scharfenberg Coupler"
+msgstr ""
+
+#: advtrains/couple.lua
+msgid ""
+"You are not allowed to couple trains without the train_operator privilege."
+msgstr ""
+
+#: advtrains/couple.lua
+msgid "<No coupler>"
+msgstr ""
+
+#: advtrains/couple.lua
+msgid "Can not couple: The couplers of the trains do not match (@1 and @2)."
+msgstr ""
+
+#: advtrains/craft_items.lua
+msgid "Boiler"
+msgstr ""
+
+#: advtrains/craft_items.lua
+msgid "Driver's cab"
+msgstr ""
+
+#: advtrains/craft_items.lua
+msgid "Wheel"
+msgstr ""
+
+#: advtrains/craft_items.lua
+msgid "Chimney"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Restoring saved state in 1 second..."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Reload successful!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Removing unused wagon"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "from wagon_save table."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Train"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"had no wagons left because of some bug. It is being deleted. Wave it goodbye!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Saving failed: "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Instructed to save() but load() was never called!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Crash during advtrains main step - skipping the shutdown save operation to "
+"not save inconsistent data!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Detach all players, especially the offline ones, from all trains. Use only "
+"when no one serious is on a train."
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Data is being saved. While saving, advtrains will remove the players from "
+"trains. Save files will be reloaded afterwards!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Delete all train routes, force them to recalculate"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Successfully invalidated train routes"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Returns the position of the train with the given id"
+msgstr ""
+
+#: advtrains/init.lua
+msgid " does not exist or is invalid"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Train "
+msgstr ""
+
+#: advtrains/init.lua
+msgid " is at "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Teleports you to the position of the train with the given id"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Teleporting to train "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Disable the advtrains globalstep temporarily"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"The advtrains globalstep has been disabled. Trains are not moving, and no "
+"data is saved! Run '/at_disable_step no' to enable again!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Disabled advtrains successfully"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Re-enabling advtrains globalstep..."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Advtrains is already running normally!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Print advtrains status info"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "(log"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Advtrains Status: no_action"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "slowdown"
+msgstr ""
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low)"
+msgstr ""
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (high)"
+msgstr ""
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (45 degree)"
+msgstr ""
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low, 45 degree)"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can place, remove and operate trains"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid ""
+"Can place, remove and operate any train, regardless of owner, whitelist, or "
+"protection"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can place and dig tracks in unprotected areas"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can operate turnouts and signals in unprotected areas"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build near tracks without the track_builder privilege."
+msgstr ""
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build tracks without the track_builder privilege."
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build near tracks at this protected position."
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build tracks at this protected position."
+msgstr ""
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to operate turnouts and signals without the "
+"railway_operator privilege."
+msgstr ""
+
+#: advtrains/signals.lua
+msgid "Lampless Signal"
+msgstr ""
+
+#: advtrains/signals.lua
+msgid "Signal"
+msgstr ""
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (left)"
+msgstr ""
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (right)"
+msgstr ""
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (top)"
+msgstr ""
+
+#: advtrains/signals.lua
+msgid "Andrew's Cross"
+msgstr ""
+
+#: advtrains/track_reg_helper.lua advtrains/tracks.lua
+msgid "This track can not be removed!"
+msgstr ""
+
+#: advtrains/track_reg_helper.lua
+msgid "@1 Slope"
+msgstr ""
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: not pointing at node"
+msgstr ""
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: space occupied!"
+msgstr ""
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: Not enough slope items left (@1 required)"
+msgstr ""
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: There's no slope of length @1"
+msgstr ""
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: no supporting node at upper end."
+msgstr ""
+
+#: advtrains/trackplacer.lua
+msgid ""
+"Track Worker Tool\n"
+"\n"
+"Left-click: change rail type (straight/curve/switch)\n"
+"Right-click: rotate object"
+msgstr ""
+
+#: advtrains/trackplacer.lua
+msgid "This node can't be rotated using the trackworker!"
+msgstr ""
+
+#: advtrains/trackplacer.lua
+msgid "This track can not be rotated!"
+msgstr ""
+
+#: advtrains/trackplacer.lua
+msgid "This node can't be changed using the trackworker!"
+msgstr ""
+
+#: advtrains/tracks.lua
+msgid "Position is occupied by a train."
+msgstr ""
+
+#: advtrains/tracks.lua
+msgid "There's a Track Circuit Break here."
+msgstr ""
+
+#: advtrains/tracks.lua
+msgid "There's a Signal Influence Point here."
+msgstr ""
+
+#: advtrains/trainhud.lua
+msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again."
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+msgid ""
+"Wagon Properties Tool\n"
+"Punch a wagon to view and edit the Wagon Properties"
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+msgid "Wagon Properties Tool"
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+msgid "Insufficient privileges to use this!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Uninitialized init="
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Uninitialized, removing"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "This wagon is owned by @1, you can't destroy it."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Destroying wagon with inventory, but inventory is not found? Shouldn't "
+"happen!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "The wagon's inventory is not empty."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon needs to be decoupled from other wagons in order to destroy it."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Warning: If you destroy this wagon, you only get some steel back! If you are "
+"sure, hold Sneak and left-click the wagon."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid " wagon:destroy(): data is not set!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "!!! Train off track !!!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid " units"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Liquid: "
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Liquid: empty"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Show Inventory"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Onboard Computer"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon properties"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Get off"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Get off (forced)"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "(Doors closed)"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "This wagon has no seats."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "This wagon is full."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Doors are closed! (Try holding sneak key!)"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "You can't get on this wagon."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Select seat:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "This Wagon ID"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Allow these players to access your wagon:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon road number:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Freight Code:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Prev FC"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Current FC: "
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Next FC:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Save wagon properties"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train ID"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Text displayed outside on train"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Text displayed inside train"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Line"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Routingcode"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train overview /coupling control:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train overview / coupling control is only shown when the train stands."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Remote Routesetting"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Clear 'Disable ARS' flag"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Doors are closed. Use Sneak+rightclick to ignore the closed doors and get "
+"off."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "You are not allowed to access the driver stand."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Missing train_operator privilege"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Not allowed to do this."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "You don't have the train_operator privilege."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "The track you are trying to place the wagon on is not long enough!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Please specify a player name to transfer ownership to."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "That player does not exist!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Not a valid wagon id."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "That wagon does not exist!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "You have been given ownership of wagon @1"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon @1 ownership changed from @2 to @3"
+msgstr ""
+
+#: advtrains_interlocking/routesetting.lua
+msgid "Route state changed."
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point speed restriction: @1"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Set point speed restriction:"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "You are not allowed to configure this track without the @1 privilege."
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua advtrains_line_automation/stoprail.lua
+msgid "You are not allowed to configure this track."
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point Speed Restriction Track"
+msgstr ""
+
+#: advtrains_line_automation/scheduler.lua
+msgid "No callback to handle schedule"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Code"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Name"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Delay"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Dep. Speed"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua advtrains_train_track/init.lua
+msgid "Track"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Stop Time"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Side"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Closed"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Left"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Right"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Reverse train"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Kick out passengers"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Wait for signal to clear"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Trains stopping here (ARS rules)"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station code \"@1\" already exists and is owned by @2."
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "This station is owned by @1. You are not allowed to edit its name."
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Unknown Station"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Next Stop:\n"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station/Stop Track"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Unconfigured LuaATC component"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC Environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Clear Local Environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Code"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid ""
+"You are not allowed to configure this LuaATC component without the @1 "
+"privilege."
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to environment '@1'"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to an invalid environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component with error: @1"
+msgstr ""
+
+#: advtrains_luaautomation/init.lua
+msgid ""
+"Can place and configure LuaATC components, including execute potentially "
+"harmful Lua code"
+msgstr ""
+
+#: advtrains_luaautomation/mesecon_controller.lua
+msgid "LuaATC Mesecon Controller"
+msgstr ""
+
+#: advtrains_luaautomation/operation_panel.lua
+msgid "LuaATC Operation Panel"
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"Passive Component Naming Tool\n"
+"\n"
+"Right-click to name a passive component."
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"You are not allowed to name LuaATC passive components without the @1 "
+"privilege."
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid "Set name of component (empty to clear)"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Japanese signal pole"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Clear (proceed)"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Reduced speed"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Caution"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Restricted speed"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Danger (halt)"
+msgstr ""
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Distant Signal ("
+msgstr ""
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Main Signal ("
+msgstr ""
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (right)"
+msgstr ""
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (left)"
+msgstr ""
+
+#: advtrains_train_industrial/init.lua advtrains_train_japan/init.lua
+#: advtrains_train_steam/init.lua advtrains_train_subway/init.lua
+msgid "Driver Stand"
+msgstr ""
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial Train Engine"
+msgstr ""
+
+#: advtrains_train_industrial/init.lua
+msgid "Big Industrial Train Engine"
+msgstr ""
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial tank wagon"
+msgstr ""
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial wood wagon"
+msgstr ""
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Inter-Wagon Connection"
+msgstr ""
+
+#: advtrains_train_japan/init.lua advtrains_train_subway/init.lua
+msgid "Driver stand"
+msgstr ""
+
+#: advtrains_train_japan/init.lua advtrains_train_steam/init.lua
+#: advtrains_train_subway/init.lua
+msgid "Passenger area"
+msgstr ""
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Engine"
+msgstr ""
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Wagon"
+msgstr ""
+
+#: advtrains_train_steam/init.lua
+msgid "Steam Engine"
+msgstr ""
+
+#: advtrains_train_steam/init.lua
+msgid "Detailed Steam Engine"
+msgstr ""
+
+#: advtrains_train_steam/init.lua
+msgid "Passenger Wagon"
+msgstr ""
+
+#: advtrains_train_steam/init.lua
+msgid "Box Wagon"
+msgstr ""
+
+#: advtrains_train_subway/init.lua
+msgid "Subway Passenger Wagon"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "Y-turnout"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "3-way turnout"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "Perpendicular Diamond Crossing Track"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "90+Angle Diamond Crossing Track"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "Diagonal Diamond Crossing Track"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "Bumper"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "ATC controller"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "Unloading Track"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "Loading Track"
+msgstr ""
+
+#: advtrains_train_track/init.lua
+msgid "Detector Rail"
+msgstr ""
diff --git a/advtrains/po/de.po b/advtrains/po/de.po
new file mode 100644
index 0000000..458e701
--- /dev/null
+++ b/advtrains/po/de.po
@@ -0,0 +1,1071 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: advtrains\n"
+"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n"
+"POT-Creation-Date: 2025-03-25 15:40+0100\n"
+"PO-Revision-Date: 2023-10-09 11:18+0200\n"
+"Last-Translator: Y. Wang <yw05@forksworld.de>\n"
+"Language-Team: German\n"
+"Language: de\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.3.2\n"
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: doors are closed."
+msgstr ""
+"Zugbeeinflussung: Wegen geschlossener Türen werden Fahrgäste nicht zum "
+"Ausstieg gezwungen."
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: train moving."
+msgstr ""
+"Zugbeeinflussung: Der Zug befindet sich in Bewegung, Fahrgäste werden nicht "
+"zum Ausstieg gezwungen."
+
+#: advtrains/atc.lua
+msgid "ATC Reverse command warning: didn't reverse train, train moving."
+msgstr ""
+"Zugbeeinflussung: Der Zug befindet sich in Bewegung und kann nicht umgekehrt "
+"werden."
+
+#: advtrains/atc.lua
+msgid "ATC command parse error: Unknown command: @1"
+msgstr "Zugbeeinflussung: Unbekannter Befehl: @1"
+
+#: advtrains/atc.lua
+msgid "ATC command syntax error: I statement not closed: @1"
+msgstr "Zugbeeinflussung: Unvollständiger I-Befehl: @1"
+
+#: advtrains/atc.lua
+msgid ""
+"ATC controller, mode @1\n"
+"Command: @2"
+msgstr ""
+"Zugbeeinflussungsgleis in Betriebsart „@1“\n"
+"Befehl: @2"
+
+#: advtrains/atc.lua
+msgid "Command"
+msgstr "Befehl"
+
+#: advtrains/atc.lua
+msgid "Command (on)"
+msgstr "Befehl (wenn aktiviert)"
+
+#: advtrains/atc.lua
+msgid "Digiline channel"
+msgstr "Digiline-Kanal"
+
+#: advtrains/atc.lua advtrains/wagons.lua
+#: advtrains_line_automation/stoprail.lua
+#: advtrains_luaautomation/active_common.lua
+msgid "Save"
+msgstr "Speichern"
+
+#: advtrains/atc.lua
+msgid "Unconfigured ATC controller"
+msgstr "Nicht konfiguiertes Zugbeeinflussungsgleis"
+
+#: advtrains/copytool.lua
+msgid "Back of train would end up off track, cancelling."
+msgstr "Der hinterer Teil dez Zuges wäre nicht auf dem Gleis."
+
+#: advtrains/copytool.lua
+msgid "No such lua entity."
+msgstr ""
+"Sie zeigen nicht auf einem Objekt, das mit diesem Werkzeug kopiert werden "
+"kann."
+
+#: advtrains/copytool.lua
+msgid "No such train: @1."
+msgstr "Es gibt keinen mit „@1“ identifizierbaren Zug."
+
+#: advtrains/copytool.lua
+msgid "No such wagon: @1."
+msgstr "Es gibt keinen mit „@1“ identifizierbaren Waggon."
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Copy failed."
+msgstr ""
+"Wegen des fehlgeschlagenen Zugriffs auf die Metadaten konnte der Zug nicht "
+"kopiert werden."
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Paste failed."
+msgstr ""
+"Wegen des fehlgeschlagenen Zugriffs auf die Metadaten konnte eine Kopie des "
+"Zuges nicht eingefügt werden."
+
+#: advtrains/copytool.lua
+msgid "The clipboard is empty."
+msgstr "Das Clipboard ist leer."
+
+#: advtrains/copytool.lua
+msgid "The track you are trying to place the wagon on is not long enough."
+msgstr "Das Gleis, auf dem der Waggon platziert werden woll, ist zu kurz."
+
+#: advtrains/copytool.lua
+msgid "Train copied."
+msgstr "Der Zug wurde Kopiert."
+
+#: advtrains/copytool.lua
+msgid ""
+"Train copy/paste tool\n"
+"\n"
+"Left-click: copy train\n"
+"Right-click: paste train"
+msgstr ""
+"Werkzeug zur Erstellung von Zugkopien\n"
+"\n"
+"Linksklick: Zug ins Clipboard kopieren\n"
+"Right-click: Kopierten Zug einfügen"
+
+#: advtrains/copytool.lua
+msgid "You do not have the @1 privilege."
+msgstr "Ihnen fehlt das „@1“-Privileg."
+
+#: advtrains/couple.lua
+msgid "<No coupler>"
+msgstr "<Keine Kupplung vorhanden>"
+
+#: advtrains/couple.lua
+msgid "Buffer and Chain Coupler"
+msgstr "Schraubenkupplung"
+
+#: advtrains/couple.lua
+msgid "Can not couple: The couplers of the trains do not match (@1 and @2)."
+msgstr "Die Kupplungen der Züge passen nicht zueinander (@1 und @2)."
+
+#: advtrains/couple.lua
+msgid "Scharfenberg Coupler"
+msgstr "Scharfenbergkupplung"
+
+#: advtrains/couple.lua
+msgid ""
+"You are not allowed to couple trains without the train_operator privilege."
+msgstr "Sie dürfen ohne das „train_operator“-Privileg keine Züge ankuppeln."
+
+#: advtrains/craft_items.lua
+msgid "Boiler"
+msgstr ""
+
+#: advtrains/craft_items.lua
+msgid "Chimney"
+msgstr ""
+
+#: advtrains/craft_items.lua
+msgid "Driver's cab"
+msgstr "Führerstand"
+
+#: advtrains/craft_items.lua
+msgid "Wheel"
+msgstr ""
+
+#: advtrains/init.lua
+msgid " does not exist or is invalid"
+msgstr ""
+
+#: advtrains/init.lua
+msgid " is at "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "(log"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Advtrains Status: no_action"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Advtrains is already running normally!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Crash during advtrains main step - skipping the shutdown save operation to "
+"not save inconsistent data!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Data is being saved. While saving, advtrains will remove the players from "
+"trains. Save files will be reloaded afterwards!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Delete all train routes, force them to recalculate"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Detach all players, especially the offline ones, from all trains. Use only "
+"when no one serious is on a train."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Disable the advtrains globalstep temporarily"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Disabled advtrains successfully"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Instructed to save() but load() was never called!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Print advtrains status info"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Re-enabling advtrains globalstep..."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Reload successful!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Removing unused wagon"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Restoring saved state in 1 second..."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Returns the position of the train with the given id"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Saving failed: "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Successfully invalidated train routes"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Teleporting to train "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Teleports you to the position of the train with the given id"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"The advtrains globalstep has been disabled. Trains are not moving, and no "
+"data is saved! Run '/at_disable_step no' to enable again!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Train"
+msgstr ""
+
+#: advtrains/init.lua
+#, fuzzy
+msgid "Train "
+msgstr "Der Zug wurde Kopiert."
+
+#: advtrains/init.lua
+msgid "from wagon_save table."
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"had no wagons left because of some bug. It is being deleted. Wave it goodbye!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "slowdown"
+msgstr ""
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (45 degree)"
+msgstr "Hoher @1-Bahnsteig (45°)"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (high)"
+msgstr "Hoher @1-Bahnsteig"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low)"
+msgstr "Niedriger @1-Bahnsteig"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low, 45 degree)"
+msgstr "Niedriger @1-Bahnsteig (45°)"
+
+#: advtrains/protection.lua
+msgid "Can operate turnouts and signals in unprotected areas"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can place and dig tracks in unprotected areas"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid ""
+"Can place, remove and operate any train, regardless of owner, whitelist, or "
+"protection"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can place, remove and operate trains"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build near tracks at this protected position."
+msgstr "Sie dürfen an geschützten Stellen nicht in der Nähe von Gleisen bauen."
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build near tracks without the track_builder privilege."
+msgstr ""
+"Sie dürfen ohne das „track_builder“-Privileg nicht in der Nähe von Gleisen "
+"bauen."
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build tracks at this protected position."
+msgstr "Sie dürfen an geschützten Stellen kein Gleis bauen."
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build tracks without the track_builder privilege."
+msgstr "Sie dürfen ohne das „track_builder“-Privileg kein Gleis bauen."
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to operate turnouts and signals without the "
+"railway_operator privilege."
+msgstr ""
+"Sie dürfen ohne das „railway_operator“-Privileg keine Bahnanlage operieren."
+
+#: advtrains/signals.lua
+msgid "Andrew's Cross"
+msgstr "Andreaskreuz"
+
+#: advtrains/signals.lua
+msgid "Lampless Signal"
+msgstr "Mechanisches Signal"
+
+#: advtrains/signals.lua
+msgid "Signal"
+msgstr "Lichtsignal"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (left)"
+msgstr "An der linken Seite montiertes Signal"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (right)"
+msgstr "An der rechten Seite montiertes Signal"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (top)"
+msgstr "An der Decke montiertes Signal"
+
+#: advtrains/track_reg_helper.lua
+msgid "@1 Slope"
+msgstr "@1 Steigung"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: Not enough slope items left (@1 required)"
+msgstr ""
+"Es kann nicht platziert werden: Sie haben nicht genug Steigungsblöcke, es "
+"werden insgesamt @1 benötigt."
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: There's no slope of length @1"
+msgstr ""
+"Es kann nicht platziert werden: die Steigung der Länge @1 ist nicht "
+"definiert."
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: no supporting node at upper end."
+msgstr ""
+"Es kann nicht platziert werden: es gibt keinen unterstützenden Block am Ende "
+"der Steigung."
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: not pointing at node"
+msgstr "Es kann nicht platziert werden: Sie zeigen nicht auf einem Block."
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: space occupied!"
+msgstr "Es kann nicht platziert werden: Diese Position ist besetzt."
+
+#: advtrains/track_reg_helper.lua advtrains/tracks.lua
+#, fuzzy
+msgid "This track can not be removed!"
+msgstr "Dieses Gleis kann nicht entfernt werden."
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This node can't be changed using the trackworker!"
+msgstr "Dieser Block kann nicht mit dem Gleiswerkzeug bearbeitet werden."
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This node can't be rotated using the trackworker!"
+msgstr "Dieser Block kann nicht mit dem Gleiswerkzeug gedreht werden."
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This track can not be rotated!"
+msgstr "Dieses Gleis kann nicht gedreht werden."
+
+#: advtrains/trackplacer.lua
+msgid ""
+"Track Worker Tool\n"
+"\n"
+"Left-click: change rail type (straight/curve/switch)\n"
+"Right-click: rotate object"
+msgstr ""
+"Gleiswerkzeug\n"
+"\n"
+"Linksklick: Gleistyp ändern\n"
+"Rechtsklick: Objekt drehen"
+
+#: advtrains/tracks.lua
+msgid "Position is occupied by a train."
+msgstr "Ein Zug steht an dieser Position."
+
+#: advtrains/tracks.lua
+msgid "There's a Signal Influence Point here."
+msgstr "Hier ist ein Signal-Beeinflussungspunkt."
+
+#: advtrains/tracks.lua
+msgid "There's a Track Circuit Break here."
+msgstr "Hier ist eine Gleisabschnittsgrenze (TCB)."
+
+#: advtrains/trainhud.lua
+msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again."
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+msgid "Insufficient privileges to use this!"
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+#, fuzzy
+msgid "Wagon Properties Tool"
+msgstr "Waggon-Einstellungen"
+
+#: advtrains/wagonprop_tool.lua
+msgid ""
+"Wagon Properties Tool\n"
+"Punch a wagon to view and edit the Wagon Properties"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid " units"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid " wagon:destroy(): data is not set!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "!!! Train off track !!!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "(Doors closed)"
+msgstr "(Türen geschlossen)"
+
+#: advtrains/wagons.lua
+msgid "Allow these players to access your wagon:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Clear 'Disable ARS' flag"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Current FC: "
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Destroying wagon with inventory, but inventory is not found? Shouldn't "
+"happen!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Doors are closed! (Try holding sneak key!)"
+msgstr "Die Türen sind geschlossen."
+
+#: advtrains/wagons.lua
+msgid ""
+"Doors are closed. Use Sneak+rightclick to ignore the closed doors and get "
+"off."
+msgstr ""
+"Die Türen sind geschlossen. Nutzen Sie Schleichen+Rechtsklick, um trotz "
+"geschlossener Türen auszusteigen."
+
+#: advtrains/wagons.lua
+msgid "Freight Code:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Get off"
+msgstr "Aussteigen"
+
+#: advtrains/wagons.lua
+msgid "Get off (forced)"
+msgstr "Ausstieg zwingen"
+
+#: advtrains/wagons.lua
+msgid "Line"
+msgstr "Linie"
+
+#: advtrains/wagons.lua
+msgid "Liquid: "
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Liquid: empty"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Missing train_operator privilege"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Next FC:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Not a valid wagon id."
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "Not allowed to do this."
+msgstr "Sie dürfen dieses Gleis nicht konfigurieren."
+
+#: advtrains/wagons.lua
+msgid "Onboard Computer"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Please specify a player name to transfer ownership to."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Prev FC"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Remote Routesetting"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Routingcode"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Save wagon properties"
+msgstr "Waggon-Einstellungen speichern"
+
+#: advtrains/wagons.lua
+msgid "Select seat:"
+msgstr "Wählen Sie einen Sitzplatz aus:"
+
+#: advtrains/wagons.lua
+msgid "Show Inventory"
+msgstr "Inventar Zeigen"
+
+#: advtrains/wagons.lua
+msgid "Text displayed inside train"
+msgstr "Innere Anzeige"
+
+#: advtrains/wagons.lua
+msgid "Text displayed outside on train"
+msgstr "Äußere Anzeige"
+
+#: advtrains/wagons.lua
+msgid "That player does not exist!"
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "That wagon does not exist!"
+msgstr "In diesem Waggon ist kein Sitzplatz vorhanden."
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "The track you are trying to place the wagon on is not long enough!"
+msgstr "Das Gleis, auf dem der Waggon platziert werden woll, ist zu kurz."
+
+#: advtrains/wagons.lua
+msgid "The wagon's inventory is not empty."
+msgstr "Das Inventar dieses Waggons ist nicht leer."
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "This Wagon ID"
+msgstr "Der Waggon ist voll."
+
+#: advtrains/wagons.lua
+msgid "This wagon has no seats."
+msgstr "In diesem Waggon ist kein Sitzplatz vorhanden."
+
+#: advtrains/wagons.lua
+msgid "This wagon is full."
+msgstr "Der Waggon ist voll."
+
+#: advtrains/wagons.lua
+msgid "This wagon is owned by @1, you can't destroy it."
+msgstr "Dieser Waggon gehört @1, Sie dürfen ihn nicht abbauen."
+
+#: advtrains/wagons.lua
+msgid "Train ID"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train overview / coupling control is only shown when the train stands."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train overview /coupling control:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Uninitialized init="
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Uninitialized, removing"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon @1 ownership changed from @2 to @3"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon needs to be decoupled from other wagons in order to destroy it."
+msgstr "Der Waggon muss abgekoppelt sein, damit Sie ihn abbauen können."
+
+#: advtrains/wagons.lua
+msgid "Wagon properties"
+msgstr "Waggon-Einstellungen"
+
+#: advtrains/wagons.lua
+msgid "Wagon road number:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Warning: If you destroy this wagon, you only get some steel back! If you are "
+"sure, hold Sneak and left-click the wagon."
+msgstr ""
+"Warnung: Durch den Abbau des Waggons erhalten Sie nur etwas Stahl zurück. "
+"Nutzen Sie Schleichen+Linksklick, um dem Waggon abzubauen."
+
+#: advtrains/wagons.lua
+msgid "You are not allowed to access the driver stand."
+msgstr "Sie haben keinen Zugang zum Führerstand."
+
+#: advtrains/wagons.lua
+msgid "You can't get on this wagon."
+msgstr "Sie können nicht in diesen Waggon einsteigen."
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "You don't have the train_operator privilege."
+msgstr "Ihnen fehlt das „@1“-Privileg."
+
+#: advtrains/wagons.lua
+msgid "You have been given ownership of wagon @1"
+msgstr ""
+
+#: advtrains_interlocking/routesetting.lua
+msgid "Route state changed."
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point Speed Restriction Track"
+msgstr "Geschwindigkeitskontrollgleis"
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point speed restriction: @1"
+msgstr "Geschwindigkeitskontrolle: @1"
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Set point speed restriction:"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "You are not allowed to configure this track without the @1 privilege."
+msgstr "Sie dürfen ohne das „@1“-Privileg dieses Gleis nicht konfigurieren."
+
+#: advtrains_interlocking/tsr_rail.lua advtrains_line_automation/stoprail.lua
+msgid "You are not allowed to configure this track."
+msgstr "Sie dürfen dieses Gleis nicht konfigurieren."
+
+#: advtrains_line_automation/scheduler.lua
+msgid "No callback to handle schedule"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Closed"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Dep. Speed"
+msgstr "Zielgeschwindigkeit bei Abfahrt"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Delay"
+msgstr "Zeit für die Türschließung"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Side"
+msgstr "Türseite"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Kick out passengers"
+msgstr "Fahrgäste zum Ausstieg zwingen"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Left"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Next Stop:\n"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Reverse train"
+msgstr "Zug Umkehren"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Right"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Code"
+msgstr "Kennzeichen der Haltestelle"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Name"
+msgstr "Name der Haltestelle"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station code \"@1\" already exists and is owned by @2."
+msgstr ""
+"Die Haltestelle mit dem Kennzeichen „@1“ ist bereits vorhanden und wird von "
+"@2 verwaltet."
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station/Stop Track"
+msgstr "Gleis zur Kennzeichnung einer Haltestelle"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Stop Time"
+msgstr "Wartezeit"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "This station is owned by @1. You are not allowed to edit its name."
+msgstr ""
+"Diese Haltestelle wird von @1 verwaltet. Sie dürfen sie nicht umbenennen."
+
+#: advtrains_line_automation/stoprail.lua advtrains_train_track/init.lua
+msgid "Track"
+msgstr "Gleis"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Trains stopping here (ARS rules)"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Unknown Station"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Wait for signal to clear"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Clear Local Environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Code"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC Environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to an invalid environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to environment '@1'"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component with error: @1"
+msgstr "LuaATC-Bauteil mit Fehlermeldung: @1"
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Unconfigured LuaATC component"
+msgstr "Nicht konfiguierter LuaATC-Bauteil"
+
+#: advtrains_luaautomation/active_common.lua
+msgid ""
+"You are not allowed to configure this LuaATC component without the @1 "
+"privilege."
+msgstr ""
+"Sie dürfen ohne das „@1“-Privileg diesen LuaATC-Bauteil nicht konfigurieren."
+
+#: advtrains_luaautomation/init.lua
+msgid ""
+"Can place and configure LuaATC components, including execute potentially "
+"harmful Lua code"
+msgstr ""
+"Kann LuaATC-Bauteile platzieren und konfigurieren (auch evtl. schädliche "
+"Programme ausführen)"
+
+#: advtrains_luaautomation/mesecon_controller.lua
+msgid "LuaATC Mesecon Controller"
+msgstr ""
+
+#: advtrains_luaautomation/operation_panel.lua
+msgid "LuaATC Operation Panel"
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"Passive Component Naming Tool\n"
+"\n"
+"Right-click to name a passive component."
+msgstr ""
+"PC-Benennungswerkzeug\n"
+"\n"
+"Rechtsklick zur Benennung der passiven Komponente."
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid "Set name of component (empty to clear)"
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"You are not allowed to name LuaATC passive components without the @1 "
+"privilege."
+msgstr "Sie dürfen ohne das „@1“ keinen passiven LuaATC-Bauteil benennen."
+
+#: advtrains_signals_japan/init.lua
+msgid "Caution"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Clear (proceed)"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Danger (halt)"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+#, fuzzy
+msgid "Japanese signal pole"
+msgstr "Japanischer Personenzug-Passagierwaggon"
+
+#: advtrains_signals_japan/init.lua
+msgid "Reduced speed"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Restricted speed"
+msgstr ""
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Distant Signal ("
+msgstr ""
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Main Signal ("
+msgstr ""
+
+#: advtrains_train_industrial/init.lua
+msgid "Big Industrial Train Engine"
+msgstr "Große Industrielle Lokomotive"
+
+#: advtrains_train_industrial/init.lua advtrains_train_japan/init.lua
+#: advtrains_train_steam/init.lua advtrains_train_subway/init.lua
+#, fuzzy
+msgid "Driver Stand"
+msgstr "Führerstand"
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (left)"
+msgstr "Führerstand Links"
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (right)"
+msgstr "Führerstand Rechts"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial Train Engine"
+msgstr "Industrielle Lokomotive"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial tank wagon"
+msgstr "Tankwaggon"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial wood wagon"
+msgstr "Holztransportwaggon"
+
+#: advtrains_train_japan/init.lua advtrains_train_subway/init.lua
+msgid "Driver stand"
+msgstr "Führerstand"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Engine"
+msgstr "Japanische Personenzug-Lokomotive"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Inter-Wagon Connection"
+msgstr "Waggonzwischenverbindung Japanischer Personenzüge"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Wagon"
+msgstr "Japanischer Personenzug-Passagierwaggon"
+
+#: advtrains_train_japan/init.lua advtrains_train_steam/init.lua
+#: advtrains_train_subway/init.lua
+#, fuzzy
+msgid "Passenger area"
+msgstr "Passagierwaggon"
+
+#: advtrains_train_steam/init.lua
+msgid "Box Wagon"
+msgstr "Güterwaggon"
+
+#: advtrains_train_steam/init.lua
+msgid "Detailed Steam Engine"
+msgstr "Detaillierte Dampflokomotive"
+
+#: advtrains_train_steam/init.lua
+msgid "Passenger Wagon"
+msgstr "Passagierwaggon"
+
+#: advtrains_train_steam/init.lua
+msgid "Steam Engine"
+msgstr "Dampflokomotive"
+
+#: advtrains_train_subway/init.lua
+msgid "Subway Passenger Wagon"
+msgstr "U-Bahn-Waggon"
+
+#: advtrains_train_track/init.lua
+msgid "3-way turnout"
+msgstr "Dreiwegweiche"
+
+#: advtrains_train_track/init.lua
+msgid "90+Angle Diamond Crossing Track"
+msgstr "Kreuzung mit einem achsenparallelen Gleis"
+
+#: advtrains_train_track/init.lua
+msgid "ATC controller"
+msgstr "Zugbeeinflussungsgleis"
+
+#: advtrains_train_track/init.lua
+msgid "Bumper"
+msgstr "Prellbock"
+
+#: advtrains_train_track/init.lua
+msgid "Detector Rail"
+msgstr "Detektorgleis"
+
+#: advtrains_train_track/init.lua
+msgid "Diagonal Diamond Crossing Track"
+msgstr "Diagonale Gleiskreuzung"
+
+#: advtrains_train_track/init.lua
+msgid "Loading Track"
+msgstr "Beladungsgleis"
+
+#: advtrains_train_track/init.lua
+msgid "Perpendicular Diamond Crossing Track"
+msgstr "Kreuzung mit zueinander orthogonalen Gleisen"
+
+#: advtrains_train_track/init.lua
+msgid "Unloading Track"
+msgstr "Abladungsgleis"
+
+#: advtrains_train_track/init.lua
+msgid "Y-turnout"
+msgstr "Y-Weiche"
+
+#~ msgid ""
+#~ "ATC controller, mode @1\n"
+#~ "Channel: @2"
+#~ msgstr ""
+#~ "Zugbeeinflussungsgleis in Betriebsart „@1“\n"
+#~ "Kanal: @2"
+
+#~ msgid "Access to @1"
+#~ msgstr "Zugang zu @1"
+
+#~ msgid "Can't get on: wagon full or doors closed!"
+#~ msgstr ""
+#~ "Sie können nicht einsteigen: der Waggon ist voll oder die Türen sind "
+#~ "geschlossen."
+
+#~ msgid "Can't place: protected position!"
+#~ msgstr "Es kann nicht platziert werden: diese Position ist geschützt."
+
+#~ msgid "Default Seat"
+#~ msgstr "Standardsitzplatz"
+
+#~ msgid "Default Seat (driver stand)"
+#~ msgstr "Standardsitzplatz (Führerstand)"
+
+#~ msgid "Deprecated Track"
+#~ msgstr "ausrangiertes Gleis, nicht verwenden."
+
+#~ msgid "Lock couples"
+#~ msgstr "Kupplungen sperren"
+
+#~ msgid "Speed:"
+#~ msgstr "Geschw.:"
+
+#~ msgid "Target:"
+#~ msgstr "Zielges.:"
+
+#~ msgid "This position is protected!"
+#~ msgstr "Diese Position ist geschützt!"
+
+#~ msgid "This track can not be changed."
+#~ msgstr "Dieses Gleis kann nicht geändert werden."
+
+#~ msgid "Use Sneak+rightclick to bypass closed doors!"
+#~ msgstr ""
+#~ "Nutzen Sie Schleichen+Rechtsklick, um trotz geschlossener Türen "
+#~ "einzusteigen."
+
+#, fuzzy
+#~ msgid "You are not allowed to modify this protected track."
+#~ msgstr "Sie dürfen an geschützten Stellen kein Gleis bauen."
+
+#~ msgid ""
+#~ "You need to own at least one neighboring wagon to destroy this couple."
+#~ msgstr ""
+#~ "Sie müssen Besitzer eines angrenzenden Waggons sein, um hier abzukuppeln."
diff --git a/advtrains/po/fr.po b/advtrains/po/fr.po
new file mode 100644
index 0000000..d773a98
--- /dev/null
+++ b/advtrains/po/fr.po
@@ -0,0 +1,1084 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: advtrains\n"
+"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n"
+"POT-Creation-Date: 2025-03-25 15:40+0100\n"
+"PO-Revision-Date: 2025-03-25 15:06+0100\n"
+"Last-Translator: Tanavit <tanavit@posto.ovh>\n"
+"Language-Team: French\n"
+"Language: fr\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 2.4.2\n"
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: doors are closed."
+msgstr "Avertissement commande ATC Éjecter : portes closes."
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: train moving."
+msgstr "Avertissement commande ATC Éjecter : train en mouvement."
+
+#: advtrains/atc.lua
+msgid "ATC Reverse command warning: didn't reverse train, train moving."
+msgstr ""
+"Attention : Commande ATC de renversement impossible car le train se déplace."
+
+#: advtrains/atc.lua
+msgid "ATC command parse error: Unknown command: @1"
+msgstr "Erreur d'analyse de commande ATC : Commande inconnue : @1"
+
+#: advtrains/atc.lua
+msgid "ATC command syntax error: I statement not closed: @1"
+msgstr "Erreur de syntaxe de commande ATC : instruction \"I\" incomplète : @1"
+
+#: advtrains/atc.lua
+msgid ""
+"ATC controller, mode @1\n"
+"Command: @2"
+msgstr ""
+"Controlleur ATC, mode @1\n"
+"Commande : @2"
+
+#: advtrains/atc.lua
+msgid "Command"
+msgstr "Commande"
+
+#: advtrains/atc.lua
+msgid "Command (on)"
+msgstr "Commande (marche)"
+
+#: advtrains/atc.lua
+msgid "Digiline channel"
+msgstr "Canal Digiline"
+
+#: advtrains/atc.lua advtrains/wagons.lua
+#: advtrains_line_automation/stoprail.lua
+#: advtrains_luaautomation/active_common.lua
+msgid "Save"
+msgstr "Sauvegarder"
+
+#: advtrains/atc.lua
+msgid "Unconfigured ATC controller"
+msgstr "Controlleur ATC, non-configuré"
+
+#: advtrains/copytool.lua
+msgid "Back of train would end up off track, cancelling."
+msgstr "La fin du train serait hors voie : annulation."
+
+#: advtrains/copytool.lua
+msgid "No such lua entity."
+msgstr "Pas de telle entité lua."
+
+#: advtrains/copytool.lua
+msgid "No such train: @1."
+msgstr "Pas de tel train : @1."
+
+#: advtrains/copytool.lua
+msgid "No such wagon: @1."
+msgstr "Pas de tel wagon : @1."
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Copy failed."
+msgstr "Le presse-papier ne peut accéder aux métadonnées. Échec de la copie."
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Paste failed."
+msgstr "Le presse-papier ne peut accéder aux métadonnées. Échec du collage."
+
+#: advtrains/copytool.lua
+msgid "The clipboard is empty."
+msgstr "Le presse-papier est vide."
+
+#: advtrains/copytool.lua
+msgid "The track you are trying to place the wagon on is not long enough."
+msgstr "La voie sur laquelle vous tentez de placer le wagon est trop courte."
+
+#: advtrains/copytool.lua
+msgid "Train copied."
+msgstr "Train copié."
+
+#: advtrains/copytool.lua
+msgid ""
+"Train copy/paste tool\n"
+"\n"
+"Left-click: copy train\n"
+"Right-click: paste train"
+msgstr ""
+"Outil de copie/collage de train\n"
+"\n"
+"Clic-Gauche : copie\n"
+"\n"
+"Clic-Droit : collage"
+
+#: advtrains/copytool.lua
+msgid "You do not have the @1 privilege."
+msgstr "Vous ne possédez pas le privilège \"@1\"."
+
+#: advtrains/couple.lua
+msgid "<No coupler>"
+msgstr "<Pas de coupleur>"
+
+#: advtrains/couple.lua
+msgid "Buffer and Chain Coupler"
+msgstr "Attelage à tampon et vis"
+
+#: advtrains/couple.lua
+msgid "Can not couple: The couplers of the trains do not match (@1 and @2)."
+msgstr ""
+"Accouplement impossible: les attelages des trains ne concordent pas (@1 et "
+"@2)."
+
+#: advtrains/couple.lua
+msgid "Scharfenberg Coupler"
+msgstr "Attelage Scharfenberg"
+
+#: advtrains/couple.lua
+msgid ""
+"You are not allowed to couple trains without the train_operator privilege."
+msgstr ""
+"Vous n'êtes pas autorisé à coupler des trains sans le privilège "
+"\"train_operator\"."
+
+#: advtrains/craft_items.lua
+msgid "Boiler"
+msgstr "Chaudière à vapeur"
+
+#: advtrains/craft_items.lua
+msgid "Chimney"
+msgstr "Cheminée"
+
+#: advtrains/craft_items.lua
+msgid "Driver's cab"
+msgstr "Cabine de pilotage"
+
+#: advtrains/craft_items.lua
+msgid "Wheel"
+msgstr "Roue"
+
+#: advtrains/init.lua
+msgid " does not exist or is invalid"
+msgstr " n'existe pas ou est invalide"
+
+#: advtrains/init.lua
+msgid " is at "
+msgstr " est à la position "
+
+#: advtrains/init.lua
+msgid "(log"
+msgstr "(log"
+
+#: advtrains/init.lua
+msgid "Advtrains Status: no_action"
+msgstr "État d'advtrains : aucune action"
+
+#: advtrains/init.lua
+msgid "Advtrains is already running normally!"
+msgstr "Advtrains fonctionne déjà correctement !"
+
+#: advtrains/init.lua
+msgid ""
+"Crash during advtrains main step - skipping the shutdown save operation to "
+"not save inconsistent data!"
+msgstr ""
+"Crash durant le pas principal d'advtrains - saut de l'opération de "
+"sauvegarde de terminaison pour éviter l'enregistrement de données "
+"corrompues !"
+
+#: advtrains/init.lua
+msgid ""
+"Data is being saved. While saving, advtrains will remove the players from "
+"trains. Save files will be reloaded afterwards!"
+msgstr ""
+"Données en cours de sauvegarde. Durant cette phase, advtrains débarquera les "
+"joueurs des trains. Les fichiers de sauvegarde seront ultérieurement "
+"rechargés !"
+
+# Routage est il le bon terme ?
+#: advtrains/init.lua
+msgid "Delete all train routes, force them to recalculate"
+msgstr "Suppression et recalcul de tous les routages"
+
+#: advtrains/init.lua
+msgid ""
+"Detach all players, especially the offline ones, from all trains. Use only "
+"when no one serious is on a train."
+msgstr ""
+"Débarque tous les joueurs, en particulier ceux déconnectés, de tous les "
+"trains. À n'utiliser que quand aucun joueur sérieux n'a embarqué."
+
+#: advtrains/init.lua
+msgid "Disable the advtrains globalstep temporarily"
+msgstr "Désactive temporairement le pas global d'advtrains"
+
+#: advtrains/init.lua
+msgid "Disabled advtrains successfully"
+msgstr "Succès de la désactivation d'advtrains"
+
+#: advtrains/init.lua
+msgid "Instructed to save() but load() was never called!"
+msgstr "Appel de save() requis sans appel préalable de load() !"
+
+#: advtrains/init.lua
+msgid "Print advtrains status info"
+msgstr "Affiche les informations d'état d'advtrains"
+
+#: advtrains/init.lua
+msgid "Re-enabling advtrains globalstep..."
+msgstr "Réacivation du pas global d'advtrains..."
+
+#: advtrains/init.lua
+msgid "Reload successful!"
+msgstr "Succès du rechargement !"
+
+#: advtrains/init.lua
+msgid "Removing unused wagon"
+msgstr "Suppression d'un wagon inutilisé"
+
+#: advtrains/init.lua
+msgid "Restoring saved state in 1 second..."
+msgstr "Restauration du l'état sauvegardé dans une seconde..."
+
+#: advtrains/init.lua
+msgid "Returns the position of the train with the given id"
+msgstr "Affiche la position du train identifié"
+
+#: advtrains/init.lua
+msgid "Saving failed: "
+msgstr "Échec de sauvegarde : "
+
+# Routage est il le bon terme ?
+#: advtrains/init.lua
+msgid "Successfully invalidated train routes"
+msgstr "Succès d'invalidation des routages des trains"
+
+#: advtrains/init.lua
+msgid "Teleporting to train "
+msgstr "Téléportation au train "
+
+#: advtrains/init.lua
+msgid "Teleports you to the position of the train with the given id"
+msgstr "Vous téléporte à la position du train identifié"
+
+#: advtrains/init.lua
+msgid ""
+"The advtrains globalstep has been disabled. Trains are not moving, and no "
+"data is saved! Run '/at_disable_step no' to enable again!"
+msgstr ""
+"Le pas global d'advtrains est désactivé. Les trains sont immobiles et aucune "
+"donnée n'est sauvegardée. Exécutez '/at_disable_step no ' pour le réactiver !"
+
+#: advtrains/init.lua
+msgid "Train"
+msgstr "Identificateur du train"
+
+#: advtrains/init.lua
+msgid "Train "
+msgstr "Identificateur du train "
+
+#: advtrains/init.lua
+msgid "from wagon_save table."
+msgstr "de la table wagon_save."
+
+#: advtrains/init.lua
+msgid ""
+"had no wagons left because of some bug. It is being deleted. Wave it goodbye!"
+msgstr ""
+"n'a plus de wagon à cause d'un bug quelconque. Il est détruit. Faites lui "
+"coucou !"
+
+#: advtrains/init.lua
+msgid "slowdown"
+msgstr "ralentissement"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (45 degree)"
+msgstr "Quai @1 (haut, 45°)"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (high)"
+msgstr "Quai @1 (haut)"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low)"
+msgstr "Quai @1 (bas)"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low, 45 degree)"
+msgstr "Quai @1 (bas, 45°)"
+
+#: advtrains/protection.lua
+msgid "Can operate turnouts and signals in unprotected areas"
+msgstr ""
+"Possibilité d'opérer des embranchements et signaux dans les zones non "
+"protégées"
+
+#: advtrains/protection.lua
+msgid "Can place and dig tracks in unprotected areas"
+msgstr "Possibilité de poser ou retirer des voies dans les zones non protégées"
+
+#: advtrains/protection.lua
+msgid ""
+"Can place, remove and operate any train, regardless of owner, whitelist, or "
+"protection"
+msgstr ""
+"Possibilité de poser, retirer ou opérer un quelconque train, indépendamment "
+"du propriétaire, de la liste blanche ou de protection"
+
+#: advtrains/protection.lua
+msgid "Can place, remove and operate trains"
+msgstr "Possibilité de poser, retirer ou opérer les trains"
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build near tracks at this protected position."
+msgstr ""
+"Vous ne pouvez pas construire à proximité d'une voie à cet emplacement "
+"protégé."
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build near tracks without the track_builder privilege."
+msgstr ""
+"Vous ne pouvez pas construire à proximité d'une voie sans le privilège "
+"\"track_builder\" (?)"
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build tracks at this protected position."
+msgstr "Vous ne pouvez pas construire une voie à cet emplacement protégé."
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build tracks without the track_builder privilege."
+msgstr ""
+"Vous ne pouvez pas construire une voie sans le privilège \"track_builder\"."
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to operate turnouts and signals without the "
+"railway_operator privilege."
+msgstr ""
+"Vous ne pouvez pas actionner les aiguillages ou les signaux (privilège "
+"\"railway_operator\" manquant)"
+
+#: advtrains/signals.lua
+msgid "Andrew's Cross"
+msgstr "Croix de Saint André"
+
+#: advtrains/signals.lua
+msgid "Lampless Signal"
+msgstr "Sémaphore"
+
+#: advtrains/signals.lua
+msgid "Signal"
+msgstr "Signal"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (left)"
+msgstr "Signal mural (gauche)"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (right)"
+msgstr "Signal mural (droit)"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (top)"
+msgstr "Signal mural (plafond)"
+
+#: advtrains/track_reg_helper.lua
+msgid "@1 Slope"
+msgstr "Pente @1"
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: Not enough slope items left (@1 required)"
+msgstr ""
+"Placement impossible : quantité insuffisante de voie pentue (@1 manquant)"
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: There's no slope of length @1"
+msgstr "Placement impossible : il n'y a pas de voie pentue de longueur @1"
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: no supporting node at upper end."
+msgstr "Placement impossible : pas de nœud d'appui à l'extrémité supérieure."
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: not pointing at node"
+msgstr "Placement impossible : ne pointe pas un nœud"
+
+#: advtrains/track_reg_helper.lua
+msgid "Can't place: space occupied!"
+msgstr "Placement impossible : espace occupé !"
+
+#: advtrains/track_reg_helper.lua advtrains/tracks.lua
+msgid "This track can not be removed!"
+msgstr "Cette voie ne peut pas être enlevée !"
+
+#: advtrains/trackplacer.lua
+msgid "This node can't be changed using the trackworker!"
+msgstr "Ce nœud ne peut être modifié avec l'outil \"Trackworker\" !"
+
+#: advtrains/trackplacer.lua
+msgid "This node can't be rotated using the trackworker!"
+msgstr "Ce nœud ne peut être tourné avec l'outil \"Trackworker\" !"
+
+#: advtrains/trackplacer.lua
+msgid "This track can not be rotated!"
+msgstr "Cette voie ne peut pas être tournée !"
+
+#: advtrains/trackplacer.lua
+msgid ""
+"Track Worker Tool\n"
+"\n"
+"Left-click: change rail type (straight/curve/switch)\n"
+"Right-click: rotate object"
+msgstr ""
+"Outil \"Trackworker\"\n"
+"\n"
+"Clic-Gauche : change le type de rail (droit/courbé/aiguillage)\n"
+"\n"
+"Clic-Droit : tourne l'objet"
+
+#: advtrains/tracks.lua
+msgid "Position is occupied by a train."
+msgstr "Cet emplacement est occupé par un train."
+
+#: advtrains/tracks.lua
+msgid "There's a Signal Influence Point here."
+msgstr "Il y a un \"Signal Influence Point\" ici."
+
+#: advtrains/tracks.lua
+msgid "There's a Track Circuit Break here."
+msgstr "Il y a un \"Track Circuit Break\" ici."
+
+#: advtrains/trainhud.lua
+msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again."
+msgstr ""
+"Franchissement de signal rouge : examinez la situation et inversez le sens "
+"de marche du train."
+
+#: advtrains/wagonprop_tool.lua
+msgid "Insufficient privileges to use this!"
+msgstr "Privilèges insuffisants pour utiliser ceci !"
+
+#: advtrains/wagonprop_tool.lua
+msgid "Wagon Properties Tool"
+msgstr "Outil de propriété du wagon"
+
+#: advtrains/wagonprop_tool.lua
+msgid ""
+"Wagon Properties Tool\n"
+"Punch a wagon to view and edit the Wagon Properties"
+msgstr ""
+"Outil de propriété du wagon\n"
+"Frappez un wagon pour voir et modifier ses propriétés"
+
+#: advtrains/wagons.lua
+msgid " units"
+msgstr " Unités"
+
+#: advtrains/wagons.lua
+msgid " wagon:destroy(): data is not set!"
+msgstr " Appel de wagon:destroy() : données non définies !"
+
+#: advtrains/wagons.lua
+msgid "!!! Train off track !!!"
+msgstr "!!! Train hors voie !!!"
+
+#: advtrains/wagons.lua
+msgid "(Doors closed)"
+msgstr "(Portes closes)"
+
+#: advtrains/wagons.lua
+msgid "Allow these players to access your wagon:"
+msgstr "Autoriser ces joueurs à embarquer :"
+
+#: advtrains/wagons.lua
+msgid "Clear 'Disable ARS' flag"
+msgstr "Effacer le drapeau \"Désactiver l'ARS\""
+
+#: advtrains/wagons.lua
+msgid "Current FC: "
+msgstr "Code de fret courant: "
+
+#: advtrains/wagons.lua
+msgid ""
+"Destroying wagon with inventory, but inventory is not found? Shouldn't "
+"happen!"
+msgstr "Desctruction d'un wagon avec inventaire introuvable ? Anomalie !"
+
+#: advtrains/wagons.lua
+msgid "Doors are closed! (Try holding sneak key!)"
+msgstr "Portes closes : (Essayez la \"sneak key\"!\")"
+
+#: advtrains/wagons.lua
+msgid ""
+"Doors are closed. Use Sneak+rightclick to ignore the closed doors and get "
+"off."
+msgstr ""
+"Portes closes ! Utilisez \"Marcher lentement (Sneak)\" et Clic-Droit pour "
+"franchir les portes et débarquer."
+
+#: advtrains/wagons.lua
+msgid "Freight Code:"
+msgstr "Code de frêt :"
+
+#: advtrains/wagons.lua
+msgid "Get off"
+msgstr "Débarquer"
+
+#: advtrains/wagons.lua
+msgid "Get off (forced)"
+msgstr "Débarquer (de force)"
+
+#: advtrains/wagons.lua
+msgid "Line"
+msgstr "Ligne"
+
+#: advtrains/wagons.lua
+msgid "Liquid: "
+msgstr "Liquide : "
+
+#: advtrains/wagons.lua
+msgid "Liquid: empty"
+msgstr "Liquide : vide"
+
+#: advtrains/wagons.lua
+msgid "Missing train_operator privilege"
+msgstr "Privilège \"train_operator\" manquant"
+
+#: advtrains/wagons.lua
+msgid "Next FC:"
+msgstr "Code de fret suivant :"
+
+#: advtrains/wagons.lua
+msgid "Not a valid wagon id."
+msgstr "Identificateur de wagon invalide."
+
+#: advtrains/wagons.lua
+msgid "Not allowed to do this."
+msgstr "Vous n'êtes pas autorisé effectuer ceci."
+
+#: advtrains/wagons.lua
+msgid "Onboard Computer"
+msgstr "Ordinateur embarqué"
+
+#: advtrains/wagons.lua
+msgid "Please specify a player name to transfer ownership to."
+msgstr ""
+"Spécifiez le nom du joueur à qui la propriété doit être transférée, SVP."
+
+#: advtrains/wagons.lua
+msgid "Prev FC"
+msgstr "Code de fret précédent"
+
+#: advtrains/wagons.lua
+msgid "Remote Routesetting"
+msgstr "Routage à distance"
+
+#: advtrains/wagons.lua
+msgid "Routingcode"
+msgstr "Code de routage"
+
+#: advtrains/wagons.lua
+msgid "Save wagon properties"
+msgstr "Sauvegarder les propriétés du wagon"
+
+#: advtrains/wagons.lua
+msgid "Select seat:"
+msgstr "Choisir le siège :"
+
+#: advtrains/wagons.lua
+msgid "Show Inventory"
+msgstr "Montrer le stock"
+
+#: advtrains/wagons.lua
+msgid "Text displayed inside train"
+msgstr "Texte affiché à l'intérieur du train"
+
+#: advtrains/wagons.lua
+msgid "Text displayed outside on train"
+msgstr "Texte affiché à l'extérieur du train"
+
+#: advtrains/wagons.lua
+msgid "That player does not exist!"
+msgstr "Ce joueur n'existe pas !"
+
+#: advtrains/wagons.lua
+msgid "That wagon does not exist!"
+msgstr "Ce wagon n'a pas de siège !"
+
+#: advtrains/wagons.lua
+msgid "The track you are trying to place the wagon on is not long enough!"
+msgstr "La voie sur laquelle vous tentez de placer le wagon est trop courte !"
+
+#: advtrains/wagons.lua
+msgid "The wagon's inventory is not empty."
+msgstr "Le stock de ce wagon n'est pas vide."
+
+#: advtrains/wagons.lua
+msgid "This Wagon ID"
+msgstr "Identificateur du wagon"
+
+#: advtrains/wagons.lua
+msgid "This wagon has no seats."
+msgstr "Ce wagon n'a pas de siège."
+
+#: advtrains/wagons.lua
+msgid "This wagon is full."
+msgstr "Ce wagon est plein."
+
+#: advtrains/wagons.lua
+msgid "This wagon is owned by @1, you can't destroy it."
+msgstr "Ce wagon est la propriété de @1, vous ne pouvez pas le détruire."
+
+#: advtrains/wagons.lua
+msgid "Train ID"
+msgstr "Identificateur du train"
+
+#: advtrains/wagons.lua
+msgid "Train overview / coupling control is only shown when the train stands."
+msgstr ""
+"Aperçu du train / commande d'accouplement montré uniquement à l'arrêt du "
+"train."
+
+#: advtrains/wagons.lua
+msgid "Train overview /coupling control:"
+msgstr "Aperçu du train / commande d'accouplement :"
+
+#: advtrains/wagons.lua
+msgid "Uninitialized init="
+msgstr "Variable init non initialisée"
+
+#: advtrains/wagons.lua
+msgid "Uninitialized, removing"
+msgstr "Non initialisé, retiré"
+
+#: advtrains/wagons.lua
+msgid "Wagon @1 ownership changed from @2 to @3"
+msgstr "La propriété du wagon @1 a été transférée de @2 à @3"
+
+#: advtrains/wagons.lua
+msgid "Wagon needs to be decoupled from other wagons in order to destroy it."
+msgstr ""
+"Les wagons doivent être désaccouplés des autres pour pouvoir être détruits."
+
+#: advtrains/wagons.lua
+msgid "Wagon properties"
+msgstr "Propriétés du wagon"
+
+#: advtrains/wagons.lua
+msgid "Wagon road number:"
+msgstr "Immatriculation du wagon :"
+
+#: advtrains/wagons.lua
+msgid ""
+"Warning: If you destroy this wagon, you only get some steel back! If you are "
+"sure, hold Sneak and left-click the wagon."
+msgstr ""
+"Attention: Si vous détruisez ce wagon, vous ne récupérerez que de la "
+"ferraille ! Si vous êtes sûr de vous, appuyez la touche \"Marcher lentement "
+"(Sneak)\" et Clic-Gauche."
+
+#: advtrains/wagons.lua
+msgid "You are not allowed to access the driver stand."
+msgstr "Accès interdit au poste de pilotage."
+
+#: advtrains/wagons.lua
+msgid "You can't get on this wagon."
+msgstr "Montée impossible dans ce wagon."
+
+#: advtrains/wagons.lua
+msgid "You don't have the train_operator privilege."
+msgstr "Vous ne possédez pas le privilège \"train_operator\"."
+
+#: advtrains/wagons.lua
+msgid "You have been given ownership of wagon @1"
+msgstr "La propriété du wagon @1 vous a été transférée"
+
+#: advtrains_interlocking/routesetting.lua
+msgid "Route state changed."
+msgstr "Changement d'état de l'itinéraire."
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point Speed Restriction Track"
+msgstr "Voie de point de limitation de vitesse"
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point speed restriction: @1"
+msgstr "Point de limitation de vitesse : @1"
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Set point speed restriction:"
+msgstr "Placez un point de limitation de vitesse :"
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "You are not allowed to configure this track without the @1 privilege."
+msgstr "Vous n'êtes pas autorisé à configurer cette voie sans le privilège @1."
+
+#: advtrains_interlocking/tsr_rail.lua advtrains_line_automation/stoprail.lua
+msgid "You are not allowed to configure this track."
+msgstr "Vous n'êtes pas autorisé à configurer cette voie."
+
+#: advtrains_line_automation/scheduler.lua
+msgid "No callback to handle schedule"
+msgstr "Absence de fonction de gestion de planning"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Closed"
+msgstr "Fermé"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Dep. Speed"
+msgstr "Vit. de départ"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Delay"
+msgstr "Durée d'ouverture des portes"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Side"
+msgstr "Ouv. des portes coté"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Kick out passengers"
+msgstr "Éjecter les passagers"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Left"
+msgstr "Gauche"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Next Stop:\n"
+msgstr "Prochain arrêt :\n"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Reverse train"
+msgstr "Inversion du sens de marche"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Right"
+msgstr "Droit"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Code"
+msgstr "Code de Station"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Name"
+msgstr "Nom de Station"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station code \"@1\" already exists and is owned by @2."
+msgstr "Le code de station \"@1\" existe et est possédé par @2."
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station/Stop Track"
+msgstr "Voie d'arrêt en station"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Stop Time"
+msgstr "Durée d'arrêt"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "This station is owned by @1. You are not allowed to edit its name."
+msgstr ""
+"Cette station est la propriété de @1. Vous n'êtes pas autorisé à modifier "
+"son nom."
+
+#: advtrains_line_automation/stoprail.lua advtrains_train_track/init.lua
+msgid "Track"
+msgstr "Voie"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Trains stopping here (ARS rules)"
+msgstr "Trains marquant l'arrêt (règles ARS)"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Unknown Station"
+msgstr "Gare inconnue"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Wait for signal to clear"
+msgstr "En attente de signal d'autorisation"
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Clear Local Environment"
+msgstr "Effacer l'environnement LuaATC"
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Code"
+msgstr "Code"
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC Environment"
+msgstr "Environnement LuaATC"
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to an invalid environment"
+msgstr "Composant LuaATC assigné à un environnement invalide"
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to environment '@1'"
+msgstr "Composant LuaATC assigné à l'environnement '@1'"
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component with error: @1"
+msgstr "Erreur @1 du composant LuaATC"
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Unconfigured LuaATC component"
+msgstr "Composant LuaATC non configuré"
+
+#: advtrains_luaautomation/active_common.lua
+msgid ""
+"You are not allowed to configure this LuaATC component without the @1 "
+"privilege."
+msgstr "Vous ne pouvez configurer ce composant LuaATC sans le privilege @1."
+
+#: advtrains_luaautomation/init.lua
+msgid ""
+"Can place and configure LuaATC components, including execute potentially "
+"harmful Lua code"
+msgstr ""
+"Permet le placement et la configuration de composants LuaATC avec risque "
+"d'exécution de code Lua dangereux"
+
+#: advtrains_luaautomation/mesecon_controller.lua
+msgid "LuaATC Mesecon Controller"
+msgstr "Commande Mesecon de LuaATC"
+
+#: advtrains_luaautomation/operation_panel.lua
+msgid "LuaATC Operation Panel"
+msgstr "Panneau de commande de LuaATC"
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"Passive Component Naming Tool\n"
+"\n"
+"Right-click to name a passive component."
+msgstr ""
+"Outil de nommage de composant passif\n"
+"\n"
+"Clic-Droit pour nommer un composant passif."
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid "Set name of component (empty to clear)"
+msgstr "Nommer le composant (chaîne vide pour effacer)"
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"You are not allowed to name LuaATC passive components without the @1 "
+"privilege."
+msgstr "Vous ne pouvez nommer un composant LuaATC passif sans le privilege @1."
+
+#: advtrains_signals_japan/init.lua
+msgid "Caution"
+msgstr "Attention"
+
+#: advtrains_signals_japan/init.lua
+msgid "Clear (proceed)"
+msgstr "Autorisation (procédez)"
+
+#: advtrains_signals_japan/init.lua
+msgid "Danger (halt)"
+msgstr "Danger (stop)"
+
+#: advtrains_signals_japan/init.lua
+msgid "Japanese signal pole"
+msgstr "Voiture Japonaise"
+
+#: advtrains_signals_japan/init.lua
+msgid "Reduced speed"
+msgstr "Vitesse réduite"
+
+#: advtrains_signals_japan/init.lua
+msgid "Restricted speed"
+msgstr "Vitesse limitée"
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Distant Signal ("
+msgstr "Signal distant métro de Munich ("
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Main Signal ("
+msgstr "Signal principal métro de Munich ("
+
+#: advtrains_train_industrial/init.lua
+msgid "Big Industrial Train Engine"
+msgstr "Grosse locomotive industrielle"
+
+#: advtrains_train_industrial/init.lua advtrains_train_japan/init.lua
+#: advtrains_train_steam/init.lua advtrains_train_subway/init.lua
+msgid "Driver Stand"
+msgstr "Poste de pilotage"
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (left)"
+msgstr "Poste de pilotage (gauche)"
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (right)"
+msgstr "Poste de pilotage (droit)"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial Train Engine"
+msgstr "Locomotive industrielle"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial tank wagon"
+msgstr "Wagon-citerne industriel"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial wood wagon"
+msgstr "Wagon grumier industriel"
+
+#: advtrains_train_japan/init.lua advtrains_train_subway/init.lua
+msgid "Driver stand"
+msgstr "Poste de pilotage"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Engine"
+msgstr "Motrice Japonaise"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Inter-Wagon Connection"
+msgstr "Passage inter-voiture de train Japonais"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Wagon"
+msgstr "Voiture Japonaise"
+
+#: advtrains_train_japan/init.lua advtrains_train_steam/init.lua
+#: advtrains_train_subway/init.lua
+msgid "Passenger area"
+msgstr "Voiture Passager"
+
+#: advtrains_train_steam/init.lua
+msgid "Box Wagon"
+msgstr "Wagon de frêt"
+
+#: advtrains_train_steam/init.lua
+msgid "Detailed Steam Engine"
+msgstr "Locomotive à vapeur complexe"
+
+#: advtrains_train_steam/init.lua
+msgid "Passenger Wagon"
+msgstr "Voiture passager"
+
+#: advtrains_train_steam/init.lua
+msgid "Steam Engine"
+msgstr "Locomotive à vapeur"
+
+#: advtrains_train_subway/init.lua
+msgid "Subway Passenger Wagon"
+msgstr "Voiture de Métropolitain"
+
+#: advtrains_train_track/init.lua
+msgid "3-way turnout"
+msgstr "Embranchement triple"
+
+#: advtrains_train_track/init.lua
+msgid "90+Angle Diamond Crossing Track"
+msgstr "Croisement perpendiculo-diagonal"
+
+#: advtrains_train_track/init.lua
+msgid "ATC controller"
+msgstr "Controlleur ATC"
+
+#: advtrains_train_track/init.lua
+msgid "Bumper"
+msgstr "Heurtoir"
+
+#: advtrains_train_track/init.lua
+msgid "Detector Rail"
+msgstr "Voie détectrice"
+
+#: advtrains_train_track/init.lua
+msgid "Diagonal Diamond Crossing Track"
+msgstr "Croisement diagonal"
+
+#: advtrains_train_track/init.lua
+msgid "Loading Track"
+msgstr "Voie de Chargement"
+
+#: advtrains_train_track/init.lua
+msgid "Perpendicular Diamond Crossing Track"
+msgstr "Croisement perpendiculaire"
+
+#: advtrains_train_track/init.lua
+msgid "Unloading Track"
+msgstr "Voie de Déchargement"
+
+#: advtrains_train_track/init.lua
+msgid "Y-turnout"
+msgstr "Embranchement en Y"
+
+#~ msgid ", using placeholder"
+#~ msgstr ", dans un espace réservé"
+
+#~ msgid ""
+#~ "ATC controller, mode @1\n"
+#~ "Channel: @2"
+#~ msgstr ""
+#~ "Controlleur ATC, mode @1\n"
+#~ "Canal : @2"
+
+#~ msgid "Access to @1"
+#~ msgstr "Accès à @1"
+
+#~ msgid "Can't get on: wagon full or doors closed!"
+#~ msgstr ""
+#~ "Embarquement impossible : le wagon est plein ou ses portes sont closes !"
+
+#~ msgid "Can't place: protected position!"
+#~ msgstr "Placement impossible : emplacement protégé"
+
+#~ msgid "Default Seat"
+#~ msgstr "Siège par défaut"
+
+#~ msgid "Default Seat (driver stand)"
+#~ msgstr "Siège par défaut (poste de pilotage)"
+
+#~ msgid "Deprecated Track"
+#~ msgstr "Voie déconseillée"
+
+#~ msgid "Left,Right,Closed;"
+#~ msgstr "Gauche,Droit,Fermé;"
+
+#~ msgid "Lock couples"
+#~ msgstr "Verrouiller l'accouplement"
+
+#~ msgid "Speed:"
+#~ msgstr "Vitesse : "
+
+#~ msgid "Target:"
+#~ msgstr "Destination : "
+
+#, fuzzy
+#~ msgid "This node can't be rotated using the trackworker,"
+#~ msgstr "Ce nœud ne peut être tourné avec l'outil \"Trackworker\" !"
+
+#~ msgid "This position is protected!"
+#~ msgstr "Cet emplacement est protégé !"
+
+#~ msgid "This track can not be changed."
+#~ msgstr "Cette voie ne peut pas être modifiée."
+
+#~ msgid "Unable to load wagon type"
+#~ msgstr "Impossible de charger le type du wagon"
+
+#~ msgid "Use Sneak+rightclick to bypass closed doors!"
+#~ msgstr ""
+#~ "Utilisez \"Marcher lentement (Sneak)\" et Clic-Droit pour franchir les "
+#~ "portes closes !"
+
+#, fuzzy
+#~ msgid "You are not allowed to modify this protected track."
+#~ msgstr "Vous ne pouvez pas construire une voie à cet emplacement protégé"
+
+#~ msgid ""
+#~ "You need to own at least one neighboring wagon to destroy this couple."
+#~ msgstr ""
+#~ "Vous devez être propriétaire d'au moins un wagon voisin pour supprimer "
+#~ "cet attelage."
diff --git a/advtrains/po/update-translations.sh b/advtrains/po/update-translations.sh
new file mode 100755
index 0000000..4c22c85
--- /dev/null
+++ b/advtrains/po/update-translations.sh
@@ -0,0 +1,29 @@
+#!/bin/sh
+# NOTE: Please make sure you also have basic_trains installed, as it uses attrans for historical reasons
+
+PODIR=`dirname "$0"`
+ATDIR="$PODIR/../.."
+BTDIR="$ATDIR/../basic_trains"
+POTFILE="$PODIR/advtrains.pot"
+
+xgettext \
+ -D "$ATDIR" \
+ -D "$BTDIR" \
+ -d advtrains \
+ -o "$POTFILE" \
+ -p . \
+ -L lua \
+ --add-location=file \
+ --from-code=UTF-8 \
+ --sort-by-file \
+ --keyword='attrans' \
+ --keyword='S' \
+ --package-name='advtrains' \
+ --msgid-bugs-address='advtrains-discuss@lists.sr.ht' \
+ `find $ATDIR $BTDIR -name '*.lua' -printf '%P\n'` \
+ &&
+for i in "$PODIR"/*.po; do
+ msgmerge -U \
+ --sort-by-file \
+ $i "$POTFILE"
+done
diff --git a/advtrains/po/zh_CN.po b/advtrains/po/zh_CN.po
new file mode 100644
index 0000000..f1a3c0f
--- /dev/null
+++ b/advtrains/po/zh_CN.po
@@ -0,0 +1,1043 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: advtrains\n"
+"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n"
+"POT-Creation-Date: 2025-03-25 15:40+0100\n"
+"PO-Revision-Date: 2023-10-09 11:24+0200\n"
+"Last-Translator: Y. Wang <yw05@forksworld.de>\n"
+"Language-Team: Chinese (Simplified)\n"
+"Language: zh_CN\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.3.2\n"
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: doors are closed."
+msgstr "ATC 警告:车门已关闭,无法踢出乘客。"
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: train moving."
+msgstr "ATC 警告:火车正在移动,无法踢出乘客。"
+
+#: advtrains/atc.lua
+msgid "ATC Reverse command warning: didn't reverse train, train moving."
+msgstr "ATC 警告:火车正在移动,无法改变行车方向。"
+
+#: advtrains/atc.lua
+msgid "ATC command parse error: Unknown command: @1"
+msgstr "ATC 语法错误:未知命令:@1"
+
+#: advtrains/atc.lua
+msgid "ATC command syntax error: I statement not closed: @1"
+msgstr "ATC 语法错误:“I”命令不完整:@1"
+
+#: advtrains/atc.lua
+msgid ""
+"ATC controller, mode @1\n"
+"Command: @2"
+msgstr ""
+"ATC 控制器\n"
+"模式:@1\n"
+"命令:@2"
+
+#: advtrains/atc.lua
+msgid "Command"
+msgstr "命令"
+
+#: advtrains/atc.lua
+msgid "Command (on)"
+msgstr "命令 (激活时)"
+
+#: advtrains/atc.lua
+msgid "Digiline channel"
+msgstr "Digiline 频道"
+
+#: advtrains/atc.lua advtrains/wagons.lua
+#: advtrains_line_automation/stoprail.lua
+#: advtrains_luaautomation/active_common.lua
+msgid "Save"
+msgstr "保存"
+
+#: advtrains/atc.lua
+msgid "Unconfigured ATC controller"
+msgstr "ATC 控制器 (未配置)"
+
+#: advtrains/copytool.lua
+msgid "Back of train would end up off track, cancelling."
+msgstr "火车后部不在轨道上。"
+
+#: advtrains/copytool.lua
+msgid "No such lua entity."
+msgstr "您没有指向一个可以用火车复制工具复制的物体。"
+
+#: advtrains/copytool.lua
+msgid "No such train: @1."
+msgstr "ID 为“@1”的列车不存在。"
+
+#: advtrains/copytool.lua
+msgid "No such wagon: @1."
+msgstr "ID 为“@1”的车厢不存在。"
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Copy failed."
+msgstr "无法复制:剪贴板无法访问元数据。"
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Paste failed."
+msgstr "无法粘贴:剪贴板无法访问元数据。"
+
+#: advtrains/copytool.lua
+msgid "The clipboard is empty."
+msgstr "剪贴板是空的。"
+
+#: advtrains/copytool.lua
+msgid "The track you are trying to place the wagon on is not long enough."
+msgstr "轨道太短。"
+
+#: advtrains/copytool.lua
+msgid "Train copied."
+msgstr "已复制列车。"
+
+#: advtrains/copytool.lua
+msgid ""
+"Train copy/paste tool\n"
+"\n"
+"Left-click: copy train\n"
+"Right-click: paste train"
+msgstr ""
+"火车复制工具\n"
+"\n"
+"左键单击:复制\n"
+"右键单击:粘帖"
+
+#: advtrains/copytool.lua
+msgid "You do not have the @1 privilege."
+msgstr "您没有“@1”权限。"
+
+#: advtrains/couple.lua
+msgid "<No coupler>"
+msgstr "<没有车钩>"
+
+#: advtrains/couple.lua
+msgid "Buffer and Chain Coupler"
+msgstr "链式车钩"
+
+#: advtrains/couple.lua
+msgid "Can not couple: The couplers of the trains do not match (@1 and @2)."
+msgstr "您无法连接这两节车厢:这两节车厢使用不同的车钩 (@1和@2)。"
+
+#: advtrains/couple.lua
+msgid "Scharfenberg Coupler"
+msgstr "Scharfenberg 式车钩"
+
+#: advtrains/couple.lua
+msgid ""
+"You are not allowed to couple trains without the train_operator privilege."
+msgstr "您没有“train_operator”权限,不能连接这两节车厢。"
+
+#: advtrains/craft_items.lua
+msgid "Boiler"
+msgstr "锅炉"
+
+#: advtrains/craft_items.lua
+msgid "Chimney"
+msgstr "烟囱"
+
+#: advtrains/craft_items.lua
+msgid "Driver's cab"
+msgstr "驾驶室"
+
+#: advtrains/craft_items.lua
+msgid "Wheel"
+msgstr "车轮"
+
+#: advtrains/init.lua
+msgid " does not exist or is invalid"
+msgstr ""
+
+#: advtrains/init.lua
+msgid " is at "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "(log"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Advtrains Status: no_action"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Advtrains is already running normally!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Crash during advtrains main step - skipping the shutdown save operation to "
+"not save inconsistent data!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Data is being saved. While saving, advtrains will remove the players from "
+"trains. Save files will be reloaded afterwards!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Delete all train routes, force them to recalculate"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Detach all players, especially the offline ones, from all trains. Use only "
+"when no one serious is on a train."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Disable the advtrains globalstep temporarily"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Disabled advtrains successfully"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Instructed to save() but load() was never called!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Print advtrains status info"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Re-enabling advtrains globalstep..."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Reload successful!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Removing unused wagon"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Restoring saved state in 1 second..."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Returns the position of the train with the given id"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Saving failed: "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Successfully invalidated train routes"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Teleporting to train "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Teleports you to the position of the train with the given id"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"The advtrains globalstep has been disabled. Trains are not moving, and no "
+"data is saved! Run '/at_disable_step no' to enable again!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Train"
+msgstr ""
+
+#: advtrains/init.lua
+#, fuzzy
+msgid "Train "
+msgstr "已复制列车。"
+
+#: advtrains/init.lua
+msgid "from wagon_save table."
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"had no wagons left because of some bug. It is being deleted. Wave it goodbye!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "slowdown"
+msgstr ""
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (45 degree)"
+msgstr "较高的@1站台 (45°)"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (high)"
+msgstr "较高的@1站台"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low)"
+msgstr "较低的@1站台"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low, 45 degree)"
+msgstr "较低的@1站台 (45°)"
+
+#: advtrains/protection.lua
+msgid "Can operate turnouts and signals in unprotected areas"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can place and dig tracks in unprotected areas"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid ""
+"Can place, remove and operate any train, regardless of owner, whitelist, or "
+"protection"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can place, remove and operate trains"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build near tracks at this protected position."
+msgstr "这里已被保护,您不能在这里的铁路附近建任何东西。"
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build near tracks without the track_builder privilege."
+msgstr "您没有“train_operator”权限,不能在铁路附近建任何东西。"
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build tracks at this protected position."
+msgstr "这里已被保护,您不能在这里建造铁路。"
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build tracks without the track_builder privilege."
+msgstr "您没有“train_operator”权限,不能在这里建造铁路。"
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to operate turnouts and signals without the "
+"railway_operator privilege."
+msgstr "您没有“railway_operator”权限,不能控制铁路设施。"
+
+#: advtrains/signals.lua
+msgid "Andrew's Cross"
+msgstr "铁路道口信号灯"
+
+#: advtrains/signals.lua
+msgid "Lampless Signal"
+msgstr "臂板信号机"
+
+#: advtrains/signals.lua
+msgid "Signal"
+msgstr "信号灯"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (left)"
+msgstr "壁挂式信号灯 (左侧)"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (right)"
+msgstr "壁挂式信号灯 (右侧)"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (top)"
+msgstr "悬挂式信号灯"
+
+#: advtrains/track_reg_helper.lua
+msgid "@1 Slope"
+msgstr "@1斜坡"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: Not enough slope items left (@1 required)"
+msgstr "无法放置斜坡:您没有足够的铁路斜坡放置工具 (您总共需要@1个)"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: There's no slope of length @1"
+msgstr "无法放置斜坡:advtrains 不支持长度为@1米的斜坡。"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: no supporting node at upper end."
+msgstr "无法放置斜坡:较高端没有支撑方块。"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: not pointing at node"
+msgstr "无法放置斜坡:您没有选择任何方块。"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: space occupied!"
+msgstr "无法放置斜坡:此区域已被占用。"
+
+#: advtrains/track_reg_helper.lua advtrains/tracks.lua
+#, fuzzy
+msgid "This track can not be removed!"
+msgstr "您不能移除这段轨道。"
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This node can't be changed using the trackworker!"
+msgstr "您不能使用铁路调整工具调整这个方块。"
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This node can't be rotated using the trackworker!"
+msgstr "您不能使用铁路调整工具旋转这个方块。"
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This track can not be rotated!"
+msgstr "您不能旋转这段轨道。"
+
+#: advtrains/trackplacer.lua
+msgid ""
+"Track Worker Tool\n"
+"\n"
+"Left-click: change rail type (straight/curve/switch)\n"
+"Right-click: rotate object"
+msgstr ""
+"铁路调整工具\n"
+"\n"
+"左键单击:切换轨道类型\n"
+"右键单击:旋转方块"
+
+#: advtrains/tracks.lua
+msgid "Position is occupied by a train."
+msgstr ""
+
+#: advtrains/tracks.lua
+msgid "There's a Signal Influence Point here."
+msgstr ""
+
+#: advtrains/tracks.lua
+msgid "There's a Track Circuit Break here."
+msgstr ""
+
+#: advtrains/trainhud.lua
+msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again."
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+msgid "Insufficient privileges to use this!"
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+#, fuzzy
+msgid "Wagon Properties Tool"
+msgstr "车厢属性"
+
+#: advtrains/wagonprop_tool.lua
+msgid ""
+"Wagon Properties Tool\n"
+"Punch a wagon to view and edit the Wagon Properties"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid " units"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid " wagon:destroy(): data is not set!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "!!! Train off track !!!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "(Doors closed)"
+msgstr "(车门已关闭)"
+
+#: advtrains/wagons.lua
+msgid "Allow these players to access your wagon:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Clear 'Disable ARS' flag"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Current FC: "
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Destroying wagon with inventory, but inventory is not found? Shouldn't "
+"happen!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Doors are closed! (Try holding sneak key!)"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Doors are closed. Use Sneak+rightclick to ignore the closed doors and get "
+"off."
+msgstr "车门已关闭,请使用潜行+右键单击下车。"
+
+#: advtrains/wagons.lua
+msgid "Freight Code:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Get off"
+msgstr "下车"
+
+#: advtrains/wagons.lua
+msgid "Get off (forced)"
+msgstr "强制下车"
+
+#: advtrains/wagons.lua
+msgid "Line"
+msgstr "火车线路"
+
+#: advtrains/wagons.lua
+msgid "Liquid: "
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Liquid: empty"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Missing train_operator privilege"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Next FC:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Not a valid wagon id."
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "Not allowed to do this."
+msgstr "您不能调整这段轨道。"
+
+#: advtrains/wagons.lua
+msgid "Onboard Computer"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Please specify a player name to transfer ownership to."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Prev FC"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Remote Routesetting"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Routingcode"
+msgstr "路由码"
+
+#: advtrains/wagons.lua
+msgid "Save wagon properties"
+msgstr "保存车厢属性"
+
+#: advtrains/wagons.lua
+msgid "Select seat:"
+msgstr "请选择座位:"
+
+#: advtrains/wagons.lua
+msgid "Show Inventory"
+msgstr "显示物品栏"
+
+#: advtrains/wagons.lua
+msgid "Text displayed inside train"
+msgstr "车厢内部显示"
+
+#: advtrains/wagons.lua
+msgid "Text displayed outside on train"
+msgstr "车厢外部显示"
+
+#: advtrains/wagons.lua
+msgid "That player does not exist!"
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "That wagon does not exist!"
+msgstr "这节车厢没有座位。"
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "The track you are trying to place the wagon on is not long enough!"
+msgstr "轨道太短。"
+
+#: advtrains/wagons.lua
+msgid "The wagon's inventory is not empty."
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "This Wagon ID"
+msgstr "车厢已满。"
+
+#: advtrains/wagons.lua
+msgid "This wagon has no seats."
+msgstr "这节车厢没有座位。"
+
+#: advtrains/wagons.lua
+msgid "This wagon is full."
+msgstr "车厢已满。"
+
+#: advtrains/wagons.lua
+msgid "This wagon is owned by @1, you can't destroy it."
+msgstr "这是 @1 的车厢,您不能摧毁它。"
+
+#: advtrains/wagons.lua
+msgid "Train ID"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train overview / coupling control is only shown when the train stands."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train overview /coupling control:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Uninitialized init="
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Uninitialized, removing"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon @1 ownership changed from @2 to @3"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon needs to be decoupled from other wagons in order to destroy it."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon properties"
+msgstr "车厢属性"
+
+#: advtrains/wagons.lua
+msgid "Wagon road number:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Warning: If you destroy this wagon, you only get some steel back! If you are "
+"sure, hold Sneak and left-click the wagon."
+msgstr ""
+"警告:如果您摧毁此车厢,您只能拿到一些钢方块。如果您确定要摧毁这节车厢,请按"
+"潜行键并左键单击此车厢。"
+
+#: advtrains/wagons.lua
+msgid "You are not allowed to access the driver stand."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "You can't get on this wagon."
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "You don't have the train_operator privilege."
+msgstr "您没有“@1”权限。"
+
+#: advtrains/wagons.lua
+msgid "You have been given ownership of wagon @1"
+msgstr ""
+
+#: advtrains_interlocking/routesetting.lua
+msgid "Route state changed."
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point Speed Restriction Track"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point speed restriction: @1"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Set point speed restriction:"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "You are not allowed to configure this track without the @1 privilege."
+msgstr "您没有“@1”权限,不能调整这段轨道。"
+
+#: advtrains_interlocking/tsr_rail.lua advtrains_line_automation/stoprail.lua
+msgid "You are not allowed to configure this track."
+msgstr "您不能调整这段轨道。"
+
+#: advtrains_line_automation/scheduler.lua
+msgid "No callback to handle schedule"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Closed"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Dep. Speed"
+msgstr "出发速度"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Delay"
+msgstr "车门关闭时间"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Side"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Kick out passengers"
+msgstr "踢出乘客"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Left"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Next Stop:\n"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Reverse train"
+msgstr "改变行车方向"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Right"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Code"
+msgstr "车站代码"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Name"
+msgstr "车站名称"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station code \"@1\" already exists and is owned by @2."
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station/Stop Track"
+msgstr "车站轨道"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Stop Time"
+msgstr "停站时间"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "This station is owned by @1. You are not allowed to edit its name."
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua advtrains_train_track/init.lua
+msgid "Track"
+msgstr "轨道"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Trains stopping here (ARS rules)"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Unknown Station"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Wait for signal to clear"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Clear Local Environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Code"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC Environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to an invalid environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to environment '@1'"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component with error: @1"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Unconfigured LuaATC component"
+msgstr "LuaATC 部件 (未配置)"
+
+#: advtrains_luaautomation/active_common.lua
+msgid ""
+"You are not allowed to configure this LuaATC component without the @1 "
+"privilege."
+msgstr "您没有“@1”权限,不能配置这个 LuaATC 部件。"
+
+#: advtrains_luaautomation/init.lua
+msgid ""
+"Can place and configure LuaATC components, including execute potentially "
+"harmful Lua code"
+msgstr ""
+
+#: advtrains_luaautomation/mesecon_controller.lua
+msgid "LuaATC Mesecon Controller"
+msgstr ""
+
+#: advtrains_luaautomation/operation_panel.lua
+msgid "LuaATC Operation Panel"
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"Passive Component Naming Tool\n"
+"\n"
+"Right-click to name a passive component."
+msgstr ""
+"被动元件命名工具\n"
+"\n"
+"右键单击命名所选元件。"
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid "Set name of component (empty to clear)"
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"You are not allowed to name LuaATC passive components without the @1 "
+"privilege."
+msgstr "您没有“@1”权限,不能命名被动元件。"
+
+#: advtrains_signals_japan/init.lua
+msgid "Caution"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Clear (proceed)"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Danger (halt)"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+#, fuzzy
+msgid "Japanese signal pole"
+msgstr "高速列车车厢"
+
+#: advtrains_signals_japan/init.lua
+msgid "Reduced speed"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Restricted speed"
+msgstr ""
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Distant Signal ("
+msgstr ""
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Main Signal ("
+msgstr ""
+
+#: advtrains_train_industrial/init.lua
+msgid "Big Industrial Train Engine"
+msgstr "大型工业用火车头"
+
+#: advtrains_train_industrial/init.lua advtrains_train_japan/init.lua
+#: advtrains_train_steam/init.lua advtrains_train_subway/init.lua
+#, fuzzy
+msgid "Driver Stand"
+msgstr "司机座位"
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (left)"
+msgstr "左侧司机座位"
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (right)"
+msgstr "右侧司机座位"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial Train Engine"
+msgstr "工业用火车头"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial tank wagon"
+msgstr "液体运输车厢"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial wood wagon"
+msgstr "木材运输车厢"
+
+#: advtrains_train_japan/init.lua advtrains_train_subway/init.lua
+msgid "Driver stand"
+msgstr "司机座位"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Engine"
+msgstr "高速列车车头"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Inter-Wagon Connection"
+msgstr "日本火车车钩"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Wagon"
+msgstr "高速列车车厢"
+
+#: advtrains_train_japan/init.lua advtrains_train_steam/init.lua
+#: advtrains_train_subway/init.lua
+#, fuzzy
+msgid "Passenger area"
+msgstr "客车"
+
+#: advtrains_train_steam/init.lua
+msgid "Box Wagon"
+msgstr "货运车厢"
+
+#: advtrains_train_steam/init.lua
+msgid "Detailed Steam Engine"
+msgstr "精细的蒸汽机车"
+
+#: advtrains_train_steam/init.lua
+msgid "Passenger Wagon"
+msgstr "客车"
+
+#: advtrains_train_steam/init.lua
+msgid "Steam Engine"
+msgstr "蒸汽机车"
+
+#: advtrains_train_subway/init.lua
+msgid "Subway Passenger Wagon"
+msgstr "地铁车厢"
+
+#: advtrains_train_track/init.lua
+msgid "3-way turnout"
+msgstr "三开道岔"
+
+#: advtrains_train_track/init.lua
+msgid "90+Angle Diamond Crossing Track"
+msgstr "交叉轨道 (其中一条轨道与坐标轴平行)"
+
+#: advtrains_train_track/init.lua
+msgid "ATC controller"
+msgstr "ATC 控制器"
+
+#: advtrains_train_track/init.lua
+msgid "Bumper"
+msgstr "保险杠"
+
+#: advtrains_train_track/init.lua
+msgid "Detector Rail"
+msgstr "探测轨道"
+
+#: advtrains_train_track/init.lua
+msgid "Diagonal Diamond Crossing Track"
+msgstr "交叉轨道"
+
+#: advtrains_train_track/init.lua
+msgid "Loading Track"
+msgstr "装货轨道"
+
+#: advtrains_train_track/init.lua
+msgid "Perpendicular Diamond Crossing Track"
+msgstr "垂直交叉轨道"
+
+#: advtrains_train_track/init.lua
+msgid "Unloading Track"
+msgstr "卸货轨道"
+
+#: advtrains_train_track/init.lua
+msgid "Y-turnout"
+msgstr "对称道岔"
+
+#~ msgid ""
+#~ "ATC controller, mode @1\n"
+#~ "Channel: @2"
+#~ msgstr ""
+#~ "ATC 控制器\n"
+#~ "模式:@1\n"
+#~ "频道:@2"
+
+#~ msgid "Access to @1"
+#~ msgstr "可前往@1"
+
+#~ msgid "Can't get on: wagon full or doors closed!"
+#~ msgstr "无法上车:车门已关闭或车厢已满。"
+
+#~ msgid "Can't place: protected position!"
+#~ msgstr "无法放置:此区域已被保护。"
+
+#~ msgid "Default Seat"
+#~ msgstr "默认座位"
+
+#~ msgid "Default Seat (driver stand)"
+#~ msgstr "默认座位 (司机座位)"
+
+#~ msgid "Deprecated Track"
+#~ msgstr "请不要使用"
+
+#~ msgid "Lock couples"
+#~ msgstr "锁定连接处"
+
+#~ msgid "Speed:"
+#~ msgstr "速度"
+
+#~ msgid "Target:"
+#~ msgstr "目标速度"
+
+#, fuzzy
+#~ msgid "This node can't be rotated using the trackworker,"
+#~ msgstr "您不能使用铁路调整工具旋转这个方块。"
+
+#~ msgid "This position is protected!"
+#~ msgstr "这里已被保护。"
+
+#~ msgid "This track can not be changed."
+#~ msgstr "您不能调整这段轨道。"
+
+#~ msgid "Use Sneak+rightclick to bypass closed doors!"
+#~ msgstr "请使用潜行+右键上车。"
+
+#, fuzzy
+#~ msgid "You are not allowed to modify this protected track."
+#~ msgstr "这里已被保护,您不能在这里建造铁路。"
+
+#~ msgid ""
+#~ "You need to own at least one neighboring wagon to destroy this couple."
+#~ msgstr "您必须至少拥有其中一节车厢才能分开这两节车厢。"
diff --git a/advtrains/po/zh_TW.po b/advtrains/po/zh_TW.po
new file mode 100644
index 0000000..ec65737
--- /dev/null
+++ b/advtrains/po/zh_TW.po
@@ -0,0 +1,1043 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: advtrains\n"
+"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n"
+"POT-Creation-Date: 2025-03-25 15:40+0100\n"
+"PO-Revision-Date: 2023-10-09 11:31+0200\n"
+"Last-Translator: Y. Wang <yw05@forksworld.de>\n"
+"Language-Team: Chinese (Traditional)\n"
+"Language: zh_TW\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.3.2\n"
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: doors are closed."
+msgstr "ATC 警告:車門已關閉,無法踢出乘客。"
+
+#: advtrains/atc.lua
+msgid "ATC Kick command warning: train moving."
+msgstr "ATC 警告:火車正在移動,無法踢出乘客。"
+
+#: advtrains/atc.lua
+msgid "ATC Reverse command warning: didn't reverse train, train moving."
+msgstr "ATC 警告:火車正在移動,無法改變行車方向。"
+
+#: advtrains/atc.lua
+msgid "ATC command parse error: Unknown command: @1"
+msgstr "ATC 語法錯誤:未知命令:@1"
+
+#: advtrains/atc.lua
+msgid "ATC command syntax error: I statement not closed: @1"
+msgstr "ATC 語法錯誤:「I」命令不完整:@1"
+
+#: advtrains/atc.lua
+msgid ""
+"ATC controller, mode @1\n"
+"Command: @2"
+msgstr ""
+"ATC 控制器\n"
+"模式:@1\n"
+"命令:@2"
+
+#: advtrains/atc.lua
+msgid "Command"
+msgstr "命令"
+
+#: advtrains/atc.lua
+msgid "Command (on)"
+msgstr "命令 (啟用時)"
+
+#: advtrains/atc.lua
+msgid "Digiline channel"
+msgstr "Digiline 頻道"
+
+#: advtrains/atc.lua advtrains/wagons.lua
+#: advtrains_line_automation/stoprail.lua
+#: advtrains_luaautomation/active_common.lua
+msgid "Save"
+msgstr "儲存"
+
+#: advtrains/atc.lua
+msgid "Unconfigured ATC controller"
+msgstr "ATC 控制器 (未配置)"
+
+#: advtrains/copytool.lua
+msgid "Back of train would end up off track, cancelling."
+msgstr "火車後部不在軌道上。"
+
+#: advtrains/copytool.lua
+msgid "No such lua entity."
+msgstr "您沒有指向一個可以用火車複製工具複製的物體。"
+
+#: advtrains/copytool.lua
+msgid "No such train: @1."
+msgstr "ID 為「@1」的列車不存在。"
+
+#: advtrains/copytool.lua
+msgid "No such wagon: @1."
+msgstr "ID 為「@1」的車廂不存在。"
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Copy failed."
+msgstr "無法複製:剪貼簿無法訪問元資料。"
+
+#: advtrains/copytool.lua
+msgid "The clipboard couldn't access the metadata. Paste failed."
+msgstr "無法貼上:剪貼簿無法訪問元資料。"
+
+#: advtrains/copytool.lua
+msgid "The clipboard is empty."
+msgstr "剪貼簿是空的。"
+
+#: advtrains/copytool.lua
+msgid "The track you are trying to place the wagon on is not long enough."
+msgstr "軌道太短。"
+
+#: advtrains/copytool.lua
+msgid "Train copied."
+msgstr "已複製火車。"
+
+#: advtrains/copytool.lua
+msgid ""
+"Train copy/paste tool\n"
+"\n"
+"Left-click: copy train\n"
+"Right-click: paste train"
+msgstr ""
+"火車複製工具\n"
+"\n"
+"左鍵單擊:複製\n"
+"右鍵單擊:粘帖"
+
+#: advtrains/copytool.lua
+msgid "You do not have the @1 privilege."
+msgstr "您沒有「@1」許可權。"
+
+#: advtrains/couple.lua
+msgid "<No coupler>"
+msgstr "<無連結器>"
+
+#: advtrains/couple.lua
+msgid "Buffer and Chain Coupler"
+msgstr "鏈式連結器"
+
+#: advtrains/couple.lua
+msgid "Can not couple: The couplers of the trains do not match (@1 and @2)."
+msgstr "您無法連結這兩節車廂:這兩節車廂使用不同的連結器 (@1和@2)。"
+
+#: advtrains/couple.lua
+msgid "Scharfenberg Coupler"
+msgstr "Scharfenberg 式連結器"
+
+#: advtrains/couple.lua
+msgid ""
+"You are not allowed to couple trains without the train_operator privilege."
+msgstr "您沒有「train_operator」許可權,不能連結這兩節車廂。"
+
+#: advtrains/craft_items.lua
+msgid "Boiler"
+msgstr "鍋爐"
+
+#: advtrains/craft_items.lua
+msgid "Chimney"
+msgstr "煙囪"
+
+#: advtrains/craft_items.lua
+msgid "Driver's cab"
+msgstr "駕駛室"
+
+#: advtrains/craft_items.lua
+msgid "Wheel"
+msgstr "車輪"
+
+#: advtrains/init.lua
+msgid " does not exist or is invalid"
+msgstr ""
+
+#: advtrains/init.lua
+msgid " is at "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "(log"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Advtrains Status: no_action"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Advtrains is already running normally!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Crash during advtrains main step - skipping the shutdown save operation to "
+"not save inconsistent data!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Data is being saved. While saving, advtrains will remove the players from "
+"trains. Save files will be reloaded afterwards!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Delete all train routes, force them to recalculate"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"Detach all players, especially the offline ones, from all trains. Use only "
+"when no one serious is on a train."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Disable the advtrains globalstep temporarily"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Disabled advtrains successfully"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Instructed to save() but load() was never called!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Print advtrains status info"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Re-enabling advtrains globalstep..."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Reload successful!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Removing unused wagon"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Restoring saved state in 1 second..."
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Returns the position of the train with the given id"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Saving failed: "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Successfully invalidated train routes"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Teleporting to train "
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Teleports you to the position of the train with the given id"
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"The advtrains globalstep has been disabled. Trains are not moving, and no "
+"data is saved! Run '/at_disable_step no' to enable again!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "Train"
+msgstr ""
+
+#: advtrains/init.lua
+#, fuzzy
+msgid "Train "
+msgstr "已複製火車。"
+
+#: advtrains/init.lua
+msgid "from wagon_save table."
+msgstr ""
+
+#: advtrains/init.lua
+msgid ""
+"had no wagons left because of some bug. It is being deleted. Wave it goodbye!"
+msgstr ""
+
+#: advtrains/init.lua
+msgid "slowdown"
+msgstr ""
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (45 degree)"
+msgstr "較高的@1月臺 (45°)"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (high)"
+msgstr "較高的@1月臺"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low)"
+msgstr "較低的@1月臺"
+
+#: advtrains/misc_nodes.lua
+msgid "@1 Platform (low, 45 degree)"
+msgstr "較低的@1月臺 (45°)"
+
+#: advtrains/protection.lua
+msgid "Can operate turnouts and signals in unprotected areas"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can place and dig tracks in unprotected areas"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid ""
+"Can place, remove and operate any train, regardless of owner, whitelist, or "
+"protection"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "Can place, remove and operate trains"
+msgstr ""
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build near tracks at this protected position."
+msgstr "這裡已被保護,您不能在這裡的鐵路附近建任何東西。"
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build near tracks without the track_builder privilege."
+msgstr "您沒有「train_operator」許可權,不能在鐵路附近建任何東西。"
+
+#: advtrains/protection.lua
+msgid "You are not allowed to build tracks at this protected position."
+msgstr "這裡已被保護,您不能在這裡建造鐵路。"
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to build tracks without the track_builder privilege."
+msgstr "您沒有「train_operator」許可權,不能在這裡建造鐵路。"
+
+#: advtrains/protection.lua
+msgid ""
+"You are not allowed to operate turnouts and signals without the "
+"railway_operator privilege."
+msgstr "您沒有「railway_operator」許可權,不能控制鐵路設施。"
+
+#: advtrains/signals.lua
+msgid "Andrew's Cross"
+msgstr "平交道號誌燈"
+
+#: advtrains/signals.lua
+msgid "Lampless Signal"
+msgstr "臂木式號誌機"
+
+#: advtrains/signals.lua
+msgid "Signal"
+msgstr "色燈號誌機"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (left)"
+msgstr "壁掛式色燈號誌機 (左側)"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (right)"
+msgstr "壁掛式色燈號誌機 (右側)"
+
+#: advtrains/signals.lua
+msgid "Wallmounted Signal (top)"
+msgstr "懸掛式色燈號誌機"
+
+#: advtrains/track_reg_helper.lua
+msgid "@1 Slope"
+msgstr "@1斜坡"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: Not enough slope items left (@1 required)"
+msgstr "無法放置斜坡:您沒有足夠的鐵路斜坡放置工具 (您總共需要@1個)"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: There's no slope of length @1"
+msgstr "無法放置斜坡:advtrains 不支援長度為@1米的斜坡。"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: no supporting node at upper end."
+msgstr "無法放置斜坡:較高階沒有支撐方塊。"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: not pointing at node"
+msgstr "無法放置斜坡:您沒有選擇任何方塊。"
+
+#: advtrains/track_reg_helper.lua
+#, fuzzy
+msgid "Can't place: space occupied!"
+msgstr "無法放置斜坡:此區域已被佔用。"
+
+#: advtrains/track_reg_helper.lua advtrains/tracks.lua
+#, fuzzy
+msgid "This track can not be removed!"
+msgstr "您不能移除這段軌道。"
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This node can't be changed using the trackworker!"
+msgstr "您不能使用鐵路調整工具調整這個方塊。"
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This node can't be rotated using the trackworker!"
+msgstr "您不能使用鐵路調整工具旋轉這個方塊。"
+
+#: advtrains/trackplacer.lua
+#, fuzzy
+msgid "This track can not be rotated!"
+msgstr "您不能旋轉這段軌道。"
+
+#: advtrains/trackplacer.lua
+msgid ""
+"Track Worker Tool\n"
+"\n"
+"Left-click: change rail type (straight/curve/switch)\n"
+"Right-click: rotate object"
+msgstr ""
+"鐵路調整工具\n"
+"\n"
+"左鍵單擊:切換軌道型別\n"
+"右鍵單擊:旋轉方塊"
+
+#: advtrains/tracks.lua
+msgid "Position is occupied by a train."
+msgstr ""
+
+#: advtrains/tracks.lua
+msgid "There's a Signal Influence Point here."
+msgstr ""
+
+#: advtrains/tracks.lua
+msgid "There's a Track Circuit Break here."
+msgstr ""
+
+#: advtrains/trainhud.lua
+msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again."
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+msgid "Insufficient privileges to use this!"
+msgstr ""
+
+#: advtrains/wagonprop_tool.lua
+#, fuzzy
+msgid "Wagon Properties Tool"
+msgstr "車廂屬性"
+
+#: advtrains/wagonprop_tool.lua
+msgid ""
+"Wagon Properties Tool\n"
+"Punch a wagon to view and edit the Wagon Properties"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid " units"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid " wagon:destroy(): data is not set!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "!!! Train off track !!!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "(Doors closed)"
+msgstr "(車門已關閉)"
+
+#: advtrains/wagons.lua
+msgid "Allow these players to access your wagon:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Clear 'Disable ARS' flag"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Current FC: "
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Destroying wagon with inventory, but inventory is not found? Shouldn't "
+"happen!"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Doors are closed! (Try holding sneak key!)"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Doors are closed. Use Sneak+rightclick to ignore the closed doors and get "
+"off."
+msgstr "車門已關閉,請使用潛行+右鍵單擊下車。"
+
+#: advtrains/wagons.lua
+msgid "Freight Code:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Get off"
+msgstr "下車"
+
+#: advtrains/wagons.lua
+msgid "Get off (forced)"
+msgstr "強制下車"
+
+#: advtrains/wagons.lua
+msgid "Line"
+msgstr "火車線路"
+
+#: advtrains/wagons.lua
+msgid "Liquid: "
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Liquid: empty"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Missing train_operator privilege"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Next FC:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Not a valid wagon id."
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "Not allowed to do this."
+msgstr "您不能調整這段軌道。"
+
+#: advtrains/wagons.lua
+msgid "Onboard Computer"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Please specify a player name to transfer ownership to."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Prev FC"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Remote Routesetting"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Routingcode"
+msgstr "路由碼"
+
+#: advtrains/wagons.lua
+msgid "Save wagon properties"
+msgstr "儲存車廂屬性"
+
+#: advtrains/wagons.lua
+msgid "Select seat:"
+msgstr "請選擇座位:"
+
+#: advtrains/wagons.lua
+msgid "Show Inventory"
+msgstr "顯示物品欄"
+
+#: advtrains/wagons.lua
+msgid "Text displayed inside train"
+msgstr "車廂內部顯示"
+
+#: advtrains/wagons.lua
+msgid "Text displayed outside on train"
+msgstr "車廂外部顯示"
+
+#: advtrains/wagons.lua
+msgid "That player does not exist!"
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "That wagon does not exist!"
+msgstr "這節車廂沒有座位。"
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "The track you are trying to place the wagon on is not long enough!"
+msgstr "軌道太短。"
+
+#: advtrains/wagons.lua
+msgid "The wagon's inventory is not empty."
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "This Wagon ID"
+msgstr "車廂已滿。"
+
+#: advtrains/wagons.lua
+msgid "This wagon has no seats."
+msgstr "這節車廂沒有座位。"
+
+#: advtrains/wagons.lua
+msgid "This wagon is full."
+msgstr "車廂已滿。"
+
+#: advtrains/wagons.lua
+msgid "This wagon is owned by @1, you can't destroy it."
+msgstr "這是 @1 的車廂,您不能摧毀它。"
+
+#: advtrains/wagons.lua
+msgid "Train ID"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train overview / coupling control is only shown when the train stands."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Train overview /coupling control:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Uninitialized init="
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Uninitialized, removing"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon @1 ownership changed from @2 to @3"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon needs to be decoupled from other wagons in order to destroy it."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "Wagon properties"
+msgstr "車廂屬性"
+
+#: advtrains/wagons.lua
+msgid "Wagon road number:"
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid ""
+"Warning: If you destroy this wagon, you only get some steel back! If you are "
+"sure, hold Sneak and left-click the wagon."
+msgstr ""
+"警告:如果您摧毀此車廂,您只能拿到一些鋼方塊。如果您確定要摧毀這節車廂,請按"
+"潛行鍵並左鍵單擊此車廂。"
+
+#: advtrains/wagons.lua
+msgid "You are not allowed to access the driver stand."
+msgstr ""
+
+#: advtrains/wagons.lua
+msgid "You can't get on this wagon."
+msgstr ""
+
+#: advtrains/wagons.lua
+#, fuzzy
+msgid "You don't have the train_operator privilege."
+msgstr "您沒有「@1」許可權。"
+
+#: advtrains/wagons.lua
+msgid "You have been given ownership of wagon @1"
+msgstr ""
+
+#: advtrains_interlocking/routesetting.lua
+msgid "Route state changed."
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point Speed Restriction Track"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Point speed restriction: @1"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "Set point speed restriction:"
+msgstr ""
+
+#: advtrains_interlocking/tsr_rail.lua
+msgid "You are not allowed to configure this track without the @1 privilege."
+msgstr "您沒有「@1」許可權,不能調整這段軌道。"
+
+#: advtrains_interlocking/tsr_rail.lua advtrains_line_automation/stoprail.lua
+msgid "You are not allowed to configure this track."
+msgstr "您不能調整這段軌道。"
+
+#: advtrains_line_automation/scheduler.lua
+msgid "No callback to handle schedule"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Closed"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Dep. Speed"
+msgstr "出發速度"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Delay"
+msgstr "車門關閉時間"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Door Side"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Kick out passengers"
+msgstr "踢出乘客"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Left"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Next Stop:\n"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Reverse train"
+msgstr "改變行車方向"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Right"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Code"
+msgstr "車站碼"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station Name"
+msgstr "車站名稱"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station code \"@1\" already exists and is owned by @2."
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Station/Stop Track"
+msgstr "車站軌道"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Stop Time"
+msgstr "停站時間"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "This station is owned by @1. You are not allowed to edit its name."
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua advtrains_train_track/init.lua
+msgid "Track"
+msgstr "軌道"
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Trains stopping here (ARS rules)"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Unknown Station"
+msgstr ""
+
+#: advtrains_line_automation/stoprail.lua
+msgid "Wait for signal to clear"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Clear Local Environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Code"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC Environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to an invalid environment"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component assigned to environment '@1'"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "LuaATC component with error: @1"
+msgstr ""
+
+#: advtrains_luaautomation/active_common.lua
+msgid "Unconfigured LuaATC component"
+msgstr "LuaATC 元件 (未配置)"
+
+#: advtrains_luaautomation/active_common.lua
+msgid ""
+"You are not allowed to configure this LuaATC component without the @1 "
+"privilege."
+msgstr "您沒有「@1」許可權,不能配置這個 LuaATC 元件。"
+
+#: advtrains_luaautomation/init.lua
+msgid ""
+"Can place and configure LuaATC components, including execute potentially "
+"harmful Lua code"
+msgstr ""
+
+#: advtrains_luaautomation/mesecon_controller.lua
+msgid "LuaATC Mesecon Controller"
+msgstr ""
+
+#: advtrains_luaautomation/operation_panel.lua
+msgid "LuaATC Operation Panel"
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"Passive Component Naming Tool\n"
+"\n"
+"Right-click to name a passive component."
+msgstr ""
+"被動元件命名工具\n"
+"\n"
+"右鍵單擊命名所選元件。"
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid "Set name of component (empty to clear)"
+msgstr ""
+
+#: advtrains_luaautomation/pcnaming.lua
+msgid ""
+"You are not allowed to name LuaATC passive components without the @1 "
+"privilege."
+msgstr "您沒有「@1」許可權,不能命名這個元件。"
+
+#: advtrains_signals_japan/init.lua
+msgid "Caution"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Clear (proceed)"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Danger (halt)"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+#, fuzzy
+msgid "Japanese signal pole"
+msgstr "高速列車車廂"
+
+#: advtrains_signals_japan/init.lua
+msgid "Reduced speed"
+msgstr ""
+
+#: advtrains_signals_japan/init.lua
+msgid "Restricted speed"
+msgstr ""
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Distant Signal ("
+msgstr ""
+
+#: advtrains_signals_muc_ubahn/init.lua
+msgid "Munich U-Bahn Main Signal ("
+msgstr ""
+
+#: advtrains_train_industrial/init.lua
+msgid "Big Industrial Train Engine"
+msgstr "大型工業用火車頭"
+
+#: advtrains_train_industrial/init.lua advtrains_train_japan/init.lua
+#: advtrains_train_steam/init.lua advtrains_train_subway/init.lua
+#, fuzzy
+msgid "Driver Stand"
+msgstr "司機座位"
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (left)"
+msgstr "左側司機座位"
+
+#: advtrains_train_industrial/init.lua advtrains_train_steam/init.lua
+msgid "Driver Stand (right)"
+msgstr "右側司機座位"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial Train Engine"
+msgstr "工業用火車頭"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial tank wagon"
+msgstr "液體運輸車廂"
+
+#: advtrains_train_industrial/init.lua
+msgid "Industrial wood wagon"
+msgstr "木材運輸車廂"
+
+#: advtrains_train_japan/init.lua advtrains_train_subway/init.lua
+msgid "Driver stand"
+msgstr "司機座位"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Engine"
+msgstr "高速列車車頭"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Inter-Wagon Connection"
+msgstr "日本火車連結器"
+
+#: advtrains_train_japan/init.lua
+msgid "Japanese Train Wagon"
+msgstr "高速列車車廂"
+
+#: advtrains_train_japan/init.lua advtrains_train_steam/init.lua
+#: advtrains_train_subway/init.lua
+#, fuzzy
+msgid "Passenger area"
+msgstr "客車"
+
+#: advtrains_train_steam/init.lua
+msgid "Box Wagon"
+msgstr "貨運車廂"
+
+#: advtrains_train_steam/init.lua
+msgid "Detailed Steam Engine"
+msgstr "精細的蒸汽機車"
+
+#: advtrains_train_steam/init.lua
+msgid "Passenger Wagon"
+msgstr "客車"
+
+#: advtrains_train_steam/init.lua
+msgid "Steam Engine"
+msgstr "蒸汽機車"
+
+#: advtrains_train_subway/init.lua
+msgid "Subway Passenger Wagon"
+msgstr "地鐵車廂"
+
+#: advtrains_train_track/init.lua
+msgid "3-way turnout"
+msgstr "三開道岔"
+
+#: advtrains_train_track/init.lua
+msgid "90+Angle Diamond Crossing Track"
+msgstr "交叉軌道 (其中一條軌道與座標軸平行)"
+
+#: advtrains_train_track/init.lua
+msgid "ATC controller"
+msgstr "ATC 控制器"
+
+#: advtrains_train_track/init.lua
+msgid "Bumper"
+msgstr "保險槓"
+
+#: advtrains_train_track/init.lua
+msgid "Detector Rail"
+msgstr "探測軌道"
+
+#: advtrains_train_track/init.lua
+msgid "Diagonal Diamond Crossing Track"
+msgstr "交叉軌道"
+
+#: advtrains_train_track/init.lua
+msgid "Loading Track"
+msgstr "裝貨軌道"
+
+#: advtrains_train_track/init.lua
+msgid "Perpendicular Diamond Crossing Track"
+msgstr "垂直交叉軌道"
+
+#: advtrains_train_track/init.lua
+msgid "Unloading Track"
+msgstr "卸貨軌道"
+
+#: advtrains_train_track/init.lua
+msgid "Y-turnout"
+msgstr "對稱道岔"
+
+#~ msgid ""
+#~ "ATC controller, mode @1\n"
+#~ "Channel: @2"
+#~ msgstr ""
+#~ "ATC 控制器\n"
+#~ "模式:@1\n"
+#~ "頻道:@2"
+
+#~ msgid "Access to @1"
+#~ msgstr "可前往@1"
+
+#~ msgid "Can't get on: wagon full or doors closed!"
+#~ msgstr "無法上車:車門已關閉或車廂已滿。"
+
+#~ msgid "Can't place: protected position!"
+#~ msgstr "無法放置:此區域已被保護。"
+
+#~ msgid "Default Seat"
+#~ msgstr "預設座位"
+
+#~ msgid "Default Seat (driver stand)"
+#~ msgstr "預設座位 (司機座位)"
+
+#~ msgid "Deprecated Track"
+#~ msgstr "請不要使用"
+
+#~ msgid "Lock couples"
+#~ msgstr "鎖定連結處"
+
+#~ msgid "Speed:"
+#~ msgstr "速度"
+
+#~ msgid "Target:"
+#~ msgstr "目標速度"
+
+#, fuzzy
+#~ msgid "This node can't be rotated using the trackworker,"
+#~ msgstr "您不能使用鐵路調整工具旋轉這個方塊。"
+
+#~ msgid "This position is protected!"
+#~ msgstr "這裡已被保護。"
+
+#~ msgid "This track can not be changed."
+#~ msgstr "您不能調整這段軌道。"
+
+#~ msgid "Use Sneak+rightclick to bypass closed doors!"
+#~ msgstr "請使用潛行+右鍵上車。"
+
+#, fuzzy
+#~ msgid "You are not allowed to modify this protected track."
+#~ msgstr "這裡已被保護,您不能在這裡建造鐵路。"
+
+#~ msgid ""
+#~ "You need to own at least one neighboring wagon to destroy this couple."
+#~ msgstr "您必須至少擁有其中一節車廂才能分開這兩節車廂。"
diff --git a/advtrains/poconvert.lua b/advtrains/poconvert.lua
new file mode 100644
index 0000000..74f962e
--- /dev/null
+++ b/advtrains/poconvert.lua
@@ -0,0 +1,185 @@
+local unescape_string
+do
+ local schartbl = { -- https://en.wikipedia.org/wiki/Escape_sequences_in_C
+ a = "\a",
+ b = "\b",
+ e = string.char(0x1b),
+ f = "\f",
+ n = "\n",
+ r = "\r",
+ t = "\t",
+ v = "\v",
+ }
+ local function replace_single(pfx, c)
+ local pl = #pfx
+ if pl % 2 == 0 then
+ return string.sub(pfx, 1, pl/2) .. c
+ end
+ return string.sub(pfx, 1, math.floor(pl/2)) .. (schartbl[c] or c)
+ end
+ unescape_string = function(str)
+ return string.gsub(str, [[(\+)([abefnrtv'"?])]], replace_single)
+ end
+end
+
+local function readstring_aux(str, pos)
+ local _, spos = string.find(str, [[^%s*"]], pos)
+ if not spos then
+ return nil
+ end
+ local ipos = spos
+ while true do
+ local _, epos, m = string.find(str, [[(\*)"]], ipos+1)
+ if not epos then
+ return error("String extends beyond the end of input")
+ end
+ ipos = epos
+ if #m % 2 == 0 then
+ return unescape_string(string.sub(str, spos+1, epos-1)), epos+1
+ end
+ end
+end
+
+local function readstring(str, pos)
+ local st = {}
+ local nxt = pos
+ while true do
+ local s, npos = readstring_aux(str, nxt)
+ if not s then
+ if not st[1] then
+ return nil, nxt
+ else
+ return table.concat(st), nxt
+ end
+ end
+ nxt = npos
+ table.insert(st, s)
+ end
+end
+
+local function readtoken(str, pos)
+ local _, epos, tok = string.find(str, [[^%s*(%S+)]], pos)
+ if epos == nil then
+ return nil, pos
+ end
+ return tok, epos+1
+end
+
+local function readcomment_add_flags(flags, s)
+ for flag in string.gmatch(s, ",%s*([^,]+)") do
+ flags[flag] = true
+ end
+end
+
+local function readcomment_aux(str, pos)
+ local _, epos, sval = string.find(str, "^\n*#([^\n]*)", pos)
+ if not epos then
+ return nil
+ end
+ return sval, epos+1
+end
+
+local function readcomment(str, pos)
+ local st = {}
+ local nxt = pos
+ local flags = {}
+ while true do
+ local s, npos = readcomment_aux(str, nxt)
+ if not npos then
+ local t = {
+ comment = table.concat(st, "\n"),
+ flags = flags,
+ }
+ return t, nxt
+ end
+ if string.sub(s, 1, 1) == "," then
+ readcomment_add_flags(flags, s)
+ end
+ table.insert(st, s)
+ nxt = npos
+ end
+end
+
+local function readpo(str)
+ local st = {}
+ local pos = 1
+ while true do
+ local entry, nxt = readcomment(str, pos)
+ local msglines = 0
+ while true do
+ local tok, npos = readtoken(str, nxt)
+ if tok == nil or string.sub(tok, 1, 1) == "#" then
+ break
+ elseif string.sub(tok, 1, 3) ~= "msg" then
+ return error("Invalid token: " .. tok)
+ elseif entry[tok] ~= nil then
+ break
+ else
+ local value, npos = readstring(str, npos)
+ assert(value ~= nil, "No string provided for " .. tok)
+ entry[tok] = value
+ nxt = npos
+ msglines = msglines+1
+ end
+ end
+ if msglines == 0 then
+ return st
+ elseif entry.msgid ~= "" then
+ assert(entry.msgid ~= nil, "Missing untranslated string")
+ assert(entry.msgstr ~= nil, "Missing translated string")
+ table.insert(st, entry)
+ end
+ pos = nxt
+ end
+end
+
+local escape_lookup = {
+ ["="] = "@=",
+ ["\n"] = "@n"
+}
+local function escape_string(st)
+ return (string.gsub(st, "[=\n]", escape_lookup))
+end
+
+local function convert_po_string(textdomain, str)
+ local st = {string.format("# textdomain: %s", textdomain)}
+ for _, entry in ipairs(readpo(str)) do
+ local line = ("%s=%s"):format(escape_string(entry.msgid), escape_string(entry.msgstr))
+ if entry.flags.fuzzy then
+ line = "#" .. line
+ end
+ table.insert(st, line)
+ end
+ return table.concat(st, "\n")
+end
+
+local function convert_po_file(textdomain, inpath, outpath)
+ local f, err = io.open(inpath, "rb")
+ assert(f, err)
+ local str = convert_po_string(textdomain, f:read("*a"))
+ f:close()
+ minetest.safe_file_write(outpath, str)
+ return str
+end
+
+local function convert_flat_po_directory(textdomain, modpath)
+ assert(textdomain, "No textdomain specified for po file conversion")
+ local mp = modpath or minetest.get_modpath(textdomain)
+ assert(mp ~= nil, "No path to write for " .. textdomain)
+ local popath = mp .. "/po"
+ local trpath = mp .. "/locale"
+ for _, infile in pairs(minetest.get_dir_list(popath, false)) do
+ local lang = string.match(infile, [[^([^%.]+)%.po$]])
+ if lang then
+ local inpath = popath .. "/" .. infile
+ local outpath = ("%s/%s.%s.tr"):format(trpath, textdomain, lang)
+ convert_po_file(textdomain, inpath, outpath)
+ end
+ end
+end
+
+return {
+ from_string = convert_po_string,
+ from_file = convert_po_file,
+ from_flat = convert_flat_po_directory,
+}
diff --git a/advtrains/protection.lua b/advtrains/protection.lua
index 36f4192..ac1cd66 100644
--- a/advtrains/protection.lua
+++ b/advtrains/protection.lua
@@ -25,13 +25,6 @@ minetest.register_privilege("railway_operator", {
give_to_singleplayer= true,
});
--- Other privileges
-minetest.register_privilege("train_ghost", {
- description = "Poskytuje imunitu proti sražení vlakem.",
- give_to_singleplayer = false,
-});
-
-
-- there is a configuration option "allow_build_only_owner". If this is active, a player having track_builder can only build rails and operate signals/turnouts in an area explicitly belonging to him
-- (checked using a dummy player called "*dummy*" (which is not an allowed player name))
@@ -152,24 +145,12 @@ function advtrains.check_track_protection(pos, pname, near, prot_p)
--atdebug("CTP: ",pos,pname,near,prot_p,"priv=",priv,"prot=",prot,"dprot=",dprot)
if not priv and (not boo or prot or not dprot) then
- local s
- if near then
- s = "Nemůžete stavět poblíž kolejí, protože vám chybí právo track_builder. Pokud toto právo chcete, domluvte se s Administrací."
- else
- s = "Nemůžete stavět koleje, protože vám chybí právo track_builder. Pokud toto právo chcete, domluvte se s Administrací."
- end
- minetest.chat_send_player(pname, s)
+ minetest.chat_send_player(pname, near and attrans("You are not allowed to build near tracks without the track_builder privilege.") or attrans("You are not allowed to build tracks without the track_builder privilege."))
minetest.log("action", pname.." tried to modify terrain "..nears.."track at "..minetest.pos_to_string(apos).." but is not permitted to (no privilege)")
return false
end
if prot then
- local s
- if near then
- s = "Zde nemůžete stavět, protože oblast je zastřežena!"
- else
- s = "Zde nemůžete stavět koleje, protože oblast je zastřežena!"
- end
- minetest.chat_send_player(pname, s)
+ minetest.chat_send_player(pname, near and attrans("You are not allowed to build near tracks at this protected position.") or attrans("You are not allowed to build tracks at this protected position."))
minetest.record_protection_violation(pos, pname)
minetest.log("action", pname.." tried to modify "..nears.."track at "..minetest.pos_to_string(apos).." but position is protected!")
return false
@@ -200,7 +181,7 @@ function advtrains.check_turnout_signal_protection(pos, pname)
nocheck=false
return true
else
- minetest.chat_send_player(pname, "Nemůžete ovládat výhybky a návěstidla. (požadované právo: railway_operator)")
+ minetest.chat_send_player(pname, attrans("You are not allowed to operate turnouts and signals without the railway_operator privilege."))
minetest.log("action", pname.." tried to operate turnout/signal at "..minetest.pos_to_string(pos).." but does not have railway_operator")
nocheck=false
return false
diff --git a/advtrains/signals.lua b/advtrains/signals.lua
index 93fd99e..35e118c 100644
--- a/advtrains/signals.lua
+++ b/advtrains/signals.lua
@@ -42,9 +42,6 @@ end
for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", als="green"}}) do
- -- advtrains.trackplacer.register_tracktype("advtrains:retrosignal", "")
- -- advtrains.trackplacer.register_tracktype("advtrains:signal", "")
-
for rotid, rotation in ipairs({"", "_30", "_45", "_60"}) do
local crea=1
if rotid==1 and r=="off" then crea=0 end
@@ -52,7 +49,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
minetest.register_node("advtrains:retrosignal_"..r..rotation, {
drawtype = "mesh",
paramtype="light",
- paramtype2="4dir",
+ paramtype2="facedir",
walkable = false,
selection_box = {
type = "fixed",
@@ -60,10 +57,9 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
},
mesh = "advtrains_retrosignal_"..r..rotation..".b3d",
tiles = {"advtrains_retrosignal.png"},
- use_texture_alpha = "opaque",
inventory_image="advtrains_retrosignal_inv.png",
drop="advtrains:retrosignal_off",
- description=attrans("Lampless Signal (@1)", attrans(r..rotation)),
+ description=attrans("Lampless Signal"),
sunlight_propagates=true,
groups = {
cracky=3,
@@ -87,7 +83,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
on_rightclick=function(pos, node, player)
local pname = player:get_player_name()
local sigd = advtrains.interlocking and advtrains.interlocking.db.get_sigd_for_signal(pos)
- if sigd then
+ if sigd and not player:get_player_control().aux1 then
advtrains.interlocking.show_signalling_form(sigd, pname)
elseif advtrains.interlocking and player:get_player_control().aux1 then
advtrains.interlocking.show_ip_form(pos, pname)
@@ -106,17 +102,17 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
main_aspects = main_aspects,
apply_aspect = simple_apply_aspect("advtrains:retrosignal_off"..rotation, "advtrains:retrosignal_on"..rotation),
get_aspect_info = function() return aspect(r=="on") end,
+ route_role = "main",
},
can_dig = can_dig_func,
after_dig_node = after_dig_func,
--TODO add rotation using trackworker
})
- -- advtrains.trackplacer.add_worked("advtrains:retrosignal", r, rotation, nil)
minetest.register_node("advtrains:signal_"..r..rotation, {
drawtype = "mesh",
paramtype="light",
- paramtype2="4dir",
+ paramtype2="facedir",
walkable = false,
selection_box = {
type = "fixed",
@@ -126,7 +122,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
tiles = {"advtrains_signal_"..r..".png"},
inventory_image="advtrains_signal_inv.png",
drop="advtrains:signal_off",
- description=attrans("Signal (@1)", attrans(r..rotation)),
+ description=attrans("Signal"),
groups = {
cracky=3,
not_blocking_trains=1,
@@ -145,7 +141,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
on_rightclick=function(pos, node, player)
local pname = player:get_player_name()
local sigd = advtrains.interlocking and advtrains.interlocking.db.get_sigd_for_signal(pos)
- if sigd then
+ if sigd and not player:get_player_control().aux1 then
advtrains.interlocking.show_signalling_form(sigd, pname)
elseif advtrains.interlocking and player:get_player_control().aux1 then
advtrains.interlocking.show_ip_form(pos, pname)
@@ -158,6 +154,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
main_aspects = main_aspects,
apply_aspect = simple_apply_aspect("advtrains:signal_off"..rotation, "advtrains:signal_on"..rotation),
get_aspect_info = function() return aspect(r=="on") end,
+ route_role = "main",
node_state = f.ls,
node_state_map = { red = "advtrains:signal_off"..rotation, green = "advtrains:signal_on"..rotation},
node_on_switch_state = function(pos, new_node, old_state, new_state)
@@ -173,24 +170,22 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
after_dig_node = after_dig_func,
--TODO add rotation using trackworker
})
- -- advtrains.trackplacer.add_worked("advtrains:signal", r, rotation, nil)
end
local crea=1
if r=="off" then crea=0 end
--tunnel signals. no rotations.
- for loc, sbox in pairs({
- l={-1/2, -1/2, -1/4, 0, 1/2, 1/4},
- r={0, -1/2, -1/4, 1/2, 1/2, 1/4},
- t={-1/2, 0, -1/4, 1/2, 1/2, 1/4},
- b={-1/4, -1/2, 1/2 - 1/8, 1/4, 1/2, 1/2},
- p={-1/4, -1/2, 5/8, 1/4, 1/2, 7/8},
- }) do
- local def = {
+ local swdesc = { -- needed for xgettext
+ l = attrans("Wallmounted Signal (left)"),
+ r = attrans("Wallmounted Signal (right)"),
+ t = attrans("Wallmounted Signal (top)"),
+ }
+ for loc, sbox in pairs({l={-1/2, -1/2, -1/4, 0, 1/2, 1/4}, r={0, -1/2, -1/4, 1/2, 1/2, 1/4}, t={-1/2, 0, -1/4, 1/2, 1/2, 1/4}}) do
+ minetest.register_node("advtrains:signal_wall_"..loc.."_"..r, {
drawtype = "mesh",
paramtype="light",
- paramtype2="4dir",
+ paramtype2="facedir",
walkable = false,
selection_box = {
type = "fixed",
@@ -199,7 +194,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
mesh = "advtrains_signal_wall_"..loc..".b3d",
tiles = {"advtrains_signal_wall_"..r..".png"},
drop="advtrains:signal_wall_"..loc.."_off",
- description=attrans("Wallmounted Signal ("..loc..")"),
+ description=swdesc[loc],
groups = {
cracky=3,
not_blocking_trains=1,
@@ -218,7 +213,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
on_rightclick=function(pos, node, player)
local pname = player:get_player_name()
local sigd = advtrains.interlocking and advtrains.interlocking.db.get_sigd_for_signal(pos)
- if sigd then
+ if sigd and not player:get_player_control().aux1 then
advtrains.interlocking.show_signalling_form(sigd, pname)
elseif advtrains.interlocking and player:get_player_control().aux1 then
advtrains.interlocking.show_ip_form(pos, pname)
@@ -231,6 +226,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
main_aspects = main_aspects,
apply_aspect = simple_apply_aspect("advtrains:signal_wall_"..loc.."_off", "advtrains:signal_wall_"..loc.."_on"),
get_aspect_info = function() return aspect(r=="on") end,
+ route_role = "main",
node_state = f.ls,
node_state_map = { red = "advtrains:signal_wall_"..loc.."_off", green = "advtrains:signal_wall_"..loc.."_on" },
node_on_switch_state = function(pos, new_node, old_state, new_state)
@@ -244,11 +240,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red",
},
can_dig = can_dig_func,
after_dig_node = after_dig_func,
- }
- if loc == "b" or loc == "p" then
- def.mesh = "advtrains_signal_wall_"..loc..".obj"
- end
- minetest.register_node("advtrains:signal_wall_"..loc.."_"..r, def)
+ })
end
end
@@ -330,15 +322,6 @@ minetest.register_node("advtrains:across_on", {
end,
})
-minetest.register_craft({
- output = "advtrains:across_off",
- recipe = {
- {"default:steel_ingot", "", "default:steel_ingot"},
- {"", "mesecons_lightstone:lightstone_red_off", ""},
- {"default:steel_ingot", "", "default:steel_ingot"},
- },
-})
-
minetest.register_abm(
{
label = "Sound for Level Crossing",
@@ -346,18 +329,11 @@ minetest.register_abm(
interval = 3,
chance = 1,
action = function(pos, node, active_object_count, active_object_count_wider)
- local meta = minetest.get_meta(pos)
- local state = meta:get_int("crossing_state")
- if state <= 0 then
- minetest.sound_play("advtrains_crossing_bell", {
- pos = pos,
- gain = 1.0, -- default
- max_hear_distance = 16, -- default, uses an euclidean metric
- })
- meta:set_int("crossing_state", 2)
- else
- meta:set_int("crossing_state", state - 1)
- end
+ minetest.sound_play("advtrains_crossing_bell", {
+ pos = pos,
+ gain = 1.0, -- default
+ max_hear_distance = 16, -- default, uses an euclidean metric
+ })
end,
}
)
diff --git a/advtrains/track_reg_helper.lua b/advtrains/track_reg_helper.lua
index f2ada81..e2f71e8 100644
--- a/advtrains/track_reg_helper.lua
+++ b/advtrains/track_reg_helper.lua
@@ -168,47 +168,12 @@ advtrains.ap.t_30deg_slope={
vst31={conns = conns(8,0,0,0.33), rail_y = 0.16, desc = "uphill 1/3", slope=true},
vst32={conns = conns(8,0,0.33,0.66), rail_y = 0.5, desc = "uphill 2/3", slope=true},
vst33={conns = conns(8,0,0.66,1), rail_y = 0.83, desc = "uphill 3/3", slope=true},
- vst41={conns = conns(8,0,0,1/4), rail_y = 1/4 - 1/8, desc = "uphill 1/4", slope=true},
- vst42={conns = conns(8,0,1/4,2/4), rail_y = 2/4 - 1/8, desc = "uphill 2/4", slope=true},
- vst43={conns = conns(8,0,2/4,3/4), rail_y = 3/4 - 1/8, desc = "uphill 3/4", slope=true},
- vst44={conns = conns(8,0,3/4,1), rail_y = 1 - 1/8, desc = "uphill 4/4", slope=true},
- vst51={conns = conns(8,0,0,1/5), rail_y = 1/5 - 1/10, desc = "uphill 1/5", slope=true},
- vst52={conns = conns(8,0,1/5,2/5), rail_y = 2/5 - 1/10, desc = "uphill 2/5", slope=true},
- vst53={conns = conns(8,0,2/5,3/5), rail_y = 3/5 - 1/10, desc = "uphill 3/5", slope=true},
- vst54={conns = conns(8,0,3/5,4/5), rail_y = 4/5 - 1/10, desc = "uphill 4/5", slope=true},
- vst55={conns = conns(8,0,4/5,1), rail_y = 5/5 - 1/10, desc = "uphill 5/5", slope=true},
- vst61={conns = conns(8,0,0,1/6), rail_y = 1/6 - 1/12, desc = "uphill 1/6", slope=true},
- vst62={conns = conns(8,0,1/6,2/6), rail_y = 2/6 - 1/12, desc = "uphill 2/6", slope=true},
- vst63={conns = conns(8,0,2/6,3/6), rail_y = 3/6 - 1/12, desc = "uphill 3/6", slope=true},
- vst64={conns = conns(8,0,3/6,4/6), rail_y = 4/6 - 1/12, desc = "uphill 4/6", slope=true},
- vst65={conns = conns(8,0,4/6,5/6), rail_y = 5/6 - 1/12, desc = "uphill 5/6", slope=true},
- vst66={conns = conns(8,0,5/6,1), rail_y = 6/6 - 1/12, desc = "uphill 6/6", slope=true},
- vst71={conns = conns(8,0,0,1/7), rail_y = 1/7 - 1/14, desc = "uphill 1/7", slope=true},
- vst72={conns = conns(8,0,1/7,2/7), rail_y = 2/7 - 1/14, desc = "uphill 2/7", slope=true},
- vst73={conns = conns(8,0,2/7,3/7), rail_y = 3/7 - 1/14, desc = "uphill 3/7", slope=true},
- vst74={conns = conns(8,0,3/7,4/7), rail_y = 4/7 - 1/14, desc = "uphill 4/7", slope=true},
- vst75={conns = conns(8,0,4/7,5/7), rail_y = 5/7 - 1/14, desc = "uphill 5/7", slope=true},
- vst76={conns = conns(8,0,5/7,6/7), rail_y = 6/7 - 1/14, desc = "uphill 6/7", slope=true},
- vst77={conns = conns(8,0,6/7,1), rail_y = 7/7 - 1/14, desc = "uphill 7/7", slope=true},
- vst81={conns = conns(8,0,0,1/8), rail_y = 1/8 - 1/16, desc = "uphill 1/8", slope=true},
- vst82={conns = conns(8,0,1/8,2/8), rail_y = 2/8 - 1/16, desc = "uphill 2/8", slope=true},
- vst83={conns = conns(8,0,2/8,3/8), rail_y = 3/8 - 1/16, desc = "uphill 3/8", slope=true},
- vst84={conns = conns(8,0,3/8,4/8), rail_y = 4/8 - 1/16, desc = "uphill 4/8", slope=true},
- vst85={conns = conns(8,0,4/8,5/8), rail_y = 5/8 - 1/16, desc = "uphill 5/8", slope=true},
- vst86={conns = conns(8,0,5/8,6/8), rail_y = 6/8 - 1/16, desc = "uphill 6/8", slope=true},
- vst87={conns = conns(8,0,6/8,7/8), rail_y = 7/8 - 1/16, desc = "uphill 7/8", slope=true},
- vst88={conns = conns(8,0,7/8,1), rail_y = 8/8 - 1/16, desc = "uphill 8/8", slope=true},
},
regsp=true,
slopeplacer={
[2]={"vst1", "vst2"},
[3]={"vst31", "vst32", "vst33"},
- [4]={"vst41", "vst42", "vst43", "vst44"},
- [5]={"vst51", "vst52", "vst53", "vst54", "vst55"},
- [6]={"vst61", "vst62", "vst63", "vst64", "vst65", "vst66"},
- [7]={"vst71", "vst72", "vst73", "vst74", "vst75", "vst76", "vst77"},
- [8]={"vst81", "vst82", "vst83", "vst84", "vst85", "vst86", "vst87", "vst88"},
- max=8,--highest entry
+ max=3,--highest entry
},
slopeplacer_45={
[2]={"vst1_45", "vst2_45"},
@@ -519,6 +484,11 @@ local function append_statemap_suffix(state_map, nnpref, rot)
return t
end
+function advtrains.default_suitable_substrate(upos)
+ return core.registered_nodes[core.get_node(upos).name]
+ and core.registered_nodes[core.get_node(upos).name].walkable
+end
+
function advtrains.register_tracks(tracktype, def, preset)
if not preset.v25_format then
error("advtrains.register_tracks(): A track preset for pre-v2.5 is used with advtrains 2.5+. Mod probably defines own track preset instead of using it from the advtrains.ap table! Please check track mod compatibility!")
@@ -531,7 +501,7 @@ function advtrains.register_tracks(tracktype, def, preset)
inventory_image = def.texture_prefix.."_placer.png",
wield_image = def.texture_prefix.."_placer.png",
groups={advtrains_trackplacer=1, digtron_on_place=1},
- liquids_pointable = true,
+ liquids_pointable = false,
on_place = function(itemstack, placer, pointed_thing)
local name = placer:get_player_name()
if not name then
@@ -543,20 +513,8 @@ function advtrains.register_tracks(tracktype, def, preset)
if not advtrains.check_track_protection(pos, name) then
return itemstack, false
end
- local node = core.get_node(pos)
- local nname = node.name
- local ndef = core.registered_nodes[nname]
- if ndef ~= nil and ndef.buildable_to then
- local s
- if def.suitable_substrate ~= nil then
- s = def.suitable_substrate(upos)
- else
- local unode = core.get_node(upos)
- local uname = unode.name
- local udef = core.registered_nodes[uname]
- s = udef ~= nil and udef.walkable
- end
- if s then
+ if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to then
+ if (def.suitable_substrate and def.suitable_substrate or advtrains.default_suitable_substrate)(upos) then
-- minetest.chat_send_all(nnprefix)
local yaw = placer:get_look_horizontal()
advtrains.trackplacer.place_track(pos, nnprefix, name, yaw)
@@ -705,21 +663,6 @@ function sl.register_placer(def, preset)
on_place = sl.create_slopeplacer_on_place(def, preset)
})
end
-
-local function check_slope_exists(nodename_prefix, lookup, step)
- if not lookup[step] then
- return false
- end
- local placenodes = lookup[step]
- while step > 0 do
- if core.registered_nodes[nodename_prefix.."_"..placenodes[step]] == nil then
- return false
- end
- step=step-1
- end
- return true
-end
-
--(itemstack, placer, pointed_thing)
function sl.create_slopeplacer_on_place(def, preset)
return function(istack, player, pt)
@@ -774,7 +717,7 @@ function sl.create_slopeplacer_on_place(def, preset)
--next node solid?
if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to or advtrains.is_protected(pos, player:get_player_name()) then
--do slopes of this distance exist?
- if check_slope_exists(def.nodename_prefix, lookup, step) then
+ if lookup[step] then
if minetest.settings:get_bool("creative_mode") or istack:get_count()>=step then
--start placing
local placenodes=lookup[step]
@@ -798,7 +741,7 @@ function sl.create_slopeplacer_on_place(def, preset)
pos=vector.add(pos, dirvec)
end
minetest.chat_send_player(player:get_player_name(), attrans("Can't place: no supporting node at upper end."))
- return istack
+ return itemstack
end
end
diff --git a/advtrains/tracks.lua b/advtrains/tracks.lua
index dba0d7a..fa7b702 100644
--- a/advtrains/tracks.lua
+++ b/advtrains/tracks.lua
@@ -1,273 +1,273 @@
--- tracks.lua
--- rewritten with advtrains 2.5 according to new track registration system
-
-
---[[
-
-Tracks in advtrains are defined by the node definition. They must have at least 2 connections, but can have any number.
-Switchable nodes (turnouts, single/double-slip switches) are implemented by having a separate node (node name) for each of the possible states.
-
- minetest.register_node(nodename, {
- ... usual node definition ...
- groups = {
- advtrains_track = 1,
- advtrains_track_<tracktype>=1
- ^- these groups tell that the node is a track
- not_blocking_trains=1,
- ^- this group tells that the node should not block trains although it's walkable.
- },
-
- at_rail_y = 0,
- ^- Height of this rail node (the y position of a wagon that stands centered on this rail)
- at_conns = {
- [1] = { c=0..15, y=0..1 },
- [2] = { c=0..15, y=0..1 },
- ( [3] = { c=0..15, y=0..1 }, )
- ( [4] = { c=0..15, y=0..1 }, )
- ( ... )
- }
- ^- Connections of this rail. There are two general cases:
- a) SIMPLE TRACK - the track has exactly 2 connections, and does not feature a turnout, crossing or other contraption
- For simple tracks, except for the at_conns table no further setup needs to be specified. A train entering on conn 1 will go out at conn 2 and vice versa.
- A track with only one connection defined is not permitted.
- b) COMPOUND TRACK - the track has more than 2 connections
- This will be used for turnouts and crossings. Tracks with more than 2 conns MUST define 'at_conn_map'.
- Switchable nodes, whose state can be changed (e.g. turnouts) MUST define a 'state_map' within the advtrains table as well.
- This differs from the behavior up until 2.4.2, where the conn mapping was fixed.
- ^- Connection definition:
- - c is the direction of the connection (0-16). For the mapping to world directions see helpers.lua.
- - Connections will be auto-rotated with param2 of the node (horizontal, param2 values 0-3 only)
- - y is the height of the connection (rail will only connect when this matches)
- ^- The index of a connection inside the conns table (1, 2, 3, ...) is referred throughout advtrains code as 'connid'
- ^- IMPORTANT: For switchable nodes (any kind of turnout), it is crucial that for all of the node's variants the at_conns table stays the same. See below.
-
- at_conn_map = {
- [1] = 2,
- [2] = 1,
- [3] = 1,
- }
- ^- Connection map of this rail. It specifies when a train enters the track on connid X, on which connid it will leave
- This field MUST be specified when the number of connections in at_conns is greater than 2
- This field may, and obviously will, vary between nodes for switchable nodes.
-
- can_dig = advtrains.track_can_dig_callback
- after_dig_node = advtrains.track_update_callback
- after_place_node = advtrains.track_update_callback
- ^- the code in these 3 default minetest API functions is required for advtrains to work, however you can add your own code
-
- on_rightclick = advtrains.state_node_on_rightclick_callback
- ^- Must be added if the node is a turnout and if it should be switched by right-click. It will cause the turnout to be switched to next_state.
-
- advtrains = {
- on_train_enter=function(pos, train_id, train, index) end
- ^- called when a train enters the rail
- on_train_leave=function(pos, train_id, train, index) end
- ^- called when a train leaves the rail
-
- -- The following function is only in effect when interlocking is enabled:
- on_train_approach = function(pos, train_id, train, index, has_entered, lzbdata)
- ^- called when a train is approaching this position, called exactly once for every path recalculation (which can happen at any time)
- ^- This is called so that if the train would start braking now, it would come to halt about(wide approx) 5 nodes before the rail.
- ^- has_entered: when true, the train is already standing on this node with its front tip, and the enter callback has already been called.
- Possibly, some actions need not to be taken in this case. Only set if it's the very first node the train is standing on.
- ^- lzbdata should be ignored and nothing should be assigned to it
-
- -- The following information is required if the node is a turnout (e.g. can be switched into different positions)
- node_state = "st"
- ^- The name of the state this node represents
- ^- Conventions for this field are as follows:
- - Two-way straight/turn switches: 'st'=straight branch, 'cr'=diverting/turn branch
- - 3-way turnouts, Y-turnouts: 'l'=left branch, 's'=straight branch, 'r'=right branch
-
- node_next_state = "cr"
- ^- The name of the state that the turnout should be switched to when it is right-clicked
-
- node_fallback_state = "st"
- ^- The name of the state that the turnout should "fall back" to when it is released
- Only used by the interlocking system, when a route on the node is released it is switched back to this state.
-
- node_state_map = {
- ["st"] = "<node name of the st variant>",
- ["cr"] = "<node name of the cr variant>",
- ... etc ...
- }
- ^- Map of state name to the appropriate node name that should be set by advtrains when a switch is requested
- Note that for all of those nodes, the at_conns table must be identical (however the conn_map will vary)
-
- node_on_switch_state = function(pos, node, oldstate, newstate)
- ^- Called when the node state is switched by advtrains, after the node replacement has commenced.
-
- Turnout switching can happen programmatically via advtrains.setstate(pos, state), via user right_click or via the interlocking system.
- In no other situation is it permissible to exchange track nodes in-place, unless both at_conns and at_conn_map stay identical.
-
- Note that the fields node_state, node_next_state and node_state_map completely replace the getstate/setstate functions.
- There must be a one-to-one mapping between states and node names and no function can be defined for state switching.
- This principle enables the seamless working of the interlocking autorouter and reduces failure points.
- The node_state_* system can also be used as drop-in replacement for the passive-API-enabled nodes (andrews-cross, mesecon_switch etc.)
- The advtrains API functions advtrains.getstate() and advtrains.setstate() remain the programmatic access points, but will now utilize the new state system.
-
-
- trackworker_next_rot = <nodename of next rotation step>,
- ^- if set, right-click with trackworker will set this node
- trackworker_rot_incr_param2 = true
- ^- if set, trackworker will increase node param2 on rightclick
-
- trackworker_next_var = <nodename of next variant>
- ^- if set, left-click with trackworker will set this node
- }
- })
-
-]]--
-
--- This file provides some utilities to register tracks, but tries to not get into the way too much
-
-
-function advtrains.track_can_dig_callback(pos, player)
- local ok, reason = advtrains.can_dig_or_modify_track(pos)
- if not ok and player then
- minetest.chat_send_player(player:get_player_name(), attrans("This track can not be removed!") .. " " .. reason)
- end
- return ok
-end
-
-function advtrains.track_update_callback(pos)
- advtrains.ndb.update(pos)
-end
-
-function advtrains.state_node_on_rightclick_callback(pos, node, player)
- if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
- local ndef = minetest.registered_nodes[node.name]
- if ndef and ndef.advtrains and ndef.advtrains.node_next_state then
- advtrains.setstate(pos, ndef.advtrains.node_next_state, node)
- advtrains.log("Switch", player:get_player_name(), pos)
- end
- end
-end
-
--- advtrains.register_node_4rot(name, nodedef)
--- Registers four rotations for the node defined by nodedef (0°, 30°, 45° and 60°; the 4 90°-steps are already handled by the param2, resulting in 16 directions total).
--- You must provide the definition for the base node, and certain fields are altered automatically for the 3 additional rotations:
--- name: appends the suffix "_30", "_45" or "_60"
--- description: appends the rotation (human-readable) in parenthesis
--- tiles_prefix: if defined, "tiles" field will be set as prefix..rotationExtension..".png"
--- mesh_prefix, mesh_suffix: if defined, "mesh" field will be set as prefix..rotationExtension..suffix
--- at_conns: are rotated according to the node rotation
--- node_state_map, trackworker_next_var: appends the suffix appropriately.
--- groups: applies save_in_at_nodedb and not_blocking_trains groups if not already present
--- The nodes are registered in the trackworker to be rotated with right-click.
--- definition_mangling_function is an optional parameter. For each of the 4 rotations, it gets passed the modified node definition and may perform final modifications to it.
--- signature: function definition_mangling_function(name, nodedef, rotationIndex, rotationSuffix)
--- Example usage: define the setstate function of turnouts (if that is not done via the "automatic" way of state_node_map)
-local rotations = {
- {i = 0, s = "", h = " (0)", n = "_30"},
- {i = 1, s = "_30", h = " (30)", n = "_45"},
- {i = 2, s = "_45", h = " (45)", n = "_60"},
- {i = 3, s = "_60", h = " (60)", n = ""},
-}
-function advtrains.register_node_4rot(ori_name, ori_ndef, definition_mangling_function)
- for _, rot in ipairs(rotations) do
- local ndef = table.copy(ori_ndef)
- if ori_ndef.advtrains then
- -- make sure advtrains table is deep-copied because we may need to replace node_state_map
- ndef.advtrains = table.copy(ori_ndef.advtrains)
- else
- ndef.advtrains = {} -- we need the table later for trackworker
- end
- -- Perform the name mangling
- local suffix = rot.s
- local name = ori_name..suffix
- ndef.description = ori_ndef.description .. rot.h
- if ori_ndef.tiles_prefix then
- ndef.tiles = { ori_ndef.tiles_prefix .. suffix .. ".png" }
- end
- if ori_ndef.mesh_prefix then
- ndef.mesh = ori_ndef.mesh_prefix .. suffix .. ori_ndef.mesh_suffix
- end
- -- rotate connections
- if ori_ndef.at_conns then
- ndef.at_conns = advtrains.rotate_conn_by(ori_ndef.at_conns, rot.i)
- end
- -- update node state map if present
- if ori_ndef.advtrains then
- if ori_ndef.advtrains.node_state_map then
- local new_nsm = {}
- for state, nname in pairs(ori_ndef.advtrains.node_state_map) do
- new_nsm[state] = nname .. suffix
- end
- ndef.advtrains.node_state_map = new_nsm
- end
- if ori_ndef.advtrains.trackworker_next_var then
- ndef.advtrains.trackworker_next_var = ori_ndef.advtrains.trackworker_next_var .. suffix
- end
- -- apply trackworker rot field
- ndef.advtrains.trackworker_next_rot = ori_name .. rot.n
- ndef.advtrains.trackworker_rot_incr_param2 = (rot.n=="")
- end
- -- apply groups
- ndef.groups.save_in_at_nodedb = 1
- ndef.groups.not_blocking_trains = 1
-
- -- give the definition mangling function an option to do some adjustments
- if definition_mangling_function then
- definition_mangling_function(name, ndef, rot.i, suffix)
- end
-
- -- register node
- minetest.register_node(":"..name, ndef)
-
- -- if this has the track_place_group set, register as a candidate for the track_place_group
- if ndef.advtrains.track_place_group then
- advtrains.trackplacer.register_candidate(ndef.advtrains.track_place_group, name, ndef, ndef.advtrains.track_place_single, true)
- end
- end
-end
-
--- track-related helper functions
-
-function advtrains.is_track(nodename)
- if not minetest.registered_nodes[nodename] then
- return false
- end
- local nodedef=minetest.registered_nodes[nodename]
- if nodedef and nodedef.groups.advtrains_track then
- return true
- end
- return false
-end
-
--- returns the connection tables of the track with given node details
--- returns: conns table, railheight, conn_map table
-function advtrains.get_track_connections(name, param2)
- local nodedef=minetest.registered_nodes[name]
- if not nodedef then atprint(" get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return nil end
- local noderot=param2
- if not param2 then noderot=0 end
- if noderot > 3 then atprint(" get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end
-
- if not nodedef.at_conns then
- return nil
- end
- --atdebug("Track connections of ",name,param2,":",nodedef.at_conns)
- return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), nodedef.at_conn_map
-end
-
--- Function called when a track is about to be dug or modified by the trackworker
--- Returns either true (ok) or false,"translated string describing reason why it isn't allowed"
--- Impl Note: possibly duplicate code in "self contained TCB" - see interlocking/tcb_ts_ui.lua!
-function advtrains.can_dig_or_modify_track(pos)
- if advtrains.get_train_at_pos(pos) then
- return false, attrans("Position is occupied by a train.")
- end
- -- interlocking: tcb, signal IP a.s.o.
- if advtrains.interlocking then
- -- TCB?
- if advtrains.interlocking.db.get_tcb(pos) then
- return false, attrans("There's a Track Circuit Break here.")
- end
- -- signal ip?
- if advtrains.interlocking.db.is_ip_at(pos, true) then -- is_ip_at with purge parameter
- return false, attrans("There's a Signal Influence Point here.")
- end
- end
- return true
-end
+-- tracks.lua
+-- rewritten with advtrains 2.5 according to new track registration system
+
+
+--[[
+
+Tracks in advtrains are defined by the node definition. They must have at least 2 connections, but can have any number.
+Switchable nodes (turnouts, single/double-slip switches) are implemented by having a separate node (node name) for each of the possible states.
+
+ minetest.register_node(nodename, {
+ ... usual node definition ...
+ groups = {
+ advtrains_track = 1,
+ advtrains_track_<tracktype>=1
+ ^- these groups tell that the node is a track
+ not_blocking_trains=1,
+ ^- this group tells that the node should not block trains although it's walkable.
+ },
+
+ at_rail_y = 0,
+ ^- Height of this rail node (the y position of a wagon that stands centered on this rail)
+ at_conns = {
+ [1] = { c=0..15, y=0..1 },
+ [2] = { c=0..15, y=0..1 },
+ ( [3] = { c=0..15, y=0..1 }, )
+ ( [4] = { c=0..15, y=0..1 }, )
+ ( ... )
+ }
+ ^- Connections of this rail. There are two general cases:
+ a) SIMPLE TRACK - the track has exactly 2 connections, and does not feature a turnout, crossing or other contraption
+ For simple tracks, except for the at_conns table no further setup needs to be specified. A train entering on conn 1 will go out at conn 2 and vice versa.
+ A track with only one connection defined is not permitted.
+ b) COMPOUND TRACK - the track has more than 2 connections
+ This will be used for turnouts and crossings. Tracks with more than 2 conns MUST define 'at_conn_map'.
+ Switchable nodes, whose state can be changed (e.g. turnouts) MUST define a 'state_map' within the advtrains table as well.
+ This differs from the behavior up until 2.4.2, where the conn mapping was fixed.
+ ^- Connection definition:
+ - c is the direction of the connection (0-16). For the mapping to world directions see helpers.lua.
+ - Connections will be auto-rotated with param2 of the node (horizontal, param2 values 0-3 only)
+ - y is the height of the connection (rail will only connect when this matches)
+ ^- The index of a connection inside the conns table (1, 2, 3, ...) is referred throughout advtrains code as 'connid'
+ ^- IMPORTANT: For switchable nodes (any kind of turnout), it is crucial that for all of the node's variants the at_conns table stays the same. See below.
+
+ at_conn_map = {
+ [1] = 2,
+ [2] = 1,
+ [3] = 1,
+ }
+ ^- Connection map of this rail. It specifies when a train enters the track on connid X, on which connid it will leave
+ This field MUST be specified when the number of connections in at_conns is greater than 2
+ This field may, and obviously will, vary between nodes for switchable nodes.
+
+ can_dig = advtrains.track_can_dig_callback
+ after_dig_node = advtrains.track_update_callback
+ after_place_node = advtrains.track_update_callback
+ ^- the code in these 3 default minetest API functions is required for advtrains to work, however you can add your own code
+
+ on_rightclick = advtrains.state_node_on_rightclick_callback
+ ^- Must be added if the node is a turnout and if it should be switched by right-click. It will cause the turnout to be switched to next_state.
+
+ advtrains = {
+ on_train_enter=function(pos, train_id, train, index) end
+ ^- called when a train enters the rail
+ on_train_leave=function(pos, train_id, train, index) end
+ ^- called when a train leaves the rail
+
+ -- The following function is only in effect when interlocking is enabled:
+ on_train_approach = function(pos, train_id, train, index, has_entered, lzbdata)
+ ^- called when a train is approaching this position, called exactly once for every path recalculation (which can happen at any time)
+ ^- This is called so that if the train would start braking now, it would come to halt about(wide approx) 5 nodes before the rail.
+ ^- has_entered: when true, the train is already standing on this node with its front tip, and the enter callback has already been called.
+ Possibly, some actions need not to be taken in this case. Only set if it's the very first node the train is standing on.
+ ^- lzbdata should be ignored and nothing should be assigned to it
+
+ -- The following information is required if the node is a turnout (e.g. can be switched into different positions)
+ node_state = "st"
+ ^- The name of the state this node represents
+ ^- Conventions for this field are as follows:
+ - Two-way straight/turn switches: 'st'=straight branch, 'cr'=diverting/turn branch
+ - 3-way turnouts, Y-turnouts: 'l'=left branch, 's'=straight branch, 'r'=right branch
+
+ node_next_state = "cr"
+ ^- The name of the state that the turnout should be switched to when it is right-clicked
+
+ node_fallback_state = "st"
+ ^- The name of the state that the turnout should "fall back" to when it is released
+ Only used by the interlocking system, when a route on the node is released it is switched back to this state.
+
+ node_state_map = {
+ ["st"] = "<node name of the st variant>",
+ ["cr"] = "<node name of the cr variant>",
+ ... etc ...
+ }
+ ^- Map of state name to the appropriate node name that should be set by advtrains when a switch is requested
+ Note that for all of those nodes, the at_conns table must be identical (however the conn_map will vary)
+
+ node_on_switch_state = function(pos, node, oldstate, newstate)
+ ^- Called when the node state is switched by advtrains, after the node replacement has commenced.
+
+ Turnout switching can happen programmatically via advtrains.setstate(pos, state), via user right_click or via the interlocking system.
+ In no other situation is it permissible to exchange track nodes in-place, unless both at_conns and at_conn_map stay identical.
+
+ Note that the fields node_state, node_next_state and node_state_map completely replace the getstate/setstate functions.
+ There must be a one-to-one mapping between states and node names and no function can be defined for state switching.
+ This principle enables the seamless working of the interlocking autorouter and reduces failure points.
+ The node_state_* system can also be used as drop-in replacement for the passive-API-enabled nodes (andrews-cross, mesecon_switch etc.)
+ The advtrains API functions advtrains.getstate() and advtrains.setstate() remain the programmatic access points, but will now utilize the new state system.
+
+
+ trackworker_next_rot = <nodename of next rotation step>,
+ ^- if set, right-click with trackworker will set this node
+ trackworker_rot_incr_param2 = true
+ ^- if set, trackworker will increase node param2 on rightclick
+
+ trackworker_next_var = <nodename of next variant>
+ ^- if set, left-click with trackworker will set this node
+ }
+ })
+
+]]--
+
+-- This file provides some utilities to register tracks, but tries to not get into the way too much
+
+
+function advtrains.track_can_dig_callback(pos, player)
+ local ok, reason = advtrains.can_dig_or_modify_track(pos)
+ if not ok and player then
+ minetest.chat_send_player(player:get_player_name(), attrans("This track can not be removed!") .. " " .. reason)
+ end
+ return ok
+end
+
+function advtrains.track_update_callback(pos)
+ advtrains.ndb.update(pos)
+end
+
+function advtrains.state_node_on_rightclick_callback(pos, node, player)
+ if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then
+ local ndef = minetest.registered_nodes[node.name]
+ if ndef and ndef.advtrains and ndef.advtrains.node_next_state then
+ advtrains.setstate(pos, ndef.advtrains.node_next_state, node)
+ advtrains.log("Switch", player:get_player_name(), pos)
+ end
+ end
+end
+
+-- advtrains.register_node_4rot(name, nodedef)
+-- Registers four rotations for the node defined by nodedef (0°, 30°, 45° and 60°; the 4 90°-steps are already handled by the param2, resulting in 16 directions total).
+-- You must provide the definition for the base node, and certain fields are altered automatically for the 3 additional rotations:
+-- name: appends the suffix "_30", "_45" or "_60"
+-- description: appends the rotation (human-readable) in parenthesis
+-- tiles_prefix: if defined, "tiles" field will be set as prefix..rotationExtension..".png"
+-- mesh_prefix, mesh_suffix: if defined, "mesh" field will be set as prefix..rotationExtension..suffix
+-- at_conns: are rotated according to the node rotation
+-- node_state_map, trackworker_next_var: appends the suffix appropriately.
+-- groups: applies save_in_at_nodedb and not_blocking_trains groups if not already present
+-- The nodes are registered in the trackworker to be rotated with right-click.
+-- definition_mangling_function is an optional parameter. For each of the 4 rotations, it gets passed the modified node definition and may perform final modifications to it.
+-- signature: function definition_mangling_function(name, nodedef, rotationIndex, rotationSuffix)
+-- Example usage: define the setstate function of turnouts (if that is not done via the "automatic" way of state_node_map)
+local rotations = {
+ {i = 0, s = "", h = " (0)", n = "_30"},
+ {i = 1, s = "_30", h = " (30)", n = "_45"},
+ {i = 2, s = "_45", h = " (45)", n = "_60"},
+ {i = 3, s = "_60", h = " (60)", n = ""},
+}
+function advtrains.register_node_4rot(ori_name, ori_ndef, definition_mangling_function)
+ for _, rot in ipairs(rotations) do
+ local ndef = table.copy(ori_ndef)
+ if ori_ndef.advtrains then
+ -- make sure advtrains table is deep-copied because we may need to replace node_state_map
+ ndef.advtrains = table.copy(ori_ndef.advtrains)
+ else
+ ndef.advtrains = {} -- we need the table later for trackworker
+ end
+ -- Perform the name mangling
+ local suffix = rot.s
+ local name = ori_name..suffix
+ ndef.description = ori_ndef.description .. rot.h
+ if ori_ndef.tiles_prefix then
+ ndef.tiles = { ori_ndef.tiles_prefix .. suffix .. ".png" }
+ end
+ if ori_ndef.mesh_prefix then
+ ndef.mesh = ori_ndef.mesh_prefix .. suffix .. ori_ndef.mesh_suffix
+ end
+ -- rotate connections
+ if ori_ndef.at_conns then
+ ndef.at_conns = advtrains.rotate_conn_by(ori_ndef.at_conns, rot.i)
+ end
+ -- update node state map if present
+ if ori_ndef.advtrains then
+ if ori_ndef.advtrains.node_state_map then
+ local new_nsm = {}
+ for state, nname in pairs(ori_ndef.advtrains.node_state_map) do
+ new_nsm[state] = nname .. suffix
+ end
+ ndef.advtrains.node_state_map = new_nsm
+ end
+ if ori_ndef.advtrains.trackworker_next_var then
+ ndef.advtrains.trackworker_next_var = ori_ndef.advtrains.trackworker_next_var .. suffix
+ end
+ -- apply trackworker rot field
+ ndef.advtrains.trackworker_next_rot = ori_name .. rot.n
+ ndef.advtrains.trackworker_rot_incr_param2 = (rot.n=="")
+ end
+ -- apply groups
+ ndef.groups.save_in_at_nodedb = 1
+ ndef.groups.not_blocking_trains = 1
+
+ -- give the definition mangling function an option to do some adjustments
+ if definition_mangling_function then
+ definition_mangling_function(name, ndef, rot.i, suffix)
+ end
+
+ -- register node
+ minetest.register_node(":"..name, ndef)
+
+ -- if this has the track_place_group set, register as a candidate for the track_place_group
+ if ndef.advtrains.track_place_group then
+ advtrains.trackplacer.register_candidate(ndef.advtrains.track_place_group, name, ndef, ndef.advtrains.track_place_single, true)
+ end
+ end
+end
+
+-- track-related helper functions
+
+function advtrains.is_track(nodename)
+ if not minetest.registered_nodes[nodename] then
+ return false
+ end
+ local nodedef=minetest.registered_nodes[nodename]
+ if nodedef and nodedef.groups.advtrains_track then
+ return true
+ end
+ return false
+end
+
+-- returns the connection tables of the track with given node details
+-- returns: conns table, railheight, conn_map table
+function advtrains.get_track_connections(name, param2)
+ local nodedef=minetest.registered_nodes[name]
+ if not nodedef then atprint(" get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return nil end
+ local noderot=param2
+ if not param2 then noderot=0 end
+ if noderot > 3 then atprint(" get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end
+
+ if not nodedef.at_conns then
+ return nil
+ end
+ --atdebug("Track connections of ",name,param2,":",nodedef.at_conns)
+ return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), nodedef.at_conn_map
+end
+
+-- Function called when a track is about to be dug or modified by the trackworker
+-- Returns either true (ok) or false,"translated string describing reason why it isn't allowed"
+-- Impl Note: possibly duplicate code in "self contained TCB" - see interlocking/tcb_ts_ui.lua!
+function advtrains.can_dig_or_modify_track(pos)
+ if advtrains.get_train_at_pos(pos) then
+ return false, attrans("Position is occupied by a train.")
+ end
+ -- interlocking: tcb, signal IP a.s.o.
+ if advtrains.interlocking then
+ -- TCB?
+ if advtrains.interlocking.db.get_tcb(pos) then
+ return false, attrans("There's a Track Circuit Break here.")
+ end
+ -- signal ip?
+ if advtrains.interlocking.db.is_ip_at(pos, true) then -- is_ip_at with purge parameter
+ return false, attrans("There's a Signal Influence Point here.")
+ end
+ end
+ return true
+end
diff --git a/advtrains/wagons.lua b/advtrains/wagons.lua
index 15e0c61..760c7da 100644
--- a/advtrains/wagons.lua
+++ b/advtrains/wagons.lua
@@ -7,11 +7,13 @@
-- An entity is ONLY spawned by update_trainpart_properties when it finds it useful.
-- Only data that are only important to the entity itself are stored in the luaentity
+-- Translation
+S = attrans
+
-- TP delay when getting off wagon
-local GETOFF_TP_DELAY = 0.25
+local GETOFF_TP_DELAY = 0.5
local IGNORE_WORLD = advtrains.IGNORE_WORLD
-local has_wielded_light = core.get_modpath("wielded_light")
advtrains.wagons = {}
advtrains.wagon_alias = {}
@@ -50,21 +52,18 @@ local function make_inv_name(uid)
end
-local wagon_base_initial_properties = {
+local wagon={
collisionbox = {-0.5,-0.5,-0.5, 0.5,0.5,0.5},
--physical = true,
visual = "mesh",
mesh = "wagon.b3d",
visual_size = {x=1, y=1},
textures = {"black.png"},
- static_save=false,
-}
-
-local wagon = {
is_wagon=true,
wagon_span=1,--how many index units of space does this wagon consume
wagon_width=3, -- Wagon width in meters
has_inventory=false,
+ static_save=false,
}
@@ -158,12 +157,12 @@ function wagon:ensure_init()
end
end
if not self.noninitticks then
- atwarn("wagon",self.id,"uninitialized init=",self.initialized)
+ atwarn("Wagon",self.id,S("Uninitialized init="),self.initialized)
self.noninitticks=0
end
self.noninitticks=self.noninitticks+1
if self.noninitticks>20 then
- atwarn("wagon",self.id,"uninitialized, removing")
+ atwarn("Wagon",self.id,S("Uninitialized, removing"))
self:destroy()
else
self.object:set_velocity({x=0,y=0,z=0})
@@ -186,7 +185,7 @@ function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direct
return
end
if data.owner and puncher:get_player_name()~=data.owner and (not minetest.check_player_privs(puncher, {train_admin = true })) then
- minetest.chat_send_player(puncher:get_player_name(), attrans("This wagon is owned by @1, you can't destroy it.", data.owner));
+ minetest.chat_send_player(puncher:get_player_name(), S("This wagon is owned by @1, you can't destroy it.", data.owner));
return
end
@@ -205,25 +204,25 @@ function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direct
if self.has_inventory then
local inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..self.id})
if not inv then -- inventory is not initialized when wagon was never loaded - should never happen
- atwarn("Destroying wagon with inventory, but inventory is not found? Shouldn't happen!")
+ atwarn(S("Destroying wagon with inventory, but inventory is not found? Shouldn't happen!"))
return
end
for listname, _ in pairs(inv:get_lists()) do
if not inv:is_empty(listname) then
- minetest.chat_send_player(puncher:get_player_name(), attrans("The wagon's inventory is not empty."));
+ minetest.chat_send_player(puncher:get_player_name(), S("The wagon's inventory is not empty."));
return
end
end
end
if #(self:train().trainparts)>1 then
- minetest.chat_send_player(puncher:get_player_name(), attrans("Wagon needs to be decoupled from other wagons in order to destroy it."));
+ minetest.chat_send_player(puncher:get_player_name(), S("Wagon needs to be decoupled from other wagons in order to destroy it."));
return
end
local pc=puncher:get_player_control()
if not pc.sneak then
- minetest.chat_send_player(puncher:get_player_name(), attrans("Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon."))
+ minetest.chat_send_player(puncher:get_player_name(), S("Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon."))
return
end
@@ -244,7 +243,7 @@ function wagon:destroy()
if self.id then
local data = advtrains.wagons[self.id]
if not data then
- atwarn("wagon:destroy(): data is not set!")
+ atwarn(S(" wagon:destroy(): data is not set!"))
return
end
@@ -309,9 +308,6 @@ function wagon:on_step(dtime)
if self.custom_on_step then
self:custom_on_step(dtime, data, train)
end
- if has_wielded_light and self.light_level ~= nil then
- wielded_light.track_user_entity(self.object, "wagon", string.format("ch_core:light_%02d", self.light_level))
- end
--driver control
for seatno, seat in ipairs(self.seats) do
@@ -357,31 +353,32 @@ function wagon:on_step(dtime)
if pc.up or pc.down then
self:get_off(seatno)
end
- end
+ end
end
if pc.aux1 and pc.sneak then
self:get_off(seatno)
end
end
end
-
+
--check infotext
local outside=train.text_outside or ""
if setting_show_ids then
- outside = outside .. "\nvlak:" .. data.train_id .. " vagon:" .. self.id .. " vlastník/ice:" .. ch_core.prihlasovaci_na_zobrazovaci(data.owner)
+ outside = outside .. "\nT:" .. data.train_id .. " W:" .. self.id .. " O:" .. data.owner
end
-
+
+
--show off-track information in outside text instead of notifying the whole server about this
if train.off_track then
- outside = outside .."\n!!! Vlak mimo koleje !!!"
+ outside = outside .."\n"..S("!!! Train off track !!!")
end
-- liquid container: display liquid contents in infotext
if self.techage_liquid_capacity then
if data.techage_liquid and data.techage_liquid.name then
- outside = outside .."\nKapalina: "..data.techage_liquid.name..", "..data.techage_liquid.amount.." jednotek"
+ outside = outside .."\n"..S("Liquid: ")..data.techage_liquid.name..", "..data.techage_liquid.amount..S(" units")
else
- outside = outside .."\nKapalina: empty"
+ outside = outside .."\n"..S("Liquid: empty")
end
end
@@ -467,26 +464,34 @@ function wagon:on_step(dtime)
--needs to know index and path
if train.velocity==0 and self.door_entry and train.door_open and train.door_open~=0 then
--using the mapping created by the trainlogic globalstep
+ local platform_offset = math.floor(self.wagon_width / 2)
for i, ino in ipairs(self.door_entry) do
--fct is the flipstate flag from door animation above
local aci = advtrains.path_get_index_by_offset(train, index, ino*fct)
local ix1, ix2 = advtrains.path_get_adjacent(train, aci)
-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
-- (x z) rotated by 90deg is (-z x) (http://stackoverflow.com/a/4780141)
- local add = { x = (ix2.z-ix1.z)*train.door_open, y = 0, z = (ix1.x-ix2.x)*train.door_open }
- local pts1=vector.round(vector.add(ix1, add))
- local pts2=vector.round(vector.add(ix2, add))
- if minetest.get_item_group(minetest.get_node(pts1).name, "platform")>0 then
- local ckpts={
- pts1,
- pts2,
- vector.add(pts1, {x=0, y=1, z=0}),
- vector.add(pts2, {x=0, y=1, z=0}),
- }
- for _,ckpos in ipairs(ckpts) do
- local cpp=minetest.pos_to_string(ckpos)
- if advtrains.playersbypts[cpp] then
- self:on_rightclick(advtrains.playersbypts[cpp])
+ local add = {
+ x = atround((ix2.z-ix1.z)*train.door_open),
+ y = 0,
+ z = atround((ix1.x-ix2.x)*train.door_open)
+ }
+ for offset = (platform_offset == 0 and 0 or 1), platform_offset do
+ local scaled_add = vector.multiply(add, offset)
+ local pts1=vector.add(ix1, scaled_add)
+ local pts2=vector.add(ix2, scaled_add)
+ if minetest.get_item_group(minetest.get_node(pts1).name, "platform")>0 then
+ local ckpts={
+ pts1,
+ pts2,
+ vector.add(pts1, {x=0, y=1, z=0}),
+ vector.add(pts2, {x=0, y=1, z=0}),
+ }
+ for _,ckpos in ipairs(ckpts) do
+ local cpp=minetest.pos_to_string(ckpos)
+ if advtrains.playersbypts[cpp] then
+ self:on_rightclick(advtrains.playersbypts[cpp])
+ end
end
end
end
@@ -582,20 +587,18 @@ function wagon:on_step(dtime)
end
end
- local wagon_yaw_changed = not advtrains.yaw_equals(self.old_yaw, oyaw)
-
if not self.old_velocity_vector
or not vector.equals(velocityvec, self.old_velocity_vector)
or not self.old_acceleration_vector
or not vector.equals(accelerationvec, self.old_acceleration_vector)
- or wagon_yaw_changed
+ or self.old_yaw~=oyaw
or updatepct_timer_elapsed then--only send update packet if something changed
self.object:set_pos(pos)
self.object:set_velocity(velocityvec)
self.object:set_acceleration(accelerationvec)
- if #self.seats > 0 and wagon_yaw_changed then
+ if #self.seats > 0 and self.old_yaw ~= oyaw then
if not self.player_yaw then
self.player_yaw = {}
end
@@ -614,7 +617,7 @@ function wagon:on_step(dtime)
end
end
self.turning = true
- elseif not wagon_yaw_changed then
+ elseif self.old_yaw == oyaw then
-- train is no longer turning
self.turning = false
end
@@ -669,21 +672,21 @@ function wagon:on_rightclick(clicker)
end
end
if self.has_inventory and self.get_inventory_formspec and advtrains.check_driving_couple_protection(pname, data.owner, data.whitelist) then
- poss[#poss+1]={name=attrans("Show Inventory"), key="inv"}
+ poss[#poss+1]={name=S("Show Inventory"), key="inv"}
end
if self.seat_groups[sgr].driving_ctrl_access and advtrains.check_driving_couple_protection(pname, data.owner, data.whitelist) then
- poss[#poss+1]={name=attrans("Onboard Computer"), key="bordcom"}
+ poss[#poss+1]={name=S("Onboard Computer"), key="bordcom"}
end
if data.owner==pname then
- poss[#poss+1]={name=attrans("Wagon properties"), key="prop"}
+ poss[#poss+1]={name=S("Wagon properties"), key="prop"}
end
if not self.seat_groups[sgr].require_doors_open or self:train().door_open~=0 then
- poss[#poss+1]={name=attrans("Get off"), key="off"}
+ poss[#poss+1]={name=S("Get off"), key="off"}
else
if clicker:get_player_control().sneak then
- poss[#poss+1]={name=attrans("Get off (forced)"), key="off"}
+ poss[#poss+1]={name=S("Get off (forced)"), key="off"}
else
- poss[#poss+1]={name=attrans("(Doors closed)"), key="dcwarn"}
+ poss[#poss+1]={name=S("(Doors closed)"), key="dcwarn"}
end
end
if #poss==0 then
@@ -693,7 +696,7 @@ function wagon:on_rightclick(clicker)
else
local form = "size[5,"..1+(#poss).."]"
for pos,ent in ipairs(poss) do
- form = form .. "button_exit[0.5,"..(pos-0.5)..";4,1;"..ent.key..";"..ent.name.."]"
+ form = form.. "button_exit[0.5,"..(pos-0.5)..";4,1;"..ent.key..";"..ent.name.."]"
end
minetest.show_formspec(pname, "advtrains_seating_"..self.id, form)
end
@@ -712,7 +715,7 @@ function wagon:on_rightclick(clicker)
end
local doors_open = self:train().door_open~=0 or clicker:get_player_control().sneak
- local allow, rsn=false, attrans("This wagon has no seats.")
+ local allow, rsn=false, S("This wagon has no seats.")
for _,sgr in ipairs(self.assign_to_seat_group) do
allow, rsn = self:check_seat_group_access(pname, sgr)
if allow then
@@ -723,16 +726,16 @@ function wagon:on_rightclick(clicker)
self:get_on(clicker, seatid)
return
else
- rsn=attrans("This wagon is full.")
+ rsn=S("This wagon is full.")
end
else
- rsn=attrans("Doors are closed! (Try holding sneak key!)")
+ rsn=S("Doors are closed! (Try holding sneak key!)")
end
end
end
end
end
- minetest.chat_send_player(pname, rsn or attrans("You can't get on this wagon."))
+ minetest.chat_send_player(pname, rsn or S("You can't get on this wagon."))
else
self:show_get_on_form(pname)
end
@@ -858,7 +861,7 @@ function wagon:show_get_on_form(pname)
end
return
end
- local form, comma="size[5,8]label[0.5,0.5;"..attrans("Select seat:").."]textlist[0.5,1;4,6;seat;", ""
+ local form, comma="size[5,8]label[0.5,0.5;"..S("Select seat:").."]textlist[0.5,1;4,6;seat;", ""
for seatno, seattbl in ipairs(self.seats) do
local addtext, colorcode="", ""
if data.seatp and data.seatp[seatno] then
@@ -870,7 +873,7 @@ function wagon:show_get_on_form(pname)
end
form=form..";0,false]"
if self.has_inventory and self.get_inventory_formspec then
- form=form.."button_exit[1,7;3,1;inv;"..attrans("Show Inventory").."]"
+ form=form.."button_exit[1,7;3,1;inv;"..S("Show Inventory").."]"
end
minetest.show_formspec(pname, "advtrains_geton_"..self.id, form)
end
@@ -882,26 +885,26 @@ function wagon:show_wagon_properties(pname)
]]
local data = advtrains.wagons[self.id]
local form="size[5,5]"
- form=form.."label[0.2,0;"..attrans("This Wagon ID")..": "..self.id.."]"
- form = form .. "field[0.5,1;4.5,1;whitelist;"..attrans("Allow these players to access your wagon:")..";"..minetest.formspec_escape(data.whitelist or "").."]"
- form = form .. "field[0.5,2;4.5,1;roadnumber;"..attrans("Wagon road number:")..";"..minetest.formspec_escape(data.roadnumber or "").."]"
+ form=form.."label[0.2,0;"..S("This Wagon ID")..": "..self.id.." ("..data.owner..")]"
+ form = form.."field[0.5,1;4.5,1;whitelist;"..S("Allow these players to access your wagon:")..";"..minetest.formspec_escape(data.whitelist or "").."]"
+ form = form.."field[0.5,2;4.5,1;roadnumber;"..S("Wagon road number:")..";"..minetest.formspec_escape(data.roadnumber or "").."]"
local fc = ""
if data.fc then
fc = table.concat(data.fc, "!")
end
- form = form .. "field[0.5,3;4.5,1;fc;" .. attrans("Freight Code:") ..";"..fc.."]"
+ form = form.. "field[0.5,3;4.5,1;fc;"..S("Freight Code:")..";"..fc.."]"
if data.fc then
if not data.fcind then data.fcind = 1 end
if data.fcind > 1 then
- form=form.."button[0.5,3.5;1,1;fcp;" .. attrans("prev FC") .."]"
+ form=form.."button[0.5,3.5;1,1;fcp;"..S("Prev FC").."]"
end
- form=form.."label[1.5,3.5;" .. attrans("Current FC:").."]"
+ form=form.."label[1.5,3.5;"..S("Current FC: ").."]"
local cur = data.fc[data.fcind] or ""
form=form.."label[1.5,3.75;"..minetest.formspec_escape(cur).."]"
- form=form.."button[3.5,3.5;1,1;fcn;" .. attrans("next FC") .. "]"
+ form=form.."button[3.5,3.5;1,1;fcn;"..S("Next FC:").."]"
end
- form=form.."button_exit[0.5,4.5;4,1;save;"..attrans("Save wagon properties").."]"
+ form=form.."button_exit[0.5,4.5;4,1;save;"..S("Save wagon properties").."]"
minetest.show_formspec(pname, "advtrains_prop_"..self.id, form)
end
@@ -976,17 +979,7 @@ function advtrains.step_fc(data)
end
-local function limit_text(t, limit)
- local tbl = t:split("\n")
- if #tbl <= limit then
- return t
- else
- for i = #t, limit + 1, -1 do
- tbl[i] = nil
- end
- return table.concat(tbl, "\n")
- end
-end
+
function wagon:show_bordcom(pname)
@@ -996,30 +989,30 @@ function wagon:show_bordcom(pname)
local linhei
local form = "size[11,9]label[0.5,0;AdvTrains Boardcom v0.1]"
- form=form.."textarea[7.5,0.05;10,1;;"..attrans("Train ID")..": "..(minetest.formspec_escape(train.id or ""))..";]"
- form=form.."textarea[0.5,1.5;7,1;text_outside;"..attrans("Text displayed outside on train")..";"..(minetest.formspec_escape(train.text_outside or "")).."]"
- form=form.."textarea[0.5,3;7,1;text_inside;"..attrans("Text displayed inside train")..";"..(minetest.formspec_escape(train.text_inside or "")).."]"
- form=form.."field[7.5,1.75;3,1;line;"..attrans("Line")..";"..(minetest.formspec_escape(train.line or "")).."]"
- form=form.."field[7.5,3.25;3,1;routingcode;"..attrans("Routingcode")..";"..(minetest.formspec_escape(train.routingcode or "")).."]"
+ form=form.."textarea[7.5,0.05;10,1;;"..S("Train ID")..": "..(minetest.formspec_escape(train.id or ""))..";]"
+ form=form.."textarea[0.5,1.5;7,1;text_outside;"..S("Text displayed outside on train")..";"..(minetest.formspec_escape(train.text_outside or "")).."]"
+ form=form.."textarea[0.5,3;7,1;text_inside;"..S("Text displayed inside train")..";"..(minetest.formspec_escape(train.text_inside or "")).."]"
+ form=form.."field[7.5,1.75;3,1;line;"..S("Line")..";"..(minetest.formspec_escape(train.line or "")).."]"
+ form=form.."field[7.5,3.25;3,1;routingcode;"..S("Routingcode")..";"..(minetest.formspec_escape(train.routingcode or "")).."]"
--row 5 : train overview and autocoupling
if train.velocity==0 then
- form=form.."label[0.5,4;"..attrans("Train overview/coupling control:").."]"
+ form=form.."label[0.5,4;"..S("Train overview /coupling control:").."])"
linhei=5
local pre_own, pre_wl, owns_any = nil, nil, minetest.check_player_privs(pname, "train_admin")
for i, tpid in ipairs(train.trainparts) do
local ent = advtrains.wagons[tpid]
if ent then
local roadnumber = ent.roadnumber or ""
- form = form .. string.format("button[%d,%d;%d,%d;%s;%s]", i, linhei, 1, 0.2, "wgprp"..i, roadnumber)
+ form = form.. string.format("button[%d,%d;%d,%d;%s;%s]", i, linhei, 1, 0.2, "wgprp"..i, roadnumber)
local ename = ent.type
- form = form .. "item_image["..i..","..(linhei+0.5)..";1,1;"..ename.."]"
+ form = form.. "item_image["..i..","..(linhei+0.5)..";1,1;"..ename.."]"
if i~=1 then
if checklock(pname, ent.owner, pre_own, ent.whitelist, pre_wl) then
- form = form .. "image_button["..(i-0.5)..","..(linhei+1.5)..";1,1;advtrains_discouple.png;dcpl_"..i..";]"
+ form = form.. "image_button["..(i-0.5)..","..(linhei+1.5)..";1,1;advtrains_discouple.png;dcpl_"..i..";]"
end
end
if i == data.pos_in_trainparts then
- form = form .. "box["..(i-0.1)..","..(linhei+0.4)..";1,1;green]"
+ form = form.. "box["..(i-0.1)..","..(linhei+0.4)..";1,1;green]"
end
pre_own = ent.owner
pre_wl = ent.whitelist
@@ -1028,24 +1021,24 @@ function wagon:show_bordcom(pname)
end
if train.movedir==1 then
- form = form .. "label["..(#train.trainparts+1)..","..(linhei)..";-->]"
+ form = form.. "label["..(#train.trainparts+1)..","..(linhei)..";-->]"
else
- form = form .. "label[0.5,"..(linhei)..";<--]"
+ form = form.. "label[0.5,"..(linhei)..";<--]"
end
--check cpl_eid_front and _back of train
local couple_front = checkcouple(train.cpl_front)
local couple_back = checkcouple(train.cpl_back)
if couple_front then
- form = form .. "image_button[0.5,"..(linhei+1)..";1,1;advtrains_couple.png;cpl_f;]"
+ form = form.. "image_button[0.5,"..(linhei+1)..";1,1;advtrains_couple.png;cpl_f;]"
end
if couple_back then
- form = form .. "image_button["..(#train.trainparts+0.5)..","..(linhei+1)..";1,1;advtrains_couple.png;cpl_b;]"
+ form = form.. "image_button["..(#train.trainparts+0.5)..","..(linhei+1)..";1,1;advtrains_couple.png;cpl_b;]"
end
else
- form=form.."label[0.5,4.5;" .. attrans("Train overview / coupling control is only shown when the train stands.") .. "]"
+ form=form.."label[0.5,4.5;"..S("Train overview / coupling control is only shown when the train stands.").."]"
end
- form = form .. "button[0.5,8;3,1;save;" .. attrans("Save") .. "]"
+ form = form.. "button[0.5,8;3,1;save;"..S("Save").."]"
-- Interlocking functionality: If the interlocking module is loaded, you can set the signal aspect
-- from inside the train
@@ -1055,14 +1048,14 @@ function wagon:show_bordcom(pname)
local oci = train.lzb.checkpoints[i]
if oci.udata and oci.udata.signal_pos then
if advtrains.interlocking.db.get_sigd_for_signal(oci.udata.signal_pos) then
- form = form .. "button[4.5,8;5,1;ilrs;" .. attrans("Remote Routesetting") .. "]"
+ form = form.. "button[4.5,8;5,1;ilrs;"..S("Remote Routesetting").."]"
break
end
end
i=i+1
end
if train.ars_disable then
- form = form .. "button[4.5,7;5,1;ilarsenable;" .. attrans("Clear 'Disable ARS' flag") .. "]"
+ form = form.. "button[4.5,7;5,1;ilarsenable;"..S("Clear 'Disable ARS' flag").."]"
end
end
@@ -1079,14 +1072,14 @@ function wagon:handle_bordcom_fields(pname, formname, fields)
if not train then return end
if fields.text_outside then
if fields.text_outside~="" then
- train.text_outside = limit_text(fields.text_outside, 3)
+ train.text_outside=fields.text_outside
else
train.text_outside=nil
end
end
if fields.text_inside then
if fields.text_inside~="" then
- train.text_inside = limit_text(fields.text_inside, 5)
+ train.text_inside=fields.text_inside
else
train.text_inside=nil
end
@@ -1268,18 +1261,18 @@ function wagon:seating_from_key_helper(pname, fields, no)
end
if fields.inv and self.has_inventory and self.get_inventory_formspec then
minetest.close_formspec(pname, "advtrains_seating_"..self.id)
- minetest.after(0.1, minetest.show_formspec, pname, "advtrains_inv_"..self.id, self:get_inventory_formspec(pname, make_inv_name(self.id)))
+ minetest.show_formspec(pname, "advtrains_inv_"..self.id, self:get_inventory_formspec(pname, make_inv_name(self.id)))
end
if fields.prop and data.owner==pname then
minetest.close_formspec(pname, "advtrains_seating_"..self.id)
- minetest.after(0.1, function(pn) self:show_wagon_properties(pn) end, pname)
+ self:show_wagon_properties(pname)
end
if fields.bordcom and self.seat_groups[sgr].driving_ctrl_access and advtrains.check_driving_couple_protection(pname, data.owner, data.whitelist) then
minetest.close_formspec(pname, "advtrains_seating_"..self.id)
- minetest.after(0.1, function(pn) self:show_bordcom(pn) end, pname)
+ self:show_bordcom(pname)
end
if fields.dcwarn then
- minetest.chat_send_player(pname, attrans("Doors are closed. Use Sneak+rightclick to ignore the closed doors and get off."))
+ minetest.chat_send_player(pname, S("Doors are closed. Use Sneak+rightclick to ignore the closed doors and get off."))
end
if fields.off then
self:get_off(no)
@@ -1288,7 +1281,7 @@ end
function wagon:check_seat_group_access(pname, sgr)
local data = advtrains.wagons[self.id]
if self.seat_groups[sgr].driving_ctrl_access and not (advtrains.check_driving_couple_protection(pname, data.owner, data.whitelist)) then
- return false, attrans("You are not allowed to access the driver stand.")
+ return false, S("You are not allowed to access the driver stand.")
end
if self.seat_groups[sgr].driving_ctrl_access then
advtrains.log("Drive", pname, self.object:get_pos(), self:train().text_outside)
@@ -1308,7 +1301,7 @@ end
function advtrains.safe_decouple_wagon(w_id, pname, try_run)
if not minetest.check_player_privs(pname, "train_operator") then
- minetest.chat_send_player(pname, attrans("Missing train_operator privilege"))
+ minetest.chat_send_player(pname, S("Missing train_operator privilege"))
return false
end
local data = advtrains.wagons[w_id]
@@ -1326,7 +1319,7 @@ function advtrains.safe_decouple_wagon(w_id, pname, try_run)
end
if not checklock(pname, data.owner, owdata.owner, data.whitelist, owdata.whitelist) then
- minetest.chat_send_player(pname, attrans("Not allowed to do this."))
+ minetest.chat_send_player(pname, S("Not allowed to do this."))
return false
end
@@ -1351,7 +1344,7 @@ function advtrains.get_wagon_prototype(data)
end
local rt, proto = advtrains.resolve_wagon_alias(wt)
if not rt then
- --atwarn("Unable to load wagon type",wt,", using placeholder")
+ --atwarn(S("Unable to load wagon type"),wt,S(", using placeholder"))
rt = "advtrains:wagon_placeholder"
proto = advtrains.wagon_prototypes[rt]
end
@@ -1388,7 +1381,7 @@ function advtrains.standard_inventory_formspec(self, pname, invname)
local r = "size[8,11]"..
"list["..invname..";box;0,0;8,3;]"
if data.owner==pname then
- r = r .. "button_exit[0,9;4,1;prop;"..attrans("Wagon properties").."]"
+ r = r .. "button_exit[0,9;4,1;prop;"..S("Wagon properties").."]"
end
r = r .. "list[current_player;main;0,5;8,4;]"..
"listring[]"
@@ -1400,41 +1393,24 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati
if not string.match(sysname, ":") then
sysname = "advtrains:"..sysname_p
end
- if prototype.initial_properties ~= nil then
- local ip = prototype.initial_properties
- if ip.selectionbox == nil or ip.selectionbox.rotate == nil then
- assert(prototype.wagon_span ~= nil)
- assert(type(prototype.wagon_span) == "number")
- local wagon_span = prototype.wagon_span
- ip.selectionbox = {-0.9, 0, -wagon_span + 0.25, 0.9, 2.25, wagon_span - 0.25, rotate = true}
- end
- end
setmetatable(prototype, {__index=wagon})
minetest.register_entity(":"..sysname,prototype)
advtrains.wagon_prototypes[sysname] = prototype
--group classification to make recipe searching easier
- local wagon_groups = {
- not_in_creative_inventory = nincreative and 1 or 0,
- at_wagon = 1,
- }
- if prototype.is_locomotive then
- wagon_groups['at_loco'] = 1
- end
+ local wagon_groups = { not_in_creative_inventory = nincreative and 1 or 0}
+ if prototype.is_locomotive then wagon_groups['at_loco'] = 1 end
if prototype.seat_groups then
if prototype.seat_groups.dstand then wagon_groups['at_control'] = 1 end
if prototype.seat_groups.pass then wagon_groups['at_pax'] = 1 end
end
if prototype.has_inventory then wagon_groups['at_freight'] = 1 end
- local max_speed = tonumber(prototype.max_speed) or 20
-
minetest.register_craftitem(":"..sysname, {
description = desc,
inventory_image = inv_img,
wield_image = inv_img,
stack_max = 1,
- _ch_help = "max. rychlost vozu: "..max_speed,
groups = wagon_groups,
@@ -1462,7 +1438,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati
return itemstack
end
if not minetest.check_player_privs(placer, {train_operator = true }) then
- minetest.chat_send_player(pname, attrans("You don't have the train_operator privilege."))
+ minetest.chat_send_player(pname, S("You don't have the train_operator privilege."))
return itemstack
end
if not minetest.check_player_privs(placer, {train_admin = true }) and minetest.is_protected(pos, placer:get_player_name()) then
@@ -1472,9 +1448,9 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati
local yaw = placer:get_look_horizontal()
local plconnid = advtrains.yawToClosestConn(yaw, tconns)
- local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid, prototype.drives_on)
+ local prevpos = advtrains.get_adjacent_rail(pos, tconns, plconnid)
if not prevpos then
- minetest.chat_send_player(pname, attrans("The track you are trying to place the wagon on is not long enough!"))
+ minetest.chat_send_player(pname, S("The track you are trying to place the wagon on is not long enough!"))
return
end
@@ -1592,3 +1568,32 @@ function advtrains.wagon_entity_pairs_in_train(train_id)
if not train then return function() end end
return advtrains.next_wagon_entity_in_train, train, 0
end
+
+minetest.register_chatcommand("at_chown", {
+ params = "<wagon_id> <player_name>",
+ description = "Change the owner of an advtrains wagon",
+ privs = {train_admin=true},
+ func = function(name, param)
+ local params = string.split(param," ")
+ local wid = params[1]
+ local new_owner = params[2]
+ if not wid then return false end --no params added
+ --player name checks
+ if not new_owner then return false, attrans("Please specify a player name to transfer ownership to.") end --no player name argument
+ if not core.player_exists(new_owner) then return false, attrans("That player does not exist!") end --is a valid player
+ --wagon id checks
+ if not wid:match("%d%d%d%d%d%d") then return false, attrans("Not a valid wagon id.") end -- invalid wagon id
+ local w_data = advtrains.wagons[wid]
+ if not w_data then return false, attrans("That wagon does not exist!") end
+ -- actually chown the wagon
+ local curr_owner = w_data.owner
+ w_data.owner = new_owner
+ advtrains.wagons[wid] = w_data
+ advtrains.log("Chown", name, core.get_player_by_name(name):get_pos(), "wid="..wid..", from="..curr_owner..", to="..new_owner)
+
+ if name ~= new_owner then
+ core.chat_send_player(new_owner, attrans("You have been given ownership of wagon @1", wid))
+ end
+ return true, attrans("Wagon @1 ownership changed from @2 to @3", wid, curr_owner, new_owner)
+ end
+}) \ No newline at end of file
diff --git a/advtrains_interlocking/ars.lua b/advtrains_interlocking/ars.lua
index eb10497..5182cd3 100644
--- a/advtrains_interlocking/ars.lua
+++ b/advtrains_interlocking/ars.lua
@@ -3,26 +3,89 @@
--[[
The "ARS table" and its effects:
- Every route has (or can have) an associated ARS table. This can either be
- ars = { [n] = {ln="<line>"}/{rc="<routingcode>"}/{c="<a comment>"} }
- a list of rules involving either line or routingcode matchers (or comments, those are ignored)
- The first matching rule determines the route to set.
- - or -
- ars = {default = true}
- this means that all trains that no other rule matches on should use this route
+ Every route has (or can have) an associated ARS table:
+ ars = {
+ [n] = {
+ ln = "<line>" -- either line
+ rc = "<routingcode>" -- or routingcode
+ n = true/false -- true = logical not (matches everything that does not have this line/rc)
+ conj = { -- and conjunction, optional. This must be true in addition to the main rule
+ ln=... / rc=... / n=... -- like toplevel
+ conj=... -- can be nested
+ -- note that conj cannot have prio, in inherits the prio from main rule
+ }
+ prio = <num> -- optional, a priority number. If set, enables "multi-ARS" where train can wait for multiple routes at once
+ -- or
+ c="<a comment>"
+ }
+ default = true -- Route is the default route for trains
+ default_prio -- optional, priority for multi-ars with default route
+ default_conj = {...} -- optional, conditions (conjunction) that need to be fulfilled for this to be considered default route
+ }
- Compound ("and") conjunctions are not supported (--TODO should they?)
+ In case a train matches the ARS rules of multiple routes, precedence is as follows:
+ 1. train matches rules without priority in one or more routes -> first matching route is unconditionally set
+ 2. train matches rules with priority in one or more routes -> all of the matching routes are set (multi-ars)
+ in the order given by priority, first available route is set
+ 3. route is default=true, default_prio=nil and train matches default_conj (if present) -> first default route is set
+ 4. one or more routes are default=true, with default_prio set,and train matches default_conj (if present)
+ -> all of the matching routes are set (multi-ars) in the order given by priority, first available route is set
For editing, those tables are transformed into lines in a text area:
{ln=...} -> LN ...
{rc=...} -> RC ...
{c=...} -> #...
{default=true} -> *
- See also route_ui.lua
+ n -> ! (e.g. ln=..., n=true -> !LN ...)
+ prio -> <num> (e.g. ln=..., prio=1 -> 1 LN ...)
+
+ conj -> goes on the next line, with an & prepended, e.g.:
+ {ln="S1", conj={rc="Left"}} ->
+ LN S1
+ & RC Left
+
+ Example combining everything:
+ ars = {
+ [1] = {
+ ln = "S1"
+ n = true
+ prio = 4
+ conj = {
+ rc = "R4"
+ }
+ }
+ default = true
+ default_prio = 2
+ default_conj = {
+ rc = "R5"
+ n = true
+ }
+ } ->
+ 4 !LN S1
+ & RC R4
+ 2 *
+ & !RC R5
+
]]
local il = advtrains.interlocking
+
+local function conj_to_text(conj, txt)
+ while conj do
+ n = ""
+ if conj.n then
+ n = "!"
+ end
+ if conj.ln then
+ txt[#txt+1] = "& "..n.."LN "..conj.ln
+ elseif conj.rc then
+ txt[#txt+1] = "& "..n.."RC "..conj.rc
+ end
+ conj = conj.conj
+ end
+end
+
-- The ARS data are saved in a table format, but are entered in text format. Utility functions to transform between both.
function il.ars_to_text(arstab)
if not arstab then
@@ -32,103 +95,213 @@ function il.ars_to_text(arstab)
local txt = {}
for i, arsent in ipairs(arstab) do
+ local prio = ""
+ if arsent.prio then
+ prio = arsent.prio.." "
+ end
local n = ""
if arsent.n then
n = "!"
end
if arsent.ln then
- txt[#txt+1] = n.."LN "..arsent.ln
+ txt[#txt+1] = prio..n.."LN "..arsent.ln
elseif arsent.rc then
- txt[#txt+1] = n.."RC "..arsent.rc
+ txt[#txt+1] = prio..n.."RC "..arsent.rc
elseif arsent.c then
txt[#txt+1] = "#"..arsent.c
end
+ conj_to_text(arsent.conj, txt)
end
if arstab.default then
- return "*\n" .. table.concat(txt, "\n")
+ local prio = ""
+ if arstab.default_prio then
+ prio = arstab.default_prio.." "
+ end
+ txt[#txt+1] = prio.."*"
+ conj_to_text(arstab.default_conj, txt)
end
return table.concat(txt, "\n")
end
+local function parse_ruleexp(line)
+ local excl, key, val = string.match(line, "^%s*(!?)%s*([RL][CN])%s+(.+)%s*$")
+ if key == "RC" then
+ return {rc=val, n=(excl=="!")}
+ elseif key == "LN" then
+ return {ln=val, n=(excl=="!")}
+ end
+end
+
function il.text_to_ars(t)
if not string.match(t, "%S+") then
return nil
- elseif t=="*" then
- return {default=true}
end
local arstab = {}
+ local previtem
for line in string.gmatch(t, "[^\r\n]+") do
- if line=="*" then
- arstab.default = true
+ -- a) comment
+ local ct = string.match(line, "^#(.*)$")
+ if ct then
+ arstab[#arstab+1] = {c = ct}
+ previtem = nil
else
- local c, v = string.match(line, "^(...?)%s(.*)$")
- if c and v then
- local n = nil
- if string.sub(c,1,1) == "!" then
- n = true
- c = string.sub(c,2)
- end
- local tt=string.upper(c)
- if tt=="LN" then
- arstab[#arstab+1] = {ln=v, n=n}
- elseif tt=="RC" then
- arstab[#arstab+1] = {rc=v, n=n}
+ -- b) Conjunction to the previous item
+ local conline = string.match(line, "^%s*&(.+)$")
+ if conline then
+ local conj = parse_ruleexp(conline)
+ if conj and previtem==true then
+ -- previtem was default
+ arstab.default_conj = conj
+ previtem = conj
+ elseif conj and previtem then
+ previtem.conj = conj
+ previtem = conj
+ else
+ -- dont know what to do with line, put as comment
+ arstab[#arstab+1] = {c = "? "..line}
+ previtem = nil
end
else
- local ct = string.match(line, "^#(.*)$")
- if ct then arstab[#arstab+1] = {c = ct} end
+ -- c) Normal rule spec
+ local prio, ruleline = string.match(line, "^%s*([0-9]*)%s*(.+)%s*$")
+ if ruleline == "*" then
+ -- ruleline is the asterisk, this is default
+ arstab.default = true
+ arstab.default_prio = tonumber(prio) -- evals to nil if not given
+ previtem = true -- marks that previtem was asterisk
+ elseif ruleline then
+ -- ruleline is present, parse it
+ local rule = parse_ruleexp(ruleline)
+ if not rule then
+ -- dont know what to do with line, put as comment
+ arstab[#arstab+1] = {c = "? "..line}
+ previtem = nil
+ else
+ rule.prio = tonumber(prio) -- evals to nil if not given
+ arstab[#arstab+1] = rule
+ previtem = rule
+ end
+ else
+ -- d) nothing else works, save line as comment
+ arstab[#arstab+1] = {c = "? "..line}
+ previtem = nil
+ end
end
end
end
return arstab
end
-local function find_rtematch(routes, train)
- local default
- for rteid, route in ipairs(routes) do
- if route.ars then
- if route.ars.default then
- default = rteid
- else
- if il.ars_check_rule_match(route.ars, train) then
- return rteid
- end
- end
+
+local function match_arsent(arsent, train)
+ local rule_matches = false
+ if arsent.ln then
+ local line = train.line
+ rule_matches = line and arsent.ln == line
+ if arsent.n then rule_matches = not rule_matches end
+ elseif arsent.rc then
+ local routingcode = train.routingcode
+ rule_matches = routingcode and string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true)
+ if arsent.n then rule_matches = not rule_matches end
+ end
+ if rule_matches then
+ -- if the entry has a conjunction, go on checking
+ if arsent.conj then
+ return match_arsent(arsent.conj, train)
+ else
+ return true
end
+ else
+ return false
end
- return default
end
--- Checks whether ARS rule explicitly matches. This does not take into account the "default" field, since a wider context is required for this.
--- Returns the rule number that matched, or nil if nothing matched
+-- Given an ARS rule table, check whether any of the clauses in it match the train.
+-- Returns: match_specific, match_default
+-- match_specific: One of the clauses explicitly matched (if this is non-false, match_default is not checked and always given false)
+-- match_default: The default clause (*) matched (as well as any conjunctions attached to the default clause)
+-- both of these can be either true (unconditional match), a number (priority for multi-ars) or false
function il.ars_check_rule_match(ars, train)
if not ars then
- return nil
+ return nil, nil
end
- local line = train.line
- local routingcode = train.routingcode
for arskey, arsent in ipairs(ars) do
- --atdebug(arsent, line, routingcode)
- if arsent.n then
- -- rule is inverse...
- if arsent.ln and (not line or arsent.ln ~= line) then
- return arskey
- elseif arsent.rc and (not routingcode or not string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true)) then
- return arskey
- end
- return nil
+ local rule_matches = match_arsent(arsent, train)
+ if rule_matches then
+ return (arsent.prio or true), nil
end
-
- if arsent.ln and line and arsent.ln == line then
- return arskey
- elseif arsent.rc and routingcode and string.find(" "..routingcode.." ", " "..arsent.rc.." ", nil, true) then
- return arskey
+ end
+ if ars.default then
+ local def_matches = true
+ if ars.default_conj then
+ def_matches = match_arsent(ars.default_conj, train)
end
+ if def_matches then
+ return false, (ars.default_prio or true)
+ end
+ end
+ return false,false
+end
+
+local function sort_priority(sprio)
+ -- insertion sort
+ local order = {}
+ local oprio = {}
+ for rteid, prio in pairs(sprio) do
+ local inspos = 1
+ while order[inspos] do
+ if oprio[inspos] > prio then
+ -- next item has higher priority number (= less urgent), insert before it
+ break
+ elseif oprio[inspos] == prio and order[inspos] > rteid then
+ -- next item has same priority as current and a higher routeid, insert before it
+ break
+ end
+ inspos = inspos + 1
end
+ table.insert(order, inspos, rteid)
+ table.insert(oprio, inspos, prio)
+ end
+ --atdebug("sort_priority",sprio,"result",order,oprio)
+ if #order == 1 then
+ return order[1] -- only one route, table doesnt make sense
+ end
+ return order
+end
+
+local function find_rtematch(routes, train)
+ local sprio = {}
+ local default = nil
+ local dprio = {}
+ for rteid, route in ipairs(routes) do
+ if route.ars then
+ local mspec, mdefault = il.ars_check_rule_match(route.ars, train)
+ --atdebug("route",rteid,"ars",route.ars,"gives", mspec, mdefault)
+ if mspec == true then
+ return rteid
+ elseif mspec then
+ sprio[rteid] = mspec
+ end
+ if mdefault == true then
+ if not default then default = rteid end
+ elseif mdefault then
+ dprio[rteid] = mdefault
+ end
+ end
+ end
+ if next(sprio) then
+ return sort_priority(sprio)
+ elseif default then
+ return default
+ elseif next(dprio) then
+ return sort_priority(dprio)
+ else
return nil
+ end
end
+
function advtrains.interlocking.ars_check(signalpos, train, trig_from_dst)
-- check for distant signal
-- this whole check must be delayed until after the route setting has taken place,
@@ -169,6 +342,7 @@ function advtrains.interlocking.ars_check(signalpos, train, trig_from_dst)
local rteid = find_rtematch(tcbs.routes, train)
if rteid then
+ --atdebug("Ars setting ",rteid)
--delay routesetting, it should not occur inside train step
-- using after here is OK because that gets called on every path recalculation
minetest.after(0, il.route.update_route, sigd, tcbs, rteid, nil)
diff --git a/advtrains_interlocking/database.lua b/advtrains_interlocking/database.lua
index de6f2e8..5e35dba 100644
--- a/advtrains_interlocking/database.lua
+++ b/advtrains_interlocking/database.lua
@@ -214,10 +214,11 @@ TCB data structure
-- aspect will be set accordingly.
routeset = <index in routes> -- Route set from this signal. This is the entry that is cleared once
-- train has passed the signal. (which will set the aspect to "danger" again)
- route_committed = <boolean> -- When setting/requesting a route, routetar will be set accordingly,
+ -- routeset may be a table (e.g. {1,2}) while the route is not committed yet, indicating a wait for multiple routes at once (Multi-ARS)
+ route_committed = <boolean> -- When setting/requesting a route, routeset will be set accordingly,
-- while the signal still displays danger and nothing is written to the TCs
-- As soon as the route can actually be set, all relevant TCs and turnouts are set and this field
- -- is set true, clearing the signal
+ -- is set true, clearing the signal (when this is true, routeset is never a table)
aspect = <asp> -- The aspect the signal should show. If this is nil, should show the most restrictive aspect (red)
signal_name = <string> -- The human-readable name of the signal, only for documenting purposes
routes = { <route definition> } -- a collection of routes from this signal
@@ -760,7 +761,7 @@ function ildb.update_rs_cache(ts_id)
--atdebug("== Running update_rs_cache for ",ts_id)
-- start on every of the TS's TCBs, walk the track forward and store locks along the way
for start_tcbi, start_tcbs in ipairs(ts.tc_breaks) do
- local start_pkey = advtrains.encode_pos(start_tcbs.p)
+ start_pkey = advtrains.encode_pos(start_tcbs.p)
rscache[start_pkey] = {}
--atdebug("Starting for ",start_tcbi, start_tcbs)
local locks_found = {}
@@ -770,7 +771,7 @@ function ildb.update_rs_cache(ts_id)
-- now result_table contains found route locks. Match them with the other TCBs we have in this section
for end_tcbi, end_tcbs in ipairs(ts.tc_breaks) do
if end_tcbi ~= start_tcbi then
- local end_pkey = advtrains.encode_pos(end_tcbs.p)
+ end_pkey = advtrains.encode_pos(end_tcbs.p)
if result_table[end_pkey] then
--atdebug("Set RSCache entry",end_pkey.."-"..end_pkey,"=",result_table[end_pkey])
local lockstab = result_table[end_pkey]
@@ -941,7 +942,6 @@ function ildb.remove_ts(ts_id)
if not ts then
error("remove_ts: "..ts_id.." doesn't exist")
end
- local i = 1
while ts.tc_breaks[i] do
-- get TCBS
local sigd = ts.tc_breaks[i]
diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua
index e11ffa2..ee08c30 100644
--- a/advtrains_interlocking/init.lua
+++ b/advtrains_interlocking/init.lua
@@ -1,5 +1,5 @@
--- Advtrains interlocking system
--- See database.lua for a detailed explanation
+--- Advtrains interlocking system.
+-- @module advtrains.interlocking
advtrains.interlocking = {}
diff --git a/advtrains_interlocking/route_prog.lua b/advtrains_interlocking/route_prog.lua
index 76dad28..81aa133 100644
--- a/advtrains_interlocking/route_prog.lua
+++ b/advtrains_interlocking/route_prog.lua
@@ -29,19 +29,17 @@ end
local markerent = {}
minetest.register_entity("advtrains_interlocking:routemarker", {
- initial_properties = {
- visual = "mesh",
- mesh = "trackplane.b3d",
- textures = {"at_il_route_set.png"},
- collisionbox = {-1,-0.5,-1, 1,-0.4,1},
- visual_size = {x=10, y=10},
- static_save = false,
- },
+ visual = "mesh",
+ mesh = "trackplane.b3d",
+ textures = {"at_il_route_set.png"},
+ collisionbox = {-1,-0.5,-1, 1,-0.4,1},
+ visual_size = {x=10, y=10},
on_punch = function(self)
self.object:remove()
end,
get_staticdata = function() return "STATIC" end,
on_activate = function(self, sdata) if sdata=="STATIC" then self.object:remove() end end,
+ static_save = false,
})
@@ -125,11 +123,11 @@ the distant signal aspect is determined as DANGER.
]]--
local function chat(pname, message)
- minetest.chat_send_player(pname, "[Programování cesty] "..message)
+ minetest.chat_send_player(pname, "[Route programming] "..message)
end
local function clear_lock(locks, pname, pts)
locks[pts] = nil
- chat(pname, pts.." již není ovlivněn/a, když je tato cesta nastavena.")
+ chat(pname, pts.." is no longer affected when this route is set.")
end
local function otherside(s)
@@ -176,8 +174,11 @@ function advtrains.interlocking.visualize_route(origin, route, context, tmp_lcks
end
-- display locks
for pts, state in pairs(v.locks) do
- local pos = assert(advtrains.decode_pos(pts))
- routesprite(context, pos, "fix"..k..pts, "at_il_route_lock.png", "Zajištěna ve stavu '"..state.."' po cestě "..route.name.." dokud není úsek #"..k.." uvolněn.")
+ local pos = minetest.string_to_pos(pts)
+ if not pos then
+ pos = advtrains.decode_pos(pts)
+ end
+ routesprite(context, pos, "fix"..k..pts, "at_il_route_lock.png", "Fixed in state '"..state.."' by route "..route.name.." until segment #"..k.." is freed.")
end
end
@@ -204,7 +205,7 @@ function advtrains.interlocking.visualize_route(origin, route, context, tmp_lcks
-- display locks set by player
for pts, state in pairs(tmp_lcks) do
local pos = advtrains.decode_pos(pts)
- routesprite(context, pos, "fixp"..pts, "at_il_route_lock_edit.png", "Zajištěna ve stavu '"..state.."' cestou "..route.name.." (levý klik pro uvolnění)",
+ routesprite(context, pos, "fixp"..pts, "at_il_route_lock_edit.png", "Fixed in state '"..state.."' by route "..route.name.." (punch to unfix)",
function() clear_lock(tmp_lcks, pname, pts) end)
end
end
@@ -215,7 +216,7 @@ local player_rte_prog = {}
function advtrains.interlocking.init_route_prog(pname, sigd, default_route)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local rp = {
@@ -239,7 +240,7 @@ function advtrains.interlocking.init_route_prog(pname, sigd, default_route)
end
player_rte_prog[pname] = rp
advtrains.interlocking.visualize_route(sigd, rp.route, "prog_"..pname, rp.tmp_lcks, pname)
- minetest.chat_send_player(pname, "Režim programování cesty je aktivní. Klikejte levým tlačítkem na TCB pro přidání úseků a na výhybky pro jejich uzamčení.")
+ minetest.chat_send_player(pname, "Route programming mode active. Punch TCBs to add route segments, punch turnouts to lock them.")
end
local function get_last_route_item(origin, route)
@@ -252,32 +253,33 @@ end
local function do_advance_route(pname, rp, sigd, tsref)
table.insert(rp.route, {next = sigd, locks = rp.tmp_lcks})
rp.tmp_lcks = {}
- chat(pname, "Úsek '"..(tsref and (tsref.name or "") or "--konec zab.--").."' přidán na cestu.")
+ chat(pname, "Added track section '"..(tsref and (tsref.name or "") or "--EOI--").."' to the route.")
end
local function finishrpform(pname)
local rp = player_rte_prog[pname]
if not rp then return end
- local form = "size[7,6]label[0.5,0.5;Dokončit programování cesty]"
+ local form = "size[7,6]label[0.5,0.5;Finish programming route]"
local terminal = get_last_route_item(rp.origin, rp.route)
if terminal then
local term_tcbs = advtrains.interlocking.db.get_tcbs(terminal)
if term_tcbs.signal then
- form = form .. "label[0.5,1.5;Cesta končí na signalizaci:]"
- form = form .. "label[0.5,2 ;"..term_tcbs.signal_name.."]"
+ local signalname = (term_tcbs.signal_name or "") .. sigd_to_string(terminal)
+ form = form .. "label[0.5,1.5;Route ends at signal:]"
+ form = form .. "label[0.5,2 ;"..signalname.."]"
else
- form = form .. "label[0.5,1.5;VAROVÁNÍ: Cesta nekončí na signalizaci.]"
- form = form .. "label[0.5,2 ;Cesty většinou končí na signlizacích.]"
- form = form .. "label[0.5,2.5;Nejste-li si jistý/á, zrušte programování!]"
+ form = form .. "label[0.5,1.5;WARNING: Route does not end at a signal.]"
+ form = form .. "label[0.5,2 ;Routes should in most cases end at signals.]"
+ form = form .. "label[0.5,2.5;Cancel if you are unsure!]"
end
else
- form = form .. "label[0.5,1.5;Cesta vede do]"
- form = form .. "label[0.5,2 ;nezabezpečené oblasti]"
+ form = form .. "label[0.5,1.5;Route leads into]"
+ form = form .. "label[0.5,2 ;non-interlocked area]"
end
- form = form.."field[0.8,3.5;5.2,1;name;Zadejte název cesty;]"
- form = form.."button_exit[0.5,4.5; 5,1;save;Uložit cestu]"
+ form = form.."field[0.8,3.5;5.2,1;name;Enter Route Name;]"
+ form = form.."button_exit[0.5,4.5; 5,1;save;Save Route]"
minetest.show_formspec(pname, "at_il_routepf", form)
@@ -325,7 +327,7 @@ local function check_advance_valid(tcbpos, rp)
local adv_tcbs = advtrains.interlocking.db.get_tcbs(this_sigd)
local next_tsid = adv_tcbs.ts_id
local can_over, over_ts, next_tc_bs = false, nil, nil
- local cannotover_rsn = "Rozbíhavý úsek (>2 TCB)"
+ local cannotover_rsn = "Next section is diverging (>2 TCBs)"
if next_tsid then
-- you may not advance over EOI. While this is technically possible,
-- in practise this just enters an unnecessary extra empty route item.
@@ -333,7 +335,7 @@ local function check_advance_valid(tcbpos, rp)
next_tc_bs = over_ts.tc_breaks
can_over = #next_tc_bs <= 2
else
- cannotover_rsn = "Konec zabezpečené oblasti"
+ cannotover_rsn = "End of interlocking"
end
local over_sigd = nil
@@ -375,29 +377,29 @@ local function show_routing_form(pname, tcbpos, message)
-- show nothing at all
-- In all cases, Discard and Backtrack buttons needed.
- local form = "size[7,9.5]label[0.5,0.5;Pokračovat/ukončit cestu]"
+ local form = "size[7,9.5]label[0.5,0.5;Advance/Complete Route]"
if message then
form = form .. "label[0.5,1;"..message.."]"
end
if advance_valid and not is_endpoint then
- form = form.. "label[0.5,1.8;Pokračovat s cestou do dalšího úseku]"
+ form = form.. "label[0.5,1.8;Advance to next route section]"
form = form.."image_button[0.5,2.2; 5,1;at_il_routep_advance.png;advance;]"
form = form.. "label[0.5,3.5;-------------------------]"
else
- form = form.. "label[0.5,2.3;Tato TCB není vhodná]"
- form = form.. "label[0.5,2.8;pro pokračování cesty.]"
+ form = form.. "label[0.5,2.3;This TCB is not suitable as]"
+ form = form.. "label[0.5,2.8;route continuation.]"
end
if advance_valid or is_endpoint then
- form = form.. "label[0.5,3.8;Ukonči cestu ZDE]"
+ form = form.. "label[0.5,3.8;Finish route HERE]"
form = form.."image_button[0.5, 4.2; 5,1;at_il_routep_end_here.png;endhere;]"
if can_over then
- form = form.. "label[0.5,5.3;Ukončit cestu na konci NÁSLEDUJÍCÍHO úseku]"
+ form = form.. "label[0.5,5.3;Finish route at end of NEXT section]"
form = form.."image_button[0.5,5.7; 5,1;at_il_routep_end_over.png;endover;]"
else
- form = form.. "label[0.5,5.3;Pokračování do následujícího úseku]"
- form = form.. "label[0.5,5.8;zde není možné.]"
+ form = form.. "label[0.5,5.3;Advancing over next section is]"
+ form = form.. "label[0.5,5.8;impossible at this place.]"
if cannotover_rsn then
form = form.. "label[0.5,6.3;"..cannotover_rsn.."]"
end
@@ -406,9 +408,9 @@ local function show_routing_form(pname, tcbpos, message)
form = form.. "label[0.5,7;-------------------------]"
if #rp.route > 0 then
- form = form.."button[0.5,7.4; 5,1;retract;Zpět o jeden úsek]"
+ form = form.."button[0.5,7.4; 5,1;retract;Step back one section]"
end
- form = form.."button[0.5,8.4; 5,1;cancel;Zrušit programování cesty]"
+ form = form.."button[0.5,8.4; 5,1;cancel;Cancel route programming]"
minetest.show_formspec(pname, "at_il_rprog_"..minetest.pos_to_string(tcbpos), form)
end
@@ -419,7 +421,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local tcbpts = string.match(formname, "^at_il_rprog_([^_]+)$")
local tcbpos
if tcbpts then
- tcbpos = assert(minetest.string_to_pos(tcbpts))
+ tcbpos = minetest.string_to_pos(tcbpts)
end
if tcbpos then
-- RPROG form
@@ -459,12 +461,12 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
rp.tmp_locks = rp.route[#rp.route].locks
rp.route[#rp.route] = nil
- chat(pname, "Úsek cesty "..(#rp.route+1).." odstraněn.")
+ chat(pname, "Route section "..(#rp.route+1).." removed.")
end
if fields.cancel then
player_rte_prog[pname] = nil
advtrains.interlocking.clear_visu_context("prog_"..pname)
- chat(pname, "Cesta zahozena.")
+ chat(pname, "Route discarded.")
minetest.close_formspec(pname, formname)
return
end
@@ -485,13 +487,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local rp = player_rte_prog[pname]
if rp then
if #rp.route <= 0 then
- chat(pname, "Bez cíle nemohu naprogramovat cestu.")
+ chat(pname, "Cannot program route without a target")
return
end
local tcbs = advtrains.interlocking.db.get_tcbs(rp.origin)
if not tcbs then
- chat(pname, "Původní TCB se během programování ztratilo. Zkuste cestu naprogramovat znovu.")
+ chat(pname, "The origin TCB has become unknown during programming. Try again.")
return
end
@@ -505,7 +507,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
advtrains.interlocking.clear_visu_context("prog_"..pname)
player_rte_prog[pname] = nil
- chat(pname, "Cesta úspěšně naprogramována.")
+ chat(pname, "Successfully programmed route.")
advtrains.interlocking.show_route_edit_form(pname, rp.origin, #tcbs.routes)
return
@@ -528,10 +530,10 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
local meta = minetest.get_meta(pos)
local tcbpts = meta:get_string("tcb_pos")
if tcbpts == "" then
- chat(pname, "Tato TCB není nastavena, nejprve k ní musíte přiřadit kolej")
+ chat(pname, "This TCB is unconfigured, you first need to assign it to a rail")
return
end
- local tcbpos = assert(minetest.string_to_pos(tcbpts))
+ local tcbpos = minetest.string_to_pos(tcbpts)
-- show formspec
@@ -551,7 +553,7 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
else
local state = advtrains.getstate(pos)
rp.tmp_lcks[pts] = state
- chat(pname, pts.." je držena ve stavu "..state.." , když je tato cesta nastavena a uvolněna.")
+ chat(pname, pts.." is held in "..state.." position when this route is set and freed ")
end
advtrains.interlocking.visualize_route(rp.origin, rp.route, "prog_"..pname, rp.tmp_lcks, pname)
return
diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua
index baaa957..3c7bd64 100644
--- a/advtrains_interlocking/route_ui.lua
+++ b/advtrains_interlocking/route_ui.lua
@@ -17,7 +17,7 @@ local sel_rpartcache = {}
function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
@@ -26,9 +26,9 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
local route = tcbs.routes[routeid]
if not route then return end
- local form = "size[9,11]label[0.5,0.2;Přehled cesty]"
- form = form.."field[0.8,1.2;6.5,1;name;Název cesty;"..minetest.formspec_escape(route.name).."]"
- form = form.."button[7.0,0.9;1.5,1;setname;Nastavit]"
+ local form = "size[9,11]label[0.5,0.2;Route overview]"
+ form = form.."field[0.8,1.2;6.5,1;name;Route name;"..minetest.formspec_escape(route.name).."]"
+ form = form.."button[7.0,0.9;1.5,1;setname;Set]"
-- construct textlist for route information
local tab = {}
@@ -37,7 +37,7 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
tab[#tab+1] = minetest.formspec_escape(string.gsub(t, ",", " "))
tabref[#tab] = { [rty] = true, param = rpara, seg = rseg, idx = #tab }
end
- itab(1, "("..(tcbs.signal_name or "+")..") Cesta #"..routeid, "signal", sigd)
+ itab(1, "("..(tcbs.signal_name or "+")..") Route #"..routeid, "signal", sigd)
-- this code is partially copy-pasted from routesetting.lua
-- we start at the tc designated by signal
@@ -47,12 +47,12 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
while c_sigd and i<=#route do
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
- itab("-!- Na "..sigd_to_string(c_sigd).." nejsou žádné TCB. Prosím, přenastavte cestu!")
+ itab(i, "-!- No TCBS at "..sigd_to_string(c_sigd)..". Please reconfigure route!", "err", nil)
break
end
c_ts_id = c_tcbs.ts_id
if not c_ts_id then
- itab("-!- S "..sigd_to_string(c_sigd).." nesousedí žádný traťový úsek. Prosím přenastavte cestu!")
+ itab(i, "-!- No track section adjacent to "..sigd_to_string(c_sigd)..". Please reconfigure route!", "err", nil)
break
end
c_ts = ildb.get_ts(c_ts_id)
@@ -62,15 +62,15 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
local signame = "-"
if c_tcbs and c_tcbs.signal then signame = c_tcbs.signal_name or "o" end
itab(i, ""..i.." "..sigd_to_string(c_sigd).." ("..signame..")", "signal", c_sigd)
- itab(i, "= "..(c_ts and c_ts.name or c_ts_id).." ="..(c_rseg.call_on and " [pov.]" or ""), "section", c_ts_id)
+ itab(i, "= "..(c_ts and c_ts.name or c_ts_id).." ="..(c_rseg.call_on and " [CO]" or ""), "section", c_ts_id)
if c_rseg.locks then
for pts, state in pairs(c_rseg.locks) do
local pos = advtrains.decode_pos(pts)
- itab(i, "Zámek "..core.pos_to_string(pos).." -> "..state, "lock", pos)
+ itab(i, "L "..pts.." -> "..state, "lock", pos)
if not advtrains.is_passive(pos) then
- itab("-!- Na "..core.pos_to_string(pos).." není žádná pasivní komponenta. Prosím, přenastavte cestu!")
+ itab(i, "-!- No passive component at "..pts..". Please reconfigure route!", "err", nil)
break
end
end
@@ -80,7 +80,7 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
if nvar then
local re_tcbs = ildb.get_tcbs({p = nvar.p, s = (nvar.s==1) and 2 or 1})
if not re_tcbs or not re_tcbs.ts_id or re_tcbs.ts_id~=c_ts_id then
- itab(i, "-!- Na "..sigd_to_string(c_sigd)..".neodpovídají začátek a konec úseku!", "err", nil)
+ itab(i, "-!- At "..sigd_to_string(c_sigd)..".Section Start and End do not match!", "err", nil)
break
end
end
@@ -92,13 +92,13 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
local e_tcbs = ildb.get_tcbs(c_sigd)
local signame = "-"
if e_tcbs and e_tcbs.signal then signame = e_tcbs.signal_name or "o" end
- itab(i, "K "..sigd_to_string(c_sigd).." ("..signame..")", "end", c_sigd)
+ itab(i, "E "..sigd_to_string(c_sigd).." ("..signame..")", "end", c_sigd)
else
- itab(i, "K (žádný)", "end", nil)
+ itab(i, "E (none)", "end", nil)
end
if not sel_rpartidx then sel_rpartidx = 1 end
- form = form.."textlist[0.5,2;4.5,3.9;routelog;"..table.concat(tab, ",")..";"..(sel_rpartidx or 1)..";false]"
+ form = form.."textlist[0.5,2;3.5,3.9;routelog;"..table.concat(tab, ",")..";"..(sel_rpartidx or 1)..";false]"
-- to the right of rtelog, controls are displayed for the thing in focus
-- What is in focus is determined by the parameter sel_rpartidx
@@ -113,10 +113,10 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
-- main aspect list
local signalpos = s_tcbs and s_tcbs.signal
if signalpos and rseg then
- form = form..F.label(5.5, 2, "Signál:")
+ form = form..F.label(4.5, 2, "Signal Aspect:")
local ndef = signalpos and advtrains.ndb.get_ndef(signalpos)
if ndef and ndef.advtrains and ndef.advtrains.main_aspects then
- local entries = { "<výchozí>" }
+ local entries = { "<Default Aspect>" }
local sel = 1
for i, mae in ipairs(ndef.advtrains.main_aspects) do
entries[i+1] = mae.description
@@ -124,7 +124,7 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
sel = i+1
end
end
- form = form..F.dropdown(5.5, 3.0, 4, "sa_main_aspect", entries, sel, true)
+ form = form..F.dropdown(4.5, 3.0, 4, "sa_main_aspect", entries, sel, true)
end
-- checkbox for assign distant signal
local assign_dst = rseg.assign_dst
@@ -133,21 +133,21 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
-- defaults to false for the very first signal and true for all others (= minimal user configuration overhead)
-- Note: on save, the value will be fixed at either false or true
end
- form = form..string.format("checkbox[5.5,4.0;sa_distant;Ohlásit předzvěst;%s]", assign_dst)
+ form = form..string.format("checkbox[4.5,4.0;sa_distant;Announce distant signal;%s]", assign_dst)
else
- form = form..F.label(5.5, 2, "Tato TCB nemá žádné návěstidlo")
+ form = form..F.label(4.5, 2, "No Signal at this TCB")
end
elseif sel_rpart and sel_rpart.section then
local rseg = route[sel_rpart.seg]
if rseg then
- form = form..F.label(5.5, 2, "Volby:")
+ form = form..F.label(4.5, 2, "Section Options:")
-- checkbox for call-on
- form = form..string.format("checkbox[5.5,4.0;se_callon;Povolit (úsek může být obsazen);%s]", rseg.call_on)
+ form = form..string.format("checkbox[4.5,4.0;se_callon;Call-on (section may be occupied);%s]", rseg.call_on)
end
elseif sel_rpart and sel_rpart.err then
- form = form.."textarea[5.5,2.5;4,4;errorta;Chyba:;"..tab[sel_rpartidx].."]"
+ form = form.."textarea[4.5,2.5;4,4;errorta;Error:;"..tab[sel_rpartidx].."]"
else
- form = form..F.label(5.5, 2, "<< Vyberte část cesty pro nastavení voleb")
+ form = form..F.label(4.5, 2, "<< Select a route part to edit options")
end
form = form.."button[0.5,6;1,1;prev;<<<]"
@@ -158,15 +158,15 @@ function atil.show_route_edit_form(pname, sigd, routeid, sel_rpartidx)
--if route.smartroute_generated or route.default_autoworking then
-- form = form.."button[3.5,6;2,1;noautogen;Clr Autogen]"
--end
- form = form.."button[5.5,6;3,1;delete;Smazat cestu]"
- form = form.."button[0.5,7;3,1;back;Zpět na návěstidlo]"
- form = form.."button[3.5,7;2,1;clone;Klonovat cestu]"
- form = form.."button[5.5,7;3,1;newfrom;Nová z cesty]"
+ form = form.."button[5.5,6;3,1;delete;Delete Route]"
+ form = form.."button[0.5,7;3,1;back;Back to signal]"
+ form = form.."button[3.5,7;2,1;clone;Clone Route]"
+ form = form.."button[5.5,7;3,1;newfrom;New From Route]"
--atdebug(route.ars)
form = form.."style[ars;font=mono]"
- form = form.."textarea[0.8,8.3;5,3;ars;ARS pravidla;"..atil.ars_to_text(route.ars).."]"
- form = form.."button[5.5,8.23;3,1;savears;Uložit ARS pravidla]"
+ form = form.."textarea[0.8,8.3;5,3;ars;ARS Rule List;"..atil.ars_to_text(route.ars).."]"
+ form = form.."button[5.5,8.23;3,1;savears;Save ARS List]"
local formname = "at_il_routeedit_"..minetest.pos_to_string(sigd.p).."_"..sigd.s.."_"..routeid
minetest.show_formspec(pname, formname, form)
diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua
index 1065cad..9901d23 100644
--- a/advtrains_interlocking/routesetting.lua
+++ b/advtrains_interlocking/routesetting.lua
@@ -363,7 +363,7 @@ end
-- route setting
-- Call this function to set and cancel routes!
-- sigd, tcbs: self-explanatory
--- newrte: If a new route should be set, the route index of it (in tcbs.routes). nil otherwise
+-- newrte: If a new route should be set, the route index of it (in tcbs.routes). Can also be a table (multi-ars). nil otherwise
-- cancel: true in combination with newrte=nil causes cancellation of the current route.
function ilrs.update_route(sigd, tcbs, newrte, cancel)
--atdebug("Update_Route for",sigd,tcbs.signal_name)
@@ -390,37 +390,66 @@ function ilrs.update_route(sigd, tcbs, newrte, cancel)
if tcbs.route_committed then
return
end
- if newrte then tcbs.routeset = newrte end
+ if newrte then
+ if type(newrte)=="table" and not next(newrte) then
+ error("update_route got multi-ARS with empty table, this is not allowed")
+ end
+ tcbs.routeset = newrte
+ else
+ if type(tcbs.routeset)=="table" and not next(tcbs.routeset) then
+ -- just unset, don't error
+ atwarn(sigd, "had multi-ARS route set with empty list! Cancelled!")
+ tcbs.routeset = nil
+ return
+ end
+ end
--atdebug("Setting:",tcbs.routeset)
- local succ, rsn, cbts, cblk
- local route = tcbs.routes[tcbs.routeset]
- if route then
- succ, rsn, cbts, cblk = ilrs.set_route(sigd, route)
+ -- check: single-ars or multi-ars?
+ local multi_rte
+ if type(tcbs.routeset) == "table" then
+ multi_rte = tcbs.routeset
else
- succ = false
- rsn = attrans("Route state changed.")
+ multi_rte = {tcbs.routeset}
end
- if not succ then
- tcbs.route_rsn = rsn
- --atdebug("Routesetting failed:",rsn)
- -- add cbts or cblk to callback table
- if cbts then
- --atdebug("cbts =",cbts)
- if not ilrs.rte_callbacks.ts[cbts] then ilrs.rte_callbacks.ts[cbts]={} end
- advtrains.insert_once(ilrs.rte_callbacks.ts[cbts], sigd, sigd_equal)
- end
- if cblk then
- --atdebug("cblk =",cblk)
- if not ilrs.rte_callbacks.lck[cblk] then ilrs.rte_callbacks.lck[cblk]={} end
- advtrains.insert_once(ilrs.rte_callbacks.lck[cblk], sigd, sigd_equal)
+ for multi_idx, rteid in ipairs(multi_rte) do
+ local succ, rsn, cbts, cblk
+ local route = tcbs.routes[rteid]
+ if route then
+ succ, rsn, cbts, cblk = ilrs.set_route(sigd, route)
+ else
+ succ = false
+ rsn = attrans("Route with index @1 not found", rteid)
end
- else
- --atdebug("Committed Route:",tcbs.routeset)
- -- set_route now sets the signal aspects
- --has_changed_aspect = true
- -- route success. apply default_autoworking flag if requested
- if route.default_autoworking then
- tcbs.route_auto = true --FIX 2025-01-08: never set it to false if it was true!
+ if not succ then
+ if multi_idx==1 then
+ tcbs.route_rsn = rsn
+ else
+ tcbs.route_rsn = (tcbs.route_rsn or "").."\n"..rsn
+ end
+ --atdebug("Routesetting",rteid,"failed:",rsn,"(multi-idx",multi_idx,")")
+ -- add cbts or cblk to callback table
+ if cbts then
+ --atdebug("cbts =",cbts)
+ if not ilrs.rte_callbacks.ts[cbts] then ilrs.rte_callbacks.ts[cbts]={} end
+ advtrains.insert_once(ilrs.rte_callbacks.ts[cbts], sigd, sigd_equal)
+ end
+ if cblk then
+ --atdebug("cblk =",cblk)
+ if not ilrs.rte_callbacks.lck[cblk] then ilrs.rte_callbacks.lck[cblk]={} end
+ advtrains.insert_once(ilrs.rte_callbacks.lck[cblk], sigd, sigd_equal)
+ end
+ else
+ --atdebug("Committed Route:",rteid,"(multi-idx",multi_idx,")")
+ -- replace multi_route by single actually committed route
+ tcbs.routeset = rteid
+ -- set_route now sets the signal aspects
+ --has_changed_aspect = true
+ -- route success. apply default_autoworking flag if requested
+ if route.default_autoworking then
+ tcbs.route_auto = true --FIX 2025-01-08: never set it to false if it was true!
+ end
+ -- break out of the for loop, dont try any more routes
+ break
end
end
end
diff --git a/advtrains_interlocking/signal_api.lua b/advtrains_interlocking/signal_api.lua
index 7d718a4..f624f7a 100644
--- a/advtrains_interlocking/signal_api.lua
+++ b/advtrains_interlocking/signal_api.lua
@@ -303,7 +303,7 @@ function signal.get_aspect_internal(pos, aspt)
-- look up node and nodedef
local node = advtrains.ndb.get_node_or_nil(pos)
local ndef = node and minetest.registered_nodes[node.name]
- if not aspt or not ndef then
+ if not aspt then
-- oh, no main aspect, nevermind
return signal.MASP_HALT, nil, node, ndef
end
diff --git a/advtrains_interlocking/signal_aspect_ui.lua b/advtrains_interlocking/signal_aspect_ui.lua
index 818f6d6..49e7d8b 100644
--- a/advtrains_interlocking/signal_aspect_ui.lua
+++ b/advtrains_interlocking/signal_aspect_ui.lua
@@ -38,14 +38,14 @@ function advtrains.interlocking.make_ip_formspec_component(pos, x, y, w)
local ipos = minetest.string_to_pos(pts)
ipmarker(ipos, connid)
return table.concat {
- F.S_label(x, y, "Bod účinku nastaven na @1.", string.format("%s/%s", pts, connid)),
- F.S_button_exit(x, y+0.5, w/2-0.125, "ip_set", "Změnit"),
- F.S_button_exit(x+w/2+0.125, y+0.5, w/2-0.125, "ip_clear", "Odebrat bod účinku"),
+ F.S_label(x, y, "Influence point is set at @1.", string.format("%s/%s", pts, connid)),
+ F.S_button_exit(x, y+0.5, w/2-0.125, "ip_set", "Modify"),
+ F.S_button_exit(x+w/2+0.125, y+0.5, w/2-0.125, "ip_clear", "Clear"),
}
else
return table.concat {
- F.S_label(x, y, "Bod účinku není nastaven."),
- F.S_button_exit(x, y+0.5, w, "ip_set", "Nastavit bod účinku"),
+ F.S_label(x, y, "Influence point is not set."),
+ F.S_button_exit(x, y+0.5, w, "ip_set", "Set influence point"),
}
end
end
@@ -83,10 +83,10 @@ function advtrains.interlocking.show_ip_sa_form(pos, pname)
-- Create Signal aspect formspec elements
local ndef = advtrains.ndb.get_ndef(pos)
if ndef and ndef.advtrains then
- form[#form+1] = F.label(0.5, 2, "signál:")
+ form[#form+1] = F.label(0.5, 2, "Signal Aspect:")
-- main aspect list
if ndef.advtrains.main_aspects then
- local entries = { "<žádný>" }
+ local entries = { "<none>" }
local sel = 1
for i, mae in ipairs(ndef.advtrains.main_aspects) do
entries[i+1] = mae.description
@@ -98,9 +98,9 @@ function advtrains.interlocking.show_ip_sa_form(pos, pname)
end
-- distant signal assign (is shown either when main_aspect is not none, or when pure distant signal)
if rpos then
- form[#form+1] = F.button_exit(0.5, 3.5, 4, "sa_undistant", "odpojit od: " .. minetest.pos_to_string(rpos))
+ form[#form+1] = F.button_exit(0.5, 3.5, 4, "sa_undistant", "Dst: " .. minetest.pos_to_string(rpos))
elseif (ma and not ma.halt) or not ndef.advtrains.main_aspects then
- form[#form+1] = F.button_exit(0.5, 3.5, 4, "sa_distant", "<přiřadit předzvěst>")
+ form[#form+1] = F.button_exit(0.5, 3.5, 4, "sa_distant", "<assign distant>")
end
end
@@ -165,12 +165,12 @@ end)
-- inits the signal IP assignment process
function advtrains.interlocking.init_ip_assign(pos, pname)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
--remove old IP
--advtrains.interlocking.db.clear_ip_by_signalpos(pos)
- minetest.chat_send_player(pname, attrans("Configuring Signal: Please look in train's driving direction and punch rail to set influence point."))
+ minetest.chat_send_player(pname, "Configuring Signal: Please look in train's driving direction and punch rail to set influence point.")
players_assign_ip[pname] = pos
end
@@ -178,10 +178,10 @@ end
-- inits the distant signal assignment process
function advtrains.interlocking.init_distant_assign(pos, pname)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
- minetest.chat_send_player(pname, attrans("Set distant signal: Punch the main signal to assign!"))
+ minetest.chat_send_player(pname, "Set distant signal: Punch the main signal to assign!")
players_assign_distant[pname] = pos
end
@@ -203,7 +203,7 @@ local function try_auto_assign_to_tcb(signalpos, pos, connid, pname)
advtrains.interlocking.db.assign_signal_to_tcbs(signalpos, sigd)
-- use auto-naming
advtrains.interlocking.add_autoname_to_tcbs(tcb[aconnid], pname)
- minetest.chat_send_player(pname, attrans("Assigned signal to the TCB at @1", core.pos_to_string(apos)))
+ minetest.chat_send_player(pname, "Assigned signal to the TCB at "..core.pos_to_string(apos))
advtrains.interlocking.show_tcb_marker(apos)
advtrains.interlocking.show_signalling_form(sigd, pname)
end
@@ -215,7 +215,7 @@ local function try_auto_assign_to_tcb(signalpos, pos, connid, pname)
local mainsig = advtrains.interlocking.db.get_ip_signal(pts, aconnid)
if mainsig and advtrains.interlocking.signal.get_signal_cap_level(mainsig) >= 3 then
advtrains.interlocking.signal.set_aspect(signalpos, "_default", mainsig)
- minetest.chat_send_player(pname, attrans("Assigned distant signal to the main signal at @1", core.pos_to_string(mainsig)))
+ minetest.chat_send_player(pname, "Assigned distant signal to the main signal at "..core.pos_to_string(mainsig))
return
end
end
@@ -245,19 +245,21 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
if not advtrains.interlocking.db.get_ip_signal_asp(pts, plconnid) then
advtrains.interlocking.db.set_ip_signal(pts, plconnid, signalpos)
ipmarker(pos, plconnid)
- minetest.chat_send_player(pname, attrans("Configuring Signal: Successfully set influence point"))
+ minetest.chat_send_player(pname, "Configuring Signal: Successfully set influence point")
-- Try to find a TCB ahead and auto assign this signal there
- if advtrains.interlocking.signal.get_signal_cap_level(signalpos) >= 2 then
+ local pc = player:get_player_control()
+ local no_auto_assign = pc.aux1
+ if not no_auto_assign and advtrains.interlocking.signal.get_signal_cap_level(signalpos) >= 2 then
try_auto_assign_to_tcb(signalpos, pos, plconnid, pname)
end
else
- minetest.chat_send_player(pname, attrans("Configuring Signal: Influence point of another signal is already present!"))
+ minetest.chat_send_player(pname, "Configuring Signal: Influence point of another signal is already present!")
end
else
- minetest.chat_send_player(pname, attrans("Configuring Signal: This is not a normal two-connection rail! Aborted."))
+ minetest.chat_send_player(pname, "Configuring Signal: This is not a normal two-connection rail! Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring Signal: Node is too far away. Aborted."))
+ minetest.chat_send_player(pname, "Configuring Signal: Node is too far away. Aborted.")
end
players_assign_ip[pname] = nil
end
diff --git a/advtrains_interlocking/smartroute.lua b/advtrains_interlocking/smartroute.lua
index d57a0c8..76c7814 100644
--- a/advtrains_interlocking/smartroute.lua
+++ b/advtrains_interlocking/smartroute.lua
@@ -52,7 +52,7 @@ local RTE_MAX_SECS = 16
-- find_more_than: search is aborted only if more than the specified number of routes are found
function sr.rescan(pname, sigd, tcbs, find_more_than, searching_shunt, pname)
local found_routes = {}
- local restart_tcbs = { {sigd = sigd, tcbseq = {} } }
+ local restart_tcbs = { {sigd = sigd, tcbseq = {}, secseq = {} } }
local last_len = 0
while true do
-- take first entry out of restart_tcbs (due to the way it is inserted the first entry will always be the one with the lowest length
@@ -94,7 +94,9 @@ function sr.rescan(pname, sigd, tcbs, find_more_than, searching_shunt, pname)
local nsigd = {p=end_sigd.p, s = end_sigd.s==1 and 2 or 1} -- invert to other side
-- record nsigd in the tcbseq
local ntcbseq = table.copy(cur_restart.tcbseq)
+ local nsecseq = table.copy(cur_restart.secseq)
ntcbseq[#ntcbseq+1] = nsigd
+ nsecseq[#nsecseq+1] = c_ts.name or c_ts_id
local shall_continue = true
-- check if that sigd is a route target
local tcbs = ildb.get_tcbs(nsigd)
@@ -109,6 +111,7 @@ function sr.rescan(pname, sigd, tcbs, find_more_than, searching_shunt, pname)
-- record the found route in the results
found_routes[#found_routes+1] = {
tcbseq = ntcbseq,
+ secseq = nsecseq,
shunt_route = not is_mainsignal,
name = tcbs.signal_name or atil.sigd_to_string(nsigd)
}
@@ -122,7 +125,7 @@ function sr.rescan(pname, sigd, tcbs, find_more_than, searching_shunt, pname)
end
-- unless overridden, insert the next restart point
if shall_continue then
- restart_tcbs[#restart_tcbs+1] = {sigd = nsigd, tcbseq = ntcbseq }
+ restart_tcbs[#restart_tcbs+1] = {sigd = nsigd, tcbseq = ntcbseq, secseq = nsecseq }
end
end
end
@@ -140,10 +143,10 @@ local players_smartroute_actions = {}
function sr.propose_next(pname, sigd, find_more_than, searching_shunt)
local tcbs = ildb.get_tcbs(sigd)
if not tcbs or not tcbs.routes then
- minetest.chat_send_player(pname, "Hledání cesty: Zde neexistují hranice úseků ani cesty!")
+ minetest.chat_send_player(pname, "Smartroute: TCBS or routes don't exist here!")
return
elseif not tcbs.ts_id then
- minetest.chat_send_player(pname, "Hledání cesty: Kupředu není žádný úsek!")
+ minetest.chat_send_player(pname, "Smartroute: No track section directly ahead!")
return
end
-- Step 1: search for routes using the current settings
@@ -155,14 +158,22 @@ function sr.propose_next(pname, sigd, find_more_than, searching_shunt)
found_routes = found_routes
}
-- step 3: build form
- local form = "size[5,5]label[0,0;Hledání cesty: "..#found_routes.." cest nalezeno]"
+ local form = "size[8,5]label[0,0;Route search: "..#found_routes.." found]"
local tab = {}
for idx, froute in ipairs(found_routes) do
- tab[idx] = minetest.formspec_escape(froute.name.." (Délka="..#froute.tcbseq..")")
+ local secfl = table.copy(froute.secseq)
+ table.remove(secfl, 1) -- remove first and last, because it will always be the same
+ secfl[#secfl]=nil
+ local viatext = ""
+ if next(secfl) then
+ froute.via = table.concat(secfl, ", ")
+ viatext = " (via "..froute.via..")"
+ end
+ tab[idx] = minetest.formspec_escape(froute.name..viatext)
end
- form=form.."textlist[0.5,1;4,3;rtelist;"..table.concat(tab, ",").."]"
- form=form.."button[0.5,4;2,1;continue;Hledat dál]"
- form=form.."button[2.5,4;2,1;apply;Použít]"
+ form=form.."textlist[0.5,1;7,3;rtelist;"..table.concat(tab, ",").."]"
+ form=form.."button[0.5,4;2,1;continue;Search further]"
+ form=form.."button[2.5,4;2,1;apply;Apply]"
minetest.show_formspec(pname, "at_il_smartroute_propose", form)
end
@@ -207,11 +218,19 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
local new_frte = {}
+ local endOnce = {}
+ local endTwice = {}
for _,froute in ipairs(found_routes) do
local endpoint = froute.tcbseq[#froute.tcbseq]
local endstr = advtrains.interlocking.sigd_to_string(endpoint)
if not ex_endpts[endstr] then
new_frte[#new_frte+1] = froute
+ -- record duplicate targets in froute
+ if endOnce[froute.name] then
+ endTwice[froute.name] = true
+ else
+ endOnce[froute.name] = true
+ end
else
--atdebug("(Smartroute) Throwing away",froute.name,"because endpoint",endstr,"already reached by route",ex_endpts[endstr])
end
@@ -220,6 +239,10 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
-- All remaining routes will be applied to the signal
local sel_rte = #tcbs.routes+1
for idx, froute in ipairs(new_frte) do
+ if endTwice[froute.name] then
+ -- append via text to deduplicate name
+ froute.name = froute.name .. " (via "..(froute.via or "direct")..")"
+ end
tcbs.routes[#tcbs.routes+1] = build_route_from_foundroute(froute)
end
-- if only one route present and it is newly created (there was no route before, thus sel_rte==1), make default
diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua
index a3c4fba..0be943a 100644
--- a/advtrains_interlocking/tcb_ts_ui.lua
+++ b/advtrains_interlocking/tcb_ts_ui.lua
@@ -30,7 +30,7 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
},
mesh = "at_il_tcb_node.obj",
tiles = {"at_il_tcb_node.png"},
- description=attrans("Track Circuit Break"),
+ description="Track Circuit Break",
sunlight_propagates=true,
groups = {
cracky=3,
@@ -40,12 +40,12 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
},
after_place_node = function(pos, node, player)
local meta = minetest.get_meta(pos)
- meta:set_string("infotext", attrans("Unconfigured Track Circuit Break, right-click to assign."))
+ meta:set_string("infotext", "Unconfigured Track Circuit Break, right-click to assign.")
end,
on_rightclick = function(pos, node, player)
local pname = player:get_player_name()
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
@@ -57,11 +57,11 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
if tcb then
advtrains.interlocking.show_tcb_form(tcbpos, pname)
else
- minetest.chat_send_player(pname, attrans("This TCB has been removed. Please dig marker."))
+ minetest.chat_send_player(pname, "This TCB has been removed. Please dig marker.")
end
else
--unconfigured
- minetest.chat_send_player(pname, attrans("Configuring TCB: Please punch the rail you want to assign this TCB to."))
+ minetest.chat_send_player(pname, "Configuring TCB: Please punch the rail you want to assign this TCB to.")
players_assign_tcb[pname] = pos
end
@@ -85,7 +85,7 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
local tcbpts = meta:get_string("tcb_pos")
if tcbpts ~= "" then
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local tcbpos = minetest.string_to_pos(tcbpts)
@@ -93,7 +93,7 @@ minetest.register_node("advtrains_interlocking:tcb_node", {
if not tcb then return true end
for connid=1,2 do
if tcb[connid].signal then
- minetest.chat_send_player(pname, attrans("Can't remove TCB: Both sides must have no signal assigned!"))
+ minetest.chat_send_player(pname, "Can't remove TCB: Both sides must have no signal assigned!")
return false
end
end
@@ -162,21 +162,21 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
if node_ok and #conns == 2 then
-- if there is already a tcb here, reassign it
if ildb.get_tcb(pos) then
- minetest.chat_send_player(pname, attrans("Configuring TCB: Already existed at this position, it is now linked to this TCB marker"))
+ minetest.chat_send_player(pname, "Configuring TCB: Already existed at this position, it is now linked to this TCB marker")
else
ildb.create_tcb_at(pos, pname)
end
local meta = minetest.get_meta(tcbnpos)
meta:set_string("tcb_pos", minetest.pos_to_string(pos))
- meta:set_string("infotext", attrans("TCB assigned to @1", minetest.pos_to_string(pos)))
- minetest.chat_send_player(pname, attrans("Configuring TCB: Successfully configured TCB"))
+ meta:set_string("infotext", "TCB assigned to "..minetest.pos_to_string(pos))
+ minetest.chat_send_player(pname, "Configuring TCB: Successfully configured TCB")
advtrains.interlocking.show_tcb_marker(pos)
else
minetest.chat_send_player(pname, "Configuring TCB: This is not a normal two-connection rail! Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Node is too far away. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Node is too far away. Aborted.")
end
players_assign_tcb[pname] = nil
end
@@ -194,19 +194,19 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
ildb.assign_signal_to_tcbs(pos, sigd)
-- use auto-naming
advtrains.interlocking.add_autoname_to_tcbs(tcbs, pname)
- minetest.chat_send_player(pname, "Konfigurace TCB: Návěstidlo úspěšně přiřazeno.")
+ minetest.chat_send_player(pname, "Configuring TCB: Successfully assigned signal.")
advtrains.interlocking.show_ip_form(pos, pname, true)
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Internal error, TCBS doesn't exist. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Internal error, TCBS doesn't exist. Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Cannot use static signals for routesetting. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Cannot use static signals for routesetting. Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Not a compatible signal. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Not a compatible signal. Aborted.")
end
else
- minetest.chat_send_player(pname, attrans("Configuring TCB: Node is too far away. Aborted."))
+ minetest.chat_send_player(pname, "Configuring TCB: Node is too far away. Aborted.")
end
players_assign_signal[pname] = nil
end
@@ -222,11 +222,11 @@ minetest.register_on_punchnode(function(pos, node, player, pointed_thing)
minetest.chat_send_player(pname, minetest.pos_to_string(pos).." locks in state "..state)
ts.fixed_locks[pts] = state
else
- minetest.chat_send_player(pname, "Chyba: traťová sekce se změnila, ruším operaci!")
+ minetest.chat_send_player(pname, "Error: TS modified, abort!")
players_assign_fixedlocks[pname] = nil
end
else
- minetest.chat_send_player(pname, "Ruční přidání zámků dokončeno!")
+ minetest.chat_send_player(pname, "Setting fixed locks finished!")
players_assign_fixedlocks[pname] = nil
ildb.update_rs_cache(ts_id)
advtrains.interlocking.show_ts_form(ts_id, pname)
@@ -247,12 +247,12 @@ function advtrains.interlocking.self_tcb_make_after_place_callback(fail_silently
local pname = player:get_player_name()
if not minetest.check_player_privs(pname, "interlocking") then
if not fail_silently_on_noprivs then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
end
return
end
if ildb.get_tcb(pos) then
- minetest.chat_send_player(pname, attrans("TCB already existed at this position, now linked to this node"))
+ minetest.chat_send_player(pname, "TCB already existed at this position, now linked to this node")
else
ildb.create_tcb_at(pos, pname)
end
@@ -261,7 +261,7 @@ function advtrains.interlocking.self_tcb_make_after_place_callback(fail_silently
local tcbs = ildb.get_tcbs(sigd)
-- make sure signal doesn't already exist
if tcbs.signal then
- minetest.chat_send_player(pname, attrans("Signal on B side already assigned!"))
+ minetest.chat_send_player(pname, "Signal on B side already assigned!")
return
end
ildb.assign_signal_to_tcbs(pos, sigd)
@@ -281,7 +281,7 @@ function advtrains.interlocking.self_tcb_make_can_dig_callback(is_signal)
local pname = player and player:get_player_name() or ""
-- need to duplicate logic of the regular "can_dig_or_modify_track()" function in core/tracks.lua
if advtrains.get_train_at_pos(pos) then
- minetest.chat_send_player(pname, attrans("Can't remove track, a train is here!"))
+ minetest.chat_send_player(pname, "Can't remove track, a train is here!")
return false
end
-- end of standard checks
@@ -371,17 +371,10 @@ end
-- TCB Form
-local sidecolorA = minetest.get_color_escape_sequence("#f40000")
-local sidecolorB = minetest.get_color_escape_sequence("#068b00")
-
local function mktcbformspec(pos, side, tcbs, offset, pname)
local form = ""
- local btncolor, btnpref, ts
- if side == 1 then
- btncolor, btnpref = sidecolorA, "A"
- else
- btncolor, btnpref = sidecolorB, "B"
- end
+ local btnpref = side==1 and "A" or "B"
+ local ts
-- ensure that mapping and xlink are up to date
ildb.tcbs_ensure_ts_ref_exists({p=pos, s=side, tcbs=tcbs})
ildb.validate_tcb_xlink({p=pos, s=side, tcbs=tcbs})
@@ -390,12 +383,12 @@ local function mktcbformspec(pos, side, tcbs, offset, pname)
ts = ildb.get_ts(tcbs.ts_id)
end
if ts then
- form = form.."label[0.5,"..offset..";"..btncolor..attrans("Side "..btnpref)..": "..minetest.formspec_escape(ts.name or tcbs.ts_id).."]"
- form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_gotots;"..attrans("Show track section").."]"
+ form = form.."label[0.5,"..offset..";Side "..btnpref..": "..minetest.formspec_escape(ts.name or tcbs.ts_id).."]"
+ form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_gotots;Show track section]"
else
tcbs.ts_id = nil
- form = form.."label[0.5,"..offset..";"..btncolor..attrans("Side "..btnpref)..": "..attrans("End of interlocking").."]"
- form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_makeil;"..attrans("Create Interlocked Track Section").."]"
+ form = form.."label[0.5,"..offset..";Side "..btnpref..": ".."End of interlocking]"
+ form = form.."button[0.5,"..(offset+0.5)..";5,1;"..btnpref.."_makeil;Create Interlocked Track Section]"
end
-- xlink
if tcbs.xlink then
@@ -403,17 +396,17 @@ local function mktcbformspec(pos, side, tcbs, offset, pname)
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkdel;X]"
else
if players_assign_xlink[pname] then
- form = form.."button[0.5,"..(offset+1.5)..";4,1;"..btnpref.."_xlinklink;"..attrans("Link @1", ildb.sigd_to_string(players_assign_xlink[pname])).."]"
+ form = form.."button[0.5,"..(offset+1.5)..";4,1;"..btnpref.."_xlinklink;Link "..ildb.sigd_to_string(players_assign_xlink[pname]).."]"
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkabrt;X]"
else
- form = form.."label[0.5,"..(offset+1.5)..";"..attrans("No Link").."]"
+ form = form.."label[0.5,"..(offset+1.5)..";No Link]"
form = form.."button[4.5,"..(offset+1.5)..";1,1;"..btnpref.."_xlinkadd;+]"
end
end
if tcbs.signal then
- form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_sigdia;"..attrans("Signalling").."]"
+ form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_sigdia;Signalling]"
else
- form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_asnsig;"..attrans("Assign a signal").."]"
+ form = form.."button[0.5,"..(offset+2.5)..";5,1;"..btnpref.."_asnsig;Assign a signal]"
end
return form
end
@@ -421,13 +414,13 @@ end
function advtrains.interlocking.show_tcb_form(pos, pname)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local tcb = ildb.get_tcb(pos)
if not tcb then return end
- local form = "size[6,9] label[0.5,0.5;"..attrans("Track Circuit Break Configuration").."]"
+ local form = "size[6,9] label[0.5,0.5;Track Circuit Break Configuration]"
form = form .. mktcbformspec(pos, 1, tcb[1], 1, pname)
form = form .. mktcbformspec(pos, 2, tcb[2], 5, pname)
@@ -494,14 +487,14 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
else
if f_xlinkadd[connid] then
players_assign_xlink[pname] = {p=pos, s=connid}
- minetest.chat_send_player(pname, attrans("TCB Link: Select linked TCB now!"))
+ minetest.chat_send_player(pname, "TCB Link: Select linked TCB now!")
minetest.close_formspec(pname, formname)
return -- to not reopen form
end
end
end
if f_asnsig[connid] and not tcbs.signal then
- minetest.chat_send_player(pname, attrans("Configuring TCB: Please punch the signal to assign."))
+ minetest.chat_send_player(pname, "Configuring TCB: Please punch the signal to assign.")
players_assign_signal[pname] = {p=pos, s=connid}
minetest.close_formspec(pname, formname)
return
@@ -523,15 +516,15 @@ end)
function advtrains.interlocking.show_ts_form(ts_id, pname)
if not minetest.check_player_privs(pname, "interlocking") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local ts = ildb.get_ts(ts_id)
if not ts_id then return end
- local form = "size[10,10]label[0.5,0.5;"..attrans("Track Section Detail - @1", ts_id).."]"
- form = form.."field[0.8,2;5.2,1;name;"..attrans("Section name")..";"..minetest.formspec_escape(ts.name or "").."]"
- form = form.."button[5.5,1.7;1,1;setname;"..attrans("Set").."]"
+ local form = "size[10.5,10]label[0.5,0.5;Track Section Detail - "..ts_id.."]"
+ form = form.."field[0.8,2;5.2,1;name;Section name;"..minetest.formspec_escape(ts.name or "").."]"
+ form = form.."button[5.5,1.7;1,1;setname;Set]"
local hint
local strtab = {}
@@ -540,7 +533,7 @@ function advtrains.interlocking.show_ts_form(ts_id, pname)
advtrains.interlocking.show_tcb_marker(sigd.p)
end
- form = form.."label[0.5,2.5;"..attrans("Boundary TCBs")..":]"
+ form = form.."label[0.5,2.5;Boundary TCBs:]"
form = form.."textlist[0.5,3;4,3;tcblist;"..table.concat(strtab, ",").."]"
-- additional route locks (e.g. for level crossings)
@@ -552,36 +545,36 @@ function advtrains.interlocking.show_ts_form(ts_id, pname)
minetest.pos_to_string(advtrains.decode_pos(pts)).." = "..state)
end
end
- form = form.."label[5.5,2.5;"..attrans("Fixed route locks (e.g. level crossings)")..":]"
+ form = form.."label[5.5,2.5;Fixed route locks (e.g. level crossings):]"
form = form.."textlist[5.5,3;4,3;fixedlocks;"..table.concat(strtab, ",").."]"
if ildb.may_modify_ts(ts) then
- form = form.."button[5.5,6;2,1;flk_add;"..attrans("Add locks").."]"
- form = form.."button[7.5,6;2,1;flk_clear;"..attrans("Clear locks").."]"
+ form = form.."button[5.5,6;2,1;flk_add;Add locks]"
+ form = form.."button[7.5,6;2,1;flk_clear;Clear locks]"
- form = form.."button[5.5,8;4,1;remove;"..attrans("Remove Section").."]"
- form = form.."tooltip[remove;"..attrans("This will remove the track section and set all its end points to End Of Interlocking").."]"
+ form = form.."button[5.5,8;4,1;remove;Remove Section]"
+ form = form.."tooltip[remove;This will remove the track section and set all its end points to End Of Interlocking]"
else
hint=3
end
if ts.route then
- form = form.."label[0.5,6.1;"..attrans("Route is set: @1", ts.route.rsn).."]"
+ form = form.."label[0.5,6.1;Route is set: "..ts.route.rsn.."]"
elseif ts.route_post then
- form = form.."label[0.5,6.1;"..attrans("Section holds @1 route locks.", #(ts.route_post.lcks or {})).."]"
+ form = form.."label[0.5,6.1;Section holds "..#(ts.route_post.lcks or {}).." route locks.]"
end
-- occupying trains
if ts.trains and #ts.trains>0 then
- form = form.."label[0.5,7.1;"..attrans("Trains on this section:").."]"
+ form = form.."label[0.5,7.1;Trains on this section:]"
form = form.."textlist[0.5,7.7;3,2;trnlist;"..table.concat(ts.trains, ",").."]"
else
- form = form.."label[0.5,7.1;"..attrans("No trains on this section.").."]"
+ form = form.."label[0.5,7.1;No trains on this section.]"
end
- form = form.."button[5.5,7;4,1;reset;"..attrans("Reset section state").."]"
+ form = form.."button[5.5,7;4,1;reset;Reset section state]"
if hint == 3 then
- form = form.."label[0.5,0.75;"..attrans("You cannot modify track sections when a route is set or a train is on the section.").."]"
+ form = form.."label[0.5,0.75;You cannot modify track sections when a route is set or a train is on the section.]"
--form = form.."label[0.5,1;Trying to unlink a TCB directly connected to this track will not work.]"
end
@@ -622,7 +615,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
ts.fixed_locks = {}
end
players_assign_fixedlocks[pname] = ts_id
- minetest.chat_send_player(pname, attrans("Punch components to add fixed locks. (punch anything else = end)"))
+ minetest.chat_send_player(pname, "Punch components to add fixed locks. (punch anything else = end)")
minetest.close_formspec(pname, formname)
return
elseif fields.flk_clear then
@@ -632,15 +625,15 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.reset then
-- User requested resetting the section
-- Show him what this means...
- local form = "size[7,5]label[0.5,0.5;"..attrans("Reset track section").."]"
- form = form.."label[0.5,1;"..attrans("This will clear the list of trains\nand the routesetting status of this section.\nAre you sure?").."]"
- form = form.."button_exit[0.5,2.5; 5,1;reset;"..attrans("Yes").."]"
- form = form.."button_exit[0.5,3.5; 5,1;cancel;"..attrans("Cancel").."]"
+ local form = "size[7,5]label[0.5,0.5;Reset track section]"
+ form = form.."label[0.5,1;This will clear the list of trains\nand the routesetting status of this section.\nAre you sure?]"
+ form = form.."button_exit[0.5,2.5; 5,1;reset;Yes]"
+ form = form.."button_exit[0.5,3.5; 5,1;cancel;Cancel]"
minetest.show_formspec(pname, "at_il_tsreset_"..ts_id, form)
return
end
- advtrains.interlocking.show_ts_form(ts_id, pname)
+ advtrains.interlocking.show_ts_form(ts_id, pname, sel_tcb)
return
end
@@ -658,7 +651,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local tcbs = ildb.get_tcbs(sigd)
advtrains.interlocking.signal.update_route_aspect(tcbs)
end
- minetest.chat_send_player(pname, attrans("Reset track section @1!", ts_id))
+ minetest.chat_send_player(pname, "Reset track section "..ts_id.."!")
end
end)
@@ -668,14 +661,11 @@ end)
local markerent = {}
minetest.register_entity("advtrains_interlocking:tcbmarker", {
- initial_properties = {
- visual = "mesh",
- mesh = "trackplane.b3d",
- textures = {"at_il_tcb_marker.png"},
- collisionbox = {-1,-0.5,-1, 1,-0.4,1},
- visual_size = {x=10, y=10},
- static_save = false,
- },
+ visual = "mesh",
+ mesh = "trackplane.b3d",
+ textures = {"at_il_tcb_marker.png"},
+ collisionbox = {-1,-0.5,-1, 1,-0.4,1},
+ visual_size = {x=10, y=10},
on_punch = function(self)
self.object:remove()
end,
@@ -686,6 +676,7 @@ minetest.register_entity("advtrains_interlocking:tcbmarker", {
end,
get_staticdata = function() return "STATIC" end,
on_activate = function(self, sdata) if sdata=="STATIC" then self.object:remove() end end,
+ static_save = false,
})
function advtrains.interlocking.remove_tcb_marker_pts(pts)
@@ -713,7 +704,7 @@ function advtrains.interlocking.show_tcb_marker(pos)
if ts then
itex[connid] = ts.name or tcbs.ts_id or "???"
else
- itex[connid] = "--kon.zab.ob.--"
+ itex[connid] = "--EOI--"
end
end
@@ -773,11 +764,11 @@ function advtrains.interlocking.check_route_valid(route, sigd)
while c_sigd and i<=#route do
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
- return false, attrans("No TCBS at @1", sigd_to_string(c_sigd))
+ return false, "No TCBS at "..sigd_to_string(c_sigd)
end
c_ts_id = c_tcbs.ts_id
if not c_ts_id then
- return false, attrans("No track section adjacent to @1", sigd_to_string(c_sigd))
+ return false, "No track section adjacent to "..sigd_to_string(c_sigd)
end
c_ts = ildb.get_ts(c_ts_id)
@@ -787,7 +778,7 @@ function advtrains.interlocking.check_route_valid(route, sigd)
for pts, state in pairs(c_rseg.locks) do
local pos = advtrains.decode_pos(pts)
if not advtrains.is_passive(pos) then
- return false, attrans("No passive component for lock at @1", pts)
+ return false, "No passive component for lock at "..pts
end
end
end
@@ -796,7 +787,7 @@ function advtrains.interlocking.check_route_valid(route, sigd)
if nvar then
local re_tcbs = ildb.get_tcbs({p = nvar.p, s = (nvar.s==1) and 2 or 1})
if not re_tcbs or not re_tcbs.ts_id or re_tcbs.ts_id~=c_ts_id then
- return false, attrans("TCB at @1 has different section than previous TCB.", minetest.pos_to_string(nvar.p))
+ return false, "TCB at "..minetest.pos_to_string(nvar.p).." has different section than previous TCB."
end
end
-- advance
@@ -805,11 +796,11 @@ function advtrains.interlocking.check_route_valid(route, sigd)
end
-- check end TCB
if not c_sigd then
- return false, attrans("Final TCBS unset (legacy-style buffer route)")
+ return false, "Final TCBS unset (legacy-style buffer route)"
end
c_tcbs = ildb.get_tcbs(c_sigd)
if not c_tcbs then
- return false, attrans("Final TCBS missing at @1", sigd_to_string(c_sigd))
+ return false, "Final TCBS missing at "..sigd_to_string(c_sigd)
end
return true, nil, c_sigd
end
@@ -823,7 +814,7 @@ local p_open_sig_form = {}
function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, called_from_form_update)
if not minetest.check_player_privs(pname, "train_operator") then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
local hasprivs = minetest.check_player_privs(pname, "interlocking")
@@ -831,38 +822,52 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
if not tcbs.signal then return end
if not tcbs.routes then tcbs.routes = {} end
- if not tcbs.signal_name then tcbs.signal_name = minetest.pos_to_string(sigd.p) end
-
- local form = "size[7,10]label[0.5,0.5;"..attrans("Signal at @1", minetest.pos_to_string(sigd.p)).."]"
- form = form.."field[0.8,1.5;5.2,1;name;"..attrans("Signal name")..";"..minetest.formspec_escape(tcbs.signal_name).."]"
- form = form.."button[5.5,1.2;1,1;setname;"..attrans("Set").."]"
+
+ local form = "size[7,10.25]label[0.5,0.5;Signal at "..minetest.pos_to_string(sigd.p).."]"
+ form = form.."field[0.8,1.5;5.2,1;name;Signal name;"..minetest.formspec_escape(tcbs.signal_name or "").."]"
+ form = form.."button[5.5,1.2;1,1;setname;Set]"
if tcbs.routeset then
- local rte = tcbs.routes[tcbs.routeset]
- if not rte then
- atwarn("Unknown route set from signal!")
- tcbs.routeset = nil
- return
+ if type(tcbs.routeset)=="table" then
+ local rtenames = {}
+ for midx,rteid in ipairs(tcbs.routeset) do
+ local rte = tcbs.routes[rteid]
+ if not rte then
+ atwarn("Unknown route set from signal!")
+ tcbs.routeset = nil
+ return
+ end
+ rtenames[midx] = rte.name
+ end
+ form = form.."label[0.5,2.5;Multiple routes are requested (first available is set):]"
+ form = form.."label[0.5,3.0;"..minetest.formspec_escape(table.concat(rtenames,", ")).."]"
+ else
+ local rte = tcbs.routes[tcbs.routeset]
+ if not rte then
+ atwarn("Unknown route set from signal!")
+ tcbs.routeset = nil
+ return
+ end
+ form = form.."label[0.5,2.5;A route is requested from this signal:]"
+ form = form.."label[0.5,3.0;"..minetest.formspec_escape(rte.name).."]"
end
- form = form.."label[0.5,2.5;"..attrans("A route is requested from this signal:").."]"
- form = form.."label[0.5,3.0;"..minetest.formspec_escape(rte.name).."]"
if tcbs.route_committed then
- form = form.."label[0.5,3.5;"..attrans("Route has been set.").."]"
+ form = form.."label[0.5,3.5;Route has been set.]"
else
- form = form.."label[0.5,3.5;"..attrans("Waiting for route to be set...").."]"
+ form = form.."label[0.5,3.5;Waiting for route to be set...]"
if tcbs.route_rsn then
form = form.."label[0.5,4;"..minetest.formspec_escape(tcbs.route_rsn).."]"
end
end
if not tcbs.route_auto then
- form = form.."button[0.5,7; 5,1;auto;"..attrans("Enable Automatic Working").."]"
+ form = form.."button[0.5,7; 5,1;auto;Enable Automatic Working]"
else
- form = form.."label[0.5,7 ;"..attrans("Automatic Working is active.").."]"
- form = form.."label[0.5,7.3;"..attrans("Route is re-set when a train passed.").."]"
- form = form.."button[0.5,7.7; 5,1;noauto;"..attrans("Disable Automatic Working").."]"
+ form = form.."label[0.5,7 ;Automatic Working is active.]"
+ form = form.."label[0.5,7.3;Route is re-set when a train passed.]"
+ form = form.."button[0.5,7.7; 5,1;noauto;Disable Automatic Working]"
end
- form = form.."button[0.5,6; 5,1;cancelroute;"..attrans("Cancel Route").."]"
+ form = form.."button[0.5,6; 5,1;cancelroute;Cancel Route]"
else
if not tcbs.route_origin then
if #tcbs.routes > 0 then
@@ -883,35 +888,35 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
end
strtab[#strtab+1] = clr .. minetest.formspec_escape(rname)
end
- form = form.."label[0.5,2.5;"..attrans("Routes:").."]"
+ form = form.."label[0.5,2.5;Routes:]"
form = form.."textlist[0.5,3;5,3;rtelist;"..table.concat(strtab, ",")
if sel_rte then
form = form .. ";" .. sel_rte .."]"
- form = form.."button[0.5,6; 5,1;setroute;"..attrans("Set Route").."]"
- form = form.."button[0.5,7;2,1;dsproute;"..attrans("Show").."]"
+ form = form.."button[0.5,6; 5,1;setroute;Set Route]"
+ form = form.."button[0.5,7;2,1;dsproute;Show]"
if hasprivs then
- form = form.."button[5.5,3.3;1,0.3;setarsdefault;Vých]tooltip[setarsdefault;"..attrans("Set ARS default route").."]"
- form = form.."button[3.5,7;2,1;editroute;"..attrans("Edit").."]"
+ form = form.."button[5.5,3.3;1,0.3;setarsdefault;D]tooltip[setarsdefault;Set ARS default route]"
+ form = form.."button[3.5,7;2,1;editroute;Edit]"
if sel_rte > 1 then
form = form .. "button[5.5,4;1,0.3;moveup;↑]"
end
if sel_rte < #strtab then
form = form .. "button[5.5,4.7;1,0.3;movedown;↓]"
end
- form = form.."button[5.5,5.4;1,0.3;delroute;X]tooltip[delroute;"..attrans("Delete this route").."]"
+ form = form.."button[5.5,5.4;1,0.3;delroute;X]tooltip[delroute;Delete this route]"
end
else
form = form .. "]"
if tcbs.ars_disabled then
- form = form.."label[0.5,6 ;"..attrans("NOTE: ARS is disabled.").."]"
- form = form.."label[0.5,6.5;"..attrans("Routes are not automatically set.").."]"
+ form = form.."label[0.5,6 ;NOTE: ARS is disabled.]"
+ form = form.."label[0.5,6.5;Routes are not automatically set.]"
end
end
if hasprivs then
- form = form.."button[0.5,8;2.5,1;smartroute;"..attrans("Smart Route").."]"
- form = form.."button[ 3,8;2.5,1;newroute;"..attrans("New (Manual)").."]"
- form = form..string.format("checkbox[0.5,8.75;ars;"..attrans("Automatic routesetting")..";%s]", not tcbs.ars_disabled)
- form = form..string.format("checkbox[0.5,9.25;dstarstrig;"..attrans("Distant signal triggers ARS")..";%s]", not tcbs.no_dst_ars_trig)
+ form = form.."button[0.5,8;2.5,1;smartroute;Smart Route]"
+ form = form.."button[ 3,8;2.5,1;newroute;New (Manual)]"
+ form = form..string.format("checkbox[0.5,8.75;ars;Automatic routesetting;%s]", not tcbs.ars_disabled)
+ form = form..string.format("checkbox[0.5,9.25;dstarstrig;Distant signal triggers ARS;%s]", not tcbs.no_dst_ars_trig)
end
else
-- no route is active, and no route is so far defined
@@ -919,29 +924,29 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle
local caps = advtrains.interlocking.signal.get_signal_cap_level(tcbs.signal)
if caps >= 4 then
-- offer user the "block signal mode"
- form = form.."label[0.5,2.5;"..attrans("No routes are yet defined.").."]"
+ form = form.."label[0.5,2.5;No routes are yet defined.]"
if hasprivs then
- form = form.."button[0.5,4;2.5,1;smartroute;"..attrans("Smart Route").."]"
- form = form.."button[ 3,4;2.5,1;newroute;"..attrans("New (Manual)").."]"
+ form = form.."button[0.5,4;2.5,1;smartroute;Smart Route]"
+ form = form.."button[ 3,4;2.5,1;newroute;New (Manual)]"
end
elseif caps >= 3 then
-- it's a buffer!
- form = form.."label[0.5,2.5;Tento signál vždy ukazuje červenou.\n"
- .."Vlakové cesty odsud nemohou být nastaveny.]"
+ form = form.."label[0.5,2.5;This is an always-halt signal (e.g. a buffer)\n"
+ .."No routes can be set from here.]"
else
-- signal caps say it cannot be route start/end
- form = form.."label[0.5,2.5;Toto je vzdálená předzvěst.\n"
- .."Aktuálně tudy není nastavena vlaková cesta.]"
+ form = form.."label[0.5,2.5;This is a pure distant signal\n"
+ .."No route is currently set through.]"
end
end
elseif sigd_equal(tcbs.route_origin, sigd) then
-- something has gone wrong: tcbs.routeset should have been set...
- form = form.."label[0.5,2.5;"..attrans("Inconsistent state: route_origin is same TCBS but no route set. Try again.").."]"
+ form = form.."label[0.5,2.5;Inconsistent state: route_origin is same TCBS but no route set. Try again.]"
ilrs.cancel_route_from(sigd)
else
- form = form.."label[0.5,2.5;"..attrans("Route is set over this signal by:").."\n"..sigd_to_string(tcbs.route_origin).."]"
- form = form.."label[0.5,4;"..attrans("Wait for this route to be cancelled in order to do anything here.").."]"
+ form = form.."label[0.5,2.5;Route is set over this signal by:\n"..sigd_to_string(tcbs.route_origin).."]"
+ form = form.."label[0.5,4;Wait for this route to be cancelled in order to do anything here.]"
end
end
sig_pselidx[pname] = sel_rte
@@ -1010,9 +1015,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
end
if tcbs.routeset and fields.cancelroute then
- if tcbs.routes[tcbs.routeset] and tcbs.routes[tcbs.routeset].ars then
- tcbs.ars_ignore_next = true
- end
+ tcbs.ars_ignore_next = true
-- if route committed, cancel route ts info
ilrs.update_route(sigd, tcbs, nil, true)
end
@@ -1035,7 +1038,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.dsproute then
local t = os.clock()
advtrains.interlocking.visualize_route(sigd, tcbs.routes[sel_rte], "disp_"..t)
- minetest.after(60, function() advtrains.interlocking.clear_visu_context("disp_"..t) end)
+ minetest.after(10, function() advtrains.interlocking.clear_visu_context("disp_"..t) end)
end
if fields.editroute and hasprivs then
advtrains.interlocking.show_route_edit_form(pname, sigd, sel_rte)
@@ -1064,7 +1067,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
end
if fields.delroute and hasprivs then
if tcbs.routes[sel_rte] and tcbs.routes[sel_rte].ars then
- minetest.chat_send_player(pname, attrans("Cannot delete route which has ARS rules, please review and then delete through edit dialog!"))
+ minetest.chat_send_player(pname, "Cannot delete route which has ARS rules, please review and then delete through edit dialog!")
else
table.remove(tcbs.routes,sel_rte)
end
@@ -1074,13 +1077,6 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.ars then
tcbs.ars_disabled = not minetest.is_yes(fields.ars)
- local action
- if tcbs.ars_disabled then
- action = "disabled"
- else
- action = "enabled"
- end
- core.log("action", pname.." "..action.." ARS at "..pts)
end
if fields.dstarstrig then
diff --git a/advtrains_interlocking/tool.lua b/advtrains_interlocking/tool.lua
index c8f8521..5ceae04 100644
--- a/advtrains_interlocking/tool.lua
+++ b/advtrains_interlocking/tool.lua
@@ -5,17 +5,17 @@ local ilrs = advtrains.interlocking.route
local function node_right_click(pos, pname, player)
if advtrains.is_passive(pos) then
- local form = "size[7,5]label[0.5,0.5;Průzkumník zámků]"
+ local form = "size[7,5]label[0.5,0.5;Route lock inspector]"
local pts = advtrains.encode_pos(pos)
local rtl = ilrs.has_route_lock(pts)
if rtl then
- form = form.."label[0.5,1;Právě uzamčeno:\n"..rtl.."]"
- form = form.."button_exit[0.5,3.5; 5,1;clear;Odemknout vše]"
+ form = form.."label[0.5,1;Route locks currently put:\n"..rtl.."]"
+ form = form.."button_exit[0.5,3.5; 5,1;clear;Clear]"
else
- form = form.."label[0.5,1;Nic není uzamčeno]"
- form = form.."button_exit[0.5,3.5; 5,1;emplace;Uzamknout ručně]"
+ form = form.."label[0.5,1;No route locks set]"
+ form = form.."button_exit[0.5,3.5; 5,1;emplace;Emplace manual lock]"
end
minetest.show_formspec(pname, "at_il_rtool_"..pts, form)
@@ -25,7 +25,7 @@ local function node_right_click(pos, pname, player)
-- If not a turnout, check the track section and show a form
local node_ok, conns, rail_y=advtrains.get_rail_info_at(pos)
if not node_ok then
- minetest.chat_send_player(pname, "Tento blok není kolej!")
+ minetest.chat_send_player(pname, "Node is not a track!")
return
end
if advtrains.interlocking.db.get_tcb(pos) then
@@ -37,14 +37,14 @@ local function node_right_click(pos, pname, player)
if ts_id then
advtrains.interlocking.show_ts_form(ts_id, pname)
else
- minetest.chat_send_player(pname, "Zde není zabezpečený traťový úsek!")
+ minetest.chat_send_player(pname, "No track section at this location!")
end
end
local function node_left_click(pos, pname, player)
local node_ok, conns, rail_y=advtrains.get_rail_info_at(pos)
if not node_ok then
- minetest.chat_send_player(pname, "Tento blok není kolej!")
+ minetest.chat_send_player(pname, "Node is not a track!")
return
end
@@ -62,14 +62,13 @@ local function node_left_click(pos, pname, player)
advtrains.interlocking.db.update_rs_cache(ts_id)
advtrains.interlocking.highlight_track_section(pos)
else
- minetest.chat_send_player(pname, "Zde není zabezpečený traťový úsek!")
+ minetest.chat_send_player(pname, "No track section at this location!")
end
end
minetest.register_craftitem("advtrains_interlocking:tool",{
- description = "ovladač traťového zabezpečení",
- _ch_help = "levý klik: zvýraznit traťový úsek\npravý klik: prozkoumat/zkontrolovat zámky nebo zobrazit informace o traťovém úseku",
+ description = "Interlocking tool\nPunch: Highlight track section\nPlace: check route locks/show track section info",
groups = {cracky=1}, -- key=name, value=rating; rating=1..3.
inventory_image = "at_il_tool.png",
wield_image = "at_il_tool.png",
@@ -80,7 +79,7 @@ minetest.register_craftitem("advtrains_interlocking:tool",{
return
end
if not minetest.check_player_privs(pname, {interlocking=true}) then
- minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!"))
+ minetest.chat_send_player(pname, "Insufficient privileges to use this!")
return
end
if pointed_thing.type=="node" then
@@ -120,8 +119,14 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
ilrs.remove_route_locks(pts)
end
if fields.emplace then
- ilrs.add_manual_route_lock(pts, attrans("Manual lock (@1)", pname))
+ ilrs.add_manual_route_lock(pts, "Manual lock ("..pname..")")
end
end
end
end)
+
+minetest.register_craft({
+ output = "advtrains_interlocking:tool",
+ type = "shapeless",
+ recipe = {"dye:green","advtrains:trackworker", "advtrains_interlocking:tcb_node"}
+}) \ No newline at end of file
diff --git a/advtrains_line_automation/init.lua b/advtrains_line_automation/init.lua
index 9de25fb..814dc27 100644
--- a/advtrains_line_automation/init.lua
+++ b/advtrains_line_automation/init.lua
@@ -22,7 +22,9 @@ dofile(modpath.."railwaytime.lua")
dofile(modpath.."line_functions.lua")
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.."time_table.lua")
diff --git a/advtrains_line_automation/scheduler.lua b/advtrains_line_automation/scheduler.lua
index 6025b02..5cba0a0 100644
--- a/advtrains_line_automation/scheduler.lua
+++ b/advtrains_line_automation/scheduler.lua
@@ -59,7 +59,7 @@ function sched.run()
-- run it
callbacks[elem.e](elem.d)
else
- atwarn("[lines][scheduler] No callback to handle schedule",elem)
+ atwarn("[lines][scheduler] "..S("No callback to handle schedule"),elem)
end
cnt=cnt+1
ucn = units_cnt[elem.u]
diff --git a/advtrains_line_automation/stoprail.lua b/advtrains_line_automation/stoprail.lua
index 33ca0cc..8553c97 100644
--- a/advtrains_line_automation/stoprail.lua
+++ b/advtrains_line_automation/stoprail.lua
@@ -2,6 +2,8 @@
-- adds "stop rail". Recognized by lzb. (part of behavior is implemented there)
local rwt = assert(advtrains.lines.rwt)
+-- Translation
+S = attrans
local function to_int(n)
--- Disallow floating-point numbers
@@ -25,7 +27,7 @@ local function updatemeta(pos)
end
local door_dropdown = {L=1, R=2, C=3}
-local door_dropdown_rev = {["vpravo"]="R", ["vlevo"]="L", ["neotvírat"]="C"}
+local door_dropdown_code = {"L", "R", "C"} -- switch to numerical index of selection : for conversion of the numerical index in the opening side selection dropdown box to the internal codification
local function get_stn_dropdown(stn, player_name)
local stations = advtrains.lines.load_stations_for_formspec()
@@ -53,7 +55,7 @@ local function show_stoprailform(pos, player)
local pe = advtrains.encode_pos(pos)
local pname = player:get_player_name()
if minetest.is_protected(pos, pname) then
- minetest.chat_send_player(pname, attrans("Position is protected!"))
+ minetest.chat_send_player(pname, S("You are not allowed to configure this track."))
return
end
@@ -89,7 +91,7 @@ local function show_stoprailform(pos, player)
get_stn_dropdown(player_to_stn_override[pname] or stdata.stn, pname_unless_admin)..
"field[6.75,2;1,0.75;track;"..attrans("Track")..";"..minetest.formspec_escape(stdata.track).."]"..
"label[0.25,3.4;"..attrans("Door Side").."]"..
- "dropdown[2.25,3;2,0.75;doors;vlevo,vpravo,neotvírat;"..door_dropdown[stdata.doors].."]"..
+ "dropdown[2.25,3;2,0.75;doors;"..S("Left")..","..S("Right")..","..S("Closed")..";"..door_dropdown[stdata.doors]..";true]".. -- switch to numerical index of the selection
"checkbox[4.5,3.25;reverse;"..attrans("Reverse train")..";"..(stdata.reverse and "true" or "false").."]"..
"checkbox[4.5,3.75;kick;"..attrans("Kick out passengers")..";"..(stdata.kick and "true" or "false").."]"..
"checkbox[4.5,4.25;keepopen;Nezavírat dveře na odj.;"..(stdata.keepopen and "true" or "false").."]"..
@@ -143,7 +145,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local pos = advtrains.decode_pos(pe)
if pos then
if minetest.is_protected(pos, pname) then
- minetest.chat_send_player(pname, attrans("Position is protected!"))
+ minetest.chat_send_player(pname, S("You are not allowed to configure this track."))
return
end
@@ -160,6 +162,9 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
if fields.keepopen then
tmp_checkboxes[pe].keepopen = (fields.keepopen == "true")
end
+ if fields.waitsig then
+ tmp_checkboxes[pe].waitsig = (fields.waitsig == "true")
+ end
if fields.stn then
local new_index = tonumber(fields.stn)
@@ -204,7 +209,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
-- dropdowns
if fields.doors then
- stdata.doors = door_dropdown_rev[fields.doors] or "C"
+ stdata.doors = door_dropdown_code[tonumber(fields.doors)] or "C" -- switch to numerical index of selection; attention : fields.doors is string typed, needed to be converted to an integer typed index in door_dropdown_code table
end
if fields.track then
@@ -289,7 +294,7 @@ local adefunc = function(def, preset, suffix, rotation)
after_place_node=function(pos)
local pe = advtrains.encode_pos(pos)
advtrains.lines.stops[pe] = {
- stn="", track="", doors="R", wait=10
+ stn="", track="", doors="R", wait=10, waitsig = true
}
updatemeta(pos)
end,
@@ -340,7 +345,7 @@ if minetest.get_modpath("advtrains_train_track") ~= nil then
models_prefix="advtrains_dtrack",
models_suffix=".b3d",
shared_texture="advtrains_dtrack_shared_stop.png",
- description=attrans("Station/Stop Rail"),
+ description=S("Station/Stop Track"),
formats={},
get_additional_definiton = adefunc,
}, advtrains.trackpresets.t_30deg_straightonly)
diff --git a/advtrains_luaautomation/README.md b/advtrains_luaautomation/README.md
new file mode 100755
index 0000000..275653c
--- /dev/null
+++ b/advtrains_luaautomation/README.md
@@ -0,0 +1,466 @@
+
+# Advtrains - Lua Automation features
+
+This mod offers components that run LUA code and interface with each other through a global environment. It makes complex automated railway systems possible. The mod is sometimes abbreviated as 'LuaATC' or 'atlatc'. This stands for AdvTrainsLuaATC. This short name has been chosen for user convenience, since the name of this mod ('advtrains_luaautomation') is very long.
+
+A probably more complete documentation of LuaATC is found on the [Advtrains Wiki](http://advtrains.de/wiki/doku.php?id=usage:atlatc:start)
+
+## Privileges
+To perform any operations using this mod (except executing operation panels), players need the "atlatc" privilege.
+This privilege should never be granted to anyone except trusted administrators. Even though the LUA environment is sandboxed, it is still possible to DoS the server by coding infinite loops or requesting expotentially growing interrupts.
+
+## Environments
+
+Each active component is assigned to an environment where all atlac data is held. Components in different environments can't inferface with each other.
+This system allows multiple independent automation systems to run simultaneously without polluting each other's environment.
+
+ - `/env_create <env_name>`:
+Create environment with the given name. To be able to do anything, you first need to create an environment. Choose the name wisely, you can't change it afterwards without deleting the environment and starting again.
+
+ - `/env_setup <env_name>`:
+Invoke the form to edit the environment's initialization code. For more information, see the section on active components. You can also delete an environment from here.
+
+ - `/env_subscribe <env_name>`, `/env_unsubscribe <env_name>`:
+Subscribe or unsubscribe from log/error messages originating from this environment
+
+ - `/env_subscriptions [env_name]`:
+List your subscriptions or players subscribed to an environment.
+
+
+## Functions and variables
+### General Functions and Variables
+The following standard Lua libraries are available:
+ - `string`
+ - `math`
+ - `table`
+ - `os`
+
+The following standard Lua functions are available:
+ - `assert`
+ - `error`
+ - `ipairs`
+ - `pairs`
+ - `next`
+ - `select`
+ - `tonumber`
+ - `tostring`
+ - `type`
+ - `unpack`
+
+Any attempt to overwrite the predefined values results in an error.
+
+### LuaAutomation Global Variables
+ - `S`
+The variable 'S' contains a table which is shared between all components of the environment. Its contents are persistent over server restarts. May not contain functions, every other value is allowed.
+
+ - `F`
+The variable 'F' also contains a table which is shared between all components of the environment. Its contents are discarded on server shutdown or when the init code gets re-run. Every data type is allowed, even functions.
+The purpose of this table is not to save data, but to provide static value and function definitions. The table should be populated by the init code.
+
+### LuaAutomation Global Functions
+> Note: in the following functions, all parameters named `pos` designate a position. You can use the following:
+> - a default Minetest position vector (eg. {x=34, y=2, z=-18})
+> - the POS(34,2,-18) shorthand below.
+> - A string, the passive component name. See 'passive component naming'.
+
+
+
+ - `POS(x,y,z)`
+Shorthand function to create a position vector {x=?, y=?, z=?} with less characters.
+
+ - `getstate(pos)`
+Get the state of the passive component at position `pos`.
+
+ - `setstate(pos, newstate)`
+Set the state of the passive component at position `pos`.
+
+ - `is_passive(pos)`
+Checks whether there is a passive component at the position pos (and/or whether a passive component with this name exists)
+
+ - `interrupt(time, message)`
+Cause LuaAutomation to trigger an `int` event on this component after the given time in seconds with the specified `message` field. `message` can be of any Lua data type. Returns true. *Not available in init code.*
+
+ - `interrupt_safe(time, message)`
+Like `interrupt()`, but does not add an interrupt and returns false when an interrupt (of any type) is already present for this component. Returns true when interrupt was successfully added.
+
+ - `interrupt_pos(pos, message)`
+Immediately trigger an `ext_int` event on the active component at position pos. `message` is like in interrupt(). Use with care, or better **_don't use_**! Incorrect use can result in **_expotential growth of interrupts_**.
+
+ - `clear_interrupts()`
+Removes any pending interrupts of this node.
+
+ - `digiline_send(channel, message)`
+Make this active component send a digiline message on the specified channel.
+Not available in init code.
+
+ - `trainparts(train_id)`
+ returns a table with the ids of the cars the train is composed of, or false if `train_id` is invalid. `train_id` can be replaced with `atc_id` when used in LuaATC Rails.
+
+ - `atc_send_to_train(<train_id>, <atc_command>)`
+ Sends the specified ATC command to the train specified by its train id. This happens regardless of where the train is in the world, and can be used to remote-control trains. Returns true on success. If the train ID does not exist, returns false and does nothing. See [atc_command.txt](../atc_command.txt) for the ATC command syntax.
+
+#### Interlocking Route Management Functions
+If `advtrains_interlocking` is enabled, the following aditional functions can be used:
+
+ - `can_set_route(pos, route_name)`
+Returns whether it is possible to set the route designated by route_name from the signal at pos.
+
+ - `set_route(pos, route_name)`
+Requests the given route from the signal at pos. Has the same effect as clicking "Set Route" in the signalling dialog.
+
+ - `cancel_route(pos)`
+Cancels the route that is set from the signal at pos. Has the same effect as clicking "Cancel Route" in the signalling dialog.
+
+ - `get_aspect(pos)`
+Returns the signal aspect of the signal at pos. A signal aspect has the following format:
+```lua
+asp = {
+ main = <int speed>,
+ -- Main signal aspect, tells state and permitted speed of next section
+ -- 0 = section is blocked
+ -- >0 = section is free, speed limit is this value
+ -- -1 = section is free, maximum speed permitted
+ -- false = Signal doesn't provide main signal information, retain current speed limit.
+ shunt = <boolean>,
+ -- Whether train may proceed as shunt move, on sight
+ -- main aspect takes precedence over this
+ -- When main==0, train switches to shunt move and is restricted to speed 8
+ proceed_as_main = <boolean>,
+ -- If an approaching train is a shunt move and 'shunt' is false,
+ -- the train may proceed as a train move under the "main" aspect
+ -- if the main aspect permits it (i.e. main!=0)
+ -- If this is not set, shunt moves are NOT allowed to switch to
+ -- a train move, and must stop even if "main" would permit passing.
+ -- This is intended to be used for "Halt for shunt moves" signs.
+
+ dst = <int speed>,
+ -- Distant signal aspect, tells state and permitted speed of the section after next section
+ -- The character of these information is purely informational
+ -- At this time, this field is not actively used
+ -- 0 = section is blocked
+ -- >0 = section is free, speed limit is this value
+ -- -1 = section is free, maximum speed permitted
+ -- false = Signal doesn't provide distant signal information.
+
+ -- the character of call_on and dead_end is purely informative
+ call_on = <boolean>, -- Call-on route, expect train in track ahead (not implemented yet)
+ dead_end = <boolean>, -- Route ends on a dead end (e.g. bumper) (not implemented yet)
+}
+```
+As of September 2024, the 'dst', 'call_on' and 'dead_end' fields are not used.
+
+#### Lines
+
+The advtrains_line_automation component adds a few contraptions that should make creating timeable systems easier.
+Part of its functionality is also available in LuaATC:
+
+- `rwt.*` - all Railway Time functions are included as documented in [the wiki](https://advtrains.de/wiki/doku.php?id=dev:api:railway_time_api)
+
+ - `schedule(rw_time, msg)`, `schedule_in(rw_dtime, msg)`
+Schedules an event of type {type="schedule", schedule=true, msg=msg} at (resp. after) the specified railway time (which can be in any format). You can only schedule one event this way. (uses the new lines-internal scheduler)
+
+Note: Using the lines scheduler is preferred over using `interrupt()`, as it's more performant and safer to use.
+
+## Events
+The event table is a variable created locally by the component being triggered. It is a table with the following format:
+```lua
+event = {
+ type = "<event type>",
+ <event type> = true,
+ --additional event-specific content
+}
+```
+You can check the event type by using the following:
+```lua
+if event.type == "wanted" then
+ --do stuff
+end
+```
+or
+```lua
+if event.wanted then
+ --do stuff
+end
+```
+where `wanted` is the event type to check for.
+See the "Active Components" section below for details on the various event types as not all of them are applicable to all components.
+
+## Components
+Atlac components introduce automation-capable components that fall within two categories:
+ - Active Components are components that are able to run Lua code, triggered by specific events.
+ - Passive Components can't perform actions themselves. Their state can be read and set by active components or manually by the player.
+
+### Lua ATC Rails
+Lua ATC rails are the only components that can actually interface with trains. The following event types are available to the Lua ATC rails:
+ - `{type="train", train=true, id="<train_id>"}`
+ * This event is fired when a train enters the rail. The field `id` is the unique train ID, which is 6-digit random numerical string.
+ * If the world contains trains from an older advtrains version, this string may be longer and contain a dot `.`
+
+ - `{type="int", int=true, msg=<message>}`
+ * Fired when an interrupt set by the `interrupt` function runs out. `<message>` is the message passed to the interrupt function.
+ * For backwards compatiblity reasons, `<message>` is also contained in an `event.message` variable.
+
+ - `{type="ext_int", ext_int=true, message=<message>}`
+ * Fired when another node called `interrupt_pos` on this position. `message` is the message passed to the interrupt_pos function.
+
+ - `{type="digiline", digiline=true, channel=<channel>, msg=<message>}`
+ * Fired when the controller receives a digiline message.
+
+#### Basic Lua Rail Functions and Variables
+In addition to the above environment functions, the following functions are available to whilst the train is in contact with the LuaATC rail:
+
+ - `atc_send(<atc_command>)`
+ Sends the specified ATC command to the train (a string) and returns true. If there is no train, returns false and does nothing. See [atc_command.txt](../atc_command.txt) for the ATC command syntax.
+
+ - `atc_reset()`
+ Resets the train's current ATC command. If there is no train, returns false and does nothing.
+
+ - `atc_arrow`
+ Boolean, true when the train is driving in the direction of the arrows of the ATC rail. Nil if there is no train.
+
+ - `atc_id`
+ Train ID of the train currently passing the controller. Nil if there's no train.
+
+ - `atc_speed`
+ Speed of the train, or nil if there is no train.
+
+ - `atc_set_text_outside(text)`
+ Set text shown on the outside of the train. Pass nil to show no text. `text` must be a string.
+
+ - `atc_set_text_inside(text)`
+ Set text shown to train passengers. Pass nil to show no text. `text` must be a string.
+
+ - `atc_set_text_inside(text) / atc_set_text_outside(text)`
+ Getters for inside/outside text, return nil when no train is there.
+
+ - `get_line()`
+ Returns the "Line" property of the train (a string).
+ This can be used to distinguish between trains of different lines and route them appropriately.
+ The interlocking system also uses this property for Automatic Routesetting.
+
+ - `set_line(line)`
+ Sets the "Line" property of the train (a string).
+ If the first digit of this string is a number (0-9), any subway wagons on the train (from advtrains_train_subway) will have this one displayed as line number
+ (where "0" is actually shown as Line 10 on the train)
+
+ - `get_rc()`
+ Returns the "Routingcode" property of the train (a string).
+ The interlocking system uses this property for Automatic Routesetting.
+
+ - `set_rc(routingcode)`
+ Sets the "Routingcode" property of the train (a string).
+ The interlocking system uses this property for Automatic Routesetting.
+
+#### Shunting Functions and Variables
+There are several functions available especially for shunting operations.
+Some of these functions make use of Freight Codes (FC) set in the Wagon Properties of each wagon and/or locomotive.
+FCs are composed of codes separated by exclamation marks (`!`), for instance `"foo!bar!baz"`.
+Each wagon has a current FC, indicating its next destination.
+
+ - `split_at_index(index, atc_command)`
+ Splits the train at the specified index, into a train with index-1 wagons and a second train starting with the index-th wagon. The `atc_command` specified is sent to the second train after decoupling. `"S0"` or `"B0"` is common to ensure any locomotives in the remaining train don't continue to move.
+
+ `index` must be more than 1 to avoid trying to decouple the very front of a train.
+
+ Example: train has wagons `"foo","foo","foo","bar","bar","bar"`
+ Command: `split_at_index(4,"S0")`
+ Result: first train (continues at previous speed): `"foo","foo","foo"`, second train (slows at S0): `"bar","bar","bar"`
+
+ - `get_fc()`
+ Returns a table with the entire FC list for each wagon in the train.
+ Command: `get_fc()`
+ Result: `{"", "foo!bar", "testing", "fc_1!fc_2!fc_3!?", "hello_world"}`
+
+ - `get_fc_index()`
+ Returns a table with the current FC index for each wagon in the train. Use in conjunction with the result from `get_fc()` to find a the current FC for a wagon.
+ Command: `get_fc_index()`
+ Result: `{1, 1, 1, 2, 1}`
+
+ - `set_fc(fc_list, reset_index)`
+ Overwrites the FC list according to a table `fc_list`. A false or nil entry will leave the wagon unaffected, however all others will be overwritten.
+ Useful for mass-programming freight trains that use FC-shunting instead of walking to each wagon individually. If the new FC entry for a wagon is shorter than the old entry, the index will clip to the last FC in the new entry.
+ If `reset_index` is true, all Current FC values will reset to the first entry in the list, instead of remaining at the current index.
+
+ Example: train has FC lists: `"", "foo!bar", "testing", "fc_1!fc_2!fc_3!?", "hello_world"`
+ Command: `set_fc({"", "foo!turtle", nil, "4tehlulz", false})`
+ Result: `""` `"foo!turtle"` `"testing"` `"4tehlulz"` `"hello_world"`
+
+ - `split_at_fc(atc_command, len)`
+ Splits the train in such a way that all cars with non-empty current FC of the first part of the train have the same FC. The
+ `atc_command` specified is sent to the rear part, as with split_at_index. It returns the fc of the cars of the first part.
+
+ Example : Train has current FCs `"" "" "bar" "foo" "bar"`
+ Command: `split_at_fc(<atc_command>)`
+ Result: `train "" "" "bar"` and `train "foo" "bar"`
+ The function returns `"bar"` in this case.
+
+ The optional argument `len` specifies the maximum length for the
+ first part of the train.
+ Example: Train has current FCs `"foo" "foo" "foo" "foo" "bar" "bar"`
+ Command: `split_at_fc(<atc_command>,3)`
+ Result: `"foo" "foo" "foo"` and `"foo" "bar" "bar"`
+ The function returns `"foo"` in this case.
+
+ - `split_off_locomotive(command, len)`
+ Splits off the locomotives at the front of the train, which are
+ identified by an empty FC. `command` specifies the ATC command to be
+ executed by the rear half of the train. The optional argument `len` specifies the maximum length for the
+ first part of the train as above.
+
+ - `step_fc()`
+ Steps the FCs of all train cars forward, selecting the next
+ code after the `!`. If the end of the string is reached, then the
+ first code is selected, except if the string ends with a question
+ mark (`?`), then the order is reversed.
+
+ - `train_length()`
+ returns the number of cars the train is composed of.
+
+ - `set_autocouple()`
+ Sets the train into autocouple mode. The train will couple to the next train it collides with.
+
+ - `unset_autocouple()`
+ Unsets autocouple mode
+
+Deprecated:
+
+ - `set_shunt()`, `unset_shunt()`
+ deprecated aliases for set_autocouple() and unset_autocouple(), will be removed from a later release.
+
+
+#### Interlocking
+These additional functions are available when advtrains_interlocking is enabled:
+
+ - `atc_set_ars_disable(boolean)`
+ Disables (true) or enables (false) the use of ARS for this train. The train will not trigger ARS (automatic route setting) on signals then.
+
+ Note: If you want to disable ARS from an approach callback, the call to `atc_set_ars_disable(true)` *must* happen during the approach callback, and may not be deferred to an interrupt(). Else the train might trigger an ARS before the interrupt fires.
+
+ - `section_occupancy(section_id)`
+ Returns a table of train ids for the specified section, nil if no section id is provided, false if the section id is invalid, an empty table if the section id is valid but empty of trains.
+
+#### Approach callbacks
+The LuaATC interface provides a way to hook into the approach callback system, which is for example used in the TSR rails (provided by advtrains_interlocking) or the station tracks (provided by advtrains_lines). However, for compatibility reasons, this behavior needs to be explicitly enabled.
+
+Enabling the receiving of approach events works by setting a variable in the local environment of the ATC rail, by inserting the following code:
+
+```lua
+__approach_callback_mode = 1
+-- to receive approach callbacks only in arrow direction
+-- or alternatively
+__approach_callback_mode = 2
+-- to receive approach callbacks in both directions
+```
+
+The following event will be emitted when a train approaches:
+```lua
+{type="approach", approach=true, id="<train_id>"}
+```
+
+Please note these important considerations when using approach callbacks:
+
+ - Approach events might be generated multiple times for the same approaching train. If you are using atc_set_lzb_tsr(), you need to call this function on every run of the approach callback, even if you issued it before for the same train.
+ - A reference to the train is available while executing this event, so that functions such as atc_send() or atc_set_text_outside() can be called. On any consecutive interrupts, that reference will no longer be available until the train enters the track ("train" event)
+ - Unlike all other callbacks, approach callbacks are executed synchronous during the train step. This may cause unexpected side effects when performing certain actions (such as switching turnouts, setting signals/routes) from inside such a callback. I strongly encourage you to only run things that are absolutely necessary at this point in time, and defer anything else to an interrupt(). Be aware that certain things might trigger unexpected behavior.
+
+Operations that are safe to execute in approach callbacks:
+
+ - anything related only to the global environment (setting things in S)
+ - digiline_send()
+ - atc_set_text_*()
+ - atc_set_lzb_tsr() (see below)
+
+In the context of approach callbacks, one more function is available:
+
+ - `atc_set_lzb_tsr(speed)`
+Impose a Temporary Speed Restriction at the location of this rail, making the train pass this rail at the specified speed. (Causes the same behavior as the TSR rail)
+
+#### Timetable Automation
+
+The advtrains_line_automation component adds a few contraptions that should make creating timeable systems easier.
+Part of its functionality is also available in LuaATC:
+
+- `rwt.*`
+All Railway Time functions are included as documented in https://advtrains.de/wiki/doku.php?id=dev:lines:rwt
+
+- `schedule(rw_time, msg)`
+- `schedule_in(rw_dtime, msg)`
+Schedules the following event `{type="schedule", schedule=true, msg=msg}` at (resp. after) the specified railway time (which can be in any format). You can only schedule one event this way. Uses the new lines-internal scheduler.
+
+### Operator panel
+This simple node executes its actions when punched. It can be used to change a switch and update the corresponding signals or similar applications. It can also be connected to by the`digilines` mod.
+
+The event fired is `{type="punch", punch=true}` by default. In case of an interrupt or a digiline message, the events are similar to the ones of the ATC rail.
+
+### Init code
+The initialization code is not a component as such, but rather a part of the whole environment. It can (and should) be used to make definitions that other components can refer to.
+A basic example function to define behavior for trains in stations:
+```lua
+function F.station(station_name)
+ if event.train then
+ atc_send("B0WOL")
+ atc_set_text_inside(station_name)
+ interrupt(10,"depart")
+ end
+ if event.int and event.message="depart" then
+ atc_set_text_inside("") --an empty string clears the displayed text
+ atc_send("OCD1SM")
+ end
+end
+```
+
+The corresponding Lua ATC Rail(s) would then contain the following or similar:
+```lua
+F.station("Main Station")
+```
+
+The init code is run whenever the F table needs to be refilled with data. This is the case on server startup and whenever the init code is changed and you choose to run it.
+The event table of the init code is always `{type="init", init=true}` and can not be anything else.
+Functions are run in the environment of the currently active node, regardless of where they were defined.
+
+### Passive components
+
+All passive components can be interfaced with the `setstate()` and `getstate()` functions (see above).
+Each node below has been mapped to specific "states":
+
+#### Signals
+The red/green light signals `advtrains:signal_on/off` are interfaceable. Others such as `advtrains:retrosignal_on/off` are not. If advtrains_interlocking is enabled, trains will obey the signal if the influence point is set.
+
+ - "green" - Signal shows green light
+ - "red" - Signal shows red light
+
+#### Switches/Turnouts
+All default rail switches are interfaceable, independent of orientation.
+
+ - "cr" The switch is set in the direction that is not straight.
+ - "st" The switch is set in the direction that is straight.
+
+The "Y" and "3-Way" switches have custom states. Looking from the convergence point:
+
+ - "l" The switch is set towards the left.
+ - "c" The switch is set towards the center (3-way only).
+ - "r" The switch is set towards the right.
+
+
+#### Mesecon Switch
+The Mesecon switch can be switched using LuaAutomation. Note that this is not possible on levers or protected mesecon switches, only the unprotected full-node 'Switch' block `mesecons_switch:mesecon_switch_on/off`.
+
+ - "on" - the switch is switched on.
+ - "off" - the switch is switched off.
+
+#### Andrew's Cross
+
+ - "on" - it blinks.
+ - "off" - it does not blink.
+
+#### Passive Component Naming
+You can assign names to passive components using the Passive Component Naming tool.
+Once you set a name for any component, you can reference it by that name in the `getstate()` and `setstate()` functions.
+This way, you don't need to memorize positions.
+
+Example: signal named `"Stn_P1_out"` at `(1,2,3)`
+Use `setstate("Stn_P1_out", "green")` instead of `setstate(POS(1,2,3), "green")`
+
+If `advtrains_interlocking` is enabled, PC-Naming can also be used to name interlocking signals for route setting via the `set_route()` functions.
+**Important**: The "Signal Name" field in the signalling formspec is completely independent from PC-Naming and can't be used to look up the position. You need to explicitly use the PC-Naming tool.
+
diff --git a/advtrains_luaautomation/active_common.lua b/advtrains_luaautomation/active_common.lua
new file mode 100644
index 0000000..074d3b3
--- /dev/null
+++ b/advtrains_luaautomation/active_common.lua
@@ -0,0 +1,206 @@
+local S = atltrans
+
+local ac = {nodes={}}
+
+function ac.load(data)
+ if data then
+ ac.nodes=data.nodes
+ end
+end
+function ac.save()
+ return {nodes = ac.nodes}
+end
+
+function ac.after_place_node(pos, player)
+ local meta=minetest.get_meta(pos)
+ meta:set_string("formspec", ac.getform(pos, meta))
+ meta:set_string("infotext", S("Unconfigured LuaATC component"))
+ local ph=minetest.pos_to_string(pos)
+ --just get first available key!
+ for en,_ in pairs(atlatc.envs) do
+ ac.nodes[ph]={env=en}
+ return
+ end
+end
+function ac.getform(pos, meta_p)
+ local meta = meta_p or minetest.get_meta(pos)
+ local envs_asvalues={}
+
+ local ph=minetest.pos_to_string(pos)
+ local nodetbl = ac.nodes[ph]
+ local env, code, err = nil, "", ""
+ if nodetbl then
+ code=nodetbl.code or ""
+ err=nodetbl.err or ""
+ env=nodetbl.env or ""
+ end
+ local sel = 1
+ for n,_ in pairs(atlatc.envs) do
+ envs_asvalues[#envs_asvalues+1]=minetest.formspec_escape(n)
+ if n==env then
+ sel=#envs_asvalues
+ end
+ end
+ local form = "size["..atlatc.CODE_FORM_SIZE.."]"
+ .."style[code;font=mono]"
+ .."label[0,-0.1;"..S("LuaATC Environment").."]"
+ .."dropdown[0,0.3;3;env;"..table.concat(envs_asvalues, ",")..";"..sel.."]"
+ .."button[5,0.2;2,1;save;"..S("Save").."]"
+ .."button[7,0.2;3,1;cle;"..S("Clear Local Environment").."]"
+ .."textarea[0.3,1.5;"..atlatc.CODE_FORM_SIZE..";code;"..S("Code")..";"..minetest.formspec_escape(code).."]"
+ .."label["..atlatc.CODE_FORM_ERRLABELPOS..";"..err.."]"
+ return form
+end
+
+function ac.after_dig_node(pos, node, player)
+ advtrains.invalidate_all_paths(pos)
+ advtrains.ndb.clear(pos)
+ atlatc.interrupt.clear_ints_at_pos(pos)
+ if advtrains.lines and advtrains.lines.sched then
+ advtrains.lines.sched.discard_all(advtrains.encode_pos(pos))
+ end
+ local ph=minetest.pos_to_string(pos)
+ ac.nodes[ph]=nil
+end
+
+function ac.on_receive_fields(pos, formname, fields, player)
+ if not minetest.check_player_privs(player:get_player_name(), {atlatc=true}) then
+ minetest.chat_send_player(player:get_player_name(), S("You are not allowed to configure this LuaATC component without the @1 privilege.", "atlatc"))
+ return
+ end
+
+ local meta=minetest.get_meta(pos)
+ local ph=minetest.pos_to_string(pos)
+ local nodetbl = ac.nodes[ph] or {}
+ --if fields.quit then return end
+ if fields.env then
+ nodetbl.env=fields.env
+ end
+ if fields.code then
+ nodetbl.code=fields.code
+ end
+ if fields.save then
+ -- reset certain things
+ nodetbl.err=nil
+ if advtrains.lines and advtrains.lines.sched then
+ -- discard all schedules for this node
+ advtrains.lines.sched.discard_all(advtrains.encode_pos(pos))
+ end
+ end
+ if fields.cle then
+ nodetbl.data={}
+ end
+
+ ac.nodes[ph]=nodetbl
+
+ meta:set_string("formspec", ac.getform(pos, meta))
+ if nodetbl.env then
+ meta:set_string("infotext", S("LuaATC component assigned to environment '@1'", nodetbl.env))
+ else
+ meta:set_string("infotext", S("LuaATC component assigned to an invalid environment"))
+ end
+end
+
+function ac.run_in_env(pos, evtdata, customfct_p, ignore_no_code)
+ local ph=minetest.pos_to_string(pos)
+ local nodetbl = ac.nodes[ph]
+ if not nodetbl then
+ atwarn("LuaATC component at",ph,": Data not in memory! Please visit component and click 'Save'!")
+ return
+ end
+
+ local meta
+ if advtrains.is_node_loaded(pos) then
+ meta=minetest.get_meta(pos)
+ end
+
+ if not nodetbl.env or not atlatc.envs[nodetbl.env] then
+ atwarn("LuaATC component at",ph,": Not an existing environment: "..(nodetbl.env or "<nil>"))
+ return false
+ end
+ local env = atlatc.envs[nodetbl.env]
+ if not nodetbl.code or nodetbl.code=="" then
+ if not ignore_no_code then
+ env:log("warning", "LuaATC component at",ph,": No code to run! (insert -- to suppress warning)")
+ end
+ return false
+ end
+
+ local customfct=customfct_p or {}
+ -- add interrupt function
+ customfct.interrupt=function(t, imesg)
+ assertt(t, "number")
+ assert(t >= 0)
+ atlatc.interrupt.add(t, pos, {type="int", int=true, message=imesg, msg=imesg}) --Compatiblity "message" field.
+ end
+ customfct.interrupt_safe=function(t, imesg)
+ assertt(t, "number")
+ assert(t >= 0)
+ if atlatc.interrupt.has_at_pos(pos) then
+ return false
+ end
+ atlatc.interrupt.add(t, pos, {type="int", int=true, message=imesg, msg=imesg}) --Compatiblity "message" field.
+ return true
+ end
+ customfct.clear_interrupts=function()
+ atlatc.interrupt.clear_ints_at_pos(pos)
+ end
+ -- add digiline_send function, if digiline is loaded
+ if minetest.global_exists("digiline") then
+ customfct.digiline_send=function(channel, msg)
+ assertt(channel, "string")
+ if advtrains.is_node_loaded(pos) then
+ digiline:receptor_send(pos, digiline.rules.default, channel, msg)
+ end
+ end
+ end
+ -- add lines scheduler if enabled
+ if advtrains.lines and advtrains.lines.sched then
+ customfct.schedule = function(rwtime, msg)
+ return advtrains.lines.sched.enqueue(rwtime, "atlatc_env", {pos=pos, msg=msg}, advtrains.encode_pos(pos), 1)
+ end
+ customfct.schedule_in = function(rwtime, msg)
+ return advtrains.lines.sched.enqueue_in(rwtime, "atlatc_env", {pos=pos, msg=msg}, advtrains.encode_pos(pos), 1)
+ end
+ end
+
+ local datain=nodetbl.data or {}
+ local succ, dataout = env:execute_code(datain, nodetbl.code, evtdata, customfct)
+ if succ then
+ atlatc.active.nodes[ph].data=atlatc.remove_invalid_data(dataout)
+ else
+ atlatc.active.nodes[ph].err=dataout
+ env:log("error", "LuaATC component at",ph,": LUA Error:",dataout)
+ if meta then
+ meta:set_string("infotext", S("LuaATC component with error: @1", dataout))
+ end
+ --TODO temporary
+ --if customfct.atc_id then
+ -- advtrains.drb_dump(customfct.atc_id)
+ -- error("Debug: LuaATC error hit!")
+ --end
+ end
+ if meta then
+ meta:set_string("formspec", ac.getform(pos, meta))
+ end
+end
+
+function ac.on_digiline_receive(pos, node, channel, msg)
+ atlatc.interrupt.add(0, pos, {type="digiline", digiline=true, channel = channel, msg = msg})
+end
+
+if advtrains.lines and advtrains.lines.sched then
+ advtrains.lines.sched.register_callback("atlatc_env", function(data)
+ -- This adds another interrupt to the atlatc queue... there might be a better way
+ atlatc.interrupt.add(0, data.pos, {type="schedule",schedule=true, msg=data.msg})
+ end)
+end
+
+ac.trackdef_advtrains_defs = {
+ on_train_enter = function(pos, train_id)
+ --do async. Event is fired in train steps
+ atlatc.interrupt.add(0, pos, {type="train", train=true, id=train_id})
+ end,
+}
+
+atlatc.active=ac
diff --git a/advtrains_luaautomation/atc_rail.lua b/advtrains_luaautomation/atc_rail.lua
new file mode 100644
index 0000000..c98f62b
--- /dev/null
+++ b/advtrains_luaautomation/atc_rail.lua
@@ -0,0 +1,291 @@
+-- atc_rail.lua
+-- registers and handles the ATC rail. Active component.
+-- This is the only component that can interface with trains, so train interface goes here too.
+
+--Using subtable
+local r={}
+
+-- Note on appr_internal:
+-- The Approach callback is a special corner case: the train is not on the node, and it is executed synchronized
+-- (in the train step right during LZB traversal). We therefore need access to the train id and the lzbdata table
+function r.fire_event(pos, evtdata, appr_internal)
+
+ local ph=minetest.pos_to_string(pos)
+ local railtbl = atlatc.active.nodes[ph]
+
+ if not railtbl then
+ atwarn("LuaATC interface rail at",ph,": Data not in memory! Please visit position and click 'Save'!")
+ return
+ end
+
+ --prepare ingame API for ATC. Regenerate each time since pos needs to be known
+ --If no train, then return false.
+
+ -- try to get the train from the event data
+ -- This workaround is required because the callback is one step delayed, and a fast train may have already left the node.
+ -- Also used for approach callback
+ local train_id = evtdata._train_id
+ local atc_arrow = evtdata._train_arrow
+ local train, tvel
+
+ if train_id then
+ train=advtrains.trains[train_id]
+ -- speed
+ tvel=train.velocity
+ -- if still no train_id available, try to get the train at my position
+ else
+ train_id=advtrains.get_train_at_pos(pos)
+ if train_id then
+ train=advtrains.trains[train_id]
+ advtrains.train_ensure_init(train_id, train)
+ -- look up atc_arrow
+ local index = advtrains.path_lookup(train, pos)
+ atc_arrow = (train.path_cn[index] == 1)
+ -- speed
+ tvel=train.velocity
+ end
+ end
+
+ local customfct={
+ atc_send = function(cmd)
+ if not train_id then return false end
+ assertt(cmd, "string")
+ advtrains.atc.train_set_command(train, cmd, atc_arrow)
+ return true
+ end,
+ split_at_index = function(index, cmd)
+ if not train_id then return false end
+ assertt(cmd, "string")
+ if type(index) ~= "number" or index < 2 then
+ return false
+ end
+ local new_id = advtrains.split_train_at_index(train, index)
+ if new_id then
+ minetest.after(1,advtrains.atc.train_set_command,advtrains.trains[new_id], cmd, atc_arrow)
+ return new_id
+ end
+ return false
+ end,
+ split_at_fc = function(cmd, len)
+ assertt(cmd, "string")
+ if not train_id then return false end
+ local new_id, fc = advtrains.split_train_at_fc(train, false, len)
+ if new_id then
+ minetest.after(1,advtrains.atc.train_set_command,advtrains.trains[new_id], cmd, atc_arrow)
+ end
+ return (fc or ""), new_id
+ end,
+ split_off_locomotive = function(cmd, len)
+ assertt(cmd, "string")
+ if not train_id then return false end
+ local new_id, fc = advtrains.split_train_at_fc(train, true, len)
+ if new_id then
+ minetest.after(1,advtrains.atc.train_set_command,advtrains.trains[new_id], cmd, atc_arrow)
+ end
+ return (fc or ""), new_id
+ end,
+ train_length = function ()
+ if not train_id then return false end
+ return #train.trainparts
+ end,
+ step_fc = function()
+ if not train_id then return false end
+ advtrains.train_step_fc(train)
+ end,
+ get_fc = function()
+ if not train_id then return end
+ local fc_list = {}
+ for index,wagon_id in ipairs(train.trainparts) do
+ fc_list[index] = table.concat(advtrains.wagons[wagon_id].fc or {},"!")
+ end
+ return fc_list
+ end,
+ get_fc_index = function()
+ if not train_id then return end
+ local fc_index_list = {}
+ for widx, wagon_id in ipars(train.trainparts) do
+ fc_index_list[widx] = advtrains.wagons[wagon_id].fcind or 1
+ end
+ return fc_index_list
+ end,
+ set_fc = function(fc_list,reset_index)
+ assertt(fc_list, "table")
+ if not train_id then return false end
+ -- safety type-check for entered values
+ for _,v in ipairs(fc_list) do
+ if v and type(v) ~= "string" then
+ error("FC entries must be a string")
+ return
+ end
+ end
+ for index,wagon_id in ipairs(train.trainparts) do
+ if fc_list[index] then -- has FC to enter to this wagon
+ local data = advtrains.wagons[wagon_id]
+ if data then -- wagon actually exists
+ --effectively copyied from wagons.lua, allowing for the :split function and reset_index
+ data.fc = fc_list[index]:split("!")
+ if reset_index or not data.fcind then
+ data.fcind = 1
+ elseif data.fcind > #data.fc then
+ data.fcind = #data.fc
+ end
+ end
+ end
+ end
+ end,
+ set_shunt = function()
+ -- enable shunting mode
+ if not train_id then return false end
+ train.is_shunt = true
+ end,
+ unset_shunt = function()
+ if not train_id then return false end
+ train.is_shunt = nil
+ end,
+ set_autocouple = function ()
+ if not train_id then return false end
+ train.autocouple = true
+ end,
+ unset_autocouple = function ()
+ if not train_id then return false end
+ train.autocouple = nil
+ end,
+ set_line = function(line)
+ if type(line)~="string" and type(line)~="number" then
+ return false
+ end
+ train.line = line .. ""
+ minetest.after(0, advtrains.invalidate_path, train_id)
+ return true
+ end,
+ get_line = function()
+ return train.line
+ end,
+ set_rc = function(rc)
+ if type(rc)~="string"then
+ return false
+ end
+ train.routingcode = rc
+ minetest.after(0, advtrains.invalidate_path, train_id)
+ return true
+ end,
+ get_rc = function()
+ return train.routingcode
+ end,
+ atc_reset = function()
+ if not train_id then return false end
+ advtrains.atc.train_reset_command(train)
+ return true
+ end,
+ atc_arrow = atc_arrow,
+ atc_id = train_id,
+ atc_speed = tvel,
+ atc_set_text_outside = function(text)
+ if not train_id then return false end
+ if text then assertt(text, "string") end
+ advtrains.trains[train_id].text_outside=text
+ return true
+ end,
+ atc_set_text_inside = function(text)
+ if not train_id then return false end
+ if text then assertt(text, "string") end
+ advtrains.trains[train_id].text_inside=text
+ return true
+ end,
+ atc_get_text_outside = function()
+ if not train_id then return false end
+ return advtrains.trains[train_id].text_outside
+ end,
+ atc_get_text_inside = function(text)
+ if not train_id then return false end
+ return advtrains.trains[train_id].text_inside
+ end,
+ atc_set_lzb_tsr = function(speed)
+ if not appr_internal then
+ error("atc_set_lzb_tsr() can only be used during 'approach' events!")
+ end
+ assert(tonumber(speed), "Number expected!")
+
+ local index = appr_internal.index
+ advtrains.lzb_add_checkpoint(train, index, speed, nil)
+
+ return true
+ end,
+ }
+ -- interlocking specific
+ if advtrains.interlocking then
+ customfct.atc_set_ars_disable = function(value)
+ advtrains.interlocking.ars_set_disable(train, value)
+ end
+ end
+
+ atlatc.active.run_in_env(pos, evtdata, customfct)
+
+end
+
+advtrains.register_tracks("default", {
+ nodename_prefix="advtrains_luaautomation:dtrack",
+ texture_prefix="advtrains_dtrack_atc",
+ models_prefix="advtrains_dtrack",
+ models_suffix=".b3d",
+ shared_texture="advtrains_dtrack_shared_atc.png",
+ description=atltrans("LuaATC Track"),
+ formats={},
+ get_additional_definiton = function(def, preset, suffix, rotation)
+ return {
+ after_place_node = atlatc.active.after_place_node,
+ after_dig_node = atlatc.active.after_dig_node,
+
+ on_receive_fields = function(pos, ...)
+ atlatc.active.on_receive_fields(pos, ...)
+
+ --set arrowconn (for ATC)
+ local ph=minetest.pos_to_string(pos)
+ local _, conns=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
+ local nodeent = atlatc.active.nodes[ph]
+ if nodeent then
+ nodeent.arrowconn=conns[1].c
+ end
+ end,
+
+ advtrains = {
+ on_train_enter = function(pos, train_id, train, index)
+ --do async. Event is fired in train steps
+ atlatc.interrupt.add(0, pos, {type="train", train=true, id=train_id,
+ _train_id = train_id, _train_arrow = (train.path_cn[index] == 1)})
+ end,
+ on_train_approach = function(pos, train_id, train, index, has_entered, lzbdata)
+ -- Insert an event only if the rail indicated that it supports approach callbacks
+ local ph=minetest.pos_to_string(pos)
+ local railtbl = atlatc.active.nodes[ph]
+ -- uses a "magic variable" in the local environment of the node
+ -- This hack is necessary because code might not be prepared to get approach events...
+ if railtbl and railtbl.data and railtbl.data.__approach_callback_mode then
+ local acm = railtbl.data.__approach_callback_mode
+ local in_arrow = (train.path_cn[index] == 1)
+ if acm==2 or (acm==1 and in_arrow) then
+ local evtdata = {type="approach", approach=true, id=train_id, has_entered = has_entered,
+ _train_id = train_id, _train_arrow = in_arrow} -- reuses code from train_enter
+ -- This event is *required* to run synchronously, because it might set the ars_disable flag on the train and add LZB checkpoints,
+ -- although this is generally discouraged because this happens right in a train step
+ -- At this moment, I am not aware whether this may cause side effects, and I must encourage users not to do expensive calculations here.
+ r.fire_event(pos, evtdata, {train_id = train_id, train = train, index = index, lzbdata = lzbdata})
+ end
+ end
+ end,
+ },
+ luaautomation = {
+ fire_event=r.fire_event
+ },
+ digiline = {
+ receptor = {},
+ effector = {
+ action = atlatc.active.on_digiline_receive
+ },
+ },
+ }
+ end,
+}, advtrains.trackpresets.t_30deg_straightonly)
+
+
+atlatc.rail = r
diff --git a/advtrains_luaautomation/environment.lua b/advtrains_luaautomation/environment.lua
new file mode 100755
index 0000000..a6ed2c7
--- /dev/null
+++ b/advtrains_luaautomation/environment.lua
@@ -0,0 +1,399 @@
+-------------
+-- lua sandboxed environment
+
+-- function to cross out functions and userdata.
+-- modified from dump()
+function atlatc.remove_invalid_data(o, nested)
+ if o==nil then return nil end
+ local valid_dt={["nil"]=true, boolean=true, number=true, string=true}
+ if type(o) ~= "table" then
+ --check valid data type
+ if not valid_dt[type(o)] then
+ return nil
+ end
+ return o
+ end
+ -- Contains table -> true/nil of currently nested tables
+ nested = nested or {}
+ if nested[o] then
+ return nil
+ end
+ nested[o] = true
+ for k, v in pairs(o) do
+ v = atlatc.remove_invalid_data(v, nested)
+ end
+ nested[o] = nil
+ return o
+end
+
+
+local env_proto={
+ load = function(self, envname, data)
+ self.name=envname
+ self.sdata=data.sdata and atlatc.remove_invalid_data(data.sdata) or {}
+ self.fdata={}
+ self.init_code=data.init_code or ""
+ self.subscribers=data.subscribers or {}
+ end,
+ save = function(self)
+ -- throw any function values out of the sdata table
+ self.sdata = atlatc.remove_invalid_data(self.sdata)
+ return {sdata = self.sdata, init_code=self.init_code, subscribers=self.subscribers}
+ end,
+}
+
+--Environment
+--Code modified from mesecons_luacontroller (credit goes to Jeija and mesecons contributors)
+
+local safe_globals = {
+ "assert", "error", "ipairs", "next", "pairs", "select",
+ "tonumber", "tostring", "type", "unpack", "_VERSION"
+}
+
+local function safe_date(f, t)
+ if not f then
+ -- fall back to old behavior
+ return(os.date("*t",os.time()))
+ else
+ --pass parameters
+ return os.date(f,t)
+ end
+end
+
+-- string.rep(str, n) with a high value for n can be used to DoS
+-- the server. Therefore, limit max. length of generated string.
+local function safe_string_rep(str, n)
+ if #str * n > 2000 then
+ debug.sethook() -- Clear hook
+ error("string.rep: string length overflow", 2)
+ end
+
+ return string.rep(str, n)
+end
+
+-- string.find with a pattern can be used to DoS the server.
+-- Therefore, limit string.find to patternless matching.
+-- Note: Disabled security since there are enough security leaks and this would be unneccessary anyway to DoS the server
+local function safe_string_find(...)
+ --if (select(4, ...)) ~= true then
+ -- debug.sethook() -- Clear hook
+ -- error("string.find: 'plain' (fourth parameter) must always be true for security reasons.")
+ --end
+
+ return string.find(...)
+end
+
+local mp=minetest.get_modpath("advtrains_luaautomation")
+
+local static_env = {
+ --core LUA functions
+ string = {
+ byte = string.byte,
+ char = string.char,
+ format = string.format,
+ len = string.len,
+ lower = string.lower,
+ upper = string.upper,
+ rep = safe_string_rep,
+ reverse = string.reverse,
+ sub = string.sub,
+ find = safe_string_find,
+ },
+ math = {
+ abs = math.abs,
+ acos = math.acos,
+ asin = math.asin,
+ atan = math.atan,
+ atan2 = math.atan2,
+ ceil = math.ceil,
+ cos = math.cos,
+ cosh = math.cosh,
+ deg = math.deg,
+ exp = math.exp,
+ floor = math.floor,
+ fmod = math.fmod,
+ frexp = math.frexp,
+ huge = math.huge,
+ ldexp = math.ldexp,
+ log = math.log,
+ log10 = math.log10,
+ max = math.max,
+ min = math.min,
+ modf = math.modf,
+ pi = math.pi,
+ pow = math.pow,
+ rad = math.rad,
+ random = math.random,
+ sin = math.sin,
+ sinh = math.sinh,
+ sqrt = math.sqrt,
+ tan = math.tan,
+ tanh = math.tanh,
+ },
+ table = {
+ concat = table.concat,
+ insert = table.insert,
+ maxn = table.maxn,
+ remove = table.remove,
+ sort = table.sort,
+ },
+ os = {
+ clock = os.clock,
+ difftime = os.difftime,
+ time = os.time,
+ date = safe_date,
+ },
+ POS = function(x,y,z) return {x=x, y=y, z=z} end,
+ getstate = advtrains.getstate,
+ setstate = advtrains.setstate,
+ is_passive = advtrains.is_passive,
+ --interrupts are handled per node, position unknown. (same goes for digilines)
+ --however external interrupts can be set here.
+ interrupt_pos = function(parpos, imesg)
+ local pos=atlatc.pcnaming.resolve_pos(parpos, "interrupt_pos")
+ atlatc.interrupt.add(0, pos, {type="ext_int", ext_int=true, message=imesg})
+ end,
+ train_parts = function(train_id)
+ if not train_id then return false end
+ local train = advtrains.trains[train_id]
+ if not train then return false end
+ return table.copy(train.trainparts or {})
+ end,
+ -- sends an atc command to train regardless of where it is in the world
+ atc_send_to_train = function(train_id, command)
+ assertt(command, "string")
+ local train = advtrains.trains[train_id]
+ if train then
+ advtrains.atc.train_set_command(train, command, true)
+ return true
+ else
+ return false
+ end
+ end,
+ get_slowdown = function()
+ return advtrains.global_slowdown
+ end
+}
+
+-- If interlocking is present, enable route setting functions
+if advtrains.interlocking then
+ local function gen_checks(signal, route_name, noroutesearch)
+ assertt(route_name, "string")
+ local pos = atlatc.pcnaming.resolve_pos(signal)
+ local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos)
+ if not sigd then
+ error("There's no signal at "..minetest.pos_to_string(pos))
+ end
+ local tcbs = advtrains.interlocking.db.get_tcbs(sigd)
+ if not tcbs then
+ error("Inconsistent configuration, no tcbs for signal at "..minetest.pos_to_string(pos))
+ end
+
+ local routeid, route
+ if not noroutesearch then
+ for routeidt, routet in ipairs(tcbs.routes) do
+ if routet.name == route_name then
+ routeid = routeidt
+ route = routet
+ break
+ end
+ end
+ if not route then
+ error("No route called "..route_name.." at "..minetest.pos_to_string(pos))
+ end
+ end
+ return pos, sigd, tcbs, routeid, route
+ end
+
+
+ static_env.can_set_route = function(signal, route_name)
+ local pos, sigd, tcbs, routeid, route = gen_checks(signal, route_name)
+ -- if route is already set on signal, return whether it's committed
+ if tcbs.routeset == routeid then
+ return tcbs.route_committed
+ end
+ -- actually try setting route (parameter 'true' designates try-run
+ local ok = advtrains.interlocking.route.set_route(sigd, route, true)
+ return ok
+ end
+ static_env.set_route = function(signal, route_name)
+ local pos, sigd, tcbs, routeid, route = gen_checks(signal, route_name)
+ return advtrains.interlocking.route.update_route(sigd, tcbs, routeid)
+ end
+ static_env.cancel_route = function(signal)
+ local pos, sigd, tcbs, routeid, route = gen_checks(signal, "", true)
+ return advtrains.interlocking.route.update_route(sigd, tcbs, nil, true)
+ end
+ static_env.get_aspect = function(signal)
+ local pos = atlatc.pcnaming.resolve_pos(signal)
+ return advtrains.interlocking.signal.get_aspect_info(pos)
+ end
+ static_env.set_aspect = function(signal, main_asp, rem_signal)
+ if type(main_asp) == "table" then
+ error("set_aspect: Parameters of this method have changed to (signal, main_asp, rem_signal) with introduction of distant signalling: parameter 2 is now the main aspect name (a string)")
+ end
+ local pos = atlatc.pcnaming.resolve_pos(signal)
+ local rem_pos = rem_signal and atlatc.pcnaming.resolve_pos(rem_signal)
+ return advtrains.interlocking.signal_set_aspect(pos, main_asp, rem_pos)
+ end
+
+ --section_occupancy()
+ static_env.section_occupancy = function(ts_id)
+ if not ts_id then return nil end
+ ts_id = tostring(ts_id)
+ local response = advtrains.interlocking.db.get_ts(ts_id)
+ if not response then return false end
+ return (response.trains and table.copy(response.trains)) or {}
+ end
+end
+
+-- Lines-specific:
+if advtrains.lines then
+ local atlrwt = advtrains.lines.rwt
+ static_env.rwt = {
+ now = atlrwt.now,
+ new = atlrwt.new,
+ copy = atlrwt.copy,
+ to_table = atlrwt.to_table,
+ to_secs = atlrwt.to_secs,
+ to_string = atlrwt.to_string,
+ add = atlrwt.add,
+ diff = atlrwt.diff,
+ sub = atlrwt.sub,
+ adj_diff = atlrwt.adj_diff,
+ adjust_cycle = atlrwt.adjust_cycle,
+ adjust = atlrwt.adjust,
+ to_string = atlrwt.to_string,
+ get_time_until = atlrwt.get_time_until,
+ next_rpt = atlrwt.next_rpt,
+ last_rpt = atlrwt.last_rpt,
+ time_from_last_rpt = atlrwt.time_from_last_rpt,
+ time_to_next_rpt = atlrwt.time_to_next_rpt,
+ }
+end
+
+
+atlatc.register_function = function (name, f)
+ static_env[name] = f
+end
+
+for _, name in pairs(safe_globals) do
+ static_env[name] = _G[name]
+end
+
+--The environment all code calls get is a table that has set static_env as metatable.
+--In general, every variable is local to a single code chunk, but kept persistent over code re-runs. Data is also saved, but functions and userdata and circular references are removed
+--Init code and step code's environments are not saved
+-- S - Table that can contain any save data global to the environment. Will be saved statically. Can't contain functions or userdata or circular references.
+-- F - Table global to the environment, can contain volatile data that is deleted when server quits.
+-- The init code should populate this table with functions and other definitions.
+
+local proxy_env={}
+--proxy_env gets a new metatable in every run, but is the shared environment of all functions ever defined.
+
+-- returns: true, fenv if successful; nil, error if error
+function env_proto:execute_code(localenv, code, evtdata, customfct)
+ -- create us a print function specific for this environment
+ if not self.safe_print_func then
+ local myenv = self
+ self.safe_print_func = function(...)
+ myenv:log("info", ...)
+ end
+ end
+
+ local metatbl ={
+ __index = function(t, i)
+ if i=="S" then
+ return self.sdata
+ elseif i=="F" then
+ return self.fdata
+ elseif i=="event" then
+ return evtdata
+ elseif customfct and customfct[i] then
+ return customfct[i]
+ elseif localenv and localenv[i] then
+ return localenv[i]
+ elseif i=="print" then
+ return self.safe_print_func
+ end
+ return static_env[i]
+ end,
+ __newindex = function(t, i, v)
+ if i=="S" or i=="F" or i=="event" or (customfct and customfct[i]) or static_env[i] then
+ debug.sethook()
+ error("Trying to overwrite environment contents")
+ end
+ localenv[i]=v
+ end,
+ }
+ setmetatable(proxy_env, metatbl)
+ local fun, err=loadstring(code)
+ if not fun then
+ return false, err
+ end
+
+ setfenv(fun, proxy_env)
+ local succ, data = pcall(fun)
+ if succ then
+ data=localenv
+ end
+ return succ, data
+end
+
+function env_proto:run_initcode()
+ if self.init_code and self.init_code~="" then
+ local old_fdata=self.fdata
+ self.fdata = {}
+ --atprint("[atlatc]Running initialization code for environment '"..self.name.."'")
+ local succ, err = self:execute_code({}, self.init_code, {type="init", init=true})
+ if not succ then
+ self:log("error", "Executing InitCode for '"..self.name.."' failed:"..err)
+ self.init_err=err
+ if old_fdata then
+ self.fdata=old_fdata
+ self:log("warning", "The 'F' table has been restored to the previous state.")
+ end
+ end
+ end
+end
+
+-- log to environment subscribers. severity can be "error", "warning" or "info" (used by internal print)
+function env_proto:log(severity, ...)
+ local text=advtrains.print_concat_table({"[atlatc "..self.name.." "..severity.."]", ...})
+ minetest.log("action", text)
+ for _, pname in ipairs(self.subscribers) do
+ minetest.chat_send_player(pname, text)
+ end
+end
+
+-- env.subscribers table may be directly altered by callers.
+
+
+--- class interface
+
+function atlatc.env_new(name)
+ local newenv={
+ name=name,
+ init_code="",
+ sdata={},
+ subscribers={},
+ }
+ setmetatable(newenv, {__index=env_proto})
+ return newenv
+end
+function atlatc.env_load(name, data)
+ local newenv={}
+ setmetatable(newenv, {__index=env_proto})
+ newenv:load(name, data)
+ return newenv
+end
+
+function atlatc.run_initcode()
+ for envname, env in pairs(atlatc.envs) do
+ env:run_initcode()
+ end
+end
+
+
+
+
diff --git a/advtrains_luaautomation/init.lua b/advtrains_luaautomation/init.lua
new file mode 100644
index 0000000..a2f4eb9
--- /dev/null
+++ b/advtrains_luaautomation/init.lua
@@ -0,0 +1,120 @@
+-- advtrains_luaautomation/init.lua
+-- Lua automation features for advtrains
+-- Uses global table 'atlatc' (AdvTrains_LuaATC)
+
+atltrans = attrans
+local S = atltrans
+
+--Privilege
+--Only trusted players should be enabled to build stuff which can break the server.
+
+atlatc = { envs = {}}
+
+minetest.register_privilege("atlatc", { description = S("Can place and configure LuaATC components, including execute potentially harmful Lua code"), give_to_singleplayer = false, default= false })
+
+--Size of code input forms in X,Y notation. Must be at least 10x10
+atlatc.CODE_FORM_SIZE = "15,12"
+--Position of Error Label in Code Form
+atlatc.CODE_FORM_ERRLABELPOS = "0,12"
+
+--assertt helper. error if a variable is not of a type
+function assertt(var, typ)
+ if type(var)~=typ then
+ error("Assertion failed, variable has to be of type "..typ)
+ end
+end
+
+local mp=minetest.get_modpath("advtrains_luaautomation")
+if not mp then
+ error("Mod name error: Mod folder is not named 'advtrains_luaautomation'!")
+end
+dofile(mp.."/environment.lua")
+dofile(mp.."/interrupt.lua")
+dofile(mp.."/active_common.lua")
+dofile(mp.."/atc_rail.lua")
+dofile(mp.."/operation_panel.lua")
+if mesecon then
+ dofile(mp.."/mesecon_controller.lua")
+end
+dofile(mp.."/pcnaming.lua")
+
+dofile(mp.."/chatcmds.lua")
+
+if minetest.settings:get_bool("advtrains_luaautomation_enable_atlac_recipes",false) == true then
+ dofile(mp.."/recipes.lua")
+end
+
+local filename=minetest.get_worldpath().."/advtrains_luaautomation"
+
+function atlatc.load(tbl)
+ if tbl.version==1 then
+ for envname, data in pairs(tbl.envs) do
+ atlatc.envs[envname]=atlatc.env_load(envname, data)
+ end
+ atlatc.active.load(tbl.active)
+ atlatc.interrupt.load(tbl.interrupt)
+ atlatc.pcnaming.load(tbl.pcnaming)
+ end
+ -- run init code of all environments
+ atlatc.run_initcode()
+end
+
+function atlatc.load_pre_v4()
+ minetest.log("action", "[atlatc] Loading pre-v4 save file")
+ local file, err = io.open(filename, "r")
+ if not file then
+ minetest.log("warning", " Failed to read advtrains_luaautomation save data from file "..filename..": "..(err or "Unknown Error"))
+ minetest.log("warning", " (this is normal when first enabling advtrains on this world)")
+ else
+ atprint("luaautomation reading file:",filename)
+ local tbl = minetest.deserialize(file:read("*a"))
+ if type(tbl) == "table" then
+ if tbl.version==1 then
+ for envname, data in pairs(tbl.envs) do
+ atlatc.envs[envname]=atlatc.env_load(envname, data)
+ end
+ atlatc.active.load(tbl.active)
+ atlatc.interrupt.load(tbl.interrupt)
+ atlatc.pcnaming.load(tbl.pcnaming)
+ end
+ else
+ minetest.log("error", " Failed to read advtrains_luaautomation save data from file "..filename..": Not a table!")
+ end
+ file:close()
+ end
+ -- run init code of all environments
+ atlatc.run_initcode()
+end
+
+
+atlatc.save = function()
+ --versions:
+ -- 1 - Initial save format.
+
+ local envdata={}
+ for envname, env in pairs(atlatc.envs) do
+ envdata[envname]=env:save()
+ end
+ local save_tbl={
+ version = 1,
+ envs=envdata,
+ active = atlatc.active.save(),
+ interrupt = atlatc.interrupt.save(),
+ pcnaming = atlatc.pcnaming.save(),
+ }
+
+ return save_tbl
+end
+
+--[[
+-- globalstep for step code
+local timer, step_int=0, 2
+
+function atlatc.mainloop_stepcode(dtime)
+ timer=timer+dtime
+ if timer>step_int then
+ timer=0
+ atlatc.run_stepcode()
+ end
+end
+]]
diff --git a/advtrains_luaautomation/mesecon_controller.lua b/advtrains_luaautomation/mesecon_controller.lua
new file mode 100644
index 0000000..6981839
--- /dev/null
+++ b/advtrains_luaautomation/mesecon_controller.lua
@@ -0,0 +1,260 @@
+-- mesecon_controller.lua
+-- Mesecon-interfaceable Operation Panel alternative
+-- Looks like a Mesecon Luacontroller
+
+-- Luacontroller Adapted Code
+-- From Mesecons mod https://mesecons.net/
+-- (c) Jeija and Contributors
+
+local S = atltrans
+local BASENAME = "advtrains_luaautomation:mesecon_controller"
+
+local rules = {
+ a = {x = -1, y = 0, z = 0, name="A"},
+ b = {x = 0, y = 0, z = 1, name="B"},
+ c = {x = 1, y = 0, z = 0, name="C"},
+ d = {x = 0, y = 0, z = -1, name="D"},
+}
+
+local function generate_name(ports)
+ local d = ports.d and 1 or 0
+ local c = ports.c and 1 or 0
+ local b = ports.b and 1 or 0
+ local a = ports.a and 1 or 0
+ return BASENAME..d..c..b..a
+end
+
+
+local function set_port(pos, rule, state)
+ if state then
+ mesecon.receptor_on(pos, {rule})
+ else
+ mesecon.receptor_off(pos, {rule})
+ end
+end
+
+local function clean_port_states(ports)
+ ports.a = ports.a and true or false
+ ports.b = ports.b and true or false
+ ports.c = ports.c and true or false
+ ports.d = ports.d and true or false
+end
+
+-- Local table for storing which Mesecons off events should be ignored
+-- Indexed by hex encoded position
+local ignored_off_events = {}
+
+local function set_port_states(pos, ports)
+ local node = advtrains.ndb.get_node(pos)
+ local name = node.name
+ clean_port_states(ports)
+ local vports = minetest.registered_nodes[name].virtual_portstates
+ local new_name = generate_name(ports)
+
+ if name ~= new_name and vports then
+ -- Problem:
+ -- We need to place the new node first so that when turning
+ -- off some port, it won't stay on because the rules indicate
+ -- there is an onstate output port there.
+ -- When turning the output off then, it will however cause feedback
+ -- so that the luacontroller will receive an "off" event by turning
+ -- its output off.
+ -- Solution / Workaround:
+ -- Remember which output was turned off and ignore next "off" event.
+ local ph=minetest.pos_to_string(pos)
+ local railtbl = atlatc.active.nodes[ph]
+ if not railtbl then return end
+
+ local ign = railtbl.ignored_off_events or {}
+ if ports.a and not vports.a and not mesecon.is_powered(pos, rules.a) then ign.A = true end
+ if ports.b and not vports.b and not mesecon.is_powered(pos, rules.b) then ign.B = true end
+ if ports.c and not vports.c and not mesecon.is_powered(pos, rules.c) then ign.C = true end
+ if ports.d and not vports.d and not mesecon.is_powered(pos, rules.d) then ign.D = true end
+ railtbl.ignored_off_events = ign
+
+ advtrains.ndb.swap_node(pos, {name = new_name, param2 = node.param2})
+
+ -- Apply mesecon state only if node loaded
+ -- If node is not loaded, mesecon update will occur on next load via on_updated_from_nodedb
+ if advtrains.is_node_loaded(pos) then
+ if ports.a ~= vports.a then set_port(pos, rules.a, ports.a) end
+ if ports.b ~= vports.b then set_port(pos, rules.b, ports.b) end
+ if ports.c ~= vports.c then set_port(pos, rules.c, ports.c) end
+ if ports.d ~= vports.d then set_port(pos, rules.d, ports.d) end
+ end
+ end
+end
+
+local function on_updated_from_nodedb(pos, newnode, oldnode)
+ -- Switch appropriate Mesecon receptors depending on the node change
+ local vports = minetest.registered_nodes[oldnode.name].virtual_portstates
+ local ports = minetest.registered_nodes[newnode.name].virtual_portstates
+ if ports.a ~= vports.a then set_port(pos, rules.a, ports.a) end
+ if ports.b ~= vports.b then set_port(pos, rules.b, ports.b) end
+ if ports.c ~= vports.c then set_port(pos, rules.c, ports.c) end
+ if ports.d ~= vports.d then set_port(pos, rules.d, ports.d) end
+end
+
+local function ignore_offevent(pos, rule)
+ local ph=minetest.pos_to_string(pos)
+ local railtbl = atlatc.active.nodes[ph]
+ if not railtbl then return nil end
+ local ign = railtbl.ignored_off_events
+ if ign and ign[rule.name] then
+ ign[rule.name] = nil
+ return true
+ end
+ return false
+end
+
+local valid_ports = {a=true, b=true, c=true, d=true}
+
+local function fire_event(pos, evtdata)
+ local customfct={
+ set_mesecon_outputs = function(states)
+ assertt(states, "table")
+ set_port_states(pos, states)
+ end,
+ get_mesecon_input = function(port)
+ local portl = string.lower(port)
+ if not valid_ports[portl] then
+ error("get_mesecon_input: Invalid port (expected a,b,c,d)")
+ end
+ if mesecon.is_powered(pos, rules[portl]) then
+ return true
+ end
+ return false
+ end,
+ }
+ atlatc.active.run_in_env(pos, evtdata, customfct, true)
+
+end
+
+local output_rules = {}
+local input_rules = {}
+
+local node_box = {
+ type = "fixed",
+ fixed = {
+ {-8/16, -8/16, -8/16, 8/16, -7/16, 8/16}, -- Bottom slab
+ {-5/16, -7/16, -5/16, 5/16, -6/16, 5/16}, -- Circuit board
+ {-3/16, -6/16, -3/16, 3/16, -5/16, 3/16}, -- IC
+ }
+}
+
+local selection_box = {
+ type = "fixed",
+ fixed = { -8/16, -8/16, -8/16, 8/16, -5/16, 8/16 },
+}
+
+for a = 0, 1 do -- 0 = off 1 = on
+for b = 0, 1 do
+for c = 0, 1 do
+for d = 0, 1 do
+ local cid = tostring(d)..tostring(c)..tostring(b)..tostring(a)
+ local node_name = BASENAME..cid
+ local top = "atlatc_luacontroller_top.png"
+ if a == 1 then
+ top = top.."^atlatc_luacontroller_LED_A.png"
+ end
+ if b == 1 then
+ top = top.."^atlatc_luacontroller_LED_B.png"
+ end
+ if c == 1 then
+ top = top.."^atlatc_luacontroller_LED_C.png"
+ end
+ if d == 1 then
+ top = top.."^atlatc_luacontroller_LED_D.png"
+ end
+
+ local groups
+ if a + b + c + d ~= 0 then
+ groups = {dig_immediate=2, not_in_creative_inventory=1, save_in_at_nodedb=1}
+ else
+ groups = {dig_immediate=2, save_in_at_nodedb=1}
+ end
+
+ output_rules[cid] = {}
+ input_rules[cid] = {}
+ if a == 1 then table.insert(output_rules[cid], rules.a) end
+ if b == 1 then table.insert(output_rules[cid], rules.b) end
+ if c == 1 then table.insert(output_rules[cid], rules.c) end
+ if d == 1 then table.insert(output_rules[cid], rules.d) end
+
+ if a == 0 then table.insert( input_rules[cid], rules.a) end
+ if b == 0 then table.insert( input_rules[cid], rules.b) end
+ if c == 0 then table.insert( input_rules[cid], rules.c) end
+ if d == 0 then table.insert( input_rules[cid], rules.d) end
+
+ local mesecons = {
+ effector = {
+ rules = input_rules[cid],
+ action_change = function (pos, _, rule_name, new_state)
+ if new_state == "off" then
+ -- check for ignored off event on this node
+ if ignore_offevent(pos, rule_name) then
+ return
+ end
+ end
+ --Note: rule_name is not a *name* but actually the full rule table (position + name field)
+ --Event format consistent with Mesecons Luacontroller event
+ atlatc.interrupt.add(0, pos, {type=new_state, [new_state]=true, pin=rule_name})
+ end,
+ },
+ receptor = {
+ state = mesecon.state.on,
+ rules = output_rules[cid]
+ },
+ }
+
+ minetest.register_node(node_name, {
+ description = S("LuaATC Mesecon Controller"),
+ drawtype = "nodebox",
+ tiles = {
+ top,
+ "atlatc_luacontroller_bottom.png",
+ "atlatc_luacontroller_sides.png",
+ "atlatc_luacontroller_sides.png",
+ "atlatc_luacontroller_sides.png",
+ "atlatc_luacontroller_sides.png"
+ },
+ inventory_image = top,
+ paramtype = "light",
+ is_ground_content = false,
+ groups = groups,
+ drop = BASENAME.."0000",
+ sunlight_propagates = true,
+ selection_box = selection_box,
+ node_box = node_box,
+ mesecons = mesecons,
+ -- Virtual portstates are the ports that
+ -- the node shows as powered up (light up).
+ virtual_portstates = {
+ a = a == 1,
+ b = b == 1,
+ c = c == 1,
+ d = d == 1,
+ },
+ after_dig_node = function (pos, node, player)
+ mesecon.receptor_off(pos, output_rules)
+ atlatc.active.after_dig_node(pos, node, player)
+ end,
+ after_place_node = atlatc.active.after_place_node,
+ on_receive_fields = atlatc.active.on_receive_fields,
+ advtrains = {
+ on_updated_from_nodedb = on_updated_from_nodedb
+ },
+ luaautomation = {
+ fire_event=fire_event
+ },
+ digiline = {
+ receptor = {},
+ effector = {
+ action = atlatc.active.on_digiline_receive
+ },
+ },
+ })
+end
+end
+end
+end
diff --git a/advtrains_luaautomation/operation_panel.lua b/advtrains_luaautomation/operation_panel.lua
new file mode 100644
index 0000000..8e12651
--- /dev/null
+++ b/advtrains_luaautomation/operation_panel.lua
@@ -0,0 +1,29 @@
+local S = atltrans
+
+local function on_punch(pos,node,player)
+ atlatc.interrupt.add(0, pos, {type="punch", punch=true, name=player:get_player_name()})
+end
+
+
+minetest.register_node("advtrains_luaautomation:oppanel", {
+ drawtype = "normal",
+ tiles={"atlatc_oppanel.png"},
+ description = S("LuaATC Operation Panel"),
+ groups = {
+ cracky = 1,
+ save_in_at_nodedb=1,
+ },
+ after_place_node = atlatc.active.after_place_node,
+ after_dig_node = atlatc.active.after_dig_node,
+ on_receive_fields = atlatc.active.on_receive_fields,
+ on_punch = on_punch,
+ luaautomation = {
+ fire_event=atlatc.active.run_in_env
+ },
+ digiline = {
+ receptor = {},
+ effector = {
+ action = atlatc.active.on_digiline_receive
+ },
+ },
+})
diff --git a/advtrains_luaautomation/pcnaming.lua b/advtrains_luaautomation/pcnaming.lua
new file mode 100644
index 0000000..ba8048d
--- /dev/null
+++ b/advtrains_luaautomation/pcnaming.lua
@@ -0,0 +1,93 @@
+--pcnaming.lua
+--a.k.a Passive component naming
+--Allows to assign names to passive components, so they can be called like:
+--setstate("iamasignal", "green")
+local S = atltrans
+
+atlatc.pcnaming={name_map={}}
+function atlatc.pcnaming.load(stuff)
+ if type(stuff)=="table" then
+ atlatc.pcnaming.name_map=stuff
+ end
+end
+function atlatc.pcnaming.save()
+ return atlatc.pcnaming.name_map
+end
+
+function atlatc.pcnaming.resolve_pos(pos, func_name)
+ if type(pos)=="string" then
+ local e = atlatc.pcnaming.name_map[pos]
+ if e then return e end
+ elseif type(pos)=="table" and pos.x and pos.y and pos.z then
+ return pos
+ end
+ error("Invalid position supplied to " .. (func_name or "???")..": " .. dump(pos))
+end
+
+
+local pcrename = {}
+
+minetest.register_craftitem("advtrains_luaautomation:pcnaming",{
+ description = S("Passive Component Naming Tool\n\nRight-click to name a passive component."),
+ groups = {cracky=1}, -- key=name, value=rating; rating=1..3.
+ inventory_image = "atlatc_pcnaming.png",
+ wield_image = "atlatc_pcnaming.png",
+ stack_max = 1,
+ on_place = function(itemstack, placer, pointed_thing)
+ local pname = placer:get_player_name()
+ if not pname then
+ return
+ end
+ if not minetest.check_player_privs(pname, {atlatc=true}) then
+ minetest.chat_send_player(pname, S("You are not allowed to name LuaATC passive components without the @1 privilege.", "atlatc"))
+ return
+ end
+ if pointed_thing.type=="node" then
+ local pos=pointed_thing.under
+ if advtrains.is_protected(pos, pname) then
+ minetest.record_protection_violation(pos, pname)
+ return
+ end
+
+ local node = advtrains.ndb.get_node(pos)
+ local ndef = minetest.registered_nodes[node.name]
+ if node.name and (
+ minetest.get_item_group(node.name, "advtrains_signal")>0 --is IL signal
+ or advtrains.is_passive(pos) -- is passive component
+ or (ndef and ndef.luaautomation) -- is active component
+ ) then
+ --look if this one already has a name
+ local pn=""
+ for name, npos in pairs(atlatc.pcnaming.name_map) do
+ if vector.equals(npos, pos) then
+ pn=name
+ end
+ end
+ pcrename[pname] = pos
+ minetest.show_formspec(pname, "atlatc_naming", "field[pn;"..S("Set name of component (empty to clear)")..";"..minetest.formspec_escape(pn).."]")
+ end
+ end
+ end,
+})
+minetest.register_on_player_receive_fields(function(player, formname, fields)
+ if formname == "atlatc_naming" then
+ local pname = player:get_player_name()
+ local pos=pcrename[pname]
+ if fields.pn and pos then
+ --first remove all occurences
+ for name, npos in pairs(atlatc.pcnaming.name_map) do
+ if vector.equals(npos, pos) then
+ atlatc.pcnaming.name_map[name]=nil
+ end
+ end
+ if fields.pn~="" then
+ atlatc.pcnaming.name_map[fields.pn]=pos
+ end
+ end
+ end
+end)
+minetest.register_craft({
+ output = "advtrains_luaautomation:pcnaming",
+ type = "shapeless",
+ recipe = {"dye:red","advtrains:trackworker"}
+}) \ No newline at end of file
diff --git a/advtrains_luaautomation/recipes.lua b/advtrains_luaautomation/recipes.lua
new file mode 100644
index 0000000..16121a8
--- /dev/null
+++ b/advtrains_luaautomation/recipes.lua
@@ -0,0 +1,27 @@
+-- depends on default, digilines and mesecons for crafting recipes
+minetest.register_craft({
+ output = "advtrains_luaautomation:dtrack_placer",
+ recipe = {
+ {"","mesecons_luacontroller:luacontroller0000",""},
+ {"","advtrains:dtrack_atc_placer",""},
+ {"","digilines:wire_std_00000000",""},
+ }
+})
+
+minetest.register_craft({
+ output = "advtrains_luaautomation:mesecon_controller0000",
+ recipe = {
+ {"","mesecons:wire_00000000_off",""},
+ {"mesecons:wire_00000000_off","advtrains_luaautomation:dtrack_placer","mesecons:wire_00000000_off"},
+ {"","mesecons:wire_00000000_off",""},
+ }
+})
+
+minetest.register_craft({
+ output = "advtrains_luaautomation:oppanel",
+ recipe = {
+ {"","mesecons_button:button_off",""},
+ {"","advtrains_luaautomation:mesecon_controller0000",""},
+ {"","default:stone",""},
+ }
+}) \ No newline at end of file
diff --git a/advtrains_luaautomation/settingtypes.txt b/advtrains_luaautomation/settingtypes.txt
new file mode 100644
index 0000000..20ed52e
--- /dev/null
+++ b/advtrains_luaautomation/settingtypes.txt
@@ -0,0 +1,2 @@
+# Enable or disable craft recipes for LuaATC components
+advtrains_luaautomation_enable_atlac_recipes (Enable LuaATC component craft recipes) bool true \ No newline at end of file
diff --git a/advtrains_signals_japan/.gitignore b/advtrains_signals_japan/.gitignore
new file mode 100644
index 0000000..0969b6b
--- /dev/null
+++ b/advtrains_signals_japan/.gitignore
@@ -0,0 +1 @@
+models/*
diff --git a/advtrains_signals_japan/init.lua b/advtrains_signals_japan/init.lua
new file mode 100644
index 0000000..728a91f
--- /dev/null
+++ b/advtrains_signals_japan/init.lua
@@ -0,0 +1,474 @@
+local pole_texture = "advtrains_signals_japan_mast.png"
+local signal_face_texture = "advtrains_hud_bg.png^[colorize:#000000:255"
+local pole_radius = 1/16
+local pole_box = {-pole_radius,-1/2,-pole_radius,pole_radius,1/2,pole_radius}
+local light_radius = 1/20
+local signal_width = 6*light_radius
+local signal_thickness = pole_radius*3
+local signal_height = {}
+local signal_box = {}
+local light_red = "advtrains_hud_bg.png^[colorize:red:255"
+local light_yellow = "advtrains_hud_bg.png^[colorize:orange:255"
+local light_green = "advtrains_hud_bg.png^[colorize:lime:255"
+local light_purple = "advtrains_hud_bg.png^[colorize:purple:255"
+local light_distant = light_purple
+local light_off = signal_face_texture
+
+do
+ local model_dir = core.get_modpath("advtrains_signals_japan") .. DIR_DELIM .. "models"
+ local function add_model(name, content)
+ local fn = "advtrains_signals_japan_" .. name
+ if core.features.dynamic_add_media_startup then
+ core.dynamic_add_media {
+ filename = fn,
+ filedata = content,
+ }
+ else
+ core.mkdir(model_dir)
+ core.safe_file_write(model_dir .. DIR_DELIM .. fn, content)
+ end
+ end
+ local model_path_prefix = table.concat({minetest.get_modpath("advtrains_signals_japan"), "models", "advtrains_signals_japan_"}, DIR_DELIM)
+
+ local function vertex(x, y, z)
+ return string.format("v %f %f %f", x, y, z)
+ end
+ local function texture(u, v)
+ return string.format("vt %f %f", u, v)
+ end
+ local function face_element(v, vt)
+ if vt then
+ return string.format("%d/%d", v, vt)
+ end
+ return tonumber(v)
+ end
+ local function face_elements(...)
+ local st = {"f"}
+ local args = {...}
+ local len = #args
+ for i = 1, len, 2 do
+ st[(i+3)/2] = face_element(args[i], args[i+1])
+ end
+ return table.concat(st, " ")
+ end
+ local function sequential_elements(v0, vt0, count)
+ local st = {}
+ for i = 1, count do
+ st[i] = face_element(v0+i, vt0+i)
+ end
+ return table.concat(st, " ")
+ end
+ local function mod_lower(min, a, b)
+ return min + (a-min)%b
+ end
+ local function connect_circular(v0, vt0, count)
+ return "f " .. sequential_elements(v0, vt0, count)
+ end
+ local function connect_cylindrical(v0, vt0, count)
+ local st = {}
+ for i = 0, count-1 do
+ local j = (i+1)%count
+ local v1 = v0+i+1
+ local v2 = v1+count
+ local v3 = v0+j+1
+ local v4 = v3+count
+ local vt1 = vt0+i+1
+ local vt2 = vt1+count+1
+ st[i+1] = face_elements(v1, vt1, v3, vt1+1, v4, vt2+1, v2, vt2)
+ end
+ return table.concat(st, "\n")
+ end
+ local function circular_textures(u0, v0, r, count, total, angular_offset, direction)
+ local st = {}
+ if not angular_offset then
+ angular_offset = 0
+ end
+ if not total then
+ total = count
+ end
+ if not direction then
+ direction = 1
+ end
+ for i = 0, count-1 do
+ local theta = angular_offset + direction*i/total*2*math.pi
+ local u, v = r*math.cos(theta), r*math.sin(theta)
+ st[i+1] = texture(u0+u, v0+v)
+ end
+ return table.concat(st, "\n")
+ end
+ local function rectangular_textures(u0, v0, u1, v1, count)
+ local st = {}
+ local width = u1-u0
+ for i = 0, count do
+ local u = u0+i/count*width
+ st[i+1] = texture(u, v0)
+ st[i+count+2] = texture(u, v1)
+ end
+ return table.concat(st, "\n")
+ end
+
+ -- generate pole model
+ local pole_npolygon = 32
+ local pole_vertex_count = pole_npolygon*2
+ local pole_uv_count = pole_npolygon*3+2
+ local pole_vertices = {}
+ local pole_objdef = {
+ "g pole",
+ "usemtl pole",
+ connect_circular(0, 0, pole_npolygon),
+ connect_circular(pole_npolygon, 0, pole_npolygon),
+ connect_cylindrical(0, pole_npolygon, pole_npolygon),
+ }
+ local pole_uv = {
+ circular_textures(0.5, 0.5, 0.5, pole_npolygon),
+ rectangular_textures(0, 0, 1, 1, pole_npolygon),
+ }
+ for i = 0, pole_npolygon-1 do
+ local theta = i*2/pole_npolygon*math.pi
+ local r = pole_radius
+ local x, z = r*math.sin(theta), r*math.cos(theta)
+ local lower_index = i+1
+ local upper_index = lower_index+pole_npolygon
+ pole_vertices[lower_index] = vertex(x, -0.5, z)
+ pole_vertices[upper_index] = vertex(x, 0.5, z)
+ end
+ pole_vertices = table.concat(pole_vertices, "\n")
+ pole_objdef = table.concat(pole_objdef, "\n")
+ pole_uv = table.concat(pole_uv, "\n")
+ add_model("pole.obj", table.concat({pole_vertices, pole_uv, pole_objdef}, "\n"))
+
+ -- generate signals
+ for lightcount = 5, 6 do
+ for rotname, rot in pairs {["0"] = 0, ["30"] = 26.5, ["45"] = 45, ["60"] = 63.5} do
+ local rot = math.rad(rot)
+ local lightradius = 0.05
+ local lightspacing = 0.04
+ local halfwidth = signal_width/2
+ local halfheight = (2+lightcount)*lightradius+(lightcount-1)*lightspacing/2
+ local halfthickness = signal_thickness/2
+ local half_npolygon = pole_npolygon/2
+ local quarter_npolygon = pole_npolygon/4
+ local boxside = math.max(halfwidth, halfthickness*2)
+ signal_height[lightcount] = halfheight*2
+ signal_box[lightcount] = {-boxside, -halfheight, -boxside, boxside, halfheight, boxside}
+
+ local _vertex = vertex
+ local rv = vector.new(0, rot, 0)
+ local function vertex(x, y, z)
+ local v = vector.rotate(vector.new(x, y, z), rv)
+ return _vertex(v.x, v.y, v.z)
+ end
+
+ -- generate signal face
+ local face_vertices = {}
+ local face_uv = {
+ circular_textures(0.5, 0.5+halfheight-3*lightradius, halfwidth, half_npolygon+1, pole_npolygon),
+ circular_textures(0.5, 0.5-halfheight+3*lightradius, halfwidth, half_npolygon+1, pole_npolygon, math.pi),
+ rectangular_textures(0, 0, 1, 1, 2+pole_npolygon),
+ }
+ local face_objdef = {
+ "g face",
+ "usemtl face",
+ connect_circular(pole_vertex_count+2+pole_npolygon, pole_uv_count, 2+pole_npolygon),
+ connect_circular(pole_vertex_count, pole_uv_count, 2+pole_npolygon),
+ connect_cylindrical(pole_vertex_count, pole_uv_count+2+pole_npolygon, 2+pole_npolygon),
+ }
+ local face_vertex_count = 4*half_npolygon+4
+ local face_uv_count = 2*(half_npolygon+1) + 2*(pole_npolygon+3)
+ for i = 0, half_npolygon do
+ local theta = i/half_npolygon*math.pi
+ local r = halfwidth
+ local x, y = r*math.cos(theta), halfheight-3*lightradius+r*math.sin(theta)
+ face_vertices[i+1] = vertex(x, y, -halfthickness)
+ face_vertices[i+2+half_npolygon] = vertex(-x, -y, -halfthickness)
+ face_vertices[i+3+2*half_npolygon] = vertex(x, y, halfthickness)
+ face_vertices[i+4+3*half_npolygon] = vertex(-x, -y, halfthickness)
+ end
+
+ -- generate lights
+ local light_vertices = {}
+ local light_vertex_count = 8*(half_npolygon+1)+pole_npolygon
+ local light_uv = {rectangular_textures(0, 0, 1, 1, half_npolygon)}
+ local light_uv_count = 2*(half_npolygon+1)+pole_npolygon*lightcount
+ local light_objdef_face = {}
+ local light_objdef_main = {
+ "g light",
+ "usemtl light",
+ }
+ for i = 1, lightcount do
+ local x0, y0 = 0, -halfheight + (2*i+1)*lightradius + (i-1)*lightspacing
+ local v0 = light_vertex_count*(i-1)
+ for j = 0, half_npolygon do
+ local theta = j/half_npolygon*math.pi
+ local xs, ys = math.cos(theta), math.sin(theta)
+ for k, v in pairs {
+ {xm = -1, ym = 1, rm = 1, z = 1},
+ {xm = 1, ym = 1, rm = 0.8, z = 1},
+ {xm = -1, ym = 1, rm = 1, z = 2},
+ {xm = 1, ym = 1, rm = 0.8, z = 2},
+ {xm = 1, ym = -1, rm = 1, z = 1},
+ {xm = -1, ym = -1, rm = 0.8, z = 1},
+ {xm = 1, ym = -1, rm = 1, z = 1.5},
+ {xm = -1, ym = -1, rm = 0.8, z = 1.5},
+ } do
+ local x = x0+xs*lightradius*v.xm*v.rm
+ local y = y0+ys*lightradius*v.ym*v.rm
+ light_vertices[v0+(k-1)*(half_npolygon+1)+j+1] = vertex(x, y, -halfthickness*v.z)
+ end
+ end
+ for j = 0, pole_npolygon-1 do
+ local theta = j/pole_npolygon*2*math.pi
+ local x, y = math.cos(theta), math.sin(theta)
+ light_vertices[v0+8*(half_npolygon+1)+1+j] = vertex(x0+lightradius*x, y0+lightradius*y, -halfthickness*1.05)
+ end
+ local v0 = pole_vertex_count+face_vertex_count+v0
+ local vt0 = pole_uv_count + face_uv_count
+ local ostep = 2*half_npolygon+2
+ for j = 1, half_npolygon do
+ local dv = 2*(half_npolygon+1)
+ local v0 = v0 + dv
+ local vn = v0 + dv
+ light_objdef_face[i*ostep-j+1] = face_elements(v0+j, vt0+j, v0+j+1, vt0+j+1, vn-j, vt0+half_npolygon+2+j, vn-j+1, vt0+half_npolygon+1+j)
+ local v0 = vn + dv
+ local vn = v0 + dv
+ light_objdef_face[i*ostep-half_npolygon-j+1] = face_elements(v0+j, vt0+j, v0+j+1, vt0+j+1, vn-j, vt0+half_npolygon+2+j, vn-j+1, vt0+half_npolygon+1+j)
+ end
+ local vt0 = vt0 + 2*(half_npolygon+1) + (i-1)*pole_npolygon
+ light_uv[i+1] = circular_textures(0.5, (i-1/2)/lightcount, 0.4/lightcount, pole_npolygon)
+ light_objdef_face[(i-1)*ostep+1] = connect_cylindrical(v0, pole_uv_count+2+pole_npolygon, 2+pole_npolygon)
+ light_objdef_face[(i-1)*ostep+2] = connect_cylindrical(v0+4*(half_npolygon+1), pole_uv_count+2+pole_npolygon, 2+pole_npolygon)
+ light_objdef_main[2+i] = connect_circular(v0+8*(half_npolygon+1), vt0, pole_npolygon)
+ end
+
+ -- write file
+ face_vertices = table.concat(face_vertices, "\n")
+ face_uv = table.concat(face_uv, "\n")
+ face_objdef = table.concat(face_objdef, "\n")
+ add_model(lightcount .. "_" .. rotname .. ".obj", table.concat({
+ pole_vertices,
+ face_vertices,
+ table.concat(light_vertices, "\n"),
+ pole_uv,
+ face_uv,
+ table.concat(light_uv, "\n"),
+ pole_objdef,
+ face_objdef,
+ table.concat(light_objdef_face, "\n"),
+ table.concat(light_objdef_main, "\n"),
+ }, "\n"))
+ end
+ end
+end
+
+local S = attrans
+
+minetest.register_node("advtrains_signals_japan:pole_0", {
+ description = S("Japanese signal pole"),
+ drawtype = "mesh",
+ mesh = "advtrains_signals_japan_pole.obj",
+ tiles = {pole_texture},
+
+ paramtype = "light",
+ sunlight_propagates = true,
+
+ paramtype2 = "none",
+ selection_box = {
+ type = "fixed",
+ fixed = {pole_box},
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = {pole_box},
+ },
+ groups = {
+ cracky = 2,
+ not_blocking_trains = 1,
+ not_in_creative_inventory = 0,
+ },
+ drop = "advtrains_signals_japan:pole_0",
+})
+
+--[[
+advtrains.interlocking.aspect.register_group {
+ name = "advtrains_signals_japan:5a",
+ label = S("Japanese signal"),
+ aspects = {
+ danger = {
+ label = S"Danger (halt)",
+ main = 0,
+ },
+ restrictedspeed = {
+ label = S"Restricted speed",
+ },
+ caution = {
+ label = S"Caution",
+ },
+ reducedspeed = {
+ label = S"Reduced speed",
+ },
+ clear = {
+ label = S"Clear (proceed)",
+ },
+ "clear",
+ "reducedspeed",
+ "caution",
+ "restrictedspeed",
+ "danger",
+ }
+}]]
+
+local sigdefs = {}
+local lightcolors = {
+ red = "red",
+ green = "lime",
+ yellow = "orange",
+ distant = "purple",
+}
+local function process_signal(name, sigdata, isrpt)
+ local def = {}
+ local tx = {}
+ def.textures = tx
+ def.desc = sigdata.desc
+ def.isdst = isrpt
+ def.aspects = sigdata.aspects
+ local lights = sigdata.lights
+ local lightcount = #lights
+ if isrpt then
+ lightcount = lightcount+1
+ end
+ def.lightcount = lightcount
+ def.suppasp_names = {}
+ for idx, asp in ipairs(sigdata.aspects) do
+ local aspname = asp.name
+ local tt = {
+ string.format("[combine:1x%d", lightcount),
+ string.format("0,0=(advtrains_hud_bg.png\\^[resize\\:1x%d\\^[colorize\\:#000)", lightcount),
+ }
+ for _, i in pairs(asp.lights) do
+ local color = lightcolors[lights[i]]
+ tt[#tt+1] = string.format("0,%d=(advtrains_hud_bg.png\\^[colorize\\:%s)", i-1, color)
+ end
+ if isrpt then
+ local color = lightcolors.distant
+ tt[#tt+1] = string.format("0,%d=(advtrains_hud_bg.png\\^[colorize\\:%s)", lightcount-1, color)
+ end
+ tx[aspname] = table.concat(tt, ":")
+ def.suppasp_names[idx] = aspname
+ end
+ local invimg = {
+ string.format("[combine:%dx%d", lightcount*4+1, lightcount*4+1),
+ string.format("%d,0=(advtrains_hud_bg.png\\^[resize\\:5x%d\\^[colorize\\:#000)", lightcount*2-2, lightcount*4+1),
+ }
+ for i, c in pairs(lights) do
+ local color = lightcolors[c]
+ invimg[i+2] = string.format("%d,%d=(advtrains_hud_bg.png\\^[resize\\:3x3\\^[colorize\\:%s)", 2*lightcount-1, 4*i-3, color)
+ end
+ if isrpt then
+ invimg[lightcount+2] = string.format("%d,%d=(advtrains_hud_bg.png\\^[resize\\:3x3\\^[colorize\\:%s)", 2*lightcount-1, 4*lightcount-3, lightcolors.distant)
+ end
+ def.inventory_image = table.concat(invimg, ":")
+ return def
+end
+for sigtype, sigdata in pairs {
+ ["5a"] = {
+ desc = "5A",
+ lights = {"yellow", "yellow", "red", "yellow", "green"},
+ aspects = {
+ {name = "clear", description = S"Clear (proceed)", lights = {5}, main = -1},
+ {name = "reducedspeed", description = S"Reduced speed", lights = {2, 5}, main = 12},
+ {name = "caution", description = S"Caution", lights = {4}},
+ {name = "restrictedspeed", description = S"Restricted speed", lights = {1, 4}, main = 6},
+ {name = "danger", description = S"Danger (halt)", lights = {3}, main = 0},
+ }
+ }
+} do
+ sigdefs["main_"..sigtype] = process_signal(sigtype, sigdata)
+ -- TODO re-enable this once ready
+ --sigdefs["rpt_"..sigtype] = process_signal(sigtype, sigdata, true)
+end
+
+for _, rtab in ipairs {
+ {rot = "0", ici = true},
+ {rot = "30"},
+ {rot = "45"},
+ {rot = "60"},
+} do
+ local rot = rtab.rot
+ for sigtype, siginfo in pairs(sigdefs) do
+ local lightcount = siginfo.lightcount
+ for asp, texture in pairs(siginfo.textures) do
+ minetest.register_node("advtrains_signals_japan:"..sigtype.."_"..asp.."_"..rot, {
+ description = attrans(string.format("Japanese%s signal (type %s)", siginfo.isdst and " repeating" or "", siginfo.desc)),
+ drawtype = "mesh",
+ mesh = string.format("advtrains_signals_japan_%d_%s.obj", lightcount, rot),
+ tiles = {pole_texture, signal_face_texture, texture},
+ paramtype = "light",
+ sunlight_propagates = true,
+ light_source = 4,
+ paramtype2 = "facedir",
+ selection_box = {
+ type = "fixed",
+ fixed = {pole_box, signal_box[lightcount]},
+ },
+ collision_box = {
+ type = "fixed",
+ fixed = {pole_box, signal_box[lightcount]},
+ },
+ groups = {
+ cracky = 2,
+ advtrains_signal = 2,
+ not_blocking_trains = 1,
+ save_in_at_nodedb = 1,
+ not_in_creative_inventory = rtab.ici and asp == "danger" and 0 or 1,
+ },
+ inventory_image = siginfo.inventory_image,
+ drop = "advtrains_signals_japan:"..sigtype.."_danger_0",
+ advtrains = {
+ main_aspects = siginfo.aspects,
+ apply_aspect = function(pos, node, main_aspect, rem_aspect, rem_aspinfo)
+ local asp_name = main_aspect and main_aspect.name or "danger"
+ -- if this signal is clear and remote signal is restrictive (<= 10) then degrade to caution aspect
+ if not main_aspect or main_aspect.halt then
+ asp_name = "danger"
+ elseif main_aspect.name == "clear" and rem_aspinfo and rem_aspinfo.main and rem_aspinfo.main >= 0 and rem_aspinfo.main <= 10 then
+ asp_name = "caution"
+ end
+ advtrains.ndb.swap_node(pos, {name="advtrains_signals_japan:"..sigtype.."_"..asp_name.."_"..rot, param2 = node.param2})
+ end,
+ get_aspect_info = function(pos, main_aspect)
+ if main_aspect.halt then
+ return { main = 0 } -- generic halt
+ end
+ return {
+ main = main_aspect.main,
+ proceed_as_main = true,
+ }
+ end,
+ route_role = "main_distant",
+ --[[
+ supported_aspects = {
+ group = "advtrains_signals_japan:5a",
+ name = siginfo.suppasp_names,
+ dst_shift = siginfo.isdst and 0,
+ main = (not siginfo.isdst) and {} or false
+ },
+ get_aspect = function()
+ local main
+ if siginfo.isdst then
+ main = false
+ end
+ return {group = "advtrains_signals_japan:5a", name = asp, main = main}
+ end,
+ set_aspect = function(pos, node, asp)
+ advtrains.ndb.swap_node(pos, {name = "advtrains_signals_japan:"..sigtype.."_"..(asp.name).."_"..rot, param2 = node.param2})
+ end,
+ ]]
+ },
+ on_rightclick = advtrains.interlocking.signal.on_rightclick,
+ can_dig = advtrains.interlocking.signal.can_dig,
+ after_dig_node = advtrains.interlocking.signal.after_dig,
+ })
+ --advtrains.trackplacer.add_worked("advtrains_signals_japan:"..sigtype, asp, "_"..rot)
+ end
+ end
+end
diff --git a/advtrains_signals_japan/mod.conf b/advtrains_signals_japan/mod.conf
new file mode 100644
index 0000000..8cb2cb3
--- /dev/null
+++ b/advtrains_signals_japan/mod.conf
@@ -0,0 +1,6 @@
+name=advtrains_signals_japan
+title=Advtrains Interlocking Signal Set - Japanese Signals
+description=Japanese signal set for the Advanced Trains Interlocking system
+author=yw05
+
+depends=advtrains_interlocking
diff --git a/advtrains_signals_japan/textures/advtrains_signals_japan_mast.png b/advtrains_signals_japan/textures/advtrains_signals_japan_mast.png
new file mode 100644
index 0000000..8d288a9
--- /dev/null
+++ b/advtrains_signals_japan/textures/advtrains_signals_japan_mast.png
Binary files differ
diff --git a/advtrains_signals_ks/init.lua b/advtrains_signals_ks/init.lua
index 1f89da9..97d5e44 100644
--- a/advtrains_signals_ks/init.lua
+++ b/advtrains_signals_ks/init.lua
@@ -4,8 +4,6 @@
-- Note that the group value of advtrains_signal is 2, which means "step 2 of signal capabilities"
-- advtrains_signal=1 is meant for signals that do not implement set_aspect.
-local advtrains_signals_ks_mast_tile = {name = "advtrains_signals_ks_mast.png", color = "#8f8f8f"}
-
local function asp_to_zs3type(asp)
local n = tonumber(asp)
if not n or n < 4 then return "off" end
@@ -88,38 +86,38 @@ end
local mainaspects_main = {
{
name = "proceed",
- description = "Volno",
+ description = "Proceed",
zs3 = "off"
},
{
name = "shunt",
- description = "Posun",
+ description = "Shunt",
zs3 = "off",
shunt = true,
},
{
name = "proceed_16",
- description = "Volno (rychlost 16)",
+ description = "Proceed (speed 16)",
zs3 = "16",
},
{
name = "proceed_12",
- description = "Volno (rychlost 12)",
+ description = "Proceed (speed 12)",
zs3 = "12",
},
{
name = "proceed_8",
- description = "Volno (rychlost 8)",
+ description = "Proceed (speed 8)",
zs3 = "8",
},
{
name = "proceed_6",
- description = "Volno (rychlost 6)",
+ description = "Proceed (speed 6)",
zs3 = "6",
},
{
name = "proceed_4",
- description = "Volno (rychlost 4)",
+ description = "Proceed (speed 4)",
zs3 = "4",
},
}
@@ -153,7 +151,7 @@ end
local mainaspects_dst = {
{
name = "expectclear",
- description = "Očekávej volno",
+ description = "Expect Clear",
},
}
@@ -175,7 +173,7 @@ end
local mainaspects_ra = {
{
name = "shunt",
- description = "Posun",
+ description = "Shunt",
shunt = true,
},
}
@@ -228,12 +226,11 @@ for _, rtab in ipairs({
}
end
minetest.register_node("advtrains_signals_ks:hs_"..typ.."_"..rot, {
- description = attrans("Ks Main Signal"),
+ description = "Ks Main Signal",
drawtype = "mesh",
mesh = "advtrains_signals_ks_main_smr"..rot..".obj",
- tiles = {advtrains_signals_ks_mast_tile, "advtrains_signals_ks_head.png", "advtrains_signals_ks_head.png", tile},
- use_texture_alpha = "opaque",
-
+ tiles = {"advtrains_signals_ks_mast.png", "advtrains_signals_ks_head.png", "advtrains_signals_ks_head.png", tile},
+
paramtype="light",
sunlight_propagates=true,
light_source = 4,
@@ -263,7 +260,6 @@ for _, rtab in ipairs({
on_rightclick = advtrains.interlocking.signal.on_rightclick,
can_dig = advtrains.interlocking.signal.can_dig,
after_dig_node = advtrains.interlocking.signal.after_dig,
- after_place_node = advtrains.after_place_signal,
})
-- rotatable by trackworker
end
@@ -302,10 +298,10 @@ for _, rtab in ipairs({
}
end
minetest.register_node("advtrains_signals_ks:vs_"..typ.."_"..rot, {
- description = "předzvěst KS",
+ description = "Ks Distant Signal",
drawtype = "mesh",
mesh = "advtrains_signals_ks_distant_smr"..rot..".obj",
- tiles = {advtrains_signals_ks_mast_tile, "advtrains_signals_ks_head.png", "advtrains_signals_ks_head.png", tile},
+ tiles = {"advtrains_signals_ks_mast.png", "advtrains_signals_ks_head.png", "advtrains_signals_ks_head.png", tile},
paramtype="light",
sunlight_propagates=true,
@@ -337,7 +333,6 @@ for _, rtab in ipairs({
on_rightclick = advtrains.interlocking.signal.on_rightclick,
can_dig = advtrains.interlocking.signal.can_dig,
after_dig_node = advtrains.interlocking.signal.after_dig,
- after_place_node = advtrains.after_place_signal,
})
-- rotatable by trackworker
end
@@ -355,10 +350,10 @@ for _, rtab in ipairs({
afunc = function() return prts.asp end
end
minetest.register_node("advtrains_signals_ks:ra_"..typ.."_"..rot, {
- description = "posunové návěstidlo KS",
+ description = "Ks Shunting Signal",
drawtype = "mesh",
mesh = "advtrains_signals_ks_sht_smr"..rot..".obj",
- tiles = {advtrains_signals_ks_mast_tile, "advtrains_signals_ks_head.png", "advtrains_signals_ks_head.png", "advtrains_signals_ks_ltm_"..typ..".png"},
+ tiles = {"advtrains_signals_ks_mast.png", "advtrains_signals_ks_head.png", "advtrains_signals_ks_head.png", "advtrains_signals_ks_ltm_"..typ..".png"},
paramtype="light",
sunlight_propagates=true,
@@ -367,7 +362,7 @@ for _, rtab in ipairs({
paramtype2 = "facedir",
selection_box = {
type = "fixed",
- fixed = sbox,
+ fixed = {sbox, {-1/4, -1/2, -1/4, 1/4, -7/16, 1/4}}
},
collision_box = {
type = "fixed",
@@ -393,7 +388,6 @@ for _, rtab in ipairs({
on_rightclick = advtrains.interlocking.signal.on_rightclick,
can_dig = advtrains.interlocking.signal.can_dig,
after_dig_node = advtrains.interlocking.signal.after_dig,
- after_place_node = advtrains.after_place_signal,
})
-- rotatable by trackworker
end
@@ -405,8 +399,7 @@ for _, rtab in ipairs({
drawtype = "mesh",
mesh = "advtrains_signals_ks_"..mesh.."_smr"..rot..".obj",
tiles = {"advtrains_signals_ks_signpost.png", tile2},
- use_texture_alpha = "opaque",
-
+
paramtype="light",
sunlight_propagates=true,
light_source = 4,
@@ -423,7 +416,7 @@ for _, rtab in ipairs({
save_in_at_nodedb = 1,
not_in_creative_inventory = (rtab.ici and typ == dtyp) and 0 or 1,
},
- drop = "advtrains_signals_ks:"..prefix.."_"..typ.."_0",
+ drop = "advtrains_signals_ks:"..prefix.."_"..dtyp.."_0",
inventory_image = inv,
advtrains = {
get_aspect_info = asp,
@@ -434,77 +427,27 @@ for _, rtab in ipairs({
on_rightclick = advtrains.interlocking.signal.on_rightclick,
can_dig = advtrains.interlocking.signal.can_dig,
after_dig_node = advtrains.interlocking.signal.after_dig,
- after_place_node = advtrains.after_place_signal,
})
-- rotatable by trackworker
--TODO add rotation using trackworker
end
for typ, prts in pairs {
- ["hfs"] = {
- asp = {main = false, shunt = false},
- n = "pam",
- --[[mesh = "_hfs",]]
- name = "železniční návěst: posun zakázán",
- tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_hfs.png^[makealpha:255,255,255)",
- },
- ["pam"] = {
- asp = {main = -1, shunt = false, proceed_as_main = true},
- n = "ne4",
- name = "železniční návěst: posun pokračuje jako normální vlak",
- tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_pam.png^[makealpha:255,255,255)"
- },
- ["ne4"] = {
- asp = {},
- n = "ne3x1",
- mesh="_ne4",
- name = "železniční návěst: ne4",
- tile2 = "advtrains_signals_ks_sign_ne4.png",
- inventory_image = "[combine:20x20:6,0=\\[combine\\:8x20\\:0,0=advtrains_signals_ks_sign_ne4.png",
- },
- ["ne3x1"] = {
- asp = {},
- n = "ne3x2",
- mesh="_ne3",
- name = "železniční návěst: ne3x1",
- tile2 = "advtrains_signals_ks_sign_ne3x1.png",
- inventory_image = "[combine:16x16:6,0=advtrains_signals_ks_sign_ne3x1.png\\^[resize\\:4x16",
- },
- ["ne3x2"] = {
- asp = {},
- n = "ne3x3",
- mesh="_ne3",
- name = "železniční návěst: ne3x2",
- tile2 = "advtrains_signals_ks_sign_ne3x2.png",
- inventory_image = "[combine:16x16:6,0=advtrains_signals_ks_sign_ne3x2.png\\^[resize\\:4x16",
- },
- ["ne3x3"] = {
- asp = {},
- n = "ne3x4",
- mesh="_ne3",
- name = "železniční návěst: ne3x3",
- tile2 = "advtrains_signals_ks_sign_ne3x3.png",
- inventory_image = "[combine:16x16:6,0=advtrains_signals_ks_sign_ne3x3.png\\^[resize\\:4x16",
- },
- ["ne3x4"] = {
- asp = {},
- n = "ne3x5",
- mesh="_ne3",
- name = "železniční návěst: ne3x4",
- tile2 = "advtrains_signals_ks_sign_ne3x4.png",
- inventory_image = "[combine:16x16:6,0=advtrains_signals_ks_sign_ne3x4.png\\^[resize\\:4x16",
- },
- ["ne3x5"] = {
- asp = {},
- n = "hfs",
- mesh="_ne3",
- name = "železniční návěst: ne3x5",
- tile2 = "advtrains_signals_ks_sign_ne3x5.png",
- inventory_image = "[combine:16x16:6,0=advtrains_signals_ks_sign_ne3x5.png\\^[resize\\:4x16",
- },
+ ["hfs"] = {asp = {main = false, shunt = false}, n = "pam", mesh = "_hfs", owntile = true},
+ ["pam"] = {asp = {main = -1, shunt = false, proceed_as_main = true}, n = "ne4"},
+ ["ne4"] = {asp = {}, n = "ne3x1", mesh="_ne4", owntile = true},
+ ["ne3x1"] = {asp = {}, n = "ne3x2", mesh="_ne3", owntile = true},
+ ["ne3x2"] = {asp = {}, n = "ne3x3", mesh="_ne3", owntile = true},
+ ["ne3x3"] = {asp = {}, n = "ne3x4", mesh="_ne3", owntile = true},
+ ["ne3x4"] = {asp = {}, n = "ne3x5", mesh="_ne3", owntile = true},
+ ["ne3x5"] = {asp = {}, n = "hfs", mesh="_ne3", owntile = true},
} do
local mesh = prts.mesh or ""
- register_sign("sign", typ, prts.n, prts.name, "sign"..mesh, prts.tile2, typ, prts.inventory_image or prts.tile2, prts.asp)
+ local tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_"..typ..".png^[makealpha:255,255,255)"
+ if prts.owntile then
+ tile2 = "advtrains_signals_ks_sign_"..typ..".png"
+ end
+ register_sign("sign", typ, prts.n, "Signal Sign", "sign"..mesh, tile2, "hfs", "advtrains_signals_ks_sign_lf7.png", prts.asp)
end
for typ, prts in pairs {
@@ -522,8 +465,7 @@ for _, rtab in ipairs({
if typ == "e" then
tile2 = "advtrains_signals_ks_sign_zs10.png"
end
- register_sign("sign", typ, prts.n, attrans("Permanent local speed restriction sign").." ("..(typ == "e" and attrans("end") or typ) ..")",
- "sign"..mesh, tile2, "8", "advtrains_signals_ks_sign_8.png^[invert:rgb", prts.asp)
+ register_sign("sign", typ, prts.n, "Permanent local speed restriction sign", "sign"..mesh, tile2, "8", "advtrains_signals_ks_sign_8.png^[invert:rgb", prts.asp)
end
for typ, prts in pairs {
@@ -534,10 +476,9 @@ for _, rtab in ipairs({
["16"] = {main = 16, n = "e"},
["e"] = {main = -1, n = "4"},
} do
- local tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_"..typ..".png^[makealpha:255,255,255)"..(typ == "e" and "" or "^[multiply:orange")
+ local tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_"..typ..".png^[makealpha:255,255,255)^[multiply:orange"
local inv = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_8.png^[makealpha:255,255,255)^[multiply:orange"
- register_sign("sign_lf", typ, prts.n, attrans("Temporary local speed restriction sign").." ("..(typ == "e" and attrans("end") or typ) ..")",
- "sign", tile2, "8", inv, {main = prts.main, shunt = true, type = "temp"})
+ register_sign("sign_lf", typ, prts.n, "Temporary local speed restriction sign", "sign", tile2, "8", inv, {main = prts.main, shunt = true, type = "temp"})
end
for typ, prts in pairs {
@@ -550,8 +491,7 @@ for _, rtab in ipairs({
} do
local tile2 = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_"..typ..".png^[makealpha:255,255,255)"
local inv = "advtrains_signals_ks_sign_lf7.png^(advtrains_signals_ks_sign_8.png^[makealpha:255,255,255)"
- register_sign("sign_lf7", typ, prts.n, attrans("Line speed restriction sign").." ("..(typ == "e" and attrans("end") or typ) ..")",
- "sign", tile2, "8", inv, {main = prts.main, shunt = true, type = "line"})
+ register_sign("sign_lf7", typ, prts.n, "Line speed restriction sign", "sign", tile2, "8", inv, {main = prts.main, shunt = true, type = "line"})
end
-- Geschwindigkeits(vor)anzeiger für Ks-Signale
@@ -565,9 +505,7 @@ for _, rtab in ipairs({
}) do
local def = {
drawtype = "mesh",
- tiles = {advtrains_signals_ks_mast_tile,"advtrains_signals_ks_head.png",
- "advtrains_signals_ks_sign_"..typ..".png^[invert:rgb^[noalpha"},
- use_texture_alpha = "opaque",
+ tiles = {"advtrains_signals_ks_mast.png","advtrains_signals_ks_head.png","advtrains_signals_ks_sign_"..typ..".png^[invert:rgb^[noalpha"},
paramtype = "light",
sunlight_propagates = true,
light_source = 4,
@@ -582,13 +520,12 @@ for _, rtab in ipairs({
save_in_at_nodedb = 1,
not_in_creative_inventory = (rtab.ici and prts.ici) and 0 or 1,
},
- after_dig_node = function(pos) advtrains.ndb.update(pos) end,
- after_place_node = advtrains.after_place_signal,
+ after_dig_node = function(pos) advtrains.ndb.update(pos) end
}
-- Zs 3
local t = table.copy(def)
- t.description = attrans("Ks speed limit indicator")
+ t.description = "Ks speed limit indicator"
t.mesh = "advtrains_signals_ks_zs_top_smr"..rot..".obj"
t.drop = "advtrains_signals_ks:zs3_off_0"
t.selection_box.fixed[1][5] = 0
@@ -601,7 +538,7 @@ for _, rtab in ipairs({
-- Zs 3v
local t = table.copy(def)
- t.description = attrans("Ks distant speed limit indicator")
+ t.description = "Ks distant speed limit indicator"
t.mesh = "advtrains_signals_ks_zs_bottom_smr"..rot..".obj"
t.drop = "advtrains_signals_ks:zs3v_off_0"
t.tiles[3] = t.tiles[3] .. "^[multiply:yellow"
@@ -610,21 +547,20 @@ for _, rtab in ipairs({
trackworker_rot_incr_param2 = (rot=="60")
}
minetest.register_node("advtrains_signals_ks:zs3v_"..typ.."_"..rot, t)
+ --TODO add rotation using trackworker
end
minetest.register_node("advtrains_signals_ks:mast_mast_"..rot, {
- description = attrans("Ks Mast"),
+ description = "Ks Mast",
drawtype = "mesh",
mesh = "advtrains_signals_ks_mast_smr"..rot..".obj",
tiles = {"advtrains_signals_ks_mast.png"},
- use_texture_alpha = "opaque",
-
+
paramtype="light",
sunlight_propagates=true,
--light_source = 4,
- paramtype2 = "colorfacedir",
- palette = "advtrains_signals_ks_mast_palette.png",
+ paramtype2 = "facedir",
selection_box = {
type = "fixed",
fixed = {rtab.sbox, {-1/4, -1/2, -1/4, 1/4, -7/16, 1/4}}
@@ -639,23 +575,14 @@ for _, rtab in ipairs({
trackworker_rot_incr_param2 = (rot=="60")
},
drop = "advtrains_signals_ks:mast_mast_0",
- after_place_node = advtrains.after_place_signal,
})
--TODO add rotation using trackworker
end
-- Crafting
-minetest.register_craft({
- output = "advtrains_signals_ks:hs_danger_0 2",
- recipe = {
- {'default:steel_ingot', 'dye:red', 'default:steel_ingot'},
- {'dye:yellow', 'default:steel_ingot', 'dye:dark_green'},
- {'default:steel_ingot', 'advtrains_signals_ks:mast_mast_0', 'default:steel_ingot'},
- },
-})
-
-minetest.register_craft({
+-- Ks Signals
+minetest.register_craft({ -- Ks Mast
output = "advtrains_signals_ks:mast_mast_0 10",
recipe = {
{'default:steel_ingot'},
@@ -663,25 +590,23 @@ minetest.register_craft({
{'default:steel_ingot'},
},
})
-
-minetest.register_craft({
- output = 'advtrains_signals_ks:vs_slow_0 10',
+minetest.register_craft({ -- Ks Main Signal
+ output = "advtrains_signals_ks:hs_danger_0 2",
recipe = {
- {'default:steel_ignot', 'default:steel_ingot'},
- {'dye:green', 'dye:yellow'},
+ {'default:steel_ingot', 'dye:red', 'default:steel_ingot'},
+ {'dye:yellow', 'default:steel_ingot', 'dye:dark_green'},
+ {'default:steel_ingot', 'advtrains_signals_ks:mast_mast_0', 'default:steel_ingot'},
},
})
-
-minetest.register_craft({
- output = "advtrains_signals_ks:ra_danger_0 2",
+minetest.register_craft({ -- Ks Distant Signal
+ output = "advtrains_signals_ks:vs_slow_0 2",
recipe = {
- {'dye:red', 'dye:white', 'dye:red'},
- {'dye:white', 'default:steel_ingot', 'default:steel_ingot'},
+ {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'},
+ {'dye:dark_green', 'default:steel_ingot', 'dye:yellow'},
{'default:steel_ingot', 'advtrains_signals_ks:mast_mast_0', 'default:steel_ingot'},
- },
+ }
})
-
-minetest.register_craft({
+minetest.register_craft({ -- Ks Speed Limit Indicator
output = "advtrains_signals_ks:zs3_off_0 2",
recipe = {
{"","default:steel_ingot",""},
@@ -689,7 +614,7 @@ minetest.register_craft({
{"","advtrains_signals_ks:mast_mast_0",""}
},
})
-minetest.register_craft({
+minetest.register_craft({ -- Ks Distant Speed Limit Indicator
output = "advtrains_signals_ks:zs3v_off_0 2",
recipe = {
{"","default:steel_ingot",""},
@@ -697,14 +622,22 @@ minetest.register_craft({
{"","advtrains_signals_ks:mast_mast_0",""}
},
})
+minetest.register_craft({ -- Ks Shunting Signal
+ output = "advtrains_signals_ks:ra_danger_0 2",
+ recipe = {
+ {'dye:red', 'dye:white', 'dye:red'},
+ {'dye:white', 'default:steel_ingot', 'default:steel_ingot'},
+ {'default:steel_ingot', 'advtrains_signals_ks:mast_mast_0', 'default:steel_ingot'},
+ },
+})
+-- Speed Restriction signs
+-- Crafting entry recipe for signs
local sign_material = "default:sign_wall_steel" --fallback
if minetest.get_modpath("basic_materials") then
sign_material = "basic_materials:plastic_sheet"
end
---print("Sign Material: "..sign_material)
-
-minetest.register_craft({
+minetest.register_craft({ -- Permanent Local Speed Restriction Sign
output = "advtrains_signals_ks:sign_8_0 2",
recipe = {
{sign_material, 'dye:black'},
@@ -714,57 +647,20 @@ minetest.register_craft({
})
sign_material = nil
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_8_0 1",
- recipe = {{"advtrains_signals_ks:sign_lf7_8_0"}}
-}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_hfs_0 1",
+-- Circular crafting between sign types
+minetest.register_craft{ -- Signal Sign
+ output = "advtrains_signals_ks:sign_hfs_0",
recipe = {{"advtrains_signals_ks:sign_8_0"}}
}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_pam_0 1",
+minetest.register_craft{ -- Temporary Local Speed Restriction Sign
+ output = "advtrains_signals_ks:sign_lf_8_0",
recipe = {{"advtrains_signals_ks:sign_hfs_0"}}
}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_ne4_0 1",
- recipe = {{"advtrains_signals_ks:sign_pam_0"}}
-}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_ne3x1_0 1",
- recipe = {{"advtrains_signals_ks:sign_ne4_0"}}
-}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_ne3x2_0 1",
- recipe = {{"advtrains_signals_ks:sign_ne3x1_0"}}
-}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_ne3x3_0 1",
- recipe = {{"advtrains_signals_ks:sign_ne3x2_0"}}
-}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_ne3x4_0 1",
- recipe = {{"advtrains_signals_ks:sign_ne3x3_0"}}
-}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_ne3x5_0 1",
- recipe = {{"advtrains_signals_ks:sign_ne3x4_0"}}
-}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_lf_8_0 1",
- recipe = {{"advtrains_signals_ks:sign_ne3x5_0"}}
-}
-
-minetest.register_craft{
- output = "advtrains_signals_ks:sign_lf7_8_0 1",
+minetest.register_craft{ -- Line Speed Restriction Sign
+ output = "advtrains_signals_ks:sign_lf7_8_0",
recipe = {{"advtrains_signals_ks:sign_lf_8_0"}}
}
+minetest.register_craft{ -- Permanent Local Speed Restriction Sign
+ output = "advtrains_signals_ks:sign_8_0",
+ recipe = {{"advtrains_signals_ks:sign_lf7_8_0"}}
+} \ No newline at end of file
diff --git a/advtrains_signals_ks/textures/advtrains_signals_ks_mast.png b/advtrains_signals_ks/textures/advtrains_signals_ks_mast.png
index 4fd1c8c..81b1128 100644
--- a/advtrains_signals_ks/textures/advtrains_signals_ks_mast.png
+++ b/advtrains_signals_ks/textures/advtrains_signals_ks_mast.png
Binary files differ
diff --git a/advtrains_signals_muc_ubahn/init.lua b/advtrains_signals_muc_ubahn/init.lua
new file mode 100644
index 0000000..a8eb445
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/init.lua
@@ -0,0 +1,116 @@
+-- advtrains_signals_muc_ubahn
+-- Signals modeled after the Munich U-Bahn signalling system
+-- It reuses the original historic wall signal mesh, but extends it to 4 signal lamps and supports the new signal API only.
+
+-- For a reference of the signals (in German) see: https://www.u-bahn-muenchen.de/betrieb/zugsicherung/signale/
+-- Hp4 and Hp5 are not implemented because they do not make sense.
+-- Also the speed signals are not yet added (they will be added later)
+
+local all_sigs = {
+ hp0 = { asp = { main = 0 }, crea = true }, -- halt
+ hp1 = { asp = { main = -1, proceed_as_main = true } }, -- free full speed
+ hp2 = { asp = { main = 12, proceed_as_main = true } }, -- slow speed
+ hp3 = { asp = { main = 0, shunt = true } }, -- shunting
+ vr0 = { asp = { dst = 0 }, distant = true, crea = true }, -- distant halt/slow
+ vr1 = { asp = { dst = -1 }, distant = true }, -- distant free
+}
+
+local mainaspects = {
+ { name = "hp1", description = "Hp1: Full speed" },
+ { name = "hp2", description = "Hp2: Reduced Speed" },
+ { name = "hp3", description = "Hp3: Shunt" },
+}
+local dstaspects = {
+ { name = "vr1", description = "Vr1: Expect Full speed" },
+}
+
+local function applyaspect_main(loc)
+ return function(pos, node, main_aspect, rem_aspect, rem_aspinfo)
+ local ma_node = main_aspect.name
+ if all_sigs[ma_node] and not all_sigs[ma_node].distant then
+ -- ma_node is fine
+ elseif main_aspect.halt then
+ ma_node = "hp0" -- default halt aspect
+ else
+ ma_node = "hp1" -- default free aspect
+ end
+ advtrains.ndb.swap_node(pos, {name = "advtrains_signals_muc_ubahn:signal_wall_"..loc.."_"..ma_node, param2 = node.param2})
+ end
+end
+
+local function applyaspect_distant(loc)
+ return function(pos, node, main_aspect, rem_aspect, rem_aspinfo)
+ local ma_node = "vr0" -- show expect stop by default
+ if not main_aspect.halt and (not rem_aspinfo or not rem_aspinfo.main or rem_aspinfo.main>12 or rem_aspinfo.main==-1) then
+ ma_node = "vr1" -- show free when dst is at least 12
+ end
+ advtrains.ndb.swap_node(pos, {name = "advtrains_signals_muc_ubahn:signal_wall_"..loc.."_"..ma_node, param2 = node.param2})
+ end
+end
+
+for r,f in pairs(all_sigs) do
+ for loc, sbox in pairs({l={-1/2, -1/2, -1/4, 0, 1/2, 1/4}, r={0, -1/2, -1/4, 1/2, 1/2, 1/4}, t={-1/2, 0, -1/4, 1/2, 1/2, 1/4}}) do
+ minetest.register_node("advtrains_signals_muc_ubahn:signal_wall_"..loc.."_"..r, {
+ drawtype = "mesh",
+ paramtype="light",
+ paramtype2="facedir",
+ walkable = false,
+ selection_box = {
+ type = "fixed",
+ fixed = sbox,
+ },
+ mesh = "advtrains_signals_muc_ubahn_wsig_"..loc..".obj",
+ tiles = {"advtrains_signals_muc_ubahn_"..r..".png"},
+ drop = f.distant and "advtrains_signals_muc_ubahn:signal_wall_"..loc.."_vr0" or "advtrains_signals_muc_ubahn:signal_wall_"..loc.."_hp0",
+ description = f.distant and attrans("Munich U-Bahn Distant Signal ("..loc..")") or attrans("Munich U-Bahn Main Signal ("..loc..")"),
+ groups = {
+ cracky=3,
+ not_blocking_trains=1,
+ save_in_at_nodedb=1,
+ advtrains_signal = 2,
+ not_in_creative_inventory = f.crea and 0 or 1
+ },
+ light_source = 1,
+ sunlight_propagates=true,
+ on_rightclick = advtrains.interlocking.signal.on_rightclick,
+ can_dig = advtrains.interlocking.signal.can_dig,
+ after_dig_node = advtrains.interlocking.signal.after_dig,
+ -- new signal API
+ advtrains = {
+ main_aspects = f.distant and dstaspects or mainaspects, -- main aspects only for main
+ apply_aspect = f.distant and applyaspect_distant(loc) or applyaspect_main(loc),
+ pure_distant = f.distant,
+ get_aspect_info = function() return f.asp end,
+ route_role = f.distant and "distant" or "main"
+ },
+ })
+ end
+end
+
+-- Crafting
+minetest.register_craft({ -- Main Signal Left as entry recipe
+ output = "advtrains_signals_muc_ubahn:signal_wall_l_hp0",
+ type = "shapeless",
+ recipe = {"advtrains:signal_wall_l_off", "advtrains_interlocking:tcb_node"},
+})
+minetest.register_craft({ -- Distant Signal Left as entry recipe
+ output = "advtrains_signals_muc_ubahn:signal_wall_l_vr0",
+ recipe = {
+ {"dye:orange","",""},
+ {"dye:orange","advtrains_signals_muc_ubahn:signal_wall_l_hp0","dye:dark_green"},
+ {"","","dye:dark_green"}
+ }
+})
+
+for this,nxt in pairs({l = "t", t = "r",r = "l"}) do --Circular crafting for wall-mount signals
+ minetest.register_craft({ -- Main Signal
+ output = "advtrains_signals_muc_ubahn:signal_wall_"..nxt.."_hp0",
+ type = "shapeless",
+ recipe = {"advtrains_signals_muc_ubahn:signal_wall_"..this.."_hp0"},
+ })
+ minetest.register_craft({ -- Distant Signal
+ output = "advtrains_signals_muc_ubahn:signal_wall_"..nxt.."_vr0",
+ type = "shapeless",
+ recipe = {"advtrains_signals_muc_ubahn:signal_wall_"..this.."_vr0"},
+ })
+end \ No newline at end of file
diff --git a/advtrains_signals_muc_ubahn/mod.conf b/advtrains_signals_muc_ubahn/mod.conf
new file mode 100644
index 0000000..05d1624
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/mod.conf
@@ -0,0 +1,5 @@
+name=advtrains_signals_muc_ubahn
+title=Advtrains Interlocking Signal Set - Munich U-Bahn signals
+description=Subway signal set for the Advanced Trains Interlocking system modeled after Munich U-Bahn signals
+author=orwell96
+depends=advtrains_interlocking
diff --git a/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_l.obj b/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_l.obj
new file mode 100644
index 0000000..5e80955
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_l.obj
@@ -0,0 +1,2137 @@
+# Blender 3.4.1
+# www.blender.org
+mtllib advtrains_signals_muc_ubahn_wsig_l.mtl
+o Cube
+v 0.500000 0.399750 0.043560
+v 0.500000 0.357794 0.043560
+v 0.500000 -0.357244 0.043560
+v 0.500000 -0.402505 0.043560
+v 0.500000 0.399750 -0.043560
+v 0.500000 0.357794 -0.043560
+v 0.500000 -0.357244 -0.043560
+v 0.500000 -0.402505 -0.043560
+v 0.302890 0.399750 0.043560
+v 0.302890 0.357794 0.043560
+v 0.302890 -0.357244 0.043560
+v 0.302890 -0.402505 0.043560
+v 0.302890 0.399750 -0.043560
+v 0.302890 0.357794 -0.043560
+v 0.302890 -0.357244 -0.043560
+v 0.302890 -0.402505 -0.043560
+v 0.218703 -0.357244 0.042354
+v 0.218703 0.357794 0.042353
+v 0.218703 -0.357244 -0.031584
+v 0.218703 0.357794 -0.031584
+v 0.450908 -0.357244 0.042353
+v 0.450908 0.357794 0.042353
+v 0.450908 -0.357244 -0.031584
+v 0.450908 0.357794 -0.031584
+v 0.265363 -0.310583 0.042353
+v 0.265363 0.311134 0.042353
+v 0.404248 0.311134 0.042353
+v 0.404247 -0.310583 0.042353
+v 0.265363 -0.310583 0.089581
+v 0.265363 0.311134 0.089581
+v 0.404248 0.311134 0.089581
+v 0.404247 -0.310583 0.089581
+v 0.257920 0.318577 -0.031584
+v 0.257920 -0.318027 -0.031584
+v 0.411691 0.318577 -0.031584
+v 0.411691 -0.318027 -0.031584
+v 0.331404 0.241338 -0.037331
+v 0.326280 0.189125 -0.037331
+v 0.316192 0.191128 -0.037331
+v 0.306689 0.195061 -0.037331
+v 0.298135 0.200771 -0.037331
+v 0.290861 0.208041 -0.037331
+v 0.285144 0.216591 -0.037331
+v 0.281205 0.226091 -0.037331
+v 0.279195 0.236177 -0.037331
+v 0.279191 0.246462 -0.037331
+v 0.281194 0.256550 -0.037331
+v 0.285127 0.266053 -0.037331
+v 0.290838 0.274606 -0.037331
+v 0.298107 0.281881 -0.037331
+v 0.306657 0.287598 -0.037331
+v 0.316157 0.291537 -0.037331
+v 0.326243 0.293547 -0.037331
+v 0.336528 0.293550 -0.037331
+v 0.346616 0.291547 -0.037331
+v 0.356119 0.287615 -0.037331
+v 0.364672 0.281904 -0.037331
+v 0.371947 0.274634 -0.037331
+v 0.377664 0.266085 -0.037331
+v 0.381603 0.256585 -0.037331
+v 0.383613 0.246498 -0.037331
+v 0.383616 0.236214 -0.037331
+v 0.381613 0.226126 -0.037331
+v 0.377681 0.216623 -0.037331
+v 0.371970 0.208069 -0.037331
+v 0.364700 0.200795 -0.037331
+v 0.356151 0.195078 -0.037331
+v 0.346651 0.191139 -0.037331
+v 0.336564 0.189129 -0.037331
+v 0.313532 0.182348 -0.031584
+v 0.325384 0.179994 -0.031584
+v 0.302367 0.186968 -0.031584
+v 0.292318 0.193677 -0.031584
+v 0.283771 0.202218 -0.031584
+v 0.277054 0.212263 -0.031584
+v 0.272426 0.223425 -0.031584
+v 0.270065 0.235275 -0.031584
+v 0.270060 0.247358 -0.031584
+v 0.272414 0.259210 -0.031584
+v 0.277034 0.270375 -0.031584
+v 0.283743 0.280424 -0.031584
+v 0.292285 0.288971 -0.031584
+v 0.302329 0.295687 -0.031584
+v 0.313491 0.300315 -0.031584
+v 0.325341 0.302677 -0.031584
+v 0.337424 0.302681 -0.031584
+v 0.349276 0.300328 -0.031584
+v 0.360441 0.295708 -0.031584
+v 0.370490 0.288998 -0.031584
+v 0.379037 0.280457 -0.031584
+v 0.385753 0.270413 -0.031584
+v 0.390381 0.259251 -0.031584
+v 0.392743 0.247401 -0.031584
+v 0.392747 0.235317 -0.031584
+v 0.390394 0.223466 -0.031584
+v 0.385774 0.212301 -0.031584
+v 0.379064 0.202252 -0.031584
+v 0.370523 0.193705 -0.031584
+v 0.360479 0.186988 -0.031584
+v 0.349317 0.182360 -0.031584
+v 0.337467 0.179999 -0.031584
+v 0.316192 0.191128 -0.054117
+v 0.326280 0.189125 -0.054117
+v 0.306689 0.195061 -0.054117
+v 0.298135 0.200771 -0.054117
+v 0.290861 0.208041 -0.054117
+v 0.285144 0.216591 -0.054117
+v 0.281205 0.226091 -0.054117
+v 0.279195 0.236177 -0.054117
+v 0.279191 0.246462 -0.083504
+v 0.281194 0.256550 -0.083504
+v 0.285127 0.266053 -0.083504
+v 0.290838 0.274606 -0.083504
+v 0.298107 0.281881 -0.083504
+v 0.306657 0.287598 -0.083504
+v 0.316157 0.291537 -0.083504
+v 0.326243 0.293547 -0.083504
+v 0.336528 0.293550 -0.083504
+v 0.346616 0.291547 -0.083504
+v 0.356119 0.287615 -0.083504
+v 0.364672 0.281904 -0.083504
+v 0.371947 0.274634 -0.083504
+v 0.377664 0.266085 -0.083504
+v 0.381603 0.256585 -0.083504
+v 0.383613 0.246498 -0.083504
+v 0.383616 0.236214 -0.054117
+v 0.381613 0.226126 -0.054117
+v 0.377681 0.216623 -0.054117
+v 0.371970 0.208069 -0.054117
+v 0.364700 0.200795 -0.054117
+v 0.356151 0.195078 -0.054117
+v 0.346651 0.191139 -0.054117
+v 0.336564 0.189129 -0.054117
+v 0.313532 0.182348 -0.054117
+v 0.325384 0.179994 -0.054117
+v 0.302367 0.186968 -0.054117
+v 0.292318 0.193677 -0.054117
+v 0.283771 0.202218 -0.054117
+v 0.277054 0.212263 -0.054117
+v 0.272426 0.223425 -0.054117
+v 0.270065 0.235275 -0.054117
+v 0.270060 0.247358 -0.083504
+v 0.272414 0.259210 -0.083504
+v 0.277034 0.270375 -0.083504
+v 0.283743 0.280424 -0.083504
+v 0.292284 0.288971 -0.083504
+v 0.302329 0.295687 -0.083504
+v 0.313491 0.300315 -0.083504
+v 0.325341 0.302677 -0.083504
+v 0.337424 0.302681 -0.083504
+v 0.349276 0.300328 -0.083504
+v 0.360441 0.295708 -0.083504
+v 0.370490 0.288998 -0.083504
+v 0.379037 0.280457 -0.083504
+v 0.385753 0.270413 -0.083504
+v 0.390381 0.259251 -0.083504
+v 0.392743 0.247401 -0.083504
+v 0.392747 0.235317 -0.054117
+v 0.390394 0.223466 -0.054117
+v 0.385774 0.212301 -0.054117
+v 0.379064 0.202252 -0.054117
+v 0.370523 0.193705 -0.054117
+v 0.360479 0.186988 -0.054117
+v 0.349317 0.182360 -0.054117
+v 0.337467 0.179999 -0.054117
+v 0.331404 0.091338 -0.037331
+v 0.326280 0.039125 -0.037331
+v 0.316192 0.041128 -0.037331
+v 0.306689 0.045061 -0.037331
+v 0.298135 0.050771 -0.037331
+v 0.290861 0.058041 -0.037331
+v 0.285144 0.066591 -0.037331
+v 0.281205 0.076091 -0.037331
+v 0.279195 0.086177 -0.037331
+v 0.279191 0.096462 -0.037331
+v 0.281194 0.106550 -0.037331
+v 0.285127 0.116053 -0.037331
+v 0.290838 0.124606 -0.037331
+v 0.298107 0.131881 -0.037331
+v 0.306657 0.137598 -0.037331
+v 0.316157 0.141537 -0.037331
+v 0.326243 0.143547 -0.037331
+v 0.336528 0.143550 -0.037331
+v 0.346616 0.141547 -0.037331
+v 0.356119 0.137615 -0.037331
+v 0.364672 0.131904 -0.037331
+v 0.371947 0.124634 -0.037331
+v 0.377664 0.116085 -0.037331
+v 0.381603 0.106585 -0.037331
+v 0.383613 0.096498 -0.037331
+v 0.383616 0.086214 -0.037331
+v 0.381613 0.076126 -0.037331
+v 0.377681 0.066623 -0.037331
+v 0.371970 0.058069 -0.037331
+v 0.364700 0.050795 -0.037331
+v 0.356151 0.045078 -0.037331
+v 0.346651 0.041139 -0.037331
+v 0.336564 0.039129 -0.037331
+v 0.313532 0.032348 -0.031584
+v 0.325384 0.029994 -0.031584
+v 0.302367 0.036968 -0.031584
+v 0.292318 0.043677 -0.031584
+v 0.283771 0.052218 -0.031584
+v 0.277054 0.062263 -0.031584
+v 0.272426 0.073425 -0.031584
+v 0.270065 0.085275 -0.031584
+v 0.270060 0.097358 -0.031584
+v 0.272414 0.109210 -0.031584
+v 0.277034 0.120375 -0.031584
+v 0.283743 0.130424 -0.031584
+v 0.292285 0.138971 -0.031584
+v 0.302329 0.145687 -0.031584
+v 0.313491 0.150315 -0.031584
+v 0.325341 0.152677 -0.031584
+v 0.337424 0.152681 -0.031584
+v 0.349276 0.150328 -0.031584
+v 0.360441 0.145708 -0.031584
+v 0.370490 0.138998 -0.031584
+v 0.379037 0.130457 -0.031584
+v 0.385753 0.120412 -0.031584
+v 0.390381 0.109251 -0.031584
+v 0.392743 0.097401 -0.031584
+v 0.392747 0.085317 -0.031584
+v 0.390394 0.073466 -0.031584
+v 0.385774 0.062301 -0.031584
+v 0.379064 0.052252 -0.031584
+v 0.370523 0.043705 -0.031584
+v 0.360479 0.036988 -0.031584
+v 0.349317 0.032360 -0.031584
+v 0.337467 0.029999 -0.031584
+v 0.316192 0.041128 -0.054117
+v 0.326280 0.039125 -0.054117
+v 0.306689 0.045061 -0.054117
+v 0.298135 0.050771 -0.054117
+v 0.290861 0.058041 -0.054117
+v 0.285144 0.066591 -0.054117
+v 0.281205 0.076091 -0.054117
+v 0.279195 0.086177 -0.054117
+v 0.279191 0.096462 -0.083504
+v 0.281194 0.106550 -0.083504
+v 0.285127 0.116053 -0.083504
+v 0.290838 0.124606 -0.083504
+v 0.298107 0.131881 -0.083504
+v 0.306657 0.137598 -0.083504
+v 0.316157 0.141537 -0.083504
+v 0.326243 0.143547 -0.083504
+v 0.336528 0.143550 -0.083504
+v 0.346616 0.141547 -0.083504
+v 0.356119 0.137615 -0.083504
+v 0.364672 0.131904 -0.083504
+v 0.371947 0.124634 -0.083504
+v 0.377664 0.116085 -0.083504
+v 0.381603 0.106585 -0.083504
+v 0.383613 0.096498 -0.083504
+v 0.383616 0.086214 -0.054117
+v 0.381613 0.076126 -0.054117
+v 0.377681 0.066623 -0.054117
+v 0.371970 0.058069 -0.054117
+v 0.364700 0.050795 -0.054117
+v 0.356151 0.045078 -0.054117
+v 0.346651 0.041139 -0.054117
+v 0.336564 0.039129 -0.054117
+v 0.313532 0.032348 -0.054117
+v 0.325384 0.029994 -0.054117
+v 0.302367 0.036968 -0.054117
+v 0.292318 0.043677 -0.054117
+v 0.283771 0.052218 -0.054117
+v 0.277054 0.062263 -0.054117
+v 0.272426 0.073425 -0.054117
+v 0.270065 0.085275 -0.054117
+v 0.270060 0.097358 -0.083504
+v 0.272414 0.109210 -0.083504
+v 0.277034 0.120375 -0.083504
+v 0.283743 0.130424 -0.083504
+v 0.292284 0.138971 -0.083504
+v 0.302329 0.145687 -0.083504
+v 0.313491 0.150315 -0.083504
+v 0.325341 0.152677 -0.083504
+v 0.337424 0.152681 -0.083504
+v 0.349276 0.150328 -0.083504
+v 0.360441 0.145708 -0.083504
+v 0.370490 0.138998 -0.083504
+v 0.379037 0.130457 -0.083504
+v 0.385753 0.120412 -0.083504
+v 0.390381 0.109251 -0.083504
+v 0.392743 0.097401 -0.083504
+v 0.392747 0.085317 -0.054117
+v 0.390394 0.073466 -0.054117
+v 0.385774 0.062301 -0.054117
+v 0.379064 0.052252 -0.054117
+v 0.370523 0.043705 -0.054117
+v 0.360479 0.036988 -0.054117
+v 0.349317 0.032360 -0.054117
+v 0.337467 0.029999 -0.054117
+v 0.331404 -0.058662 -0.037331
+v 0.326280 -0.110875 -0.037331
+v 0.316192 -0.108872 -0.037331
+v 0.306689 -0.104939 -0.037331
+v 0.298135 -0.099229 -0.037331
+v 0.290861 -0.091959 -0.037331
+v 0.285144 -0.083409 -0.037331
+v 0.281205 -0.073909 -0.037331
+v 0.279195 -0.063823 -0.037331
+v 0.279191 -0.053538 -0.037331
+v 0.281194 -0.043450 -0.037331
+v 0.285127 -0.033947 -0.037331
+v 0.290838 -0.025394 -0.037331
+v 0.298107 -0.018119 -0.037331
+v 0.306657 -0.012402 -0.037331
+v 0.316157 -0.008463 -0.037331
+v 0.326243 -0.006453 -0.037331
+v 0.336528 -0.006450 -0.037331
+v 0.346616 -0.008453 -0.037331
+v 0.356119 -0.012385 -0.037331
+v 0.364672 -0.018096 -0.037331
+v 0.371947 -0.025366 -0.037331
+v 0.377664 -0.033915 -0.037331
+v 0.381603 -0.043415 -0.037331
+v 0.383613 -0.053502 -0.037331
+v 0.383616 -0.063786 -0.037331
+v 0.381613 -0.073874 -0.037331
+v 0.377681 -0.083377 -0.037331
+v 0.371970 -0.091931 -0.037331
+v 0.364700 -0.099205 -0.037331
+v 0.356151 -0.104922 -0.037331
+v 0.346651 -0.108861 -0.037331
+v 0.336564 -0.110871 -0.037331
+v 0.313532 -0.117652 -0.031584
+v 0.325384 -0.120006 -0.031584
+v 0.302367 -0.113032 -0.031584
+v 0.292318 -0.106323 -0.031584
+v 0.283771 -0.097782 -0.031584
+v 0.277054 -0.087737 -0.031584
+v 0.272426 -0.076575 -0.031584
+v 0.270065 -0.064725 -0.031584
+v 0.270060 -0.052642 -0.031584
+v 0.272414 -0.040790 -0.031584
+v 0.277034 -0.029625 -0.031584
+v 0.283743 -0.019576 -0.031584
+v 0.292285 -0.011029 -0.031584
+v 0.302329 -0.004313 -0.031584
+v 0.313491 0.000315 -0.031584
+v 0.325341 0.002677 -0.031584
+v 0.337424 0.002681 -0.031584
+v 0.349276 0.000328 -0.031584
+v 0.360441 -0.004292 -0.031584
+v 0.370490 -0.011002 -0.031584
+v 0.379037 -0.019543 -0.031584
+v 0.385753 -0.029587 -0.031584
+v 0.390381 -0.040749 -0.031584
+v 0.392743 -0.052599 -0.031584
+v 0.392747 -0.064683 -0.031584
+v 0.390394 -0.076534 -0.031584
+v 0.385774 -0.087699 -0.031584
+v 0.379064 -0.097748 -0.031584
+v 0.370523 -0.106295 -0.031584
+v 0.360479 -0.113012 -0.031584
+v 0.349317 -0.117640 -0.031584
+v 0.337467 -0.120001 -0.031584
+v 0.316192 -0.108872 -0.054117
+v 0.326280 -0.110875 -0.054117
+v 0.306689 -0.104939 -0.054117
+v 0.298135 -0.099229 -0.054117
+v 0.290861 -0.091959 -0.054117
+v 0.285144 -0.083409 -0.054117
+v 0.281205 -0.073909 -0.054117
+v 0.279195 -0.063823 -0.054117
+v 0.279191 -0.053538 -0.083504
+v 0.281194 -0.043450 -0.083504
+v 0.285127 -0.033947 -0.083504
+v 0.290838 -0.025394 -0.083504
+v 0.298107 -0.018119 -0.083504
+v 0.306657 -0.012402 -0.083504
+v 0.316157 -0.008463 -0.083504
+v 0.326243 -0.006453 -0.083504
+v 0.336528 -0.006450 -0.083504
+v 0.346616 -0.008453 -0.083504
+v 0.356119 -0.012385 -0.083504
+v 0.364672 -0.018096 -0.083504
+v 0.371947 -0.025366 -0.083504
+v 0.377664 -0.033915 -0.083504
+v 0.381603 -0.043415 -0.083504
+v 0.383613 -0.053502 -0.083504
+v 0.383616 -0.063786 -0.054117
+v 0.381613 -0.073874 -0.054117
+v 0.377681 -0.083377 -0.054117
+v 0.371970 -0.091931 -0.054117
+v 0.364700 -0.099205 -0.054117
+v 0.356151 -0.104922 -0.054117
+v 0.346651 -0.108861 -0.054117
+v 0.336564 -0.110871 -0.054117
+v 0.313532 -0.117652 -0.054117
+v 0.325384 -0.120006 -0.054117
+v 0.302367 -0.113032 -0.054117
+v 0.292318 -0.106323 -0.054117
+v 0.283771 -0.097782 -0.054117
+v 0.277054 -0.087737 -0.054117
+v 0.272426 -0.076575 -0.054117
+v 0.270065 -0.064725 -0.054117
+v 0.270060 -0.052642 -0.083504
+v 0.272414 -0.040790 -0.083504
+v 0.277034 -0.029625 -0.083504
+v 0.283743 -0.019576 -0.083504
+v 0.292284 -0.011029 -0.083504
+v 0.302329 -0.004313 -0.083504
+v 0.313491 0.000315 -0.083504
+v 0.325341 0.002677 -0.083504
+v 0.337424 0.002681 -0.083504
+v 0.349276 0.000328 -0.083504
+v 0.360441 -0.004292 -0.083504
+v 0.370490 -0.011002 -0.083504
+v 0.379037 -0.019543 -0.083504
+v 0.385753 -0.029587 -0.083504
+v 0.390381 -0.040749 -0.083504
+v 0.392743 -0.052599 -0.083504
+v 0.392747 -0.064683 -0.054117
+v 0.390394 -0.076534 -0.054117
+v 0.385774 -0.087699 -0.054117
+v 0.379064 -0.097748 -0.054117
+v 0.370523 -0.106295 -0.054117
+v 0.360479 -0.113012 -0.054117
+v 0.349317 -0.117640 -0.054117
+v 0.337467 -0.120001 -0.054117
+v 0.331404 -0.208662 -0.037331
+v 0.326280 -0.260875 -0.037331
+v 0.316192 -0.258872 -0.037331
+v 0.306689 -0.254939 -0.037331
+v 0.298135 -0.249229 -0.037331
+v 0.290861 -0.241959 -0.037331
+v 0.285144 -0.233410 -0.037331
+v 0.281205 -0.223909 -0.037331
+v 0.279195 -0.213823 -0.037331
+v 0.279191 -0.203538 -0.037331
+v 0.281194 -0.193450 -0.037331
+v 0.285127 -0.183947 -0.037331
+v 0.290838 -0.175394 -0.037331
+v 0.298107 -0.168119 -0.037331
+v 0.306657 -0.162402 -0.037331
+v 0.316157 -0.158463 -0.037331
+v 0.326243 -0.156453 -0.037331
+v 0.336528 -0.156450 -0.037331
+v 0.346616 -0.158453 -0.037331
+v 0.356119 -0.162385 -0.037331
+v 0.364672 -0.168096 -0.037331
+v 0.371947 -0.175366 -0.037331
+v 0.377664 -0.183915 -0.037331
+v 0.381603 -0.193415 -0.037331
+v 0.383613 -0.203502 -0.037331
+v 0.383616 -0.213786 -0.037331
+v 0.381613 -0.223874 -0.037331
+v 0.377681 -0.233377 -0.037331
+v 0.371970 -0.241931 -0.037331
+v 0.364700 -0.249205 -0.037331
+v 0.356151 -0.254922 -0.037331
+v 0.346651 -0.258861 -0.037331
+v 0.336564 -0.260871 -0.037331
+v 0.313532 -0.267652 -0.031584
+v 0.325384 -0.270006 -0.031584
+v 0.302367 -0.263032 -0.031584
+v 0.292318 -0.256323 -0.031584
+v 0.283771 -0.247782 -0.031584
+v 0.277054 -0.237737 -0.031584
+v 0.272426 -0.226575 -0.031584
+v 0.270065 -0.214725 -0.031584
+v 0.270060 -0.202642 -0.031584
+v 0.272414 -0.190790 -0.031584
+v 0.277034 -0.179625 -0.031584
+v 0.283743 -0.169576 -0.031584
+v 0.292285 -0.161029 -0.031584
+v 0.302329 -0.154313 -0.031584
+v 0.313491 -0.149685 -0.031584
+v 0.325341 -0.147323 -0.031584
+v 0.337424 -0.147319 -0.031584
+v 0.349276 -0.149672 -0.031584
+v 0.360441 -0.154292 -0.031584
+v 0.370490 -0.161002 -0.031584
+v 0.379037 -0.169543 -0.031584
+v 0.385753 -0.179587 -0.031584
+v 0.390381 -0.190749 -0.031584
+v 0.392743 -0.202599 -0.031584
+v 0.392747 -0.214683 -0.031584
+v 0.390394 -0.226534 -0.031584
+v 0.385774 -0.237699 -0.031584
+v 0.379064 -0.247748 -0.031584
+v 0.370523 -0.256295 -0.031584
+v 0.360479 -0.263012 -0.031584
+v 0.349317 -0.267640 -0.031584
+v 0.337467 -0.270001 -0.031584
+v 0.316192 -0.258872 -0.054117
+v 0.326280 -0.260875 -0.054117
+v 0.306689 -0.254939 -0.054117
+v 0.298135 -0.249229 -0.054117
+v 0.290861 -0.241959 -0.054117
+v 0.285144 -0.233410 -0.054117
+v 0.281205 -0.223909 -0.054117
+v 0.279195 -0.213823 -0.054117
+v 0.279191 -0.203538 -0.083504
+v 0.281194 -0.193450 -0.083504
+v 0.285127 -0.183947 -0.083504
+v 0.290838 -0.175394 -0.083504
+v 0.298107 -0.168119 -0.083504
+v 0.306657 -0.162402 -0.083504
+v 0.316157 -0.158463 -0.083504
+v 0.326243 -0.156453 -0.083504
+v 0.336528 -0.156450 -0.083504
+v 0.346616 -0.158453 -0.083504
+v 0.356119 -0.162385 -0.083504
+v 0.364672 -0.168096 -0.083504
+v 0.371947 -0.175366 -0.083504
+v 0.377664 -0.183915 -0.083504
+v 0.381603 -0.193415 -0.083504
+v 0.383613 -0.203502 -0.083504
+v 0.383616 -0.213786 -0.054117
+v 0.381613 -0.223874 -0.054117
+v 0.377681 -0.233377 -0.054117
+v 0.371970 -0.241931 -0.054117
+v 0.364700 -0.249205 -0.054117
+v 0.356151 -0.254922 -0.054117
+v 0.346651 -0.258861 -0.054117
+v 0.336564 -0.260871 -0.054117
+v 0.313532 -0.267652 -0.054117
+v 0.325384 -0.270006 -0.054117
+v 0.302367 -0.263032 -0.054117
+v 0.292318 -0.256323 -0.054117
+v 0.283771 -0.247782 -0.054117
+v 0.277054 -0.237737 -0.054117
+v 0.272426 -0.226575 -0.054117
+v 0.270065 -0.214725 -0.054117
+v 0.270060 -0.202642 -0.083504
+v 0.272414 -0.190790 -0.083504
+v 0.277034 -0.179625 -0.083504
+v 0.283743 -0.169576 -0.083504
+v 0.292284 -0.161029 -0.083504
+v 0.302329 -0.154313 -0.083504
+v 0.313491 -0.149685 -0.083504
+v 0.325341 -0.147323 -0.083504
+v 0.337424 -0.147319 -0.083504
+v 0.349276 -0.149672 -0.083504
+v 0.360441 -0.154292 -0.083504
+v 0.370490 -0.161002 -0.083504
+v 0.379037 -0.169543 -0.083504
+v 0.385753 -0.179587 -0.083504
+v 0.390381 -0.190749 -0.083504
+v 0.392743 -0.202599 -0.083504
+v 0.392747 -0.214683 -0.054117
+v 0.390394 -0.226534 -0.054117
+v 0.385774 -0.237699 -0.054117
+v 0.379064 -0.247748 -0.054117
+v 0.370523 -0.256295 -0.054117
+v 0.360479 -0.263012 -0.054117
+v 0.349317 -0.267640 -0.054117
+v 0.337467 -0.270001 -0.054117
+vn -0.0000 -1.0000 -0.0000
+vn -0.0000 1.0000 -0.0000
+vn -1.0000 -0.0000 -0.0000
+vn -0.0000 -0.0000 -1.0000
+vn -0.0000 -0.0000 1.0000
+vn 1.0000 -0.0000 -0.0000
+vn 0.3830 -0.9237 -0.0000
+vn -0.1954 0.9807 -0.0000
+vn -0.8313 -0.5559 -0.0000
+vn -0.0003 1.0000 -0.0000
+vn 0.9237 0.3830 -0.0000
+vn -0.9807 -0.1954 -0.0000
+vn -0.1947 -0.9809 -0.0000
+vn -0.7073 0.7069 -0.0000
+vn 0.5559 -0.8313 -0.0000
+vn -0.3830 0.9237 -0.0000
+vn 0.3824 0.9240 -0.0000
+vn -1.0000 -0.0003 -0.0000
+vn 0.8313 0.5559 -0.0000
+vn -0.9237 -0.3830 -0.0000
+vn 0.9809 -0.1947 -0.0000
+vn 0.7074 -0.7069 -0.0000
+vn -0.5559 0.8313 -0.0000
+vn -0.7069 -0.7074 -0.0000
+vn 0.7069 0.7073 -0.0000
+vn 0.0003 -1.0000 -0.0000
+vn -0.8317 0.5553 -0.0000
+vn 0.8317 -0.5553 -0.0000
+vn -0.7074 0.7069 -0.0000
+vn 0.5553 0.8317 -0.0000
+vn 0.0003 -0.9346 -0.3557
+vn 0.9240 -0.3824 -0.0000
+vn -1.0000 -0.0004 -0.0000
+vn 0.9807 0.1954 -0.0000
+vn -0.9809 0.1948 -0.0000
+vn -0.1948 -0.9809 -0.0000
+vn 0.1954 -0.9807 -0.0000
+vn -0.3824 -0.9240 -0.0000
+vn 1.0000 0.0004 -0.0000
+vn 0.1947 0.9809 -0.0000
+vn -0.9240 0.3824 -0.0000
+vn -0.5553 -0.8317 -0.0000
+vn 0.7069 0.7074 -0.0000
+vn 1.0000 0.0003 -0.0000
+vn 0.7073 -0.7069 -0.0000
+vn -0.0004 1.0000 -0.0000
+vt 0.640016 0.630686
+vt 0.874116 0.630686
+vt 0.899031 0.371671
+vt 0.899031 0.605771
+vt 0.275073 0.371671
+vt 0.275073 0.605771
+vt 0.536051 0.632649
+vt 0.301951 0.632649
+vt 0.588281 0.578951
+vt 0.588281 0.344851
+vt 0.847296 0.319936
+vt 0.613196 0.319936
+vt 0.326808 0.319936
+vt 0.560909 0.319936
+vt 0.587786 0.580914
+vt 0.587786 0.346814
+vt 0.757066 0.513636
+vt 0.781981 0.488721
+vt 0.392123 0.488721
+vt 0.419001 0.515599
+vt 0.705331 0.461901
+vt 0.730246 0.436986
+vt 0.443858 0.436986
+vt 0.470736 0.463864
+vt 0.062341 0.000247
+vt 0.000247 0.062341
+vt 0.000248 0.359598
+vt 0.039909 0.319936
+vt 0.662834 0.000247
+vt 0.724927 0.062341
+vt 0.000247 0.960091
+vt 0.039910 0.999753
+vt 0.062341 0.062341
+vt 0.662834 0.062341
+vt 0.062341 0.319441
+vt 0.000247 0.257348
+vt 0.274579 0.359598
+vt 0.234916 0.319936
+vt 0.662834 0.319441
+vt 0.724927 0.257348
+vt 0.274579 0.960090
+vt 0.234917 0.999753
+vt 0.062341 0.257348
+vt 0.662834 0.257348
+vt 0.079095 0.359121
+vt 0.039433 0.398784
+vt 0.079095 0.960567
+vt 0.039433 0.920905
+vt 0.195731 0.960567
+vt 0.235393 0.920905
+vt 0.195731 0.359121
+vt 0.235393 0.398783
+vt 0.079095 0.398783
+vt 0.079095 0.920905
+vt 0.195731 0.920905
+vt 0.195731 0.398783
+vt 0.629899 0.095275
+vt 0.095275 0.095275
+vt 0.629899 0.224413
+vt 0.095275 0.224413
+vt 0.753412 0.903011
+vt 0.719354 0.930961
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.714555 0.923780
+vt 0.602565 0.932389
+vt 0.711250 0.915800
+vt 0.593928 0.932389
+vt 0.709565 0.907329
+vt 0.585291 0.932389
+vt 0.709565 0.898692
+vt 0.576654 0.932389
+vt 0.711250 0.890221
+vt 0.568017 0.932389
+vt 0.714556 0.882241
+vt 0.559379 0.932389
+vt 0.719354 0.875060
+vt 0.550742 0.932389
+vt 0.725461 0.868952
+vt 0.542105 0.932389
+vt 0.732643 0.864154
+vt 0.533468 0.932389
+vt 0.740623 0.860849
+vt 0.524831 0.932389
+vt 0.749094 0.859164
+vt 0.516194 0.932389
+vt 0.757731 0.859164
+vt 0.507557 0.932389
+vt 0.766202 0.860849
+vt 0.498920 0.932389
+vt 0.774182 0.864154
+vt 0.490283 0.932389
+vt 0.781363 0.868953
+vt 0.481646 0.932389
+vt 0.787470 0.875060
+vt 0.473009 0.932389
+vt 0.792269 0.882241
+vt 0.464371 0.932389
+vt 0.795574 0.890221
+vt 0.455734 0.932389
+vt 0.797259 0.898692
+vt 0.447097 0.932389
+vt 0.797259 0.907329
+vt 0.438460 0.932389
+vt 0.795574 0.915800
+vt 0.429823 0.932389
+vt 0.792269 0.923780
+vt 0.421186 0.932389
+vt 0.787470 0.930962
+vt 0.412549 0.932389
+vt 0.781363 0.937069
+vt 0.403912 0.932389
+vt 0.774181 0.941867
+vt 0.395275 0.932389
+vt 0.766201 0.945173
+vt 0.386637 0.932389
+vt 0.757730 0.946858
+vt 0.378001 0.932389
+vt 0.749093 0.946858
+vt 0.369363 0.932389
+vt 0.740622 0.945172
+vt 0.360726 0.932389
+vt 0.732643 0.941867
+vt 0.352089 0.932388
+vt 0.725461 0.937069
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.752599 0.742115
+vt 0.718541 0.770066
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.713742 0.762885
+vt 0.602565 0.932389
+vt 0.710437 0.754905
+vt 0.593928 0.932389
+vt 0.708752 0.746434
+vt 0.585291 0.932389
+vt 0.708752 0.737797
+vt 0.576654 0.932389
+vt 0.710437 0.729326
+vt 0.568017 0.932389
+vt 0.713743 0.721346
+vt 0.559379 0.932389
+vt 0.718541 0.714165
+vt 0.550742 0.932389
+vt 0.724649 0.708057
+vt 0.542105 0.932389
+vt 0.731830 0.703259
+vt 0.533468 0.932389
+vt 0.739810 0.699954
+vt 0.524831 0.932389
+vt 0.748281 0.698269
+vt 0.516194 0.932389
+vt 0.756918 0.698269
+vt 0.507557 0.932389
+vt 0.765389 0.699954
+vt 0.498920 0.932389
+vt 0.773369 0.703259
+vt 0.490283 0.932389
+vt 0.780550 0.708058
+vt 0.481646 0.932389
+vt 0.786658 0.714165
+vt 0.473009 0.932389
+vt 0.791456 0.721346
+vt 0.464371 0.932389
+vt 0.794761 0.729326
+vt 0.455734 0.932389
+vt 0.796446 0.737797
+vt 0.447097 0.932389
+vt 0.796446 0.746434
+vt 0.438460 0.932389
+vt 0.794761 0.754905
+vt 0.429823 0.932389
+vt 0.791456 0.762885
+vt 0.421186 0.932389
+vt 0.786657 0.770066
+vt 0.412549 0.932389
+vt 0.780550 0.776174
+vt 0.403912 0.932389
+vt 0.773368 0.780972
+vt 0.395275 0.932389
+vt 0.765389 0.784277
+vt 0.386637 0.932389
+vt 0.756917 0.785962
+vt 0.378001 0.932389
+vt 0.748280 0.785962
+vt 0.369363 0.932389
+vt 0.739809 0.784277
+vt 0.360726 0.932389
+vt 0.731830 0.780972
+vt 0.352089 0.932388
+vt 0.724648 0.776174
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.908735 0.903617
+vt 0.874676 0.931567
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.869878 0.924386
+vt 0.602565 0.932389
+vt 0.866572 0.916406
+vt 0.593928 0.932389
+vt 0.864888 0.907935
+vt 0.585291 0.932389
+vt 0.864888 0.899298
+vt 0.576654 0.932389
+vt 0.866573 0.890827
+vt 0.568017 0.932389
+vt 0.869878 0.882847
+vt 0.559379 0.932389
+vt 0.874676 0.875666
+vt 0.550742 0.932389
+vt 0.880784 0.869558
+vt 0.542105 0.932389
+vt 0.887965 0.864760
+vt 0.533468 0.932389
+vt 0.895945 0.861455
+vt 0.524831 0.932389
+vt 0.904416 0.859770
+vt 0.516194 0.932389
+vt 0.913053 0.859770
+vt 0.507557 0.932389
+vt 0.921524 0.861455
+vt 0.498920 0.932389
+vt 0.929504 0.864760
+vt 0.490283 0.932389
+vt 0.936685 0.869559
+vt 0.481646 0.932389
+vt 0.942793 0.875666
+vt 0.473009 0.932389
+vt 0.947591 0.882847
+vt 0.464371 0.932389
+vt 0.950896 0.890827
+vt 0.455734 0.932389
+vt 0.952581 0.899298
+vt 0.447097 0.932389
+vt 0.952581 0.907935
+vt 0.438460 0.932389
+vt 0.950896 0.916406
+vt 0.429823 0.932389
+vt 0.947591 0.924386
+vt 0.421186 0.932389
+vt 0.942792 0.931568
+vt 0.412549 0.932389
+vt 0.936685 0.937675
+vt 0.403912 0.932389
+vt 0.929504 0.942473
+vt 0.395275 0.932389
+vt 0.921524 0.945779
+vt 0.386637 0.932389
+vt 0.913053 0.947464
+vt 0.378001 0.932389
+vt 0.904416 0.947464
+vt 0.369363 0.932389
+vt 0.895945 0.945778
+vt 0.360726 0.932389
+vt 0.887965 0.942473
+vt 0.352089 0.932388
+vt 0.880783 0.937675
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.908268 0.746864
+vt 0.874210 0.774814
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.869411 0.767633
+vt 0.602565 0.932389
+vt 0.866106 0.759653
+vt 0.593928 0.932389
+vt 0.864421 0.751182
+vt 0.585291 0.932389
+vt 0.864421 0.742545
+vt 0.576654 0.932389
+vt 0.866106 0.734074
+vt 0.568017 0.932389
+vt 0.869412 0.726094
+vt 0.559379 0.932389
+vt 0.874210 0.718913
+vt 0.550742 0.932389
+vt 0.880318 0.712805
+vt 0.542105 0.932389
+vt 0.887499 0.708007
+vt 0.533468 0.932389
+vt 0.895479 0.704702
+vt 0.524831 0.932389
+vt 0.903950 0.703017
+vt 0.516194 0.932389
+vt 0.912587 0.703017
+vt 0.507557 0.932389
+vt 0.921058 0.704702
+vt 0.498920 0.932389
+vt 0.929038 0.708007
+vt 0.490283 0.932389
+vt 0.936219 0.712806
+vt 0.481646 0.932389
+vt 0.942326 0.718913
+vt 0.473009 0.932389
+vt 0.947125 0.726095
+vt 0.464371 0.932389
+vt 0.950430 0.734074
+vt 0.455734 0.932389
+vt 0.952115 0.742545
+vt 0.447097 0.932389
+vt 0.952115 0.751182
+vt 0.438460 0.932389
+vt 0.950430 0.759654
+vt 0.429823 0.932389
+vt 0.947125 0.767633
+vt 0.421186 0.932389
+vt 0.942326 0.774815
+vt 0.412549 0.932389
+vt 0.936219 0.780922
+vt 0.403912 0.932389
+vt 0.929037 0.785721
+vt 0.395275 0.932389
+vt 0.921058 0.789026
+vt 0.386637 0.932389
+vt 0.912586 0.790711
+vt 0.378001 0.932389
+vt 0.903949 0.790711
+vt 0.369363 0.932389
+vt 0.895478 0.789025
+vt 0.360726 0.932389
+vt 0.887499 0.785720
+vt 0.352089 0.932388
+vt 0.880317 0.780922
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+s 0
+g Cube_Material
+usemtl Material
+f 6/11/1 2/3/1 10/18/1 14/22/1
+f 1/1/2 5/9/2 13/21/2 9/17/2
+f 12/20/3 11/19/3 15/23/3 16/24/3
+f 10/18/3 9/17/3 13/21/3 14/22/3
+f 3/5/2 7/13/2 15/23/2 11/19/2
+f 8/15/1 4/7/1 12/20/1 16/24/1
+f 7/14/4 8/16/4 16/24/4 15/23/4
+f 5/10/4 6/12/4 14/22/4 13/21/4
+f 4/8/5 3/6/5 11/19/5 12/20/5
+f 2/4/5 1/2/5 9/17/5 10/18/5
+f 18/29/3 20/34/3 19/33/3 17/25/3
+f 33/57/4 35/59/4 36/60/4 34/58/4
+f 24/44/6 22/39/6 21/35/6 23/43/6
+f 25/45/1 28/51/1 32/56/1 29/53/1
+f 17/26/1 19/33/1 23/43/1 21/36/1
+f 22/40/2 24/44/2 20/34/2 18/30/2
+f 25/46/5 26/48/5 18/31/5 17/27/5
+f 27/50/5 28/52/5 21/37/5 22/41/5
+f 26/47/5 27/49/5 22/42/5 18/32/5
+f 28/51/5 25/45/5 17/28/5 21/38/5
+f 31/55/5 30/54/5 29/53/5 32/56/5
+f 27/49/2 26/47/2 30/54/2 31/55/2
+f 28/52/6 27/50/6 31/55/6 32/56/6
+f 26/48/3 25/46/3 29/53/3 30/54/3
+f 33/57/4 34/58/4 19/33/4 20/34/4
+f 35/59/4 33/57/4 20/34/4 24/44/4
+f 36/60/4 35/59/4 24/44/4 23/43/4
+f 34/58/4 36/60/4 23/43/4 19/33/4
+f 37/61/4 38/62/4 39/65/4
+f 37/61/4 39/65/4 40/67/4
+f 37/61/4 40/67/4 41/69/4
+f 37/61/4 41/69/4 42/71/4
+f 37/61/4 42/71/4 43/73/4
+f 37/61/4 43/73/4 44/75/4
+f 37/61/4 44/75/4 45/77/4
+f 37/61/4 45/77/4 46/79/4
+f 37/61/4 46/79/4 47/81/4
+f 37/61/4 47/81/4 48/83/4
+f 37/61/4 48/83/4 49/85/4
+f 37/61/4 49/85/4 50/87/4
+f 37/61/4 50/87/4 51/89/4
+f 37/61/4 51/89/4 52/91/4
+f 37/61/4 52/91/4 53/93/4
+f 37/61/4 53/93/4 54/95/4
+f 37/61/4 54/95/4 55/97/4
+f 37/61/4 55/97/4 56/99/4
+f 37/61/4 56/99/4 57/101/4
+f 37/61/4 57/101/4 58/103/4
+f 37/61/4 58/103/4 59/105/4
+f 37/61/4 59/105/4 60/107/4
+f 37/61/4 60/107/4 61/109/4
+f 37/61/4 61/109/4 62/111/4
+f 37/61/4 62/111/4 63/113/4
+f 37/61/4 63/113/4 64/115/4
+f 37/61/4 64/115/4 65/117/4
+f 37/61/4 65/117/4 66/119/4
+f 37/61/4 66/119/4 67/121/4
+f 37/61/4 67/121/4 68/123/4
+f 37/61/4 68/123/4 69/125/4
+f 37/61/4 69/125/4 38/62/4
+f 99/156/7 100/157/7 164/290/7 163/287/7
+f 84/141/8 85/142/8 149/259/8 148/256/8
+f 59/106/9 58/104/9 122/202/9 123/205/9
+f 38/63/10 69/126/10 133/225/10 103/162/10
+f 44/76/11 43/74/11 107/171/11 108/174/11
+f 91/148/11 92/149/11 156/273/11 155/270/11
+f 76/133/12 77/134/12 141/243/12 140/239/12
+f 55/98/13 54/96/13 118/194/13 119/197/13
+f 66/120/14 65/118/14 129/217/14 130/220/14
+f 98/155/15 99/156/15 163/287/15 162/285/15
+f 83/140/16 84/141/16 148/256/16 147/254/16
+f 40/68/17 39/66/17 102/161/17 104/166/17
+f 51/90/15 50/88/15 114/186/15 115/189/15
+f 62/112/18 61/110/18 125/208/18 126/212/18
+f 90/147/19 91/148/19 155/270/19 154/268/19
+f 75/132/20 76/133/20 140/239/20 139/237/20
+f 47/82/21 46/80/21 110/179/21 111/181/21
+f 97/154/22 98/155/22 162/285/22 161/283/22
+f 82/139/23 83/140/23 147/254/23 146/252/23
+f 58/104/24 57/102/24 121/201/24 122/202/24
+f 69/126/8 68/124/8 132/224/8 133/225/8
+f 89/146/25 90/147/25 154/268/25 153/266/25
+f 43/74/19 42/72/19 106/170/19 107/171/19
+f 54/96/26 53/94/26 117/193/26 118/194/26
+f 74/131/9 75/132/9 139/237/9 138/235/9
+f 65/118/27 64/116/27 128/216/27 129/217/27
+f 96/153/28 97/154/28 161/283/28 160/282/28
+f 81/138/29 82/139/29 146/252/29 145/251/29
+f 50/88/22 49/86/22 113/185/22 114/186/22
+f 88/145/30 89/146/30 153/266/30 152/265/30
+f 61/110/12 60/108/12 124/207/12 125/208/12
+f 73/130/24 74/131/24 138/235/24 137/234/24
+f 102/160/4 103/163/4 135/229/4 134/227/4
+f 104/165/4 102/160/4 134/227/4 136/231/4
+f 105/167/4 104/165/4 136/231/4 137/233/4
+f 106/169/4 105/167/4 137/233/4 138/236/4
+f 107/172/4 106/169/4 138/236/4 139/238/4
+f 108/173/4 107/172/4 139/238/4 140/240/4
+f 109/175/4 108/173/4 140/240/4 141/241/4
+f 110/178/31 109/176/31 141/242/31 142/244/31
+f 111/180/4 110/178/4 142/244/4 143/246/4
+f 112/182/4 111/180/4 143/246/4 144/248/4
+f 113/184/4 112/182/4 144/248/4 145/250/4
+f 114/187/4 113/184/4 145/250/4 146/253/4
+f 115/188/4 114/187/4 146/253/4 147/255/4
+f 116/190/4 115/188/4 147/255/4 148/257/4
+f 117/192/4 116/190/4 148/257/4 149/258/4
+f 118/195/4 117/192/4 149/258/4 150/260/4
+f 119/196/4 118/195/4 150/260/4 151/262/4
+f 120/198/4 119/196/4 151/262/4 152/264/4
+f 121/200/4 120/198/4 152/264/4 153/267/4
+f 122/203/4 121/200/4 153/267/4 154/269/4
+f 123/204/4 122/203/4 154/269/4 155/271/4
+f 124/206/4 123/204/4 155/271/4 156/272/4
+f 125/209/4 124/206/4 156/272/4 157/274/4
+f 126/210/31 125/209/31 157/274/31 158/276/31
+f 127/213/4 126/211/4 158/277/4 159/279/4
+f 128/215/4 127/213/4 159/279/4 160/281/4
+f 129/218/4 128/215/4 160/281/4 161/284/4
+f 130/219/4 129/218/4 161/284/4 162/286/4
+f 131/221/4 130/219/4 162/286/4 163/288/4
+f 132/223/4 131/221/4 163/288/4 164/289/4
+f 133/226/4 132/223/4 164/289/4 165/291/4
+f 103/163/4 133/226/4 165/291/4 135/229/4
+f 48/84/32 47/82/32 111/181/32 112/183/32
+f 77/134/33 78/135/33 142/245/33 141/243/33
+f 92/149/34 93/150/34 157/275/34 156/273/34
+f 63/114/35 62/112/35 126/212/35 127/214/35
+f 52/92/7 51/90/7 115/189/7 116/191/7
+f 71/128/36 70/127/36 134/228/36 135/230/36
+f 41/70/30 40/68/30 104/166/30 105/168/30
+f 85/142/10 86/143/10 150/261/10 149/259/10
+f 100/157/37 101/158/37 165/292/37 164/290/37
+f 67/122/23 66/120/23 130/220/23 131/222/23
+f 56/100/38 55/98/38 119/197/38 120/199/38
+f 78/135/35 79/136/35 143/247/35 142/245/35
+f 93/150/39 94/151/39 158/278/39 157/275/39
+f 45/78/34 44/76/34 108/174/34 109/177/34
+f 70/127/38 72/129/38 136/232/38 134/228/38
+f 60/108/20 59/106/20 123/205/20 124/207/20
+f 86/143/40 87/144/40 151/263/40 150/261/40
+f 101/159/26 71/128/26 135/230/26 165/293/26
+f 49/86/28 48/84/28 112/183/28 113/185/28
+f 79/136/41 80/137/41 144/249/41 143/247/41
+f 94/151/21 95/152/21 159/280/21 158/278/21
+f 64/116/41 63/114/41 127/214/41 128/216/41
+f 53/94/37 52/92/37 116/191/37 117/193/37
+f 72/129/42 73/130/42 137/234/42 136/232/42
+f 42/72/43 41/70/43 105/168/43 106/170/43
+f 87/144/17 88/145/17 152/265/17 151/263/17
+f 68/124/16 67/122/16 131/222/16 132/224/16
+f 39/66/40 38/64/40 103/164/40 102/161/40
+f 57/102/42 56/100/42 120/199/42 121/201/42
+f 80/137/27 81/138/27 145/251/27 144/249/27
+f 95/152/32 96/153/32 160/282/32 159/280/32
+f 46/80/44 45/78/44 109/177/44 110/179/44
+f 166/294/4 167/295/4 168/298/4
+f 166/294/4 168/298/4 169/300/4
+f 166/294/4 169/300/4 170/302/4
+f 166/294/4 170/302/4 171/304/4
+f 166/294/4 171/304/4 172/306/4
+f 166/294/4 172/306/4 173/308/4
+f 166/294/4 173/308/4 174/310/4
+f 166/294/4 174/310/4 175/312/4
+f 166/294/4 175/312/4 176/314/4
+f 166/294/4 176/314/4 177/316/4
+f 166/294/4 177/316/4 178/318/4
+f 166/294/4 178/318/4 179/320/4
+f 166/294/4 179/320/4 180/322/4
+f 166/294/4 180/322/4 181/324/4
+f 166/294/4 181/324/4 182/326/4
+f 166/294/4 182/326/4 183/328/4
+f 166/294/4 183/328/4 184/330/4
+f 166/294/4 184/330/4 185/332/4
+f 166/294/4 185/332/4 186/334/4
+f 166/294/4 186/334/4 187/336/4
+f 166/294/4 187/336/4 188/338/4
+f 166/294/4 188/338/4 189/340/4
+f 166/294/4 189/340/4 190/342/4
+f 166/294/4 190/342/4 191/344/4
+f 166/294/4 191/344/4 192/346/4
+f 166/294/4 192/346/4 193/348/4
+f 166/294/4 193/348/4 194/350/4
+f 166/294/4 194/350/4 195/352/4
+f 166/294/4 195/352/4 196/354/4
+f 166/294/4 196/354/4 197/356/4
+f 166/294/4 197/356/4 198/358/4
+f 166/294/4 198/358/4 167/295/4
+f 228/389/7 229/390/7 293/523/7 292/520/7
+f 213/374/8 214/375/8 278/492/8 277/489/8
+f 188/339/9 187/337/9 251/435/9 252/438/9
+f 167/296/10 198/359/10 262/458/10 232/395/10
+f 173/309/11 172/307/11 236/404/11 237/407/11
+f 220/381/11 221/382/11 285/506/11 284/503/11
+f 205/366/12 206/367/12 270/476/12 269/472/12
+f 184/331/13 183/329/13 247/427/13 248/430/13
+f 195/353/14 194/351/14 258/450/14 259/453/14
+f 227/388/15 228/389/15 292/520/15 291/518/15
+f 212/373/16 213/374/16 277/489/16 276/487/16
+f 169/301/17 168/299/17 231/394/17 233/399/17
+f 180/323/15 179/321/15 243/419/15 244/422/15
+f 191/345/18 190/343/18 254/441/18 255/445/18
+f 219/380/19 220/381/19 284/503/19 283/501/19
+f 204/365/20 205/366/20 269/472/20 268/470/20
+f 176/315/21 175/313/21 239/412/21 240/414/21
+f 226/387/22 227/388/22 291/518/22 290/516/22
+f 211/372/23 212/373/23 276/487/23 275/485/23
+f 187/337/24 186/335/24 250/434/24 251/435/24
+f 198/359/8 197/357/8 261/457/8 262/458/8
+f 218/379/25 219/380/25 283/501/25 282/499/25
+f 172/307/19 171/305/19 235/403/19 236/404/19
+f 183/329/26 182/327/26 246/426/26 247/427/26
+f 203/364/9 204/365/9 268/470/9 267/468/9
+f 194/351/27 193/349/27 257/449/27 258/450/27
+f 225/386/28 226/387/28 290/516/28 289/515/28
+f 210/371/29 211/372/29 275/485/29 274/484/29
+f 179/321/22 178/319/22 242/418/22 243/419/22
+f 217/378/30 218/379/30 282/499/30 281/498/30
+f 190/343/12 189/341/12 253/440/12 254/441/12
+f 202/363/24 203/364/24 267/468/24 266/467/24
+f 231/393/4 232/396/4 264/462/4 263/460/4
+f 233/398/4 231/393/4 263/460/4 265/464/4
+f 234/400/4 233/398/4 265/464/4 266/466/4
+f 235/402/4 234/400/4 266/466/4 267/469/4
+f 236/405/4 235/402/4 267/469/4 268/471/4
+f 237/406/4 236/405/4 268/471/4 269/473/4
+f 238/408/4 237/406/4 269/473/4 270/474/4
+f 239/411/31 238/409/31 270/475/31 271/477/31
+f 240/413/4 239/411/4 271/477/4 272/479/4
+f 241/415/4 240/413/4 272/479/4 273/481/4
+f 242/417/4 241/415/4 273/481/4 274/483/4
+f 243/420/4 242/417/4 274/483/4 275/486/4
+f 244/421/4 243/420/4 275/486/4 276/488/4
+f 245/423/4 244/421/4 276/488/4 277/490/4
+f 246/425/4 245/423/4 277/490/4 278/491/4
+f 247/428/4 246/425/4 278/491/4 279/493/4
+f 248/429/4 247/428/4 279/493/4 280/495/4
+f 249/431/4 248/429/4 280/495/4 281/497/4
+f 250/433/4 249/431/4 281/497/4 282/500/4
+f 251/436/4 250/433/4 282/500/4 283/502/4
+f 252/437/4 251/436/4 283/502/4 284/504/4
+f 253/439/4 252/437/4 284/504/4 285/505/4
+f 254/442/4 253/439/4 285/505/4 286/507/4
+f 255/443/31 254/442/31 286/507/31 287/509/31
+f 256/446/4 255/444/4 287/510/4 288/512/4
+f 257/448/4 256/446/4 288/512/4 289/514/4
+f 258/451/4 257/448/4 289/514/4 290/517/4
+f 259/452/4 258/451/4 290/517/4 291/519/4
+f 260/454/4 259/452/4 291/519/4 292/521/4
+f 261/456/4 260/454/4 292/521/4 293/522/4
+f 262/459/4 261/456/4 293/522/4 294/524/4
+f 232/396/4 262/459/4 294/524/4 264/462/4
+f 177/317/32 176/315/32 240/414/32 241/416/32
+f 206/367/33 207/368/33 271/478/33 270/476/33
+f 221/382/34 222/383/34 286/508/34 285/506/34
+f 192/347/35 191/345/35 255/445/35 256/447/35
+f 181/325/7 180/323/7 244/422/7 245/424/7
+f 200/361/36 199/360/36 263/461/36 264/463/36
+f 170/303/30 169/301/30 233/399/30 234/401/30
+f 214/375/10 215/376/10 279/494/10 278/492/10
+f 229/390/37 230/391/37 294/525/37 293/523/37
+f 196/355/23 195/353/23 259/453/23 260/455/23
+f 185/333/38 184/331/38 248/430/38 249/432/38
+f 207/368/35 208/369/35 272/480/35 271/478/35
+f 222/383/39 223/384/39 287/511/39 286/508/39
+f 174/311/34 173/309/34 237/407/34 238/410/34
+f 199/360/38 201/362/38 265/465/38 263/461/38
+f 189/341/20 188/339/20 252/438/20 253/440/20
+f 215/376/40 216/377/40 280/496/40 279/494/40
+f 230/392/26 200/361/26 264/463/26 294/526/26
+f 178/319/28 177/317/28 241/416/28 242/418/28
+f 208/369/41 209/370/41 273/482/41 272/480/41
+f 223/384/21 224/385/21 288/513/21 287/511/21
+f 193/349/41 192/347/41 256/447/41 257/449/41
+f 182/327/37 181/325/37 245/424/37 246/426/37
+f 201/362/42 202/363/42 266/467/42 265/465/42
+f 171/305/43 170/303/43 234/401/43 235/403/43
+f 216/377/17 217/378/17 281/498/17 280/496/17
+f 197/357/16 196/355/16 260/455/16 261/457/16
+f 168/299/40 167/297/40 232/397/40 231/394/40
+f 186/335/42 185/333/42 249/432/42 250/434/42
+f 209/370/27 210/371/27 274/484/27 273/482/27
+f 224/385/32 225/386/32 289/515/32 288/513/32
+f 175/313/44 174/311/44 238/410/44 239/412/44
+f 295/527/4 296/528/4 297/531/4
+f 295/527/4 297/531/4 298/533/4
+f 295/527/4 298/533/4 299/535/4
+f 295/527/4 299/535/4 300/537/4
+f 295/527/4 300/537/4 301/539/4
+f 295/527/4 301/539/4 302/541/4
+f 295/527/4 302/541/4 303/543/4
+f 295/527/4 303/543/4 304/545/4
+f 295/527/4 304/545/4 305/547/4
+f 295/527/4 305/547/4 306/549/4
+f 295/527/4 306/549/4 307/551/4
+f 295/527/4 307/551/4 308/553/4
+f 295/527/4 308/553/4 309/555/4
+f 295/527/4 309/555/4 310/557/4
+f 295/527/4 310/557/4 311/559/4
+f 295/527/4 311/559/4 312/561/4
+f 295/527/4 312/561/4 313/563/4
+f 295/527/4 313/563/4 314/565/4
+f 295/527/4 314/565/4 315/567/4
+f 295/527/4 315/567/4 316/569/4
+f 295/527/4 316/569/4 317/571/4
+f 295/527/4 317/571/4 318/573/4
+f 295/527/4 318/573/4 319/575/4
+f 295/527/4 319/575/4 320/577/4
+f 295/527/4 320/577/4 321/579/4
+f 295/527/4 321/579/4 322/581/4
+f 295/527/4 322/581/4 323/583/4
+f 295/527/4 323/583/4 324/585/4
+f 295/527/4 324/585/4 325/587/4
+f 295/527/4 325/587/4 326/589/4
+f 295/527/4 326/589/4 327/591/4
+f 295/527/4 327/591/4 296/528/4
+f 357/622/7 358/623/7 422/756/7 421/753/7
+f 342/607/8 343/608/8 407/725/8 406/722/8
+f 317/572/9 316/570/9 380/668/9 381/671/9
+f 296/529/10 327/592/10 391/691/10 361/628/10
+f 302/542/11 301/540/11 365/637/11 366/640/11
+f 349/614/11 350/615/11 414/739/11 413/736/11
+f 334/599/12 335/600/12 399/709/12 398/705/12
+f 313/564/13 312/562/13 376/660/13 377/663/13
+f 324/586/14 323/584/14 387/683/14 388/686/14
+f 356/621/15 357/622/15 421/753/15 420/751/15
+f 341/606/16 342/607/16 406/722/16 405/720/16
+f 298/534/17 297/532/17 360/627/17 362/632/17
+f 309/556/15 308/554/15 372/652/15 373/655/15
+f 320/578/18 319/576/18 383/674/18 384/678/18
+f 348/613/19 349/614/19 413/736/19 412/734/19
+f 333/598/20 334/599/20 398/705/20 397/703/20
+f 305/548/21 304/546/21 368/645/21 369/647/21
+f 355/620/45 356/621/45 420/751/45 419/749/45
+f 340/605/23 341/606/23 405/720/23 404/718/23
+f 316/570/24 315/568/24 379/667/24 380/668/24
+f 327/592/8 326/590/8 390/690/8 391/691/8
+f 347/612/25 348/613/25 412/734/25 411/732/25
+f 301/540/19 300/538/19 364/636/19 365/637/19
+f 312/562/26 311/560/26 375/659/26 376/660/26
+f 332/597/9 333/598/9 397/703/9 396/701/9
+f 323/584/27 322/582/27 386/682/27 387/683/27
+f 354/619/28 355/620/28 419/749/28 418/748/28
+f 339/604/29 340/605/29 404/718/29 403/717/29
+f 308/554/22 307/552/22 371/651/22 372/652/22
+f 346/611/30 347/612/30 411/732/30 410/731/30
+f 319/576/12 318/574/12 382/673/12 383/674/12
+f 331/596/24 332/597/24 396/701/24 395/700/24
+f 360/626/4 361/629/4 393/695/4 392/693/4
+f 362/631/4 360/626/4 392/693/4 394/697/4
+f 363/633/4 362/631/4 394/697/4 395/699/4
+f 364/635/4 363/633/4 395/699/4 396/702/4
+f 365/638/4 364/635/4 396/702/4 397/704/4
+f 366/639/4 365/638/4 397/704/4 398/706/4
+f 367/641/4 366/639/4 398/706/4 399/707/4
+f 368/644/31 367/642/31 399/708/31 400/710/31
+f 369/646/4 368/644/4 400/710/4 401/712/4
+f 370/648/4 369/646/4 401/712/4 402/714/4
+f 371/650/4 370/648/4 402/714/4 403/716/4
+f 372/653/4 371/650/4 403/716/4 404/719/4
+f 373/654/4 372/653/4 404/719/4 405/721/4
+f 374/656/4 373/654/4 405/721/4 406/723/4
+f 375/658/4 374/656/4 406/723/4 407/724/4
+f 376/661/4 375/658/4 407/724/4 408/726/4
+f 377/662/4 376/661/4 408/726/4 409/728/4
+f 378/664/4 377/662/4 409/728/4 410/730/4
+f 379/666/4 378/664/4 410/730/4 411/733/4
+f 380/669/4 379/666/4 411/733/4 412/735/4
+f 381/670/4 380/669/4 412/735/4 413/737/4
+f 382/672/4 381/670/4 413/737/4 414/738/4
+f 383/675/4 382/672/4 414/738/4 415/740/4
+f 384/676/31 383/675/31 415/740/31 416/742/31
+f 385/679/4 384/677/4 416/743/4 417/745/4
+f 386/681/4 385/679/4 417/745/4 418/747/4
+f 387/684/4 386/681/4 418/747/4 419/750/4
+f 388/685/4 387/684/4 419/750/4 420/752/4
+f 389/687/4 388/685/4 420/752/4 421/754/4
+f 390/689/4 389/687/4 421/754/4 422/755/4
+f 391/692/4 390/689/4 422/755/4 423/757/4
+f 361/629/4 391/692/4 423/757/4 393/695/4
+f 306/550/32 305/548/32 369/647/32 370/649/32
+f 335/600/33 336/601/33 400/711/33 399/709/33
+f 350/615/34 351/616/34 415/741/34 414/739/34
+f 321/580/35 320/578/35 384/678/35 385/680/35
+f 310/558/7 309/556/7 373/655/7 374/657/7
+f 329/594/36 328/593/36 392/694/36 393/696/36
+f 299/536/30 298/534/30 362/632/30 363/634/30
+f 343/608/10 344/609/10 408/727/10 407/725/10
+f 358/623/37 359/624/37 423/758/37 422/756/37
+f 325/588/23 324/586/23 388/686/23 389/688/23
+f 314/566/38 313/564/38 377/663/38 378/665/38
+f 336/601/35 337/602/35 401/713/35 400/711/35
+f 351/616/39 352/617/39 416/744/39 415/741/39
+f 303/544/34 302/542/34 366/640/34 367/643/34
+f 328/593/38 330/595/38 394/698/38 392/694/38
+f 318/574/20 317/572/20 381/671/20 382/673/20
+f 344/609/40 345/610/40 409/729/40 408/727/40
+f 359/625/26 329/594/26 393/696/26 423/759/26
+f 307/552/28 306/550/28 370/649/28 371/651/28
+f 337/602/41 338/603/41 402/715/41 401/713/41
+f 352/617/21 353/618/21 417/746/21 416/744/21
+f 322/582/41 321/580/41 385/680/41 386/682/41
+f 311/560/37 310/558/37 374/657/37 375/659/37
+f 330/595/42 331/596/42 395/700/42 394/698/42
+f 300/538/43 299/536/43 363/634/43 364/636/43
+f 345/610/17 346/611/17 410/731/17 409/729/17
+f 326/590/16 325/588/16 389/688/16 390/690/16
+f 297/532/40 296/530/40 361/630/40 360/627/40
+f 315/568/42 314/566/42 378/665/42 379/667/42
+f 338/603/27 339/604/27 403/717/27 402/715/27
+f 353/618/32 354/619/32 418/748/32 417/746/32
+f 304/546/44 303/544/44 367/643/44 368/645/44
+f 424/760/4 425/761/4 426/764/4
+f 424/760/4 426/764/4 427/766/4
+f 424/760/4 427/766/4 428/768/4
+f 424/760/4 428/768/4 429/770/4
+f 424/760/4 429/770/4 430/772/4
+f 424/760/4 430/772/4 431/774/4
+f 424/760/4 431/774/4 432/776/4
+f 424/760/4 432/776/4 433/778/4
+f 424/760/4 433/778/4 434/780/4
+f 424/760/4 434/780/4 435/782/4
+f 424/760/4 435/782/4 436/784/4
+f 424/760/4 436/784/4 437/786/4
+f 424/760/4 437/786/4 438/788/4
+f 424/760/4 438/788/4 439/790/4
+f 424/760/4 439/790/4 440/792/4
+f 424/760/4 440/792/4 441/794/4
+f 424/760/4 441/794/4 442/796/4
+f 424/760/4 442/796/4 443/798/4
+f 424/760/4 443/798/4 444/800/4
+f 424/760/4 444/800/4 445/802/4
+f 424/760/4 445/802/4 446/804/4
+f 424/760/4 446/804/4 447/806/4
+f 424/760/4 447/806/4 448/808/4
+f 424/760/4 448/808/4 449/810/4
+f 424/760/4 449/810/4 450/812/4
+f 424/760/4 450/812/4 451/814/4
+f 424/760/4 451/814/4 452/816/4
+f 424/760/4 452/816/4 453/818/4
+f 424/760/4 453/818/4 454/820/4
+f 424/760/4 454/820/4 455/822/4
+f 424/760/4 455/822/4 456/824/4
+f 424/760/4 456/824/4 425/761/4
+f 486/855/7 487/856/7 551/989/7 550/986/7
+f 471/840/8 472/841/8 536/958/8 535/955/8
+f 446/805/9 445/803/9 509/901/9 510/904/9
+f 425/762/46 456/825/46 520/924/46 490/861/46
+f 431/775/11 430/773/11 494/870/11 495/873/11
+f 478/847/11 479/848/11 543/972/11 542/969/11
+f 463/832/12 464/833/12 528/942/12 527/938/12
+f 442/797/13 441/795/13 505/893/13 506/896/13
+f 453/819/14 452/817/14 516/916/14 517/919/14
+f 485/854/15 486/855/15 550/986/15 549/984/15
+f 470/839/16 471/840/16 535/955/16 534/953/16
+f 427/767/17 426/765/17 489/860/17 491/865/17
+f 438/789/15 437/787/15 501/885/15 502/888/15
+f 449/811/18 448/809/18 512/907/18 513/911/18
+f 477/846/19 478/847/19 542/969/19 541/967/19
+f 462/831/20 463/832/20 527/938/20 526/936/20
+f 434/781/21 433/779/21 497/878/21 498/880/21
+f 484/853/22 485/854/22 549/984/22 548/982/22
+f 469/838/23 470/839/23 534/953/23 533/951/23
+f 445/803/24 444/801/24 508/900/24 509/901/24
+f 456/825/8 455/823/8 519/923/8 520/924/8
+f 476/845/25 477/846/25 541/967/25 540/965/25
+f 430/773/19 429/771/19 493/869/19 494/870/19
+f 441/795/26 440/793/26 504/892/26 505/893/26
+f 461/830/9 462/831/9 526/936/9 525/934/9
+f 452/817/27 451/815/27 515/915/27 516/916/27
+f 483/852/28 484/853/28 548/982/28 547/981/28
+f 468/837/29 469/838/29 533/951/29 532/950/29
+f 437/787/22 436/785/22 500/884/22 501/885/22
+f 475/844/30 476/845/30 540/965/30 539/964/30
+f 448/809/12 447/807/12 511/906/12 512/907/12
+f 460/829/24 461/830/24 525/934/24 524/933/24
+f 489/859/4 490/862/4 522/928/4 521/926/4
+f 491/864/4 489/859/4 521/926/4 523/930/4
+f 492/866/4 491/864/4 523/930/4 524/932/4
+f 493/868/4 492/866/4 524/932/4 525/935/4
+f 494/871/4 493/868/4 525/935/4 526/937/4
+f 495/872/4 494/871/4 526/937/4 527/939/4
+f 496/874/4 495/872/4 527/939/4 528/940/4
+f 497/877/31 496/875/31 528/941/31 529/943/31
+f 498/879/4 497/877/4 529/943/4 530/945/4
+f 499/881/4 498/879/4 530/945/4 531/947/4
+f 500/883/4 499/881/4 531/947/4 532/949/4
+f 501/886/4 500/883/4 532/949/4 533/952/4
+f 502/887/4 501/886/4 533/952/4 534/954/4
+f 503/889/4 502/887/4 534/954/4 535/956/4
+f 504/891/4 503/889/4 535/956/4 536/957/4
+f 505/894/4 504/891/4 536/957/4 537/959/4
+f 506/895/4 505/894/4 537/959/4 538/961/4
+f 507/897/4 506/895/4 538/961/4 539/963/4
+f 508/899/4 507/897/4 539/963/4 540/966/4
+f 509/902/4 508/899/4 540/966/4 541/968/4
+f 510/903/4 509/902/4 541/968/4 542/970/4
+f 511/905/4 510/903/4 542/970/4 543/971/4
+f 512/908/4 511/905/4 543/971/4 544/973/4
+f 513/909/31 512/908/31 544/973/31 545/975/31
+f 514/912/4 513/910/4 545/976/4 546/978/4
+f 515/914/4 514/912/4 546/978/4 547/980/4
+f 516/917/4 515/914/4 547/980/4 548/983/4
+f 517/918/4 516/917/4 548/983/4 549/985/4
+f 518/920/4 517/918/4 549/985/4 550/987/4
+f 519/922/4 518/920/4 550/987/4 551/988/4
+f 520/925/4 519/922/4 551/988/4 552/990/4
+f 490/862/4 520/925/4 552/990/4 522/928/4
+f 435/783/32 434/781/32 498/880/32 499/882/32
+f 464/833/33 465/834/33 529/944/33 528/942/33
+f 479/848/34 480/849/34 544/974/34 543/972/34
+f 450/813/35 449/811/35 513/911/35 514/913/35
+f 439/791/7 438/789/7 502/888/7 503/890/7
+f 458/827/36 457/826/36 521/927/36 522/929/36
+f 428/769/30 427/767/30 491/865/30 492/867/30
+f 472/841/10 473/842/10 537/960/10 536/958/10
+f 487/856/37 488/857/37 552/991/37 551/989/37
+f 454/821/23 453/819/23 517/919/23 518/921/23
+f 443/799/38 442/797/38 506/896/38 507/898/38
+f 465/834/35 466/835/35 530/946/35 529/944/35
+f 480/849/39 481/850/39 545/977/39 544/974/39
+f 432/777/34 431/775/34 495/873/34 496/876/34
+f 457/826/38 459/828/38 523/931/38 521/927/38
+f 447/807/20 446/805/20 510/904/20 511/906/20
+f 473/842/40 474/843/40 538/962/40 537/960/40
+f 488/858/26 458/827/26 522/929/26 552/992/26
+f 436/785/28 435/783/28 499/882/28 500/884/28
+f 466/835/41 467/836/41 531/948/41 530/946/41
+f 481/850/21 482/851/21 546/979/21 545/977/21
+f 451/815/41 450/813/41 514/913/41 515/915/41
+f 440/793/37 439/791/37 503/890/37 504/892/37
+f 459/828/42 460/829/42 524/933/42 523/931/42
+f 429/771/43 428/769/43 492/867/43 493/869/43
+f 474/843/17 475/844/17 539/964/17 538/962/17
+f 455/823/16 454/821/16 518/921/16 519/923/16
+f 426/765/40 425/763/40 490/863/40 489/860/40
+f 444/801/42 443/799/42 507/898/42 508/900/42
+f 467/836/27 468/837/27 532/950/27 531/948/27
+f 482/851/32 483/852/32 547/981/32 546/979/32
+f 433/779/44 432/777/44 496/876/44 497/878/44
diff --git a/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_r.obj b/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_r.obj
new file mode 100644
index 0000000..6843591
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_r.obj
@@ -0,0 +1,2137 @@
+# Blender 3.4.1
+# www.blender.org
+mtllib advtrains_signals_muc_ubahn_wsig_r.mtl
+o Cube
+v -0.500000 0.399750 0.043560
+v -0.500000 0.357794 0.043560
+v -0.500000 -0.357244 0.043560
+v -0.500000 -0.402505 0.043561
+v -0.500000 0.399750 -0.043560
+v -0.500000 0.357794 -0.043560
+v -0.500000 -0.357244 -0.043560
+v -0.500000 -0.402505 -0.043560
+v -0.302890 0.399750 0.043560
+v -0.302890 0.357794 0.043560
+v -0.302890 -0.357244 0.043560
+v -0.302890 -0.402505 0.043560
+v -0.302890 0.399750 -0.043560
+v -0.302890 0.357794 -0.043560
+v -0.302890 -0.357244 -0.043560
+v -0.302890 -0.402505 -0.043560
+v -0.218703 -0.357244 0.042354
+v -0.218703 0.357794 0.042354
+v -0.218703 -0.357244 -0.031584
+v -0.218703 0.357794 -0.031584
+v -0.450908 -0.357244 0.042354
+v -0.450908 0.357794 0.042354
+v -0.450908 -0.357244 -0.031584
+v -0.450908 0.357794 -0.031584
+v -0.265363 -0.310583 0.042354
+v -0.265363 0.311134 0.042354
+v -0.404248 0.311134 0.042354
+v -0.404247 -0.310583 0.042354
+v -0.265363 -0.310583 0.089581
+v -0.265363 0.311134 0.089581
+v -0.404247 0.311134 0.089581
+v -0.404247 -0.310583 0.089581
+v -0.257920 0.318577 -0.031584
+v -0.257920 -0.318027 -0.031584
+v -0.411691 0.318577 -0.031584
+v -0.411691 -0.318027 -0.031584
+v -0.331404 0.241338 -0.037331
+v -0.326280 0.189125 -0.037331
+v -0.316192 0.191128 -0.037331
+v -0.306689 0.195061 -0.037331
+v -0.298135 0.200771 -0.037331
+v -0.290861 0.208041 -0.037331
+v -0.285144 0.216591 -0.037331
+v -0.281205 0.226091 -0.037331
+v -0.279195 0.236177 -0.037331
+v -0.279191 0.246462 -0.037331
+v -0.281194 0.256550 -0.037331
+v -0.285127 0.266053 -0.037331
+v -0.290838 0.274606 -0.037331
+v -0.298107 0.281881 -0.037331
+v -0.306657 0.287598 -0.037331
+v -0.316157 0.291537 -0.037331
+v -0.326243 0.293547 -0.037331
+v -0.336528 0.293550 -0.037331
+v -0.346616 0.291547 -0.037331
+v -0.356119 0.287615 -0.037331
+v -0.364672 0.281904 -0.037331
+v -0.371947 0.274634 -0.037331
+v -0.377664 0.266085 -0.037331
+v -0.381603 0.256585 -0.037331
+v -0.383613 0.246498 -0.037331
+v -0.383616 0.236214 -0.037331
+v -0.381613 0.226126 -0.037331
+v -0.377681 0.216623 -0.037331
+v -0.371970 0.208069 -0.037331
+v -0.364700 0.200795 -0.037331
+v -0.356151 0.195078 -0.037331
+v -0.346651 0.191139 -0.037331
+v -0.336564 0.189129 -0.037331
+v -0.313532 0.182348 -0.031584
+v -0.325384 0.179994 -0.031584
+v -0.302367 0.186968 -0.031584
+v -0.292318 0.193677 -0.031584
+v -0.283771 0.202218 -0.031584
+v -0.277054 0.212263 -0.031584
+v -0.272426 0.223425 -0.031584
+v -0.270065 0.235275 -0.031584
+v -0.270060 0.247358 -0.031584
+v -0.272414 0.259210 -0.031584
+v -0.277034 0.270375 -0.031584
+v -0.283743 0.280424 -0.031584
+v -0.292285 0.288971 -0.031584
+v -0.302329 0.295687 -0.031584
+v -0.313491 0.300315 -0.031584
+v -0.325341 0.302677 -0.031584
+v -0.337424 0.302681 -0.031584
+v -0.349276 0.300328 -0.031584
+v -0.360441 0.295708 -0.031584
+v -0.370490 0.288998 -0.031584
+v -0.379037 0.280457 -0.031584
+v -0.385753 0.270413 -0.031584
+v -0.390381 0.259251 -0.031584
+v -0.392743 0.247401 -0.031584
+v -0.392747 0.235317 -0.031584
+v -0.390394 0.223466 -0.031584
+v -0.385774 0.212301 -0.031584
+v -0.379064 0.202252 -0.031584
+v -0.370523 0.193705 -0.031584
+v -0.360479 0.186988 -0.031584
+v -0.349317 0.182360 -0.031584
+v -0.337467 0.179999 -0.031584
+v -0.316192 0.191128 -0.054117
+v -0.326280 0.189125 -0.054117
+v -0.306689 0.195061 -0.054117
+v -0.298136 0.200771 -0.054117
+v -0.290861 0.208041 -0.054117
+v -0.285144 0.216591 -0.054117
+v -0.281205 0.226091 -0.054117
+v -0.279195 0.236177 -0.054117
+v -0.279191 0.246462 -0.083504
+v -0.281194 0.256550 -0.083504
+v -0.285127 0.266053 -0.083504
+v -0.290838 0.274606 -0.083504
+v -0.298107 0.281881 -0.083504
+v -0.306657 0.287598 -0.083504
+v -0.316157 0.291537 -0.083504
+v -0.326243 0.293547 -0.083504
+v -0.336528 0.293550 -0.083504
+v -0.346616 0.291547 -0.083504
+v -0.356119 0.287615 -0.083504
+v -0.364672 0.281904 -0.083504
+v -0.371947 0.274634 -0.083504
+v -0.377664 0.266085 -0.083504
+v -0.381603 0.256585 -0.083504
+v -0.383613 0.246498 -0.083504
+v -0.383616 0.236214 -0.054117
+v -0.381613 0.226126 -0.054117
+v -0.377681 0.216623 -0.054117
+v -0.371970 0.208069 -0.054117
+v -0.364700 0.200795 -0.054117
+v -0.356151 0.195078 -0.054117
+v -0.346651 0.191139 -0.054117
+v -0.336564 0.189129 -0.054117
+v -0.313532 0.182348 -0.054117
+v -0.325384 0.179994 -0.054117
+v -0.302367 0.186968 -0.054117
+v -0.292318 0.193677 -0.054117
+v -0.283771 0.202218 -0.054117
+v -0.277054 0.212263 -0.054117
+v -0.272426 0.223425 -0.054117
+v -0.270065 0.235275 -0.054117
+v -0.270060 0.247358 -0.083504
+v -0.272414 0.259210 -0.083504
+v -0.277034 0.270375 -0.083504
+v -0.283743 0.280424 -0.083504
+v -0.292285 0.288971 -0.083504
+v -0.302329 0.295687 -0.083504
+v -0.313491 0.300315 -0.083504
+v -0.325341 0.302677 -0.083504
+v -0.337424 0.302681 -0.083504
+v -0.349276 0.300328 -0.083504
+v -0.360441 0.295708 -0.083504
+v -0.370490 0.288998 -0.083504
+v -0.379037 0.280457 -0.083504
+v -0.385753 0.270413 -0.083504
+v -0.390381 0.259251 -0.083504
+v -0.392743 0.247401 -0.083504
+v -0.392747 0.235317 -0.054117
+v -0.390394 0.223466 -0.054117
+v -0.385774 0.212301 -0.054117
+v -0.379064 0.202252 -0.054117
+v -0.370523 0.193705 -0.054117
+v -0.360479 0.186988 -0.054117
+v -0.349317 0.182360 -0.054117
+v -0.337467 0.179999 -0.054117
+v -0.331404 0.091338 -0.037331
+v -0.326280 0.039125 -0.037331
+v -0.316192 0.041128 -0.037331
+v -0.306689 0.045061 -0.037331
+v -0.298135 0.050771 -0.037331
+v -0.290861 0.058041 -0.037331
+v -0.285144 0.066591 -0.037331
+v -0.281205 0.076091 -0.037331
+v -0.279195 0.086177 -0.037331
+v -0.279191 0.096462 -0.037331
+v -0.281194 0.106550 -0.037331
+v -0.285127 0.116053 -0.037331
+v -0.290838 0.124606 -0.037331
+v -0.298107 0.131881 -0.037331
+v -0.306657 0.137598 -0.037331
+v -0.316157 0.141537 -0.037331
+v -0.326243 0.143547 -0.037331
+v -0.336528 0.143550 -0.037331
+v -0.346616 0.141547 -0.037331
+v -0.356119 0.137615 -0.037331
+v -0.364672 0.131904 -0.037331
+v -0.371947 0.124634 -0.037331
+v -0.377664 0.116085 -0.037331
+v -0.381603 0.106585 -0.037331
+v -0.383613 0.096498 -0.037331
+v -0.383616 0.086214 -0.037331
+v -0.381613 0.076126 -0.037331
+v -0.377681 0.066623 -0.037331
+v -0.371970 0.058069 -0.037331
+v -0.364700 0.050795 -0.037331
+v -0.356151 0.045078 -0.037331
+v -0.346651 0.041139 -0.037331
+v -0.336564 0.039129 -0.037331
+v -0.313532 0.032348 -0.031584
+v -0.325384 0.029994 -0.031584
+v -0.302367 0.036968 -0.031584
+v -0.292318 0.043677 -0.031584
+v -0.283771 0.052218 -0.031584
+v -0.277054 0.062263 -0.031584
+v -0.272426 0.073425 -0.031584
+v -0.270065 0.085275 -0.031584
+v -0.270060 0.097358 -0.031584
+v -0.272414 0.109210 -0.031584
+v -0.277034 0.120375 -0.031584
+v -0.283743 0.130424 -0.031584
+v -0.292285 0.138971 -0.031584
+v -0.302329 0.145687 -0.031584
+v -0.313491 0.150315 -0.031584
+v -0.325341 0.152677 -0.031584
+v -0.337424 0.152681 -0.031584
+v -0.349276 0.150328 -0.031584
+v -0.360441 0.145708 -0.031584
+v -0.370490 0.138998 -0.031584
+v -0.379037 0.130457 -0.031584
+v -0.385753 0.120412 -0.031584
+v -0.390381 0.109251 -0.031584
+v -0.392743 0.097401 -0.031584
+v -0.392747 0.085317 -0.031584
+v -0.390394 0.073466 -0.031584
+v -0.385774 0.062301 -0.031584
+v -0.379064 0.052252 -0.031584
+v -0.370523 0.043705 -0.031584
+v -0.360479 0.036988 -0.031584
+v -0.349317 0.032360 -0.031584
+v -0.337467 0.029999 -0.031584
+v -0.316192 0.041128 -0.054117
+v -0.326280 0.039125 -0.054117
+v -0.306689 0.045061 -0.054117
+v -0.298136 0.050771 -0.054117
+v -0.290861 0.058041 -0.054117
+v -0.285144 0.066591 -0.054117
+v -0.281205 0.076091 -0.054117
+v -0.279195 0.086177 -0.054117
+v -0.279191 0.096462 -0.083504
+v -0.281194 0.106550 -0.083504
+v -0.285127 0.116053 -0.083504
+v -0.290838 0.124606 -0.083504
+v -0.298107 0.131881 -0.083504
+v -0.306657 0.137598 -0.083504
+v -0.316157 0.141537 -0.083504
+v -0.326243 0.143547 -0.083504
+v -0.336528 0.143550 -0.083504
+v -0.346616 0.141547 -0.083504
+v -0.356119 0.137615 -0.083504
+v -0.364672 0.131904 -0.083504
+v -0.371947 0.124634 -0.083504
+v -0.377664 0.116085 -0.083504
+v -0.381603 0.106585 -0.083504
+v -0.383613 0.096498 -0.083504
+v -0.383616 0.086214 -0.054117
+v -0.381613 0.076126 -0.054117
+v -0.377681 0.066623 -0.054117
+v -0.371970 0.058069 -0.054117
+v -0.364700 0.050795 -0.054117
+v -0.356151 0.045078 -0.054117
+v -0.346651 0.041139 -0.054117
+v -0.336564 0.039129 -0.054117
+v -0.313532 0.032348 -0.054117
+v -0.325384 0.029994 -0.054117
+v -0.302367 0.036968 -0.054117
+v -0.292318 0.043677 -0.054117
+v -0.283771 0.052218 -0.054117
+v -0.277054 0.062263 -0.054117
+v -0.272426 0.073425 -0.054117
+v -0.270065 0.085275 -0.054117
+v -0.270060 0.097358 -0.083504
+v -0.272414 0.109210 -0.083504
+v -0.277034 0.120375 -0.083504
+v -0.283743 0.130424 -0.083504
+v -0.292285 0.138971 -0.083504
+v -0.302329 0.145687 -0.083504
+v -0.313491 0.150315 -0.083504
+v -0.325341 0.152677 -0.083504
+v -0.337424 0.152681 -0.083504
+v -0.349276 0.150328 -0.083504
+v -0.360441 0.145708 -0.083504
+v -0.370490 0.138998 -0.083504
+v -0.379037 0.130457 -0.083504
+v -0.385753 0.120412 -0.083504
+v -0.390381 0.109251 -0.083504
+v -0.392743 0.097401 -0.083504
+v -0.392747 0.085317 -0.054117
+v -0.390394 0.073466 -0.054117
+v -0.385774 0.062301 -0.054117
+v -0.379064 0.052252 -0.054117
+v -0.370523 0.043705 -0.054117
+v -0.360479 0.036988 -0.054117
+v -0.349317 0.032360 -0.054117
+v -0.337467 0.029999 -0.054117
+v -0.331404 -0.058662 -0.037331
+v -0.326280 -0.110875 -0.037331
+v -0.316192 -0.108872 -0.037331
+v -0.306689 -0.104939 -0.037331
+v -0.298135 -0.099229 -0.037331
+v -0.290861 -0.091959 -0.037331
+v -0.285144 -0.083409 -0.037331
+v -0.281205 -0.073909 -0.037331
+v -0.279195 -0.063823 -0.037331
+v -0.279191 -0.053538 -0.037331
+v -0.281194 -0.043450 -0.037331
+v -0.285127 -0.033947 -0.037331
+v -0.290838 -0.025394 -0.037331
+v -0.298107 -0.018119 -0.037331
+v -0.306657 -0.012402 -0.037331
+v -0.316157 -0.008463 -0.037331
+v -0.326243 -0.006453 -0.037331
+v -0.336528 -0.006450 -0.037331
+v -0.346616 -0.008453 -0.037331
+v -0.356119 -0.012385 -0.037331
+v -0.364672 -0.018096 -0.037331
+v -0.371947 -0.025366 -0.037331
+v -0.377664 -0.033915 -0.037331
+v -0.381603 -0.043415 -0.037331
+v -0.383613 -0.053502 -0.037331
+v -0.383616 -0.063786 -0.037331
+v -0.381613 -0.073874 -0.037331
+v -0.377681 -0.083377 -0.037331
+v -0.371970 -0.091931 -0.037331
+v -0.364700 -0.099205 -0.037331
+v -0.356151 -0.104922 -0.037331
+v -0.346651 -0.108861 -0.037331
+v -0.336564 -0.110871 -0.037331
+v -0.313532 -0.117652 -0.031584
+v -0.325384 -0.120006 -0.031584
+v -0.302367 -0.113032 -0.031584
+v -0.292318 -0.106323 -0.031584
+v -0.283771 -0.097782 -0.031584
+v -0.277054 -0.087737 -0.031584
+v -0.272426 -0.076575 -0.031584
+v -0.270065 -0.064725 -0.031584
+v -0.270060 -0.052642 -0.031584
+v -0.272414 -0.040790 -0.031584
+v -0.277034 -0.029625 -0.031584
+v -0.283743 -0.019576 -0.031584
+v -0.292285 -0.011029 -0.031584
+v -0.302329 -0.004313 -0.031584
+v -0.313491 0.000315 -0.031584
+v -0.325341 0.002677 -0.031584
+v -0.337424 0.002681 -0.031584
+v -0.349276 0.000328 -0.031584
+v -0.360441 -0.004292 -0.031584
+v -0.370490 -0.011002 -0.031584
+v -0.379037 -0.019543 -0.031584
+v -0.385753 -0.029587 -0.031584
+v -0.390381 -0.040749 -0.031584
+v -0.392743 -0.052599 -0.031584
+v -0.392747 -0.064683 -0.031584
+v -0.390394 -0.076534 -0.031584
+v -0.385774 -0.087699 -0.031584
+v -0.379064 -0.097748 -0.031584
+v -0.370523 -0.106295 -0.031584
+v -0.360479 -0.113012 -0.031584
+v -0.349317 -0.117640 -0.031584
+v -0.337467 -0.120001 -0.031584
+v -0.316192 -0.108872 -0.054117
+v -0.326280 -0.110875 -0.054117
+v -0.306689 -0.104939 -0.054117
+v -0.298136 -0.099229 -0.054117
+v -0.290861 -0.091959 -0.054117
+v -0.285144 -0.083409 -0.054117
+v -0.281205 -0.073909 -0.054117
+v -0.279195 -0.063823 -0.054117
+v -0.279191 -0.053538 -0.083504
+v -0.281194 -0.043450 -0.083504
+v -0.285127 -0.033947 -0.083504
+v -0.290838 -0.025394 -0.083504
+v -0.298107 -0.018119 -0.083504
+v -0.306657 -0.012402 -0.083504
+v -0.316157 -0.008463 -0.083504
+v -0.326243 -0.006453 -0.083504
+v -0.336528 -0.006450 -0.083504
+v -0.346616 -0.008453 -0.083504
+v -0.356119 -0.012385 -0.083504
+v -0.364672 -0.018096 -0.083504
+v -0.371947 -0.025366 -0.083504
+v -0.377664 -0.033915 -0.083504
+v -0.381603 -0.043415 -0.083504
+v -0.383613 -0.053502 -0.083504
+v -0.383616 -0.063786 -0.054117
+v -0.381613 -0.073874 -0.054117
+v -0.377681 -0.083377 -0.054117
+v -0.371970 -0.091931 -0.054117
+v -0.364700 -0.099205 -0.054117
+v -0.356151 -0.104922 -0.054117
+v -0.346651 -0.108861 -0.054117
+v -0.336564 -0.110871 -0.054117
+v -0.313532 -0.117652 -0.054117
+v -0.325384 -0.120006 -0.054117
+v -0.302367 -0.113032 -0.054117
+v -0.292318 -0.106323 -0.054117
+v -0.283771 -0.097782 -0.054117
+v -0.277054 -0.087737 -0.054117
+v -0.272426 -0.076575 -0.054117
+v -0.270065 -0.064725 -0.054117
+v -0.270060 -0.052642 -0.083504
+v -0.272414 -0.040790 -0.083504
+v -0.277034 -0.029625 -0.083504
+v -0.283743 -0.019576 -0.083504
+v -0.292285 -0.011029 -0.083504
+v -0.302329 -0.004313 -0.083504
+v -0.313491 0.000315 -0.083504
+v -0.325341 0.002677 -0.083504
+v -0.337424 0.002681 -0.083504
+v -0.349276 0.000328 -0.083504
+v -0.360441 -0.004292 -0.083504
+v -0.370490 -0.011002 -0.083504
+v -0.379037 -0.019543 -0.083504
+v -0.385753 -0.029587 -0.083504
+v -0.390381 -0.040749 -0.083504
+v -0.392743 -0.052599 -0.083504
+v -0.392747 -0.064683 -0.054117
+v -0.390394 -0.076534 -0.054117
+v -0.385774 -0.087699 -0.054117
+v -0.379064 -0.097748 -0.054117
+v -0.370523 -0.106295 -0.054117
+v -0.360479 -0.113012 -0.054117
+v -0.349317 -0.117640 -0.054117
+v -0.337467 -0.120001 -0.054117
+v -0.331404 -0.208662 -0.037331
+v -0.326280 -0.260875 -0.037331
+v -0.316192 -0.258872 -0.037331
+v -0.306689 -0.254939 -0.037331
+v -0.298135 -0.249229 -0.037331
+v -0.290861 -0.241959 -0.037331
+v -0.285144 -0.233410 -0.037331
+v -0.281205 -0.223909 -0.037331
+v -0.279195 -0.213823 -0.037331
+v -0.279191 -0.203538 -0.037331
+v -0.281194 -0.193450 -0.037331
+v -0.285127 -0.183947 -0.037331
+v -0.290838 -0.175394 -0.037331
+v -0.298107 -0.168119 -0.037331
+v -0.306657 -0.162402 -0.037331
+v -0.316157 -0.158463 -0.037331
+v -0.326243 -0.156453 -0.037331
+v -0.336528 -0.156450 -0.037331
+v -0.346616 -0.158453 -0.037331
+v -0.356119 -0.162385 -0.037331
+v -0.364672 -0.168096 -0.037331
+v -0.371947 -0.175366 -0.037331
+v -0.377664 -0.183915 -0.037331
+v -0.381603 -0.193415 -0.037331
+v -0.383613 -0.203502 -0.037331
+v -0.383616 -0.213786 -0.037331
+v -0.381613 -0.223874 -0.037331
+v -0.377681 -0.233377 -0.037331
+v -0.371970 -0.241931 -0.037331
+v -0.364700 -0.249205 -0.037331
+v -0.356151 -0.254922 -0.037331
+v -0.346651 -0.258861 -0.037331
+v -0.336564 -0.260871 -0.037331
+v -0.313532 -0.267652 -0.031584
+v -0.325384 -0.270006 -0.031584
+v -0.302367 -0.263032 -0.031584
+v -0.292318 -0.256323 -0.031584
+v -0.283771 -0.247782 -0.031584
+v -0.277054 -0.237737 -0.031584
+v -0.272426 -0.226575 -0.031584
+v -0.270065 -0.214725 -0.031584
+v -0.270060 -0.202642 -0.031584
+v -0.272414 -0.190790 -0.031584
+v -0.277034 -0.179625 -0.031584
+v -0.283743 -0.169576 -0.031584
+v -0.292285 -0.161029 -0.031584
+v -0.302329 -0.154313 -0.031584
+v -0.313491 -0.149685 -0.031584
+v -0.325341 -0.147323 -0.031584
+v -0.337424 -0.147319 -0.031584
+v -0.349276 -0.149672 -0.031584
+v -0.360441 -0.154292 -0.031584
+v -0.370490 -0.161002 -0.031584
+v -0.379037 -0.169543 -0.031584
+v -0.385753 -0.179587 -0.031584
+v -0.390381 -0.190749 -0.031584
+v -0.392743 -0.202599 -0.031584
+v -0.392747 -0.214683 -0.031584
+v -0.390394 -0.226534 -0.031584
+v -0.385774 -0.237699 -0.031584
+v -0.379064 -0.247748 -0.031584
+v -0.370523 -0.256295 -0.031584
+v -0.360479 -0.263012 -0.031584
+v -0.349317 -0.267640 -0.031584
+v -0.337467 -0.270001 -0.031584
+v -0.316192 -0.258872 -0.054117
+v -0.326280 -0.260875 -0.054117
+v -0.306689 -0.254939 -0.054117
+v -0.298136 -0.249229 -0.054117
+v -0.290861 -0.241959 -0.054117
+v -0.285144 -0.233410 -0.054117
+v -0.281205 -0.223909 -0.054117
+v -0.279195 -0.213823 -0.054117
+v -0.279191 -0.203538 -0.083504
+v -0.281194 -0.193450 -0.083504
+v -0.285127 -0.183947 -0.083504
+v -0.290838 -0.175394 -0.083504
+v -0.298107 -0.168119 -0.083504
+v -0.306657 -0.162402 -0.083504
+v -0.316157 -0.158463 -0.083504
+v -0.326243 -0.156453 -0.083504
+v -0.336528 -0.156450 -0.083504
+v -0.346616 -0.158453 -0.083504
+v -0.356119 -0.162385 -0.083504
+v -0.364672 -0.168096 -0.083504
+v -0.371947 -0.175366 -0.083504
+v -0.377664 -0.183915 -0.083504
+v -0.381603 -0.193415 -0.083504
+v -0.383613 -0.203502 -0.083504
+v -0.383616 -0.213786 -0.054117
+v -0.381613 -0.223874 -0.054117
+v -0.377681 -0.233377 -0.054117
+v -0.371970 -0.241931 -0.054117
+v -0.364700 -0.249205 -0.054117
+v -0.356151 -0.254922 -0.054117
+v -0.346651 -0.258861 -0.054117
+v -0.336564 -0.260871 -0.054117
+v -0.313532 -0.267652 -0.054117
+v -0.325384 -0.270006 -0.054117
+v -0.302367 -0.263032 -0.054117
+v -0.292318 -0.256323 -0.054117
+v -0.283771 -0.247782 -0.054117
+v -0.277054 -0.237737 -0.054117
+v -0.272426 -0.226575 -0.054117
+v -0.270065 -0.214725 -0.054117
+v -0.270060 -0.202642 -0.083504
+v -0.272414 -0.190790 -0.083504
+v -0.277034 -0.179625 -0.083504
+v -0.283743 -0.169576 -0.083504
+v -0.292285 -0.161029 -0.083504
+v -0.302329 -0.154313 -0.083504
+v -0.313491 -0.149685 -0.083504
+v -0.325341 -0.147323 -0.083504
+v -0.337424 -0.147319 -0.083504
+v -0.349276 -0.149672 -0.083504
+v -0.360441 -0.154292 -0.083504
+v -0.370490 -0.161002 -0.083504
+v -0.379037 -0.169543 -0.083504
+v -0.385753 -0.179587 -0.083504
+v -0.390381 -0.190749 -0.083504
+v -0.392743 -0.202599 -0.083504
+v -0.392747 -0.214683 -0.054117
+v -0.390394 -0.226534 -0.054117
+v -0.385774 -0.237699 -0.054117
+v -0.379064 -0.247748 -0.054117
+v -0.370523 -0.256295 -0.054117
+v -0.360479 -0.263012 -0.054117
+v -0.349317 -0.267640 -0.054117
+v -0.337467 -0.270001 -0.054117
+vn -0.0000 -1.0000 -0.0000
+vn -0.0000 1.0000 -0.0000
+vn 1.0000 -0.0000 -0.0000
+vn -0.0000 -0.0000 -1.0000
+vn -0.0000 -0.0000 1.0000
+vn -1.0000 -0.0000 -0.0000
+vn -0.3830 -0.9237 -0.0000
+vn 0.1954 0.9807 -0.0000
+vn 0.8313 -0.5559 -0.0000
+vn 0.0003 1.0000 -0.0000
+vn -0.9237 0.3830 -0.0000
+vn 0.9807 -0.1954 -0.0000
+vn 0.1947 -0.9809 -0.0000
+vn 0.7073 0.7069 -0.0000
+vn -0.5559 -0.8313 -0.0000
+vn 0.3830 0.9237 -0.0000
+vn -0.3824 0.9240 -0.0000
+vn 1.0000 -0.0003 -0.0000
+vn -0.8313 0.5559 -0.0000
+vn 0.9237 -0.3830 -0.0000
+vn -0.9809 -0.1947 -0.0000
+vn -0.7074 -0.7069 -0.0000
+vn 0.5559 0.8313 -0.0000
+vn 0.7069 -0.7074 -0.0000
+vn -0.7069 0.7073 -0.0000
+vn -0.0003 -1.0000 -0.0000
+vn 0.8317 0.5553 -0.0000
+vn -0.8317 -0.5553 -0.0000
+vn 0.7074 0.7069 -0.0000
+vn -0.5553 0.8317 -0.0000
+vn -0.0003 -0.9346 -0.3557
+vn -0.9240 -0.3824 -0.0000
+vn 1.0000 -0.0004 -0.0000
+vn -0.9807 0.1954 -0.0000
+vn 0.9809 0.1948 -0.0000
+vn 0.1948 -0.9809 -0.0000
+vn -0.1954 -0.9807 -0.0000
+vn 0.3824 -0.9240 -0.0000
+vn -1.0000 0.0004 -0.0000
+vn -0.1947 0.9809 -0.0000
+vn 0.9240 0.3824 -0.0000
+vn 0.5553 -0.8317 -0.0000
+vn -0.7069 0.7074 -0.0000
+vn -1.0000 0.0003 -0.0000
+vn -0.7073 -0.7069 -0.0000
+vn 0.0004 1.0000 -0.0000
+vt 0.640016 0.630686
+vt 0.874116 0.630686
+vt 0.899031 0.371671
+vt 0.899031 0.605771
+vt 0.275073 0.371671
+vt 0.275073 0.605771
+vt 0.536051 0.632649
+vt 0.301951 0.632649
+vt 0.588281 0.578951
+vt 0.588281 0.344851
+vt 0.847296 0.319936
+vt 0.613196 0.319936
+vt 0.326808 0.319936
+vt 0.560909 0.319936
+vt 0.587786 0.580914
+vt 0.587786 0.346814
+vt 0.757066 0.513636
+vt 0.781981 0.488721
+vt 0.392123 0.488721
+vt 0.419001 0.515599
+vt 0.705331 0.461901
+vt 0.730246 0.436986
+vt 0.443858 0.436986
+vt 0.470736 0.463864
+vt 0.062341 0.000247
+vt 0.000247 0.062341
+vt 0.000248 0.359598
+vt 0.039909 0.319936
+vt 0.662834 0.000247
+vt 0.724927 0.062341
+vt 0.000247 0.960091
+vt 0.039910 0.999753
+vt 0.062341 0.062341
+vt 0.662834 0.062341
+vt 0.062341 0.319441
+vt 0.000247 0.257348
+vt 0.274579 0.359598
+vt 0.234916 0.319936
+vt 0.662834 0.319441
+vt 0.724927 0.257348
+vt 0.274579 0.960090
+vt 0.234917 0.999753
+vt 0.062341 0.257348
+vt 0.662834 0.257348
+vt 0.079095 0.359121
+vt 0.039433 0.398784
+vt 0.079095 0.960567
+vt 0.039433 0.920905
+vt 0.195731 0.960567
+vt 0.235393 0.920905
+vt 0.195731 0.359121
+vt 0.235393 0.398783
+vt 0.079095 0.398783
+vt 0.079095 0.920905
+vt 0.195731 0.920905
+vt 0.195731 0.398783
+vt 0.629899 0.095275
+vt 0.095275 0.095275
+vt 0.629899 0.224413
+vt 0.095275 0.224413
+vt 0.753412 0.903011
+vt 0.719354 0.930961
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.714555 0.923780
+vt 0.602565 0.932389
+vt 0.711250 0.915800
+vt 0.593928 0.932389
+vt 0.709565 0.907329
+vt 0.585291 0.932389
+vt 0.709565 0.898692
+vt 0.576654 0.932389
+vt 0.711250 0.890221
+vt 0.568017 0.932389
+vt 0.714556 0.882241
+vt 0.559379 0.932389
+vt 0.719354 0.875060
+vt 0.550742 0.932389
+vt 0.725461 0.868952
+vt 0.542105 0.932389
+vt 0.732643 0.864154
+vt 0.533468 0.932389
+vt 0.740623 0.860849
+vt 0.524831 0.932389
+vt 0.749094 0.859164
+vt 0.516194 0.932389
+vt 0.757731 0.859164
+vt 0.507557 0.932389
+vt 0.766202 0.860849
+vt 0.498920 0.932389
+vt 0.774182 0.864154
+vt 0.490283 0.932389
+vt 0.781363 0.868953
+vt 0.481646 0.932389
+vt 0.787470 0.875060
+vt 0.473009 0.932389
+vt 0.792269 0.882241
+vt 0.464371 0.932389
+vt 0.795574 0.890221
+vt 0.455734 0.932389
+vt 0.797259 0.898692
+vt 0.447097 0.932389
+vt 0.797259 0.907329
+vt 0.438460 0.932389
+vt 0.795574 0.915800
+vt 0.429823 0.932389
+vt 0.792269 0.923780
+vt 0.421186 0.932389
+vt 0.787470 0.930962
+vt 0.412549 0.932389
+vt 0.781363 0.937069
+vt 0.403912 0.932389
+vt 0.774181 0.941867
+vt 0.395275 0.932389
+vt 0.766201 0.945173
+vt 0.386637 0.932389
+vt 0.757730 0.946858
+vt 0.378001 0.932389
+vt 0.749093 0.946858
+vt 0.369363 0.932389
+vt 0.740622 0.945172
+vt 0.360726 0.932389
+vt 0.732643 0.941867
+vt 0.352089 0.932388
+vt 0.725461 0.937069
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.752599 0.742115
+vt 0.718541 0.770066
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.713742 0.762885
+vt 0.602565 0.932389
+vt 0.710437 0.754905
+vt 0.593928 0.932389
+vt 0.708752 0.746434
+vt 0.585291 0.932389
+vt 0.708752 0.737797
+vt 0.576654 0.932389
+vt 0.710437 0.729326
+vt 0.568017 0.932389
+vt 0.713743 0.721346
+vt 0.559379 0.932389
+vt 0.718541 0.714165
+vt 0.550742 0.932389
+vt 0.724649 0.708057
+vt 0.542105 0.932389
+vt 0.731830 0.703259
+vt 0.533468 0.932389
+vt 0.739810 0.699954
+vt 0.524831 0.932389
+vt 0.748281 0.698269
+vt 0.516194 0.932389
+vt 0.756918 0.698269
+vt 0.507557 0.932389
+vt 0.765389 0.699954
+vt 0.498920 0.932389
+vt 0.773369 0.703259
+vt 0.490283 0.932389
+vt 0.780550 0.708058
+vt 0.481646 0.932389
+vt 0.786658 0.714165
+vt 0.473009 0.932389
+vt 0.791456 0.721346
+vt 0.464371 0.932389
+vt 0.794761 0.729326
+vt 0.455734 0.932389
+vt 0.796446 0.737797
+vt 0.447097 0.932389
+vt 0.796446 0.746434
+vt 0.438460 0.932389
+vt 0.794761 0.754905
+vt 0.429823 0.932389
+vt 0.791456 0.762885
+vt 0.421186 0.932389
+vt 0.786657 0.770066
+vt 0.412549 0.932389
+vt 0.780550 0.776174
+vt 0.403912 0.932389
+vt 0.773368 0.780972
+vt 0.395275 0.932389
+vt 0.765389 0.784277
+vt 0.386637 0.932389
+vt 0.756917 0.785962
+vt 0.378001 0.932389
+vt 0.748280 0.785962
+vt 0.369363 0.932389
+vt 0.739809 0.784277
+vt 0.360726 0.932389
+vt 0.731830 0.780972
+vt 0.352089 0.932388
+vt 0.724648 0.776174
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.908735 0.903617
+vt 0.874676 0.931567
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.869878 0.924386
+vt 0.602565 0.932389
+vt 0.866572 0.916406
+vt 0.593928 0.932389
+vt 0.864888 0.907935
+vt 0.585291 0.932389
+vt 0.864888 0.899298
+vt 0.576654 0.932389
+vt 0.866573 0.890827
+vt 0.568017 0.932389
+vt 0.869878 0.882847
+vt 0.559379 0.932389
+vt 0.874676 0.875666
+vt 0.550742 0.932389
+vt 0.880784 0.869558
+vt 0.542105 0.932389
+vt 0.887965 0.864760
+vt 0.533468 0.932389
+vt 0.895945 0.861455
+vt 0.524831 0.932389
+vt 0.904416 0.859770
+vt 0.516194 0.932389
+vt 0.913053 0.859770
+vt 0.507557 0.932389
+vt 0.921524 0.861455
+vt 0.498920 0.932389
+vt 0.929504 0.864760
+vt 0.490283 0.932389
+vt 0.936685 0.869559
+vt 0.481646 0.932389
+vt 0.942793 0.875666
+vt 0.473009 0.932389
+vt 0.947591 0.882847
+vt 0.464371 0.932389
+vt 0.950896 0.890827
+vt 0.455734 0.932389
+vt 0.952581 0.899298
+vt 0.447097 0.932389
+vt 0.952581 0.907935
+vt 0.438460 0.932389
+vt 0.950896 0.916406
+vt 0.429823 0.932389
+vt 0.947591 0.924386
+vt 0.421186 0.932389
+vt 0.942792 0.931568
+vt 0.412549 0.932389
+vt 0.936685 0.937675
+vt 0.403912 0.932389
+vt 0.929504 0.942473
+vt 0.395275 0.932389
+vt 0.921524 0.945779
+vt 0.386637 0.932389
+vt 0.913053 0.947464
+vt 0.378001 0.932389
+vt 0.904416 0.947464
+vt 0.369363 0.932389
+vt 0.895945 0.945778
+vt 0.360726 0.932389
+vt 0.887965 0.942473
+vt 0.352089 0.932388
+vt 0.880783 0.937675
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.908268 0.746864
+vt 0.874210 0.774814
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.869411 0.767633
+vt 0.602565 0.932389
+vt 0.866106 0.759653
+vt 0.593928 0.932389
+vt 0.864421 0.751182
+vt 0.585291 0.932389
+vt 0.864421 0.742545
+vt 0.576654 0.932389
+vt 0.866106 0.734074
+vt 0.568017 0.932389
+vt 0.869412 0.726094
+vt 0.559379 0.932389
+vt 0.874210 0.718913
+vt 0.550742 0.932389
+vt 0.880318 0.712805
+vt 0.542105 0.932389
+vt 0.887499 0.708007
+vt 0.533468 0.932389
+vt 0.895479 0.704702
+vt 0.524831 0.932389
+vt 0.903950 0.703017
+vt 0.516194 0.932389
+vt 0.912587 0.703017
+vt 0.507557 0.932389
+vt 0.921058 0.704702
+vt 0.498920 0.932389
+vt 0.929038 0.708007
+vt 0.490283 0.932389
+vt 0.936219 0.712806
+vt 0.481646 0.932389
+vt 0.942326 0.718913
+vt 0.473009 0.932389
+vt 0.947125 0.726095
+vt 0.464371 0.932389
+vt 0.950430 0.734074
+vt 0.455734 0.932389
+vt 0.952115 0.742545
+vt 0.447097 0.932389
+vt 0.952115 0.751182
+vt 0.438460 0.932389
+vt 0.950430 0.759654
+vt 0.429823 0.932389
+vt 0.947125 0.767633
+vt 0.421186 0.932389
+vt 0.942326 0.774815
+vt 0.412549 0.932389
+vt 0.936219 0.780922
+vt 0.403912 0.932389
+vt 0.929037 0.785721
+vt 0.395275 0.932389
+vt 0.921058 0.789026
+vt 0.386637 0.932389
+vt 0.912586 0.790711
+vt 0.378001 0.932389
+vt 0.903949 0.790711
+vt 0.369363 0.932389
+vt 0.895478 0.789025
+vt 0.360726 0.932389
+vt 0.887499 0.785720
+vt 0.352089 0.932388
+vt 0.880317 0.780922
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+s 0
+g Cube_Material
+usemtl Material
+f 6/11/1 14/22/1 10/18/1 2/3/1
+f 1/1/2 9/17/2 13/21/2 5/9/2
+f 12/20/3 16/24/3 15/23/3 11/19/3
+f 10/18/3 14/22/3 13/21/3 9/17/3
+f 3/5/2 11/19/2 15/23/2 7/13/2
+f 8/15/1 16/24/1 12/20/1 4/7/1
+f 7/14/4 15/23/4 16/24/4 8/16/4
+f 5/10/4 13/21/4 14/22/4 6/12/4
+f 4/8/5 12/20/5 11/19/5 3/6/5
+f 2/4/5 10/18/5 9/17/5 1/2/5
+f 18/29/3 17/25/3 19/33/3 20/34/3
+f 33/57/4 34/58/4 36/60/4 35/59/4
+f 24/44/6 23/43/6 21/35/6 22/39/6
+f 25/45/1 29/53/1 32/56/1 28/51/1
+f 17/26/1 21/36/1 23/43/1 19/33/1
+f 22/40/2 18/30/2 20/34/2 24/44/2
+f 25/46/5 17/27/5 18/31/5 26/48/5
+f 27/50/5 22/41/5 21/37/5 28/52/5
+f 26/47/5 18/32/5 22/42/5 27/49/5
+f 28/51/5 21/38/5 17/28/5 25/45/5
+f 31/55/5 32/56/5 29/53/5 30/54/5
+f 27/49/2 31/55/2 30/54/2 26/47/2
+f 28/52/6 32/56/6 31/55/6 27/50/6
+f 26/48/3 30/54/3 29/53/3 25/46/3
+f 33/57/4 20/34/4 19/33/4 34/58/4
+f 35/59/4 24/44/4 20/34/4 33/57/4
+f 36/60/4 23/43/4 24/44/4 35/59/4
+f 34/58/4 19/33/4 23/43/4 36/60/4
+f 37/61/4 39/65/4 38/62/4
+f 37/61/4 40/67/4 39/65/4
+f 37/61/4 41/69/4 40/67/4
+f 37/61/4 42/71/4 41/69/4
+f 37/61/4 43/73/4 42/71/4
+f 37/61/4 44/75/4 43/73/4
+f 37/61/4 45/77/4 44/75/4
+f 37/61/4 46/79/4 45/77/4
+f 37/61/4 47/81/4 46/79/4
+f 37/61/4 48/83/4 47/81/4
+f 37/61/4 49/85/4 48/83/4
+f 37/61/4 50/87/4 49/85/4
+f 37/61/4 51/89/4 50/87/4
+f 37/61/4 52/91/4 51/89/4
+f 37/61/4 53/93/4 52/91/4
+f 37/61/4 54/95/4 53/93/4
+f 37/61/4 55/97/4 54/95/4
+f 37/61/4 56/99/4 55/97/4
+f 37/61/4 57/101/4 56/99/4
+f 37/61/4 58/103/4 57/101/4
+f 37/61/4 59/105/4 58/103/4
+f 37/61/4 60/107/4 59/105/4
+f 37/61/4 61/109/4 60/107/4
+f 37/61/4 62/111/4 61/109/4
+f 37/61/4 63/113/4 62/111/4
+f 37/61/4 64/115/4 63/113/4
+f 37/61/4 65/117/4 64/115/4
+f 37/61/4 66/119/4 65/117/4
+f 37/61/4 67/121/4 66/119/4
+f 37/61/4 68/123/4 67/121/4
+f 37/61/4 69/125/4 68/123/4
+f 37/61/4 38/62/4 69/125/4
+f 99/156/7 163/287/7 164/290/7 100/157/7
+f 84/141/8 148/256/8 149/259/8 85/142/8
+f 59/106/9 123/205/9 122/202/9 58/104/9
+f 38/63/10 103/162/10 133/225/10 69/126/10
+f 44/76/11 108/174/11 107/171/11 43/74/11
+f 91/148/11 155/270/11 156/273/11 92/149/11
+f 76/133/12 140/239/12 141/243/12 77/134/12
+f 55/98/13 119/197/13 118/194/13 54/96/13
+f 66/120/14 130/220/14 129/217/14 65/118/14
+f 98/155/15 162/285/15 163/287/15 99/156/15
+f 83/140/16 147/254/16 148/256/16 84/141/16
+f 40/68/17 104/166/17 102/161/17 39/66/17
+f 51/90/15 115/189/15 114/186/15 50/88/15
+f 62/112/18 126/212/18 125/208/18 61/110/18
+f 90/147/19 154/268/19 155/270/19 91/148/19
+f 75/132/20 139/237/20 140/239/20 76/133/20
+f 47/82/21 111/181/21 110/179/21 46/80/21
+f 97/154/22 161/283/22 162/285/22 98/155/22
+f 82/139/23 146/252/23 147/254/23 83/140/23
+f 58/104/24 122/202/24 121/201/24 57/102/24
+f 69/126/8 133/225/8 132/224/8 68/124/8
+f 89/146/25 153/266/25 154/268/25 90/147/25
+f 43/74/19 107/171/19 106/170/19 42/72/19
+f 54/96/26 118/194/26 117/193/26 53/94/26
+f 74/131/9 138/235/9 139/237/9 75/132/9
+f 65/118/27 129/217/27 128/216/27 64/116/27
+f 96/153/28 160/282/28 161/283/28 97/154/28
+f 81/138/29 145/251/29 146/252/29 82/139/29
+f 50/88/22 114/186/22 113/185/22 49/86/22
+f 88/145/30 152/265/30 153/266/30 89/146/30
+f 61/110/12 125/208/12 124/207/12 60/108/12
+f 73/130/24 137/234/24 138/235/24 74/131/24
+f 102/160/4 134/227/4 135/229/4 103/163/4
+f 104/165/4 136/231/4 134/227/4 102/160/4
+f 105/167/4 137/233/4 136/231/4 104/165/4
+f 106/169/4 138/236/4 137/233/4 105/167/4
+f 107/172/4 139/238/4 138/236/4 106/169/4
+f 108/173/4 140/240/4 139/238/4 107/172/4
+f 109/175/4 141/241/4 140/240/4 108/173/4
+f 110/178/31 142/244/31 141/242/31 109/176/31
+f 111/180/4 143/246/4 142/244/4 110/178/4
+f 112/182/4 144/248/4 143/246/4 111/180/4
+f 113/184/4 145/250/4 144/248/4 112/182/4
+f 114/187/4 146/253/4 145/250/4 113/184/4
+f 115/188/4 147/255/4 146/253/4 114/187/4
+f 116/190/4 148/257/4 147/255/4 115/188/4
+f 117/192/4 149/258/4 148/257/4 116/190/4
+f 118/195/4 150/260/4 149/258/4 117/192/4
+f 119/196/4 151/262/4 150/260/4 118/195/4
+f 120/198/4 152/264/4 151/262/4 119/196/4
+f 121/200/4 153/267/4 152/264/4 120/198/4
+f 122/203/4 154/269/4 153/267/4 121/200/4
+f 123/204/4 155/271/4 154/269/4 122/203/4
+f 124/206/4 156/272/4 155/271/4 123/204/4
+f 125/209/4 157/274/4 156/272/4 124/206/4
+f 126/210/31 158/276/31 157/274/31 125/209/31
+f 127/213/4 159/279/4 158/277/4 126/211/4
+f 128/215/4 160/281/4 159/279/4 127/213/4
+f 129/218/4 161/284/4 160/281/4 128/215/4
+f 130/219/4 162/286/4 161/284/4 129/218/4
+f 131/221/4 163/288/4 162/286/4 130/219/4
+f 132/223/4 164/289/4 163/288/4 131/221/4
+f 133/226/4 165/291/4 164/289/4 132/223/4
+f 103/163/4 135/229/4 165/291/4 133/226/4
+f 48/84/32 112/183/32 111/181/32 47/82/32
+f 77/134/33 141/243/33 142/245/33 78/135/33
+f 92/149/34 156/273/34 157/275/34 93/150/34
+f 63/114/35 127/214/35 126/212/35 62/112/35
+f 52/92/7 116/191/7 115/189/7 51/90/7
+f 71/128/36 135/230/36 134/228/36 70/127/36
+f 41/70/30 105/168/30 104/166/30 40/68/30
+f 85/142/10 149/259/10 150/261/10 86/143/10
+f 100/157/37 164/290/37 165/292/37 101/158/37
+f 67/122/23 131/222/23 130/220/23 66/120/23
+f 56/100/38 120/199/38 119/197/38 55/98/38
+f 78/135/35 142/245/35 143/247/35 79/136/35
+f 93/150/39 157/275/39 158/278/39 94/151/39
+f 45/78/34 109/177/34 108/174/34 44/76/34
+f 70/127/38 134/228/38 136/232/38 72/129/38
+f 60/108/20 124/207/20 123/205/20 59/106/20
+f 86/143/40 150/261/40 151/263/40 87/144/40
+f 101/159/26 165/293/26 135/230/26 71/128/26
+f 49/86/28 113/185/28 112/183/28 48/84/28
+f 79/136/41 143/247/41 144/249/41 80/137/41
+f 94/151/21 158/278/21 159/280/21 95/152/21
+f 64/116/41 128/216/41 127/214/41 63/114/41
+f 53/94/37 117/193/37 116/191/37 52/92/37
+f 72/129/42 136/232/42 137/234/42 73/130/42
+f 42/72/43 106/170/43 105/168/43 41/70/43
+f 87/144/17 151/263/17 152/265/17 88/145/17
+f 68/124/16 132/224/16 131/222/16 67/122/16
+f 39/66/40 102/161/40 103/164/40 38/64/40
+f 57/102/42 121/201/42 120/199/42 56/100/42
+f 80/137/27 144/249/27 145/251/27 81/138/27
+f 95/152/32 159/280/32 160/282/32 96/153/32
+f 46/80/44 110/179/44 109/177/44 45/78/44
+f 166/294/4 168/298/4 167/295/4
+f 166/294/4 169/300/4 168/298/4
+f 166/294/4 170/302/4 169/300/4
+f 166/294/4 171/304/4 170/302/4
+f 166/294/4 172/306/4 171/304/4
+f 166/294/4 173/308/4 172/306/4
+f 166/294/4 174/310/4 173/308/4
+f 166/294/4 175/312/4 174/310/4
+f 166/294/4 176/314/4 175/312/4
+f 166/294/4 177/316/4 176/314/4
+f 166/294/4 178/318/4 177/316/4
+f 166/294/4 179/320/4 178/318/4
+f 166/294/4 180/322/4 179/320/4
+f 166/294/4 181/324/4 180/322/4
+f 166/294/4 182/326/4 181/324/4
+f 166/294/4 183/328/4 182/326/4
+f 166/294/4 184/330/4 183/328/4
+f 166/294/4 185/332/4 184/330/4
+f 166/294/4 186/334/4 185/332/4
+f 166/294/4 187/336/4 186/334/4
+f 166/294/4 188/338/4 187/336/4
+f 166/294/4 189/340/4 188/338/4
+f 166/294/4 190/342/4 189/340/4
+f 166/294/4 191/344/4 190/342/4
+f 166/294/4 192/346/4 191/344/4
+f 166/294/4 193/348/4 192/346/4
+f 166/294/4 194/350/4 193/348/4
+f 166/294/4 195/352/4 194/350/4
+f 166/294/4 196/354/4 195/352/4
+f 166/294/4 197/356/4 196/354/4
+f 166/294/4 198/358/4 197/356/4
+f 166/294/4 167/295/4 198/358/4
+f 228/389/7 292/520/7 293/523/7 229/390/7
+f 213/374/8 277/489/8 278/492/8 214/375/8
+f 188/339/9 252/438/9 251/435/9 187/337/9
+f 167/296/10 232/395/10 262/458/10 198/359/10
+f 173/309/11 237/407/11 236/404/11 172/307/11
+f 220/381/11 284/503/11 285/506/11 221/382/11
+f 205/366/12 269/472/12 270/476/12 206/367/12
+f 184/331/13 248/430/13 247/427/13 183/329/13
+f 195/353/14 259/453/14 258/450/14 194/351/14
+f 227/388/15 291/518/15 292/520/15 228/389/15
+f 212/373/16 276/487/16 277/489/16 213/374/16
+f 169/301/17 233/399/17 231/394/17 168/299/17
+f 180/323/15 244/422/15 243/419/15 179/321/15
+f 191/345/18 255/445/18 254/441/18 190/343/18
+f 219/380/19 283/501/19 284/503/19 220/381/19
+f 204/365/20 268/470/20 269/472/20 205/366/20
+f 176/315/21 240/414/21 239/412/21 175/313/21
+f 226/387/22 290/516/22 291/518/22 227/388/22
+f 211/372/23 275/485/23 276/487/23 212/373/23
+f 187/337/24 251/435/24 250/434/24 186/335/24
+f 198/359/8 262/458/8 261/457/8 197/357/8
+f 218/379/25 282/499/25 283/501/25 219/380/25
+f 172/307/19 236/404/19 235/403/19 171/305/19
+f 183/329/26 247/427/26 246/426/26 182/327/26
+f 203/364/9 267/468/9 268/470/9 204/365/9
+f 194/351/27 258/450/27 257/449/27 193/349/27
+f 225/386/28 289/515/28 290/516/28 226/387/28
+f 210/371/29 274/484/29 275/485/29 211/372/29
+f 179/321/22 243/419/22 242/418/22 178/319/22
+f 217/378/30 281/498/30 282/499/30 218/379/30
+f 190/343/12 254/441/12 253/440/12 189/341/12
+f 202/363/24 266/467/24 267/468/24 203/364/24
+f 231/393/4 263/460/4 264/462/4 232/396/4
+f 233/398/4 265/464/4 263/460/4 231/393/4
+f 234/400/4 266/466/4 265/464/4 233/398/4
+f 235/402/4 267/469/4 266/466/4 234/400/4
+f 236/405/4 268/471/4 267/469/4 235/402/4
+f 237/406/4 269/473/4 268/471/4 236/405/4
+f 238/408/4 270/474/4 269/473/4 237/406/4
+f 239/411/31 271/477/31 270/475/31 238/409/31
+f 240/413/4 272/479/4 271/477/4 239/411/4
+f 241/415/4 273/481/4 272/479/4 240/413/4
+f 242/417/4 274/483/4 273/481/4 241/415/4
+f 243/420/4 275/486/4 274/483/4 242/417/4
+f 244/421/4 276/488/4 275/486/4 243/420/4
+f 245/423/4 277/490/4 276/488/4 244/421/4
+f 246/425/4 278/491/4 277/490/4 245/423/4
+f 247/428/4 279/493/4 278/491/4 246/425/4
+f 248/429/4 280/495/4 279/493/4 247/428/4
+f 249/431/4 281/497/4 280/495/4 248/429/4
+f 250/433/4 282/500/4 281/497/4 249/431/4
+f 251/436/4 283/502/4 282/500/4 250/433/4
+f 252/437/4 284/504/4 283/502/4 251/436/4
+f 253/439/4 285/505/4 284/504/4 252/437/4
+f 254/442/4 286/507/4 285/505/4 253/439/4
+f 255/443/31 287/509/31 286/507/31 254/442/31
+f 256/446/4 288/512/4 287/510/4 255/444/4
+f 257/448/4 289/514/4 288/512/4 256/446/4
+f 258/451/4 290/517/4 289/514/4 257/448/4
+f 259/452/4 291/519/4 290/517/4 258/451/4
+f 260/454/4 292/521/4 291/519/4 259/452/4
+f 261/456/4 293/522/4 292/521/4 260/454/4
+f 262/459/4 294/524/4 293/522/4 261/456/4
+f 232/396/4 264/462/4 294/524/4 262/459/4
+f 177/317/32 241/416/32 240/414/32 176/315/32
+f 206/367/33 270/476/33 271/478/33 207/368/33
+f 221/382/34 285/506/34 286/508/34 222/383/34
+f 192/347/35 256/447/35 255/445/35 191/345/35
+f 181/325/7 245/424/7 244/422/7 180/323/7
+f 200/361/36 264/463/36 263/461/36 199/360/36
+f 170/303/30 234/401/30 233/399/30 169/301/30
+f 214/375/10 278/492/10 279/494/10 215/376/10
+f 229/390/37 293/523/37 294/525/37 230/391/37
+f 196/355/23 260/455/23 259/453/23 195/353/23
+f 185/333/38 249/432/38 248/430/38 184/331/38
+f 207/368/35 271/478/35 272/480/35 208/369/35
+f 222/383/39 286/508/39 287/511/39 223/384/39
+f 174/311/34 238/410/34 237/407/34 173/309/34
+f 199/360/38 263/461/38 265/465/38 201/362/38
+f 189/341/20 253/440/20 252/438/20 188/339/20
+f 215/376/40 279/494/40 280/496/40 216/377/40
+f 230/392/26 294/526/26 264/463/26 200/361/26
+f 178/319/28 242/418/28 241/416/28 177/317/28
+f 208/369/41 272/480/41 273/482/41 209/370/41
+f 223/384/21 287/511/21 288/513/21 224/385/21
+f 193/349/41 257/449/41 256/447/41 192/347/41
+f 182/327/37 246/426/37 245/424/37 181/325/37
+f 201/362/42 265/465/42 266/467/42 202/363/42
+f 171/305/43 235/403/43 234/401/43 170/303/43
+f 216/377/17 280/496/17 281/498/17 217/378/17
+f 197/357/16 261/457/16 260/455/16 196/355/16
+f 168/299/40 231/394/40 232/397/40 167/297/40
+f 186/335/42 250/434/42 249/432/42 185/333/42
+f 209/370/27 273/482/27 274/484/27 210/371/27
+f 224/385/32 288/513/32 289/515/32 225/386/32
+f 175/313/44 239/412/44 238/410/44 174/311/44
+f 295/527/4 297/531/4 296/528/4
+f 295/527/4 298/533/4 297/531/4
+f 295/527/4 299/535/4 298/533/4
+f 295/527/4 300/537/4 299/535/4
+f 295/527/4 301/539/4 300/537/4
+f 295/527/4 302/541/4 301/539/4
+f 295/527/4 303/543/4 302/541/4
+f 295/527/4 304/545/4 303/543/4
+f 295/527/4 305/547/4 304/545/4
+f 295/527/4 306/549/4 305/547/4
+f 295/527/4 307/551/4 306/549/4
+f 295/527/4 308/553/4 307/551/4
+f 295/527/4 309/555/4 308/553/4
+f 295/527/4 310/557/4 309/555/4
+f 295/527/4 311/559/4 310/557/4
+f 295/527/4 312/561/4 311/559/4
+f 295/527/4 313/563/4 312/561/4
+f 295/527/4 314/565/4 313/563/4
+f 295/527/4 315/567/4 314/565/4
+f 295/527/4 316/569/4 315/567/4
+f 295/527/4 317/571/4 316/569/4
+f 295/527/4 318/573/4 317/571/4
+f 295/527/4 319/575/4 318/573/4
+f 295/527/4 320/577/4 319/575/4
+f 295/527/4 321/579/4 320/577/4
+f 295/527/4 322/581/4 321/579/4
+f 295/527/4 323/583/4 322/581/4
+f 295/527/4 324/585/4 323/583/4
+f 295/527/4 325/587/4 324/585/4
+f 295/527/4 326/589/4 325/587/4
+f 295/527/4 327/591/4 326/589/4
+f 295/527/4 296/528/4 327/591/4
+f 357/622/7 421/753/7 422/756/7 358/623/7
+f 342/607/8 406/722/8 407/725/8 343/608/8
+f 317/572/9 381/671/9 380/668/9 316/570/9
+f 296/529/10 361/628/10 391/691/10 327/592/10
+f 302/542/11 366/640/11 365/637/11 301/540/11
+f 349/614/11 413/736/11 414/739/11 350/615/11
+f 334/599/12 398/705/12 399/709/12 335/600/12
+f 313/564/13 377/663/13 376/660/13 312/562/13
+f 324/586/14 388/686/14 387/683/14 323/584/14
+f 356/621/15 420/751/15 421/753/15 357/622/15
+f 341/606/16 405/720/16 406/722/16 342/607/16
+f 298/534/17 362/632/17 360/627/17 297/532/17
+f 309/556/15 373/655/15 372/652/15 308/554/15
+f 320/578/18 384/678/18 383/674/18 319/576/18
+f 348/613/19 412/734/19 413/736/19 349/614/19
+f 333/598/20 397/703/20 398/705/20 334/599/20
+f 305/548/21 369/647/21 368/645/21 304/546/21
+f 355/620/45 419/749/45 420/751/45 356/621/45
+f 340/605/23 404/718/23 405/720/23 341/606/23
+f 316/570/24 380/668/24 379/667/24 315/568/24
+f 327/592/8 391/691/8 390/690/8 326/590/8
+f 347/612/25 411/732/25 412/734/25 348/613/25
+f 301/540/19 365/637/19 364/636/19 300/538/19
+f 312/562/26 376/660/26 375/659/26 311/560/26
+f 332/597/9 396/701/9 397/703/9 333/598/9
+f 323/584/27 387/683/27 386/682/27 322/582/27
+f 354/619/28 418/748/28 419/749/28 355/620/28
+f 339/604/29 403/717/29 404/718/29 340/605/29
+f 308/554/22 372/652/22 371/651/22 307/552/22
+f 346/611/30 410/731/30 411/732/30 347/612/30
+f 319/576/12 383/674/12 382/673/12 318/574/12
+f 331/596/24 395/700/24 396/701/24 332/597/24
+f 360/626/4 392/693/4 393/695/4 361/629/4
+f 362/631/4 394/697/4 392/693/4 360/626/4
+f 363/633/4 395/699/4 394/697/4 362/631/4
+f 364/635/4 396/702/4 395/699/4 363/633/4
+f 365/638/4 397/704/4 396/702/4 364/635/4
+f 366/639/4 398/706/4 397/704/4 365/638/4
+f 367/641/4 399/707/4 398/706/4 366/639/4
+f 368/644/31 400/710/31 399/708/31 367/642/31
+f 369/646/4 401/712/4 400/710/4 368/644/4
+f 370/648/4 402/714/4 401/712/4 369/646/4
+f 371/650/4 403/716/4 402/714/4 370/648/4
+f 372/653/4 404/719/4 403/716/4 371/650/4
+f 373/654/4 405/721/4 404/719/4 372/653/4
+f 374/656/4 406/723/4 405/721/4 373/654/4
+f 375/658/4 407/724/4 406/723/4 374/656/4
+f 376/661/4 408/726/4 407/724/4 375/658/4
+f 377/662/4 409/728/4 408/726/4 376/661/4
+f 378/664/4 410/730/4 409/728/4 377/662/4
+f 379/666/4 411/733/4 410/730/4 378/664/4
+f 380/669/4 412/735/4 411/733/4 379/666/4
+f 381/670/4 413/737/4 412/735/4 380/669/4
+f 382/672/4 414/738/4 413/737/4 381/670/4
+f 383/675/4 415/740/4 414/738/4 382/672/4
+f 384/676/31 416/742/31 415/740/31 383/675/31
+f 385/679/4 417/745/4 416/743/4 384/677/4
+f 386/681/4 418/747/4 417/745/4 385/679/4
+f 387/684/4 419/750/4 418/747/4 386/681/4
+f 388/685/4 420/752/4 419/750/4 387/684/4
+f 389/687/4 421/754/4 420/752/4 388/685/4
+f 390/689/4 422/755/4 421/754/4 389/687/4
+f 391/692/4 423/757/4 422/755/4 390/689/4
+f 361/629/4 393/695/4 423/757/4 391/692/4
+f 306/550/32 370/649/32 369/647/32 305/548/32
+f 335/600/33 399/709/33 400/711/33 336/601/33
+f 350/615/34 414/739/34 415/741/34 351/616/34
+f 321/580/35 385/680/35 384/678/35 320/578/35
+f 310/558/7 374/657/7 373/655/7 309/556/7
+f 329/594/36 393/696/36 392/694/36 328/593/36
+f 299/536/30 363/634/30 362/632/30 298/534/30
+f 343/608/10 407/725/10 408/727/10 344/609/10
+f 358/623/37 422/756/37 423/758/37 359/624/37
+f 325/588/23 389/688/23 388/686/23 324/586/23
+f 314/566/38 378/665/38 377/663/38 313/564/38
+f 336/601/35 400/711/35 401/713/35 337/602/35
+f 351/616/39 415/741/39 416/744/39 352/617/39
+f 303/544/34 367/643/34 366/640/34 302/542/34
+f 328/593/38 392/694/38 394/698/38 330/595/38
+f 318/574/20 382/673/20 381/671/20 317/572/20
+f 344/609/40 408/727/40 409/729/40 345/610/40
+f 359/625/26 423/759/26 393/696/26 329/594/26
+f 307/552/28 371/651/28 370/649/28 306/550/28
+f 337/602/41 401/713/41 402/715/41 338/603/41
+f 352/617/21 416/744/21 417/746/21 353/618/21
+f 322/582/41 386/682/41 385/680/41 321/580/41
+f 311/560/37 375/659/37 374/657/37 310/558/37
+f 330/595/42 394/698/42 395/700/42 331/596/42
+f 300/538/43 364/636/43 363/634/43 299/536/43
+f 345/610/17 409/729/17 410/731/17 346/611/17
+f 326/590/16 390/690/16 389/688/16 325/588/16
+f 297/532/40 360/627/40 361/630/40 296/530/40
+f 315/568/42 379/667/42 378/665/42 314/566/42
+f 338/603/27 402/715/27 403/717/27 339/604/27
+f 353/618/32 417/746/32 418/748/32 354/619/32
+f 304/546/44 368/645/44 367/643/44 303/544/44
+f 424/760/4 426/764/4 425/761/4
+f 424/760/4 427/766/4 426/764/4
+f 424/760/4 428/768/4 427/766/4
+f 424/760/4 429/770/4 428/768/4
+f 424/760/4 430/772/4 429/770/4
+f 424/760/4 431/774/4 430/772/4
+f 424/760/4 432/776/4 431/774/4
+f 424/760/4 433/778/4 432/776/4
+f 424/760/4 434/780/4 433/778/4
+f 424/760/4 435/782/4 434/780/4
+f 424/760/4 436/784/4 435/782/4
+f 424/760/4 437/786/4 436/784/4
+f 424/760/4 438/788/4 437/786/4
+f 424/760/4 439/790/4 438/788/4
+f 424/760/4 440/792/4 439/790/4
+f 424/760/4 441/794/4 440/792/4
+f 424/760/4 442/796/4 441/794/4
+f 424/760/4 443/798/4 442/796/4
+f 424/760/4 444/800/4 443/798/4
+f 424/760/4 445/802/4 444/800/4
+f 424/760/4 446/804/4 445/802/4
+f 424/760/4 447/806/4 446/804/4
+f 424/760/4 448/808/4 447/806/4
+f 424/760/4 449/810/4 448/808/4
+f 424/760/4 450/812/4 449/810/4
+f 424/760/4 451/814/4 450/812/4
+f 424/760/4 452/816/4 451/814/4
+f 424/760/4 453/818/4 452/816/4
+f 424/760/4 454/820/4 453/818/4
+f 424/760/4 455/822/4 454/820/4
+f 424/760/4 456/824/4 455/822/4
+f 424/760/4 425/761/4 456/824/4
+f 486/855/7 550/986/7 551/989/7 487/856/7
+f 471/840/8 535/955/8 536/958/8 472/841/8
+f 446/805/9 510/904/9 509/901/9 445/803/9
+f 425/762/46 490/861/46 520/924/46 456/825/46
+f 431/775/11 495/873/11 494/870/11 430/773/11
+f 478/847/11 542/969/11 543/972/11 479/848/11
+f 463/832/12 527/938/12 528/942/12 464/833/12
+f 442/797/13 506/896/13 505/893/13 441/795/13
+f 453/819/14 517/919/14 516/916/14 452/817/14
+f 485/854/15 549/984/15 550/986/15 486/855/15
+f 470/839/16 534/953/16 535/955/16 471/840/16
+f 427/767/17 491/865/17 489/860/17 426/765/17
+f 438/789/15 502/888/15 501/885/15 437/787/15
+f 449/811/18 513/911/18 512/907/18 448/809/18
+f 477/846/19 541/967/19 542/969/19 478/847/19
+f 462/831/20 526/936/20 527/938/20 463/832/20
+f 434/781/21 498/880/21 497/878/21 433/779/21
+f 484/853/22 548/982/22 549/984/22 485/854/22
+f 469/838/23 533/951/23 534/953/23 470/839/23
+f 445/803/24 509/901/24 508/900/24 444/801/24
+f 456/825/8 520/924/8 519/923/8 455/823/8
+f 476/845/25 540/965/25 541/967/25 477/846/25
+f 430/773/19 494/870/19 493/869/19 429/771/19
+f 441/795/26 505/893/26 504/892/26 440/793/26
+f 461/830/9 525/934/9 526/936/9 462/831/9
+f 452/817/27 516/916/27 515/915/27 451/815/27
+f 483/852/28 547/981/28 548/982/28 484/853/28
+f 468/837/29 532/950/29 533/951/29 469/838/29
+f 437/787/22 501/885/22 500/884/22 436/785/22
+f 475/844/30 539/964/30 540/965/30 476/845/30
+f 448/809/12 512/907/12 511/906/12 447/807/12
+f 460/829/24 524/933/24 525/934/24 461/830/24
+f 489/859/4 521/926/4 522/928/4 490/862/4
+f 491/864/4 523/930/4 521/926/4 489/859/4
+f 492/866/4 524/932/4 523/930/4 491/864/4
+f 493/868/4 525/935/4 524/932/4 492/866/4
+f 494/871/4 526/937/4 525/935/4 493/868/4
+f 495/872/4 527/939/4 526/937/4 494/871/4
+f 496/874/4 528/940/4 527/939/4 495/872/4
+f 497/877/31 529/943/31 528/941/31 496/875/31
+f 498/879/4 530/945/4 529/943/4 497/877/4
+f 499/881/4 531/947/4 530/945/4 498/879/4
+f 500/883/4 532/949/4 531/947/4 499/881/4
+f 501/886/4 533/952/4 532/949/4 500/883/4
+f 502/887/4 534/954/4 533/952/4 501/886/4
+f 503/889/4 535/956/4 534/954/4 502/887/4
+f 504/891/4 536/957/4 535/956/4 503/889/4
+f 505/894/4 537/959/4 536/957/4 504/891/4
+f 506/895/4 538/961/4 537/959/4 505/894/4
+f 507/897/4 539/963/4 538/961/4 506/895/4
+f 508/899/4 540/966/4 539/963/4 507/897/4
+f 509/902/4 541/968/4 540/966/4 508/899/4
+f 510/903/4 542/970/4 541/968/4 509/902/4
+f 511/905/4 543/971/4 542/970/4 510/903/4
+f 512/908/4 544/973/4 543/971/4 511/905/4
+f 513/909/31 545/975/31 544/973/31 512/908/31
+f 514/912/4 546/978/4 545/976/4 513/910/4
+f 515/914/4 547/980/4 546/978/4 514/912/4
+f 516/917/4 548/983/4 547/980/4 515/914/4
+f 517/918/4 549/985/4 548/983/4 516/917/4
+f 518/920/4 550/987/4 549/985/4 517/918/4
+f 519/922/4 551/988/4 550/987/4 518/920/4
+f 520/925/4 552/990/4 551/988/4 519/922/4
+f 490/862/4 522/928/4 552/990/4 520/925/4
+f 435/783/32 499/882/32 498/880/32 434/781/32
+f 464/833/33 528/942/33 529/944/33 465/834/33
+f 479/848/34 543/972/34 544/974/34 480/849/34
+f 450/813/35 514/913/35 513/911/35 449/811/35
+f 439/791/7 503/890/7 502/888/7 438/789/7
+f 458/827/36 522/929/36 521/927/36 457/826/36
+f 428/769/30 492/867/30 491/865/30 427/767/30
+f 472/841/10 536/958/10 537/960/10 473/842/10
+f 487/856/37 551/989/37 552/991/37 488/857/37
+f 454/821/23 518/921/23 517/919/23 453/819/23
+f 443/799/38 507/898/38 506/896/38 442/797/38
+f 465/834/35 529/944/35 530/946/35 466/835/35
+f 480/849/39 544/974/39 545/977/39 481/850/39
+f 432/777/34 496/876/34 495/873/34 431/775/34
+f 457/826/38 521/927/38 523/931/38 459/828/38
+f 447/807/20 511/906/20 510/904/20 446/805/20
+f 473/842/40 537/960/40 538/962/40 474/843/40
+f 488/858/26 552/992/26 522/929/26 458/827/26
+f 436/785/28 500/884/28 499/882/28 435/783/28
+f 466/835/41 530/946/41 531/948/41 467/836/41
+f 481/850/21 545/977/21 546/979/21 482/851/21
+f 451/815/41 515/915/41 514/913/41 450/813/41
+f 440/793/37 504/892/37 503/890/37 439/791/37
+f 459/828/42 523/931/42 524/933/42 460/829/42
+f 429/771/43 493/869/43 492/867/43 428/769/43
+f 474/843/17 538/962/17 539/964/17 475/844/17
+f 455/823/16 519/923/16 518/921/16 454/821/16
+f 426/765/40 489/860/40 490/863/40 425/763/40
+f 444/801/42 508/900/42 507/898/42 443/799/42
+f 467/836/27 531/948/27 532/950/27 468/837/27
+f 482/851/32 546/979/32 547/981/32 483/852/32
+f 433/779/44 497/878/44 496/876/44 432/777/44
diff --git a/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_t.mtl b/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_t.mtl
new file mode 100644
index 0000000..69697a9
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_t.mtl
@@ -0,0 +1,12 @@
+# Blender 3.4.1 MTL File: 'signal_wall_ceiling_muc_ubahn.blend'
+# www.blender.org
+
+newmtl Material
+Ns 250.000000
+Ka 1.000000 1.000000 1.000000
+Kd 0.800000 0.800000 0.800000
+Ks 0.500000 0.500000 0.500000
+Ke 0.000000 0.000000 0.000000
+Ni 1.000000
+d 1.000000
+illum 2
diff --git a/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_t.obj b/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_t.obj
new file mode 100644
index 0000000..c443b3c
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/models/advtrains_signals_muc_ubahn_wsig_t.obj
@@ -0,0 +1,2138 @@
+# Blender 3.4.1
+# www.blender.org
+mtllib advtrains_signals_muc_ubahn_wsig_t.mtl
+o Cube
+v 0.399475 0.500000 0.043560
+v 0.357519 0.500000 0.043560
+v -0.357519 0.500000 0.043560
+v -0.402780 0.500000 0.043560
+v 0.399475 0.500000 -0.043560
+v 0.357519 0.500000 -0.043560
+v -0.357519 0.500000 -0.043560
+v -0.402780 0.500000 -0.043560
+v 0.399475 0.302890 0.043560
+v 0.357519 0.302890 0.043560
+v -0.357519 0.302890 0.043560
+v -0.402780 0.302890 0.043560
+v 0.399475 0.302890 -0.043561
+v 0.357519 0.302890 -0.043561
+v -0.357519 0.302890 -0.043560
+v -0.402780 0.302890 -0.043560
+v -0.357519 0.218703 0.042354
+v 0.357519 0.218703 0.042353
+v -0.357519 0.218703 -0.031584
+v 0.357519 0.218703 -0.031584
+v -0.357519 0.450908 0.042354
+v 0.357519 0.450908 0.042353
+v -0.357519 0.450908 -0.031584
+v 0.357519 0.450908 -0.031584
+v -0.310859 0.265363 0.042354
+v 0.310859 0.265363 0.042353
+v 0.310859 0.404247 0.042353
+v -0.310859 0.404247 0.042354
+v -0.310858 0.265363 0.089581
+v 0.310859 0.265363 0.089581
+v 0.310859 0.404247 0.089581
+v -0.310858 0.404247 0.089581
+v 0.318302 0.257920 -0.031584
+v -0.318302 0.257920 -0.031584
+v 0.318302 0.411691 -0.031584
+v -0.318302 0.411691 -0.031584
+v 0.241062 0.331404 -0.037331
+v 0.246186 0.279191 -0.037331
+v 0.256274 0.281194 -0.037331
+v 0.265777 0.285126 -0.037331
+v 0.274330 0.290837 -0.037331
+v 0.281605 0.298107 -0.037331
+v 0.287322 0.306656 -0.037331
+v 0.291261 0.316157 -0.037331
+v 0.293271 0.326243 -0.037331
+v 0.293275 0.336528 -0.037331
+v 0.291272 0.346615 -0.037331
+v 0.287339 0.356118 -0.037331
+v 0.281628 0.364672 -0.037331
+v 0.274359 0.371947 -0.037331
+v 0.265809 0.377664 -0.037331
+v 0.256309 0.381603 -0.037331
+v 0.246223 0.383613 -0.037331
+v 0.235938 0.383616 -0.037331
+v 0.225850 0.381613 -0.037331
+v 0.216347 0.377681 -0.037331
+v 0.207794 0.371970 -0.037331
+v 0.200519 0.364700 -0.037331
+v 0.194802 0.356151 -0.037331
+v 0.190863 0.346650 -0.037331
+v 0.188853 0.336564 -0.037331
+v 0.188850 0.326279 -0.037331
+v 0.190853 0.316192 -0.037331
+v 0.194785 0.306689 -0.037331
+v 0.200496 0.298135 -0.037331
+v 0.207766 0.290860 -0.037331
+v 0.216315 0.285144 -0.037331
+v 0.225815 0.281204 -0.037331
+v 0.235902 0.279195 -0.037331
+v 0.258934 0.272413 -0.031584
+v 0.247082 0.270060 -0.031584
+v 0.270099 0.277034 -0.031584
+v 0.280148 0.283743 -0.031584
+v 0.288695 0.292284 -0.031584
+v 0.295412 0.302329 -0.031584
+v 0.300040 0.313490 -0.031584
+v 0.302401 0.325341 -0.031584
+v 0.302406 0.337424 -0.031584
+v 0.300052 0.349275 -0.031584
+v 0.295432 0.360440 -0.031584
+v 0.288723 0.370490 -0.031584
+v 0.280181 0.379037 -0.031584
+v 0.270137 0.385753 -0.031584
+v 0.258975 0.390381 -0.031584
+v 0.247125 0.392743 -0.031584
+v 0.235042 0.392747 -0.031584
+v 0.223190 0.390394 -0.031584
+v 0.212025 0.385773 -0.031584
+v 0.201976 0.379064 -0.031584
+v 0.193429 0.370523 -0.031584
+v 0.186713 0.360478 -0.031584
+v 0.182085 0.349317 -0.031584
+v 0.179723 0.337466 -0.031584
+v 0.179719 0.325383 -0.031584
+v 0.182072 0.313532 -0.031584
+v 0.186692 0.302367 -0.031584
+v 0.193402 0.292317 -0.031584
+v 0.201943 0.283770 -0.031584
+v 0.211987 0.277054 -0.031584
+v 0.223149 0.272426 -0.031584
+v 0.234999 0.270065 -0.031584
+v 0.256274 0.281194 -0.054117
+v 0.246186 0.279191 -0.054117
+v 0.265777 0.285126 -0.054117
+v 0.274330 0.290837 -0.054117
+v 0.281605 0.298107 -0.054117
+v 0.287322 0.306656 -0.054117
+v 0.291261 0.316157 -0.054117
+v 0.293271 0.326243 -0.054117
+v 0.293275 0.336528 -0.083504
+v 0.291272 0.346615 -0.083504
+v 0.287339 0.356118 -0.083504
+v 0.281628 0.364672 -0.083504
+v 0.274359 0.371947 -0.083504
+v 0.265809 0.377664 -0.083504
+v 0.256309 0.381603 -0.083504
+v 0.246223 0.383613 -0.083504
+v 0.235938 0.383616 -0.083504
+v 0.225850 0.381613 -0.083504
+v 0.216347 0.377681 -0.083504
+v 0.207794 0.371970 -0.083504
+v 0.200519 0.364700 -0.083504
+v 0.194802 0.356151 -0.083504
+v 0.190863 0.346650 -0.083504
+v 0.188853 0.336564 -0.083504
+v 0.188850 0.326279 -0.054117
+v 0.190853 0.316192 -0.054117
+v 0.194785 0.306689 -0.054117
+v 0.200496 0.298135 -0.054117
+v 0.207766 0.290860 -0.054117
+v 0.216315 0.285144 -0.054117
+v 0.225815 0.281204 -0.054117
+v 0.235902 0.279195 -0.054117
+v 0.258934 0.272413 -0.054117
+v 0.247082 0.270060 -0.054117
+v 0.270099 0.277034 -0.054117
+v 0.280148 0.283743 -0.054117
+v 0.288695 0.292284 -0.054117
+v 0.295412 0.302329 -0.054117
+v 0.300040 0.313490 -0.054117
+v 0.302401 0.325341 -0.054117
+v 0.302406 0.337424 -0.083504
+v 0.300052 0.349275 -0.083504
+v 0.295432 0.360440 -0.083504
+v 0.288723 0.370490 -0.083504
+v 0.280181 0.379037 -0.083504
+v 0.270137 0.385753 -0.083504
+v 0.258975 0.390381 -0.083504
+v 0.247125 0.392743 -0.083504
+v 0.235042 0.392747 -0.083504
+v 0.223190 0.390394 -0.083504
+v 0.212025 0.385773 -0.083504
+v 0.201976 0.379064 -0.083504
+v 0.193429 0.370523 -0.083504
+v 0.186713 0.360478 -0.083504
+v 0.182085 0.349317 -0.083504
+v 0.179723 0.337466 -0.083504
+v 0.179719 0.325383 -0.054117
+v 0.182072 0.313532 -0.054117
+v 0.186692 0.302367 -0.054117
+v 0.193402 0.292317 -0.054117
+v 0.201943 0.283770 -0.054117
+v 0.211987 0.277054 -0.054117
+v 0.223149 0.272426 -0.054117
+v 0.234999 0.270065 -0.054117
+v 0.091062 0.331404 -0.037331
+v 0.096186 0.279191 -0.037331
+v 0.106274 0.281194 -0.037331
+v 0.115777 0.285126 -0.037331
+v 0.124331 0.290837 -0.037331
+v 0.131605 0.298107 -0.037331
+v 0.137322 0.306656 -0.037331
+v 0.141261 0.316157 -0.037331
+v 0.143271 0.326243 -0.037331
+v 0.143275 0.336528 -0.037331
+v 0.141272 0.346615 -0.037331
+v 0.137339 0.356119 -0.037331
+v 0.131628 0.364672 -0.037331
+v 0.124359 0.371947 -0.037331
+v 0.115809 0.377664 -0.037331
+v 0.106309 0.381603 -0.037331
+v 0.096223 0.383613 -0.037331
+v 0.085938 0.383616 -0.037331
+v 0.075850 0.381613 -0.037331
+v 0.066347 0.377681 -0.037331
+v 0.057794 0.371970 -0.037331
+v 0.050519 0.364700 -0.037331
+v 0.044802 0.356151 -0.037331
+v 0.040863 0.346650 -0.037331
+v 0.038853 0.336564 -0.037331
+v 0.038850 0.326279 -0.037331
+v 0.040853 0.316192 -0.037331
+v 0.044785 0.306689 -0.037331
+v 0.050496 0.298135 -0.037331
+v 0.057766 0.290860 -0.037331
+v 0.066315 0.285144 -0.037331
+v 0.075815 0.281205 -0.037331
+v 0.085902 0.279195 -0.037331
+v 0.108934 0.272414 -0.031584
+v 0.097082 0.270060 -0.031584
+v 0.120099 0.277034 -0.031584
+v 0.130148 0.283743 -0.031584
+v 0.138695 0.292284 -0.031584
+v 0.145412 0.302329 -0.031584
+v 0.150040 0.313490 -0.031584
+v 0.152401 0.325341 -0.031584
+v 0.152406 0.337424 -0.031584
+v 0.150052 0.349276 -0.031584
+v 0.145432 0.360440 -0.031584
+v 0.138723 0.370490 -0.031584
+v 0.130181 0.379037 -0.031584
+v 0.120137 0.385753 -0.031584
+v 0.108975 0.390381 -0.031584
+v 0.097125 0.392743 -0.031584
+v 0.085042 0.392747 -0.031584
+v 0.073190 0.390394 -0.031584
+v 0.062025 0.385773 -0.031584
+v 0.051976 0.379064 -0.031584
+v 0.043429 0.370523 -0.031584
+v 0.036713 0.360478 -0.031584
+v 0.032085 0.349317 -0.031584
+v 0.029723 0.337467 -0.031584
+v 0.029719 0.325383 -0.031584
+v 0.032072 0.313532 -0.031584
+v 0.036692 0.302367 -0.031584
+v 0.043402 0.292317 -0.031584
+v 0.051943 0.283770 -0.031584
+v 0.061987 0.277054 -0.031584
+v 0.073149 0.272426 -0.031584
+v 0.084999 0.270065 -0.031584
+v 0.106274 0.281194 -0.054117
+v 0.096186 0.279191 -0.054117
+v 0.115777 0.285126 -0.054117
+v 0.124331 0.290837 -0.054117
+v 0.131605 0.298107 -0.054117
+v 0.137322 0.306656 -0.054117
+v 0.141261 0.316157 -0.054117
+v 0.143271 0.326243 -0.054117
+v 0.143275 0.336528 -0.083504
+v 0.141272 0.346615 -0.083504
+v 0.137339 0.356119 -0.083504
+v 0.131628 0.364672 -0.083504
+v 0.124359 0.371947 -0.083504
+v 0.115809 0.377664 -0.083504
+v 0.106309 0.381603 -0.083504
+v 0.096223 0.383613 -0.083504
+v 0.085938 0.383616 -0.083504
+v 0.075850 0.381613 -0.083504
+v 0.066347 0.377681 -0.083504
+v 0.057794 0.371970 -0.083504
+v 0.050519 0.364700 -0.083504
+v 0.044802 0.356151 -0.083504
+v 0.040863 0.346650 -0.083504
+v 0.038853 0.336564 -0.083504
+v 0.038850 0.326279 -0.054117
+v 0.040853 0.316192 -0.054117
+v 0.044785 0.306689 -0.054117
+v 0.050496 0.298135 -0.054117
+v 0.057766 0.290860 -0.054117
+v 0.066315 0.285144 -0.054117
+v 0.075815 0.281205 -0.054117
+v 0.085902 0.279195 -0.054117
+v 0.108934 0.272414 -0.054117
+v 0.097082 0.270060 -0.054117
+v 0.120099 0.277034 -0.054117
+v 0.130148 0.283743 -0.054117
+v 0.138695 0.292284 -0.054117
+v 0.145412 0.302329 -0.054117
+v 0.150040 0.313490 -0.054117
+v 0.152401 0.325341 -0.054117
+v 0.152406 0.337424 -0.083504
+v 0.150052 0.349276 -0.083504
+v 0.145432 0.360440 -0.083504
+v 0.138723 0.370490 -0.083504
+v 0.130181 0.379037 -0.083504
+v 0.120137 0.385753 -0.083504
+v 0.108975 0.390381 -0.083504
+v 0.097125 0.392743 -0.083504
+v 0.085042 0.392747 -0.083504
+v 0.073190 0.390394 -0.083504
+v 0.062025 0.385773 -0.083504
+v 0.051976 0.379064 -0.083504
+v 0.043429 0.370523 -0.083504
+v 0.036713 0.360478 -0.083504
+v 0.032085 0.349317 -0.083504
+v 0.029723 0.337466 -0.083504
+v 0.029719 0.325383 -0.054117
+v 0.032072 0.313532 -0.054117
+v 0.036692 0.302367 -0.054117
+v 0.043402 0.292317 -0.054117
+v 0.051943 0.283770 -0.054117
+v 0.061987 0.277054 -0.054117
+v 0.073149 0.272426 -0.054117
+v 0.084999 0.270065 -0.054117
+v -0.058938 0.331404 -0.037331
+v -0.053814 0.279191 -0.037331
+v -0.043726 0.281194 -0.037331
+v -0.034223 0.285126 -0.037331
+v -0.025669 0.290837 -0.037331
+v -0.018395 0.298107 -0.037331
+v -0.012678 0.306656 -0.037331
+v -0.008739 0.316157 -0.037331
+v -0.006729 0.326243 -0.037331
+v -0.006725 0.336528 -0.037331
+v -0.008728 0.346615 -0.037331
+v -0.012661 0.356119 -0.037331
+v -0.018372 0.364672 -0.037331
+v -0.025641 0.371947 -0.037331
+v -0.034191 0.377664 -0.037331
+v -0.043691 0.381603 -0.037331
+v -0.053777 0.383613 -0.037331
+v -0.064062 0.383616 -0.037331
+v -0.074150 0.381613 -0.037331
+v -0.083653 0.377681 -0.037331
+v -0.092206 0.371970 -0.037331
+v -0.099481 0.364700 -0.037331
+v -0.105198 0.356151 -0.037331
+v -0.109137 0.346650 -0.037331
+v -0.111147 0.336564 -0.037331
+v -0.111150 0.326279 -0.037331
+v -0.109147 0.316192 -0.037331
+v -0.105215 0.306689 -0.037331
+v -0.099504 0.298135 -0.037331
+v -0.092234 0.290860 -0.037331
+v -0.083685 0.285144 -0.037331
+v -0.074185 0.281205 -0.037331
+v -0.064098 0.279195 -0.037331
+v -0.041066 0.272414 -0.031584
+v -0.052918 0.270060 -0.031584
+v -0.029901 0.277034 -0.031584
+v -0.019852 0.283743 -0.031584
+v -0.011305 0.292284 -0.031584
+v -0.004588 0.302329 -0.031584
+v 0.000040 0.313490 -0.031584
+v 0.002401 0.325341 -0.031584
+v 0.002406 0.337424 -0.031584
+v 0.000052 0.349276 -0.031584
+v -0.004568 0.360440 -0.031584
+v -0.011277 0.370490 -0.031584
+v -0.019819 0.379037 -0.031584
+v -0.029863 0.385753 -0.031584
+v -0.041025 0.390381 -0.031584
+v -0.052875 0.392743 -0.031584
+v -0.064958 0.392747 -0.031584
+v -0.076810 0.390394 -0.031584
+v -0.087975 0.385773 -0.031584
+v -0.098024 0.379064 -0.031584
+v -0.106571 0.370523 -0.031584
+v -0.113287 0.360478 -0.031584
+v -0.117915 0.349317 -0.031584
+v -0.120277 0.337467 -0.031584
+v -0.120281 0.325383 -0.031584
+v -0.117928 0.313532 -0.031584
+v -0.113308 0.302367 -0.031584
+v -0.106598 0.292317 -0.031584
+v -0.098057 0.283770 -0.031584
+v -0.088013 0.277054 -0.031584
+v -0.076851 0.272426 -0.031584
+v -0.065001 0.270065 -0.031584
+v -0.043726 0.281194 -0.054117
+v -0.053814 0.279191 -0.054117
+v -0.034223 0.285126 -0.054117
+v -0.025669 0.290837 -0.054117
+v -0.018395 0.298107 -0.054117
+v -0.012678 0.306656 -0.054117
+v -0.008739 0.316157 -0.054117
+v -0.006729 0.326243 -0.054117
+v -0.006725 0.336528 -0.083504
+v -0.008728 0.346615 -0.083504
+v -0.012661 0.356119 -0.083504
+v -0.018372 0.364672 -0.083504
+v -0.025641 0.371947 -0.083504
+v -0.034191 0.377664 -0.083504
+v -0.043691 0.381603 -0.083504
+v -0.053777 0.383613 -0.083504
+v -0.064062 0.383616 -0.083504
+v -0.074150 0.381613 -0.083504
+v -0.083653 0.377681 -0.083504
+v -0.092206 0.371970 -0.083504
+v -0.099481 0.364700 -0.083504
+v -0.105198 0.356151 -0.083504
+v -0.109137 0.346650 -0.083504
+v -0.111147 0.336564 -0.083504
+v -0.111150 0.326279 -0.054117
+v -0.109147 0.316192 -0.054117
+v -0.105215 0.306689 -0.054117
+v -0.099504 0.298135 -0.054117
+v -0.092234 0.290860 -0.054117
+v -0.083685 0.285144 -0.054117
+v -0.074185 0.281205 -0.054117
+v -0.064098 0.279195 -0.054117
+v -0.041066 0.272414 -0.054117
+v -0.052918 0.270060 -0.054117
+v -0.029901 0.277034 -0.054117
+v -0.019852 0.283743 -0.054117
+v -0.011305 0.292284 -0.054117
+v -0.004588 0.302329 -0.054117
+v 0.000040 0.313490 -0.054117
+v 0.002401 0.325341 -0.054117
+v 0.002406 0.337424 -0.083504
+v 0.000052 0.349276 -0.083504
+v -0.004568 0.360440 -0.083504
+v -0.011277 0.370490 -0.083504
+v -0.019819 0.379037 -0.083504
+v -0.029863 0.385753 -0.083504
+v -0.041025 0.390381 -0.083504
+v -0.052875 0.392743 -0.083504
+v -0.064958 0.392747 -0.083504
+v -0.076810 0.390394 -0.083504
+v -0.087975 0.385773 -0.083504
+v -0.098024 0.379064 -0.083504
+v -0.106571 0.370523 -0.083504
+v -0.113287 0.360478 -0.083504
+v -0.117915 0.349317 -0.083504
+v -0.120277 0.337466 -0.083504
+v -0.120281 0.325383 -0.054117
+v -0.117928 0.313532 -0.054117
+v -0.113308 0.302367 -0.054117
+v -0.106598 0.292317 -0.054117
+v -0.098057 0.283770 -0.054117
+v -0.088013 0.277054 -0.054117
+v -0.076851 0.272426 -0.054117
+v -0.065001 0.270065 -0.054117
+v -0.208938 0.331404 -0.037331
+v -0.203814 0.279191 -0.037331
+v -0.193726 0.281194 -0.037331
+v -0.184223 0.285126 -0.037331
+v -0.175669 0.290837 -0.037331
+v -0.168395 0.298107 -0.037331
+v -0.162678 0.306656 -0.037331
+v -0.158739 0.316157 -0.037331
+v -0.156729 0.326243 -0.037331
+v -0.156725 0.336528 -0.037331
+v -0.158728 0.346615 -0.037331
+v -0.162661 0.356119 -0.037331
+v -0.168372 0.364672 -0.037331
+v -0.175641 0.371947 -0.037331
+v -0.184191 0.377664 -0.037331
+v -0.193691 0.381603 -0.037331
+v -0.203777 0.383613 -0.037331
+v -0.214062 0.383616 -0.037331
+v -0.224150 0.381613 -0.037331
+v -0.233653 0.377681 -0.037331
+v -0.242206 0.371970 -0.037331
+v -0.249481 0.364700 -0.037331
+v -0.255198 0.356151 -0.037331
+v -0.259137 0.346650 -0.037331
+v -0.261147 0.336564 -0.037331
+v -0.261150 0.326279 -0.037331
+v -0.259147 0.316192 -0.037331
+v -0.255215 0.306689 -0.037331
+v -0.249504 0.298135 -0.037331
+v -0.242234 0.290860 -0.037331
+v -0.233685 0.285144 -0.037331
+v -0.224185 0.281205 -0.037331
+v -0.214098 0.279195 -0.037331
+v -0.191066 0.272414 -0.031584
+v -0.202918 0.270060 -0.031584
+v -0.179901 0.277034 -0.031584
+v -0.169852 0.283743 -0.031584
+v -0.161305 0.292284 -0.031584
+v -0.154588 0.302329 -0.031584
+v -0.149960 0.313490 -0.031584
+v -0.147599 0.325341 -0.031584
+v -0.147594 0.337424 -0.031584
+v -0.149948 0.349276 -0.031584
+v -0.154568 0.360440 -0.031584
+v -0.161277 0.370490 -0.031584
+v -0.169818 0.379037 -0.031584
+v -0.179863 0.385753 -0.031584
+v -0.191025 0.390381 -0.031584
+v -0.202875 0.392743 -0.031584
+v -0.214958 0.392747 -0.031584
+v -0.226810 0.390394 -0.031584
+v -0.237975 0.385774 -0.031584
+v -0.248024 0.379064 -0.031584
+v -0.256571 0.370523 -0.031584
+v -0.263287 0.360478 -0.031584
+v -0.267915 0.349317 -0.031584
+v -0.270277 0.337467 -0.031584
+v -0.270281 0.325383 -0.031584
+v -0.267928 0.313532 -0.031584
+v -0.263308 0.302367 -0.031584
+v -0.256598 0.292317 -0.031584
+v -0.248057 0.283770 -0.031584
+v -0.238013 0.277054 -0.031584
+v -0.226851 0.272426 -0.031584
+v -0.215001 0.270065 -0.031584
+v -0.193726 0.281194 -0.054117
+v -0.203814 0.279191 -0.054117
+v -0.184223 0.285126 -0.054117
+v -0.175669 0.290837 -0.054117
+v -0.168395 0.298107 -0.054117
+v -0.162678 0.306656 -0.054117
+v -0.158739 0.316157 -0.054117
+v -0.156729 0.326243 -0.054117
+v -0.156725 0.336528 -0.083504
+v -0.158728 0.346615 -0.083504
+v -0.162661 0.356119 -0.083504
+v -0.168372 0.364672 -0.083504
+v -0.175641 0.371947 -0.083504
+v -0.184191 0.377664 -0.083504
+v -0.193691 0.381603 -0.083504
+v -0.203777 0.383613 -0.083504
+v -0.214062 0.383616 -0.083504
+v -0.224150 0.381613 -0.083504
+v -0.233653 0.377681 -0.083504
+v -0.242206 0.371970 -0.083504
+v -0.249481 0.364700 -0.083504
+v -0.255198 0.356151 -0.083504
+v -0.259137 0.346650 -0.083504
+v -0.261147 0.336564 -0.083504
+v -0.261150 0.326279 -0.054117
+v -0.259147 0.316192 -0.054117
+v -0.255215 0.306689 -0.054117
+v -0.249504 0.298135 -0.054117
+v -0.242234 0.290860 -0.054117
+v -0.233685 0.285144 -0.054117
+v -0.224185 0.281204 -0.054117
+v -0.214098 0.279195 -0.054117
+v -0.191066 0.272414 -0.054117
+v -0.202918 0.270060 -0.054117
+v -0.179901 0.277034 -0.054117
+v -0.169852 0.283743 -0.054117
+v -0.161305 0.292284 -0.054117
+v -0.154588 0.302329 -0.054117
+v -0.149960 0.313490 -0.054117
+v -0.147599 0.325341 -0.054117
+v -0.147594 0.337424 -0.083504
+v -0.149948 0.349276 -0.083504
+v -0.154568 0.360440 -0.083504
+v -0.161277 0.370490 -0.083504
+v -0.169819 0.379037 -0.083504
+v -0.179863 0.385753 -0.083504
+v -0.191025 0.390381 -0.083504
+v -0.202875 0.392743 -0.083504
+v -0.214958 0.392747 -0.083504
+v -0.226810 0.390394 -0.083504
+v -0.237975 0.385774 -0.083504
+v -0.248024 0.379064 -0.083504
+v -0.256571 0.370523 -0.083504
+v -0.263287 0.360478 -0.083504
+v -0.267915 0.349317 -0.083504
+v -0.270277 0.337466 -0.083504
+v -0.270281 0.325383 -0.054117
+v -0.267928 0.313532 -0.054117
+v -0.263308 0.302367 -0.054117
+v -0.256598 0.292317 -0.054117
+v -0.248057 0.283770 -0.054117
+v -0.238013 0.277054 -0.054117
+v -0.226851 0.272426 -0.054117
+v -0.215001 0.270065 -0.054117
+vn -1.0000 -0.0000 -0.0000
+vn 1.0000 -0.0000 -0.0000
+vn -0.0000 -1.0000 -0.0000
+vn -0.0000 -0.0000 -1.0000
+vn -0.0000 -0.0000 1.0000
+vn -0.0000 1.0000 -0.0000
+vn -0.3830 -0.9237 -0.0000
+vn 0.1954 0.9807 -0.0000
+vn 0.8313 -0.5559 -0.0000
+vn 0.0003 1.0000 -0.0000
+vn -0.9237 0.3830 -0.0000
+vn 0.9807 -0.1954 -0.0000
+vn 0.1947 -0.9809 -0.0000
+vn 0.7073 0.7069 -0.0000
+vn -0.5559 -0.8313 -0.0000
+vn 0.3830 0.9237 -0.0000
+vn -0.3824 0.9240 -0.0000
+vn 1.0000 -0.0003 -0.0000
+vn -0.8313 0.5559 -0.0000
+vn 0.9237 -0.3830 -0.0000
+vn -0.9809 -0.1948 -0.0000
+vn -0.7073 -0.7069 -0.0000
+vn 0.5559 0.8313 -0.0000
+vn 0.7069 -0.7074 -0.0000
+vn -0.7069 0.7073 -0.0000
+vn -0.0003 -1.0000 -0.0000
+vn 0.8317 0.5553 -0.0000
+vn -0.8317 -0.5553 -0.0000
+vn 0.7074 0.7069 -0.0000
+vn -0.7074 -0.7069 -0.0000
+vn -0.5553 0.8317 -0.0000
+vn -0.0003 -0.9346 -0.3557
+vn -0.9240 -0.3824 -0.0000
+vn 1.0000 -0.0004 -0.0000
+vn -0.9807 0.1954 -0.0000
+vn 0.9809 0.1948 -0.0000
+vn 0.1948 -0.9809 -0.0000
+vn -0.1954 -0.9807 -0.0000
+vn 0.3824 -0.9240 -0.0000
+vn -1.0000 0.0004 -0.0000
+vn -0.1947 0.9809 -0.0000
+vn 0.9240 0.3824 -0.0000
+vn -0.9809 -0.1947 -0.0000
+vn 0.5553 -0.8317 -0.0000
+vn -0.7069 0.7074 -0.0000
+vn -1.0000 0.0003 -0.0000
+vn 0.9809 0.1947 -0.0000
+vt 0.640016 0.630686
+vt 0.874116 0.630686
+vt 0.899031 0.371671
+vt 0.899031 0.605771
+vt 0.275073 0.371671
+vt 0.275073 0.605771
+vt 0.536051 0.632649
+vt 0.301951 0.632649
+vt 0.588281 0.578951
+vt 0.588281 0.344851
+vt 0.847296 0.319936
+vt 0.613196 0.319936
+vt 0.326808 0.319936
+vt 0.560909 0.319936
+vt 0.587786 0.580914
+vt 0.587786 0.346814
+vt 0.757066 0.513636
+vt 0.781981 0.488721
+vt 0.392123 0.488721
+vt 0.419001 0.515599
+vt 0.705331 0.461901
+vt 0.730246 0.436986
+vt 0.443858 0.436986
+vt 0.470736 0.463864
+vt 0.062341 0.000247
+vt 0.000247 0.062341
+vt 0.000248 0.359598
+vt 0.039909 0.319936
+vt 0.662834 0.000247
+vt 0.724927 0.062341
+vt 0.000247 0.960091
+vt 0.039910 0.999753
+vt 0.062341 0.062341
+vt 0.662834 0.062341
+vt 0.062341 0.319441
+vt 0.000247 0.257348
+vt 0.274579 0.359598
+vt 0.234916 0.319936
+vt 0.662834 0.319441
+vt 0.724927 0.257348
+vt 0.274579 0.960090
+vt 0.234917 0.999753
+vt 0.062341 0.257348
+vt 0.662834 0.257348
+vt 0.079095 0.359121
+vt 0.039433 0.398784
+vt 0.079095 0.960567
+vt 0.039433 0.920905
+vt 0.195731 0.960567
+vt 0.235393 0.920905
+vt 0.195731 0.359121
+vt 0.235393 0.398783
+vt 0.079095 0.398783
+vt 0.079095 0.920905
+vt 0.195731 0.920905
+vt 0.195731 0.398783
+vt 0.629899 0.095275
+vt 0.095275 0.095275
+vt 0.629899 0.224413
+vt 0.095275 0.224413
+vt 0.753412 0.903011
+vt 0.719354 0.930961
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.714555 0.923780
+vt 0.602565 0.932389
+vt 0.711250 0.915800
+vt 0.593928 0.932389
+vt 0.709565 0.907329
+vt 0.585291 0.932389
+vt 0.709565 0.898692
+vt 0.576654 0.932389
+vt 0.711250 0.890221
+vt 0.568017 0.932389
+vt 0.714556 0.882241
+vt 0.559379 0.932389
+vt 0.719354 0.875060
+vt 0.550742 0.932389
+vt 0.725461 0.868952
+vt 0.542105 0.932389
+vt 0.732643 0.864154
+vt 0.533468 0.932389
+vt 0.740623 0.860849
+vt 0.524831 0.932389
+vt 0.749094 0.859164
+vt 0.516194 0.932389
+vt 0.757731 0.859164
+vt 0.507557 0.932389
+vt 0.766202 0.860849
+vt 0.498920 0.932389
+vt 0.774182 0.864154
+vt 0.490283 0.932389
+vt 0.781363 0.868953
+vt 0.481646 0.932389
+vt 0.787470 0.875060
+vt 0.473009 0.932389
+vt 0.792269 0.882241
+vt 0.464371 0.932389
+vt 0.795574 0.890221
+vt 0.455734 0.932389
+vt 0.797259 0.898692
+vt 0.447097 0.932389
+vt 0.797259 0.907329
+vt 0.438460 0.932389
+vt 0.795574 0.915800
+vt 0.429823 0.932389
+vt 0.792269 0.923780
+vt 0.421186 0.932389
+vt 0.787470 0.930962
+vt 0.412549 0.932389
+vt 0.781363 0.937069
+vt 0.403912 0.932389
+vt 0.774181 0.941867
+vt 0.395275 0.932389
+vt 0.766201 0.945173
+vt 0.386637 0.932389
+vt 0.757730 0.946858
+vt 0.378001 0.932389
+vt 0.749093 0.946858
+vt 0.369363 0.932389
+vt 0.740622 0.945172
+vt 0.360726 0.932389
+vt 0.732643 0.941867
+vt 0.352089 0.932388
+vt 0.725461 0.937069
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.752599 0.742115
+vt 0.718541 0.770066
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.713742 0.762885
+vt 0.602565 0.932389
+vt 0.710437 0.754905
+vt 0.593928 0.932389
+vt 0.708752 0.746434
+vt 0.585291 0.932389
+vt 0.708752 0.737797
+vt 0.576654 0.932389
+vt 0.710437 0.729326
+vt 0.568017 0.932389
+vt 0.713743 0.721346
+vt 0.559379 0.932389
+vt 0.718541 0.714165
+vt 0.550742 0.932389
+vt 0.724649 0.708057
+vt 0.542105 0.932389
+vt 0.731830 0.703259
+vt 0.533468 0.932389
+vt 0.739810 0.699954
+vt 0.524831 0.932389
+vt 0.748281 0.698269
+vt 0.516194 0.932389
+vt 0.756918 0.698269
+vt 0.507557 0.932389
+vt 0.765389 0.699954
+vt 0.498920 0.932389
+vt 0.773369 0.703259
+vt 0.490283 0.932389
+vt 0.780550 0.708058
+vt 0.481646 0.932389
+vt 0.786658 0.714165
+vt 0.473009 0.932389
+vt 0.791456 0.721346
+vt 0.464371 0.932389
+vt 0.794761 0.729326
+vt 0.455734 0.932389
+vt 0.796446 0.737797
+vt 0.447097 0.932389
+vt 0.796446 0.746434
+vt 0.438460 0.932389
+vt 0.794761 0.754905
+vt 0.429823 0.932389
+vt 0.791456 0.762885
+vt 0.421186 0.932389
+vt 0.786657 0.770066
+vt 0.412549 0.932389
+vt 0.780550 0.776174
+vt 0.403912 0.932389
+vt 0.773368 0.780972
+vt 0.395275 0.932389
+vt 0.765389 0.784277
+vt 0.386637 0.932389
+vt 0.756917 0.785962
+vt 0.378001 0.932389
+vt 0.748280 0.785962
+vt 0.369363 0.932389
+vt 0.739809 0.784277
+vt 0.360726 0.932389
+vt 0.731830 0.780972
+vt 0.352089 0.932388
+vt 0.724648 0.776174
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.908735 0.903617
+vt 0.874676 0.931567
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.869878 0.924386
+vt 0.602565 0.932389
+vt 0.866572 0.916406
+vt 0.593928 0.932389
+vt 0.864888 0.907935
+vt 0.585291 0.932389
+vt 0.864888 0.899298
+vt 0.576654 0.932389
+vt 0.866573 0.890827
+vt 0.568017 0.932389
+vt 0.869878 0.882847
+vt 0.559379 0.932389
+vt 0.874676 0.875666
+vt 0.550742 0.932389
+vt 0.880784 0.869558
+vt 0.542105 0.932389
+vt 0.887965 0.864760
+vt 0.533468 0.932389
+vt 0.895945 0.861455
+vt 0.524831 0.932389
+vt 0.904416 0.859770
+vt 0.516194 0.932389
+vt 0.913053 0.859770
+vt 0.507557 0.932389
+vt 0.921524 0.861455
+vt 0.498920 0.932389
+vt 0.929504 0.864760
+vt 0.490283 0.932389
+vt 0.936685 0.869559
+vt 0.481646 0.932389
+vt 0.942793 0.875666
+vt 0.473009 0.932389
+vt 0.947591 0.882847
+vt 0.464371 0.932389
+vt 0.950896 0.890827
+vt 0.455734 0.932389
+vt 0.952581 0.899298
+vt 0.447097 0.932389
+vt 0.952581 0.907935
+vt 0.438460 0.932389
+vt 0.950896 0.916406
+vt 0.429823 0.932389
+vt 0.947591 0.924386
+vt 0.421186 0.932389
+vt 0.942792 0.931568
+vt 0.412549 0.932389
+vt 0.936685 0.937675
+vt 0.403912 0.932389
+vt 0.929504 0.942473
+vt 0.395275 0.932389
+vt 0.921524 0.945779
+vt 0.386637 0.932389
+vt 0.913053 0.947464
+vt 0.378001 0.932389
+vt 0.904416 0.947464
+vt 0.369363 0.932389
+vt 0.895945 0.945778
+vt 0.360726 0.932389
+vt 0.887965 0.942473
+vt 0.352089 0.932388
+vt 0.880783 0.937675
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+vt 0.908268 0.746864
+vt 0.874210 0.774814
+vt 0.334815 0.932388
+vt 0.611202 0.932388
+vt 0.869411 0.767633
+vt 0.602565 0.932389
+vt 0.866106 0.759653
+vt 0.593928 0.932389
+vt 0.864421 0.751182
+vt 0.585291 0.932389
+vt 0.864421 0.742545
+vt 0.576654 0.932389
+vt 0.866106 0.734074
+vt 0.568017 0.932389
+vt 0.869412 0.726094
+vt 0.559379 0.932389
+vt 0.874210 0.718913
+vt 0.550742 0.932389
+vt 0.880318 0.712805
+vt 0.542105 0.932389
+vt 0.887499 0.708007
+vt 0.533468 0.932389
+vt 0.895479 0.704702
+vt 0.524831 0.932389
+vt 0.903950 0.703017
+vt 0.516194 0.932389
+vt 0.912587 0.703017
+vt 0.507557 0.932389
+vt 0.921058 0.704702
+vt 0.498920 0.932389
+vt 0.929038 0.708007
+vt 0.490283 0.932389
+vt 0.936219 0.712806
+vt 0.481646 0.932389
+vt 0.942326 0.718913
+vt 0.473009 0.932389
+vt 0.947125 0.726095
+vt 0.464371 0.932389
+vt 0.950430 0.734074
+vt 0.455734 0.932389
+vt 0.952115 0.742545
+vt 0.447097 0.932389
+vt 0.952115 0.751182
+vt 0.438460 0.932389
+vt 0.950430 0.759654
+vt 0.429823 0.932389
+vt 0.947125 0.767633
+vt 0.421186 0.932389
+vt 0.942326 0.774815
+vt 0.412549 0.932389
+vt 0.936219 0.780922
+vt 0.403912 0.932389
+vt 0.929037 0.785721
+vt 0.395275 0.932389
+vt 0.921058 0.789026
+vt 0.386637 0.932389
+vt 0.912586 0.790711
+vt 0.378001 0.932389
+vt 0.903949 0.790711
+vt 0.369363 0.932389
+vt 0.895478 0.789025
+vt 0.360726 0.932389
+vt 0.887499 0.785720
+vt 0.352089 0.932388
+vt 0.880317 0.780922
+vt 0.343452 0.932388
+vt 0.618830 0.816892
+vt 0.628978 0.816892
+vt 0.608683 0.816892
+vt 0.598535 0.816892
+vt 0.588388 0.816892
+vt 0.578240 0.816892
+vt 0.568093 0.816892
+vt 0.557945 0.816892
+vt 0.547798 0.816892
+vt 0.537650 0.816892
+vt 0.527503 0.816892
+vt 0.517355 0.816892
+vt 0.507208 0.816892
+vt 0.497060 0.816892
+vt 0.486913 0.816892
+vt 0.476765 0.816892
+vt 0.466618 0.816892
+vt 0.456470 0.816892
+vt 0.446323 0.816892
+vt 0.436175 0.816892
+vt 0.426028 0.816892
+vt 0.415880 0.816892
+vt 0.405733 0.816892
+vt 0.395585 0.816892
+vt 0.385438 0.816892
+vt 0.375290 0.816892
+vt 0.365143 0.816892
+vt 0.354995 0.816892
+vt 0.344848 0.816892
+vt 0.334700 0.816892
+vt 0.324553 0.816892
+vt 0.314405 0.816892
+vt 0.639125 0.816892
+vt 0.517095 0.669905
+vt 0.602565 0.946486
+vt 0.334815 0.946485
+vt 0.515410 0.678377
+vt 0.611202 0.946485
+vt 0.520400 0.661926
+vt 0.593928 0.946485
+vt 0.525198 0.654744
+vt 0.585291 0.946486
+vt 0.531306 0.648637
+vt 0.576654 0.946486
+vt 0.568017 0.946486
+vt 0.538487 0.643839
+vt 0.546467 0.640533
+vt 0.559379 0.946486
+vt 0.554938 0.638848
+vt 0.507247 0.729756
+vt 0.550742 0.946486
+vt 0.481149 0.728166
+vt 0.542105 0.971165
+vt 0.472678 0.726481
+vt 0.533468 0.971165
+vt 0.464698 0.723176
+vt 0.524831 0.971165
+vt 0.457517 0.718377
+vt 0.516194 0.971165
+vt 0.507557 0.971165
+vt 0.451409 0.712270
+vt 0.446611 0.705089
+vt 0.498920 0.971165
+vt 0.443305 0.697109
+vt 0.490283 0.971165
+vt 0.441620 0.688638
+vt 0.481646 0.971165
+vt 0.473008 0.971165
+vt 0.441620 0.680001
+vt 0.443305 0.671530
+vt 0.464371 0.971165
+vt 0.446610 0.663550
+vt 0.455734 0.971165
+vt 0.451409 0.656369
+vt 0.447097 0.971165
+vt 0.438460 0.971165
+vt 0.457516 0.650261
+vt 0.464698 0.645463
+vt 0.429823 0.971165
+vt 0.472677 0.642157
+vt 0.421186 0.971165
+vt 0.412549 0.971165
+vt 0.481149 0.640472
+vt 0.507247 0.638882
+vt 0.554938 0.726542
+vt 0.403912 0.946486
+vt 0.546467 0.724857
+vt 0.395275 0.946486
+vt 0.538487 0.721552
+vt 0.386637 0.946486
+vt 0.378001 0.946486
+vt 0.531306 0.716753
+vt 0.525198 0.710646
+vt 0.369363 0.946486
+vt 0.520400 0.703464
+vt 0.360726 0.946485
+vt 0.517095 0.695485
+vt 0.352089 0.946485
+vt 0.343452 0.946485
+vt 0.515410 0.687014
+vt 0.509722 0.667669
+vt 0.618830 0.797969
+vt 0.507742 0.677621
+vt 0.628978 0.797969
+vt 0.513605 0.658294
+vt 0.608683 0.797969
+vt 0.519242 0.649857
+vt 0.598535 0.797969
+vt 0.588388 0.797969
+vt 0.526418 0.642681
+vt 0.578240 0.797969
+vt 0.534855 0.637043
+vt 0.568093 0.797969
+vt 0.544230 0.633160
+vt 0.554183 0.631180
+vt 0.507028 0.737458
+vt 0.557945 0.797969
+vt 0.480393 0.735834
+vt 0.547798 0.773289
+vt 0.470441 0.733854
+vt 0.537650 0.773289
+vt 0.461066 0.729971
+vt 0.527503 0.773289
+vt 0.452629 0.724334
+vt 0.517355 0.773289
+vt 0.507208 0.773290
+vt 0.445453 0.717158
+vt 0.497060 0.773290
+vt 0.439816 0.708721
+vt 0.486913 0.773290
+vt 0.435932 0.699346
+vt 0.433953 0.689393
+vt 0.476765 0.773290
+vt 0.433953 0.679246
+vt 0.466618 0.773290
+vt 0.435932 0.669293
+vt 0.456470 0.773290
+vt 0.439815 0.659918
+vt 0.446323 0.773289
+vt 0.436175 0.773289
+vt 0.445453 0.651481
+vt 0.426028 0.773289
+vt 0.452628 0.644305
+vt 0.415880 0.773289
+vt 0.461066 0.638668
+vt 0.470441 0.634784
+vt 0.405733 0.773289
+vt 0.480393 0.632805
+vt 0.395585 0.773289
+vt 0.507028 0.631180
+vt 0.554183 0.734210
+vt 0.385438 0.797969
+vt 0.544230 0.732230
+vt 0.375290 0.797969
+vt 0.534855 0.728347
+vt 0.365143 0.797969
+vt 0.354995 0.797969
+vt 0.526418 0.722709
+vt 0.344848 0.797969
+vt 0.519243 0.715534
+vt 0.334700 0.797969
+vt 0.513605 0.707096
+vt 0.509721 0.697721
+vt 0.324553 0.797969
+vt 0.507742 0.687769
+vt 0.314405 0.797969
+vt 0.639125 0.797969
+s 0
+g Cube_Material
+usemtl Material
+f 6/11/1 14/22/1 10/18/1 2/3/1
+f 1/1/2 9/17/2 13/21/2 5/9/2
+f 12/20/3 16/24/3 15/23/3 11/19/3
+f 10/18/3 14/22/3 13/21/3 9/17/3
+f 3/5/2 11/19/2 15/23/2 7/13/2
+f 8/15/1 16/24/1 12/20/1 4/7/1
+f 7/14/4 15/23/4 16/24/4 8/16/4
+f 5/10/4 13/21/4 14/22/4 6/12/4
+f 4/8/5 12/20/5 11/19/5 3/6/5
+f 2/4/5 10/18/5 9/17/5 1/2/5
+f 18/29/3 17/25/3 19/33/3 20/34/3
+f 33/57/4 34/58/4 36/60/4 35/59/4
+f 24/44/6 23/43/6 21/35/6 22/39/6
+f 25/45/1 29/53/1 32/56/1 28/51/1
+f 17/26/1 21/36/1 23/43/1 19/33/1
+f 22/40/2 18/30/2 20/34/2 24/44/2
+f 25/46/5 17/27/5 18/31/5 26/48/5
+f 27/50/5 22/41/5 21/37/5 28/52/5
+f 26/47/5 18/32/5 22/42/5 27/49/5
+f 28/51/5 21/38/5 17/28/5 25/45/5
+f 31/55/5 32/56/5 29/53/5 30/54/5
+f 27/49/2 31/55/2 30/54/2 26/47/2
+f 28/52/6 32/56/6 31/55/6 27/50/6
+f 26/48/3 30/54/3 29/53/3 25/46/3
+f 33/57/4 20/34/4 19/33/4 34/58/4
+f 35/59/4 24/44/4 20/34/4 33/57/4
+f 36/60/4 23/43/4 24/44/4 35/59/4
+f 34/58/4 19/33/4 23/43/4 36/60/4
+f 37/61/4 39/65/4 38/62/4
+f 37/61/4 40/67/4 39/65/4
+f 37/61/4 41/69/4 40/67/4
+f 37/61/4 42/71/4 41/69/4
+f 37/61/4 43/73/4 42/71/4
+f 37/61/4 44/75/4 43/73/4
+f 37/61/4 45/77/4 44/75/4
+f 37/61/4 46/79/4 45/77/4
+f 37/61/4 47/81/4 46/79/4
+f 37/61/4 48/83/4 47/81/4
+f 37/61/4 49/85/4 48/83/4
+f 37/61/4 50/87/4 49/85/4
+f 37/61/4 51/89/4 50/87/4
+f 37/61/4 52/91/4 51/89/4
+f 37/61/4 53/93/4 52/91/4
+f 37/61/4 54/95/4 53/93/4
+f 37/61/4 55/97/4 54/95/4
+f 37/61/4 56/99/4 55/97/4
+f 37/61/4 57/101/4 56/99/4
+f 37/61/4 58/103/4 57/101/4
+f 37/61/4 59/105/4 58/103/4
+f 37/61/4 60/107/4 59/105/4
+f 37/61/4 61/109/4 60/107/4
+f 37/61/4 62/111/4 61/109/4
+f 37/61/4 63/113/4 62/111/4
+f 37/61/4 64/115/4 63/113/4
+f 37/61/4 65/117/4 64/115/4
+f 37/61/4 66/119/4 65/117/4
+f 37/61/4 67/121/4 66/119/4
+f 37/61/4 68/123/4 67/121/4
+f 37/61/4 69/125/4 68/123/4
+f 37/61/4 38/62/4 69/125/4
+f 99/156/7 163/287/7 164/290/7 100/157/7
+f 84/141/8 148/256/8 149/259/8 85/142/8
+f 59/106/9 123/205/9 122/202/9 58/104/9
+f 38/63/10 103/162/10 133/225/10 69/126/10
+f 44/76/11 108/174/11 107/171/11 43/74/11
+f 91/148/11 155/270/11 156/273/11 92/149/11
+f 76/133/12 140/239/12 141/243/12 77/134/12
+f 55/98/13 119/197/13 118/194/13 54/96/13
+f 66/120/14 130/220/14 129/217/14 65/118/14
+f 98/155/15 162/285/15 163/287/15 99/156/15
+f 83/140/16 147/254/16 148/256/16 84/141/16
+f 40/68/17 104/166/17 102/161/17 39/66/17
+f 51/90/15 115/189/15 114/186/15 50/88/15
+f 62/112/18 126/212/18 125/208/18 61/110/18
+f 90/147/19 154/268/19 155/270/19 91/148/19
+f 75/132/20 139/237/20 140/239/20 76/133/20
+f 47/82/21 111/181/21 110/179/21 46/80/21
+f 97/154/22 161/283/22 162/285/22 98/155/22
+f 82/139/23 146/252/23 147/254/23 83/140/23
+f 58/104/24 122/202/24 121/201/24 57/102/24
+f 69/126/8 133/225/8 132/224/8 68/124/8
+f 89/146/25 153/266/25 154/268/25 90/147/25
+f 43/74/19 107/171/19 106/170/19 42/72/19
+f 54/96/26 118/194/26 117/193/26 53/94/26
+f 74/131/9 138/235/9 139/237/9 75/132/9
+f 65/118/27 129/217/27 128/216/27 64/116/27
+f 96/153/28 160/282/28 161/283/28 97/154/28
+f 81/138/29 145/251/29 146/252/29 82/139/29
+f 50/88/30 114/186/30 113/185/30 49/86/30
+f 88/145/31 152/265/31 153/266/31 89/146/31
+f 61/110/12 125/208/12 124/207/12 60/108/12
+f 73/130/24 137/234/24 138/235/24 74/131/24
+f 102/160/4 134/227/4 135/229/4 103/163/4
+f 104/165/4 136/231/4 134/227/4 102/160/4
+f 105/167/4 137/233/4 136/231/4 104/165/4
+f 106/169/4 138/236/4 137/233/4 105/167/4
+f 107/172/4 139/238/4 138/236/4 106/169/4
+f 108/173/4 140/240/4 139/238/4 107/172/4
+f 109/175/4 141/241/4 140/240/4 108/173/4
+f 110/178/32 142/244/32 141/242/32 109/176/32
+f 111/180/4 143/246/4 142/244/4 110/178/4
+f 112/182/4 144/248/4 143/246/4 111/180/4
+f 113/184/4 145/250/4 144/248/4 112/182/4
+f 114/187/4 146/253/4 145/250/4 113/184/4
+f 115/188/4 147/255/4 146/253/4 114/187/4
+f 116/190/4 148/257/4 147/255/4 115/188/4
+f 117/192/4 149/258/4 148/257/4 116/190/4
+f 118/195/4 150/260/4 149/258/4 117/192/4
+f 119/196/4 151/262/4 150/260/4 118/195/4
+f 120/198/4 152/264/4 151/262/4 119/196/4
+f 121/200/4 153/267/4 152/264/4 120/198/4
+f 122/203/4 154/269/4 153/267/4 121/200/4
+f 123/204/4 155/271/4 154/269/4 122/203/4
+f 124/206/4 156/272/4 155/271/4 123/204/4
+f 125/209/4 157/274/4 156/272/4 124/206/4
+f 126/210/32 158/276/32 157/274/32 125/209/32
+f 127/213/4 159/279/4 158/277/4 126/211/4
+f 128/215/4 160/281/4 159/279/4 127/213/4
+f 129/218/4 161/284/4 160/281/4 128/215/4
+f 130/219/4 162/286/4 161/284/4 129/218/4
+f 131/221/4 163/288/4 162/286/4 130/219/4
+f 132/223/4 164/289/4 163/288/4 131/221/4
+f 133/226/4 165/291/4 164/289/4 132/223/4
+f 103/163/4 135/229/4 165/291/4 133/226/4
+f 48/84/33 112/183/33 111/181/33 47/82/33
+f 77/134/34 141/243/34 142/245/34 78/135/34
+f 92/149/35 156/273/35 157/275/35 93/150/35
+f 63/114/36 127/214/36 126/212/36 62/112/36
+f 52/92/7 116/191/7 115/189/7 51/90/7
+f 71/128/37 135/230/37 134/228/37 70/127/37
+f 41/70/31 105/168/31 104/166/31 40/68/31
+f 85/142/10 149/259/10 150/261/10 86/143/10
+f 100/157/38 164/290/38 165/292/38 101/158/38
+f 67/122/23 131/222/23 130/220/23 66/120/23
+f 56/100/39 120/199/39 119/197/39 55/98/39
+f 78/135/36 142/245/36 143/247/36 79/136/36
+f 93/150/40 157/275/40 158/278/40 94/151/40
+f 45/78/35 109/177/35 108/174/35 44/76/35
+f 70/127/39 134/228/39 136/232/39 72/129/39
+f 60/108/20 124/207/20 123/205/20 59/106/20
+f 86/143/41 150/261/41 151/263/41 87/144/41
+f 101/159/26 165/293/26 135/230/26 71/128/26
+f 49/86/28 113/185/28 112/183/28 48/84/28
+f 79/136/42 143/247/42 144/249/42 80/137/42
+f 94/151/43 158/278/43 159/280/43 95/152/43
+f 64/116/42 128/216/42 127/214/42 63/114/42
+f 53/94/38 117/193/38 116/191/38 52/92/38
+f 72/129/44 136/232/44 137/234/44 73/130/44
+f 42/72/45 106/170/45 105/168/45 41/70/45
+f 87/144/17 151/263/17 152/265/17 88/145/17
+f 68/124/16 132/224/16 131/222/16 67/122/16
+f 39/66/41 102/161/41 103/164/41 38/64/41
+f 57/102/44 121/201/44 120/199/44 56/100/44
+f 80/137/27 144/249/27 145/251/27 81/138/27
+f 95/152/33 159/280/33 160/282/33 96/153/33
+f 46/80/46 110/179/46 109/177/46 45/78/46
+f 166/294/4 168/298/4 167/295/4
+f 166/294/4 169/300/4 168/298/4
+f 166/294/4 170/302/4 169/300/4
+f 166/294/4 171/304/4 170/302/4
+f 166/294/4 172/306/4 171/304/4
+f 166/294/4 173/308/4 172/306/4
+f 166/294/4 174/310/4 173/308/4
+f 166/294/4 175/312/4 174/310/4
+f 166/294/4 176/314/4 175/312/4
+f 166/294/4 177/316/4 176/314/4
+f 166/294/4 178/318/4 177/316/4
+f 166/294/4 179/320/4 178/318/4
+f 166/294/4 180/322/4 179/320/4
+f 166/294/4 181/324/4 180/322/4
+f 166/294/4 182/326/4 181/324/4
+f 166/294/4 183/328/4 182/326/4
+f 166/294/4 184/330/4 183/328/4
+f 166/294/4 185/332/4 184/330/4
+f 166/294/4 186/334/4 185/332/4
+f 166/294/4 187/336/4 186/334/4
+f 166/294/4 188/338/4 187/336/4
+f 166/294/4 189/340/4 188/338/4
+f 166/294/4 190/342/4 189/340/4
+f 166/294/4 191/344/4 190/342/4
+f 166/294/4 192/346/4 191/344/4
+f 166/294/4 193/348/4 192/346/4
+f 166/294/4 194/350/4 193/348/4
+f 166/294/4 195/352/4 194/350/4
+f 166/294/4 196/354/4 195/352/4
+f 166/294/4 197/356/4 196/354/4
+f 166/294/4 198/358/4 197/356/4
+f 166/294/4 167/295/4 198/358/4
+f 228/389/7 292/520/7 293/523/7 229/390/7
+f 213/374/8 277/489/8 278/492/8 214/375/8
+f 188/339/9 252/438/9 251/435/9 187/337/9
+f 167/296/10 232/395/10 262/458/10 198/359/10
+f 173/309/11 237/407/11 236/404/11 172/307/11
+f 220/381/11 284/503/11 285/506/11 221/382/11
+f 205/366/12 269/472/12 270/476/12 206/367/12
+f 184/331/13 248/430/13 247/427/13 183/329/13
+f 195/353/14 259/453/14 258/450/14 194/351/14
+f 227/388/15 291/518/15 292/520/15 228/389/15
+f 212/373/16 276/487/16 277/489/16 213/374/16
+f 169/301/17 233/399/17 231/394/17 168/299/17
+f 180/323/15 244/422/15 243/419/15 179/321/15
+f 191/345/18 255/445/18 254/441/18 190/343/18
+f 219/380/19 283/501/19 284/503/19 220/381/19
+f 204/365/20 268/470/20 269/472/20 205/366/20
+f 176/315/21 240/414/21 239/412/21 175/313/21
+f 226/387/22 290/516/22 291/518/22 227/388/22
+f 211/372/23 275/485/23 276/487/23 212/373/23
+f 187/337/24 251/435/24 250/434/24 186/335/24
+f 198/359/8 262/458/8 261/457/8 197/357/8
+f 218/379/25 282/499/25 283/501/25 219/380/25
+f 172/307/19 236/404/19 235/403/19 171/305/19
+f 183/329/26 247/427/26 246/426/26 182/327/26
+f 203/364/9 267/468/9 268/470/9 204/365/9
+f 194/351/27 258/450/27 257/449/27 193/349/27
+f 225/386/28 289/515/28 290/516/28 226/387/28
+f 210/371/29 274/484/29 275/485/29 211/372/29
+f 179/321/30 243/419/30 242/418/30 178/319/30
+f 217/378/31 281/498/31 282/499/31 218/379/31
+f 190/343/12 254/441/12 253/440/12 189/341/12
+f 202/363/24 266/467/24 267/468/24 203/364/24
+f 231/393/4 263/460/4 264/462/4 232/396/4
+f 233/398/4 265/464/4 263/460/4 231/393/4
+f 234/400/4 266/466/4 265/464/4 233/398/4
+f 235/402/4 267/469/4 266/466/4 234/400/4
+f 236/405/4 268/471/4 267/469/4 235/402/4
+f 237/406/4 269/473/4 268/471/4 236/405/4
+f 238/408/4 270/474/4 269/473/4 237/406/4
+f 239/411/32 271/477/32 270/475/32 238/409/32
+f 240/413/4 272/479/4 271/477/4 239/411/4
+f 241/415/4 273/481/4 272/479/4 240/413/4
+f 242/417/4 274/483/4 273/481/4 241/415/4
+f 243/420/4 275/486/4 274/483/4 242/417/4
+f 244/421/4 276/488/4 275/486/4 243/420/4
+f 245/423/4 277/490/4 276/488/4 244/421/4
+f 246/425/4 278/491/4 277/490/4 245/423/4
+f 247/428/4 279/493/4 278/491/4 246/425/4
+f 248/429/4 280/495/4 279/493/4 247/428/4
+f 249/431/4 281/497/4 280/495/4 248/429/4
+f 250/433/4 282/500/4 281/497/4 249/431/4
+f 251/436/4 283/502/4 282/500/4 250/433/4
+f 252/437/4 284/504/4 283/502/4 251/436/4
+f 253/439/4 285/505/4 284/504/4 252/437/4
+f 254/442/4 286/507/4 285/505/4 253/439/4
+f 255/443/32 287/509/32 286/507/32 254/442/32
+f 256/446/4 288/512/4 287/510/4 255/444/4
+f 257/448/4 289/514/4 288/512/4 256/446/4
+f 258/451/4 290/517/4 289/514/4 257/448/4
+f 259/452/4 291/519/4 290/517/4 258/451/4
+f 260/454/4 292/521/4 291/519/4 259/452/4
+f 261/456/4 293/522/4 292/521/4 260/454/4
+f 262/459/4 294/524/4 293/522/4 261/456/4
+f 232/396/4 264/462/4 294/524/4 262/459/4
+f 177/317/33 241/416/33 240/414/33 176/315/33
+f 206/367/34 270/476/34 271/478/34 207/368/34
+f 221/382/35 285/506/35 286/508/35 222/383/35
+f 192/347/36 256/447/36 255/445/36 191/345/36
+f 181/325/7 245/424/7 244/422/7 180/323/7
+f 200/361/37 264/463/37 263/461/37 199/360/37
+f 170/303/31 234/401/31 233/399/31 169/301/31
+f 214/375/10 278/492/10 279/494/10 215/376/10
+f 229/390/38 293/523/38 294/525/38 230/391/38
+f 196/355/23 260/455/23 259/453/23 195/353/23
+f 185/333/39 249/432/39 248/430/39 184/331/39
+f 207/368/36 271/478/36 272/480/36 208/369/36
+f 222/383/40 286/508/40 287/511/40 223/384/40
+f 174/311/35 238/410/35 237/407/35 173/309/35
+f 199/360/39 263/461/39 265/465/39 201/362/39
+f 189/341/20 253/440/20 252/438/20 188/339/20
+f 215/376/41 279/494/41 280/496/41 216/377/41
+f 230/392/26 294/526/26 264/463/26 200/361/26
+f 178/319/28 242/418/28 241/416/28 177/317/28
+f 208/369/42 272/480/42 273/482/42 209/370/42
+f 223/384/43 287/511/43 288/513/43 224/385/43
+f 193/349/42 257/449/42 256/447/42 192/347/42
+f 182/327/38 246/426/38 245/424/38 181/325/38
+f 201/362/44 265/465/44 266/467/44 202/363/44
+f 171/305/45 235/403/45 234/401/45 170/303/45
+f 216/377/17 280/496/17 281/498/17 217/378/17
+f 197/357/16 261/457/16 260/455/16 196/355/16
+f 168/299/41 231/394/41 232/397/41 167/297/41
+f 186/335/44 250/434/44 249/432/44 185/333/44
+f 209/370/27 273/482/27 274/484/27 210/371/27
+f 224/385/33 288/513/33 289/515/33 225/386/33
+f 175/313/46 239/412/46 238/410/46 174/311/46
+f 295/527/4 297/531/4 296/528/4
+f 295/527/4 298/533/4 297/531/4
+f 295/527/4 299/535/4 298/533/4
+f 295/527/4 300/537/4 299/535/4
+f 295/527/4 301/539/4 300/537/4
+f 295/527/4 302/541/4 301/539/4
+f 295/527/4 303/543/4 302/541/4
+f 295/527/4 304/545/4 303/543/4
+f 295/527/4 305/547/4 304/545/4
+f 295/527/4 306/549/4 305/547/4
+f 295/527/4 307/551/4 306/549/4
+f 295/527/4 308/553/4 307/551/4
+f 295/527/4 309/555/4 308/553/4
+f 295/527/4 310/557/4 309/555/4
+f 295/527/4 311/559/4 310/557/4
+f 295/527/4 312/561/4 311/559/4
+f 295/527/4 313/563/4 312/561/4
+f 295/527/4 314/565/4 313/563/4
+f 295/527/4 315/567/4 314/565/4
+f 295/527/4 316/569/4 315/567/4
+f 295/527/4 317/571/4 316/569/4
+f 295/527/4 318/573/4 317/571/4
+f 295/527/4 319/575/4 318/573/4
+f 295/527/4 320/577/4 319/575/4
+f 295/527/4 321/579/4 320/577/4
+f 295/527/4 322/581/4 321/579/4
+f 295/527/4 323/583/4 322/581/4
+f 295/527/4 324/585/4 323/583/4
+f 295/527/4 325/587/4 324/585/4
+f 295/527/4 326/589/4 325/587/4
+f 295/527/4 327/591/4 326/589/4
+f 295/527/4 296/528/4 327/591/4
+f 357/622/7 421/753/7 422/756/7 358/623/7
+f 342/607/8 406/722/8 407/725/8 343/608/8
+f 317/572/9 381/671/9 380/668/9 316/570/9
+f 296/529/10 361/628/10 391/691/10 327/592/10
+f 302/542/11 366/640/11 365/637/11 301/540/11
+f 349/614/11 413/736/11 414/739/11 350/615/11
+f 334/599/12 398/705/12 399/709/12 335/600/12
+f 313/564/13 377/663/13 376/660/13 312/562/13
+f 324/586/14 388/686/14 387/683/14 323/584/14
+f 356/621/15 420/751/15 421/753/15 357/622/15
+f 341/606/16 405/720/16 406/722/16 342/607/16
+f 298/534/17 362/632/17 360/627/17 297/532/17
+f 309/556/15 373/655/15 372/652/15 308/554/15
+f 320/578/18 384/678/18 383/674/18 319/576/18
+f 348/613/19 412/734/19 413/736/19 349/614/19
+f 333/598/20 397/703/20 398/705/20 334/599/20
+f 305/548/21 369/647/21 368/645/21 304/546/21
+f 355/620/22 419/749/22 420/751/22 356/621/22
+f 340/605/23 404/718/23 405/720/23 341/606/23
+f 316/570/24 380/668/24 379/667/24 315/568/24
+f 327/592/8 391/691/8 390/690/8 326/590/8
+f 347/612/25 411/732/25 412/734/25 348/613/25
+f 301/540/19 365/637/19 364/636/19 300/538/19
+f 312/562/26 376/660/26 375/659/26 311/560/26
+f 332/597/9 396/701/9 397/703/9 333/598/9
+f 323/584/27 387/683/27 386/682/27 322/582/27
+f 354/619/28 418/748/28 419/749/28 355/620/28
+f 339/604/29 403/717/29 404/718/29 340/605/29
+f 308/554/30 372/652/30 371/651/30 307/552/30
+f 346/611/31 410/731/31 411/732/31 347/612/31
+f 319/576/12 383/674/12 382/673/12 318/574/12
+f 331/596/24 395/700/24 396/701/24 332/597/24
+f 360/626/4 392/693/4 393/695/4 361/629/4
+f 362/631/4 394/697/4 392/693/4 360/626/4
+f 363/633/4 395/699/4 394/697/4 362/631/4
+f 364/635/4 396/702/4 395/699/4 363/633/4
+f 365/638/4 397/704/4 396/702/4 364/635/4
+f 366/639/4 398/706/4 397/704/4 365/638/4
+f 367/641/4 399/707/4 398/706/4 366/639/4
+f 368/644/32 400/710/32 399/708/32 367/642/32
+f 369/646/4 401/712/4 400/710/4 368/644/4
+f 370/648/4 402/714/4 401/712/4 369/646/4
+f 371/650/4 403/716/4 402/714/4 370/648/4
+f 372/653/4 404/719/4 403/716/4 371/650/4
+f 373/654/4 405/721/4 404/719/4 372/653/4
+f 374/656/4 406/723/4 405/721/4 373/654/4
+f 375/658/4 407/724/4 406/723/4 374/656/4
+f 376/661/4 408/726/4 407/724/4 375/658/4
+f 377/662/4 409/728/4 408/726/4 376/661/4
+f 378/664/4 410/730/4 409/728/4 377/662/4
+f 379/666/4 411/733/4 410/730/4 378/664/4
+f 380/669/4 412/735/4 411/733/4 379/666/4
+f 381/670/4 413/737/4 412/735/4 380/669/4
+f 382/672/4 414/738/4 413/737/4 381/670/4
+f 383/675/4 415/740/4 414/738/4 382/672/4
+f 384/676/32 416/742/32 415/740/32 383/675/32
+f 385/679/4 417/745/4 416/743/4 384/677/4
+f 386/681/4 418/747/4 417/745/4 385/679/4
+f 387/684/4 419/750/4 418/747/4 386/681/4
+f 388/685/4 420/752/4 419/750/4 387/684/4
+f 389/687/4 421/754/4 420/752/4 388/685/4
+f 390/689/4 422/755/4 421/754/4 389/687/4
+f 391/692/4 423/757/4 422/755/4 390/689/4
+f 361/629/4 393/695/4 423/757/4 391/692/4
+f 306/550/33 370/649/33 369/647/33 305/548/33
+f 335/600/34 399/709/34 400/711/34 336/601/34
+f 350/615/35 414/739/35 415/741/35 351/616/35
+f 321/580/36 385/680/36 384/678/36 320/578/36
+f 310/558/7 374/657/7 373/655/7 309/556/7
+f 329/594/37 393/696/37 392/694/37 328/593/37
+f 299/536/31 363/634/31 362/632/31 298/534/31
+f 343/608/10 407/725/10 408/727/10 344/609/10
+f 358/623/38 422/756/38 423/758/38 359/624/38
+f 325/588/23 389/688/23 388/686/23 324/586/23
+f 314/566/39 378/665/39 377/663/39 313/564/39
+f 336/601/36 400/711/36 401/713/36 337/602/36
+f 351/616/40 415/741/40 416/744/40 352/617/40
+f 303/544/35 367/643/35 366/640/35 302/542/35
+f 328/593/39 392/694/39 394/698/39 330/595/39
+f 318/574/20 382/673/20 381/671/20 317/572/20
+f 344/609/41 408/727/41 409/729/41 345/610/41
+f 359/625/26 423/759/26 393/696/26 329/594/26
+f 307/552/28 371/651/28 370/649/28 306/550/28
+f 337/602/42 401/713/42 402/715/42 338/603/42
+f 352/617/43 416/744/43 417/746/43 353/618/43
+f 322/582/42 386/682/42 385/680/42 321/580/42
+f 311/560/38 375/659/38 374/657/38 310/558/38
+f 330/595/44 394/698/44 395/700/44 331/596/44
+f 300/538/45 364/636/45 363/634/45 299/536/45
+f 345/610/17 409/729/17 410/731/17 346/611/17
+f 326/590/16 390/690/16 389/688/16 325/588/16
+f 297/532/41 360/627/41 361/630/41 296/530/41
+f 315/568/44 379/667/44 378/665/44 314/566/44
+f 338/603/27 402/715/27 403/717/27 339/604/27
+f 353/618/33 417/746/33 418/748/33 354/619/33
+f 304/546/46 368/645/46 367/643/46 303/544/46
+f 424/760/4 426/764/4 425/761/4
+f 424/760/4 427/766/4 426/764/4
+f 424/760/4 428/768/4 427/766/4
+f 424/760/4 429/770/4 428/768/4
+f 424/760/4 430/772/4 429/770/4
+f 424/760/4 431/774/4 430/772/4
+f 424/760/4 432/776/4 431/774/4
+f 424/760/4 433/778/4 432/776/4
+f 424/760/4 434/780/4 433/778/4
+f 424/760/4 435/782/4 434/780/4
+f 424/760/4 436/784/4 435/782/4
+f 424/760/4 437/786/4 436/784/4
+f 424/760/4 438/788/4 437/786/4
+f 424/760/4 439/790/4 438/788/4
+f 424/760/4 440/792/4 439/790/4
+f 424/760/4 441/794/4 440/792/4
+f 424/760/4 442/796/4 441/794/4
+f 424/760/4 443/798/4 442/796/4
+f 424/760/4 444/800/4 443/798/4
+f 424/760/4 445/802/4 444/800/4
+f 424/760/4 446/804/4 445/802/4
+f 424/760/4 447/806/4 446/804/4
+f 424/760/4 448/808/4 447/806/4
+f 424/760/4 449/810/4 448/808/4
+f 424/760/4 450/812/4 449/810/4
+f 424/760/4 451/814/4 450/812/4
+f 424/760/4 452/816/4 451/814/4
+f 424/760/4 453/818/4 452/816/4
+f 424/760/4 454/820/4 453/818/4
+f 424/760/4 455/822/4 454/820/4
+f 424/760/4 456/824/4 455/822/4
+f 424/760/4 425/761/4 456/824/4
+f 486/855/7 550/986/7 551/989/7 487/856/7
+f 471/840/8 535/955/8 536/958/8 472/841/8
+f 446/805/9 510/904/9 509/901/9 445/803/9
+f 425/762/10 490/861/10 520/924/10 456/825/10
+f 431/775/11 495/873/11 494/870/11 430/773/11
+f 478/847/11 542/969/11 543/972/11 479/848/11
+f 463/832/12 527/938/12 528/942/12 464/833/12
+f 442/797/13 506/896/13 505/893/13 441/795/13
+f 453/819/14 517/919/14 516/916/14 452/817/14
+f 485/854/15 549/984/15 550/986/15 486/855/15
+f 470/839/16 534/953/16 535/955/16 471/840/16
+f 427/767/17 491/865/17 489/860/17 426/765/17
+f 438/789/15 502/888/15 501/885/15 437/787/15
+f 449/811/18 513/911/18 512/907/18 448/809/18
+f 477/846/19 541/967/19 542/969/19 478/847/19
+f 462/831/20 526/936/20 527/938/20 463/832/20
+f 434/781/21 498/880/21 497/878/21 433/779/21
+f 484/853/30 548/982/30 549/984/30 485/854/30
+f 469/838/23 533/951/23 534/953/23 470/839/23
+f 445/803/24 509/901/24 508/900/24 444/801/24
+f 456/825/8 520/924/8 519/923/8 455/823/8
+f 476/845/25 540/965/25 541/967/25 477/846/25
+f 430/773/19 494/870/19 493/869/19 429/771/19
+f 441/795/26 505/893/26 504/892/26 440/793/26
+f 461/830/9 525/934/9 526/936/9 462/831/9
+f 452/817/27 516/916/27 515/915/27 451/815/27
+f 483/852/28 547/981/28 548/982/28 484/853/28
+f 468/837/29 532/950/29 533/951/29 469/838/29
+f 437/787/30 501/885/30 500/884/30 436/785/30
+f 475/844/31 539/964/31 540/965/31 476/845/31
+f 448/809/12 512/907/12 511/906/12 447/807/12
+f 460/829/24 524/933/24 525/934/24 461/830/24
+f 489/859/4 521/926/4 522/928/4 490/862/4
+f 491/864/4 523/930/4 521/926/4 489/859/4
+f 492/866/4 524/932/4 523/930/4 491/864/4
+f 493/868/4 525/935/4 524/932/4 492/866/4
+f 494/871/4 526/937/4 525/935/4 493/868/4
+f 495/872/4 527/939/4 526/937/4 494/871/4
+f 496/874/4 528/940/4 527/939/4 495/872/4
+f 497/877/32 529/943/32 528/941/32 496/875/32
+f 498/879/4 530/945/4 529/943/4 497/877/4
+f 499/881/4 531/947/4 530/945/4 498/879/4
+f 500/883/4 532/949/4 531/947/4 499/881/4
+f 501/886/4 533/952/4 532/949/4 500/883/4
+f 502/887/4 534/954/4 533/952/4 501/886/4
+f 503/889/4 535/956/4 534/954/4 502/887/4
+f 504/891/4 536/957/4 535/956/4 503/889/4
+f 505/894/4 537/959/4 536/957/4 504/891/4
+f 506/895/4 538/961/4 537/959/4 505/894/4
+f 507/897/4 539/963/4 538/961/4 506/895/4
+f 508/899/4 540/966/4 539/963/4 507/897/4
+f 509/902/4 541/968/4 540/966/4 508/899/4
+f 510/903/4 542/970/4 541/968/4 509/902/4
+f 511/905/4 543/971/4 542/970/4 510/903/4
+f 512/908/4 544/973/4 543/971/4 511/905/4
+f 513/909/32 545/975/32 544/973/32 512/908/32
+f 514/912/4 546/978/4 545/976/4 513/910/4
+f 515/914/4 547/980/4 546/978/4 514/912/4
+f 516/917/4 548/983/4 547/980/4 515/914/4
+f 517/918/4 549/985/4 548/983/4 516/917/4
+f 518/920/4 550/987/4 549/985/4 517/918/4
+f 519/922/4 551/988/4 550/987/4 518/920/4
+f 520/925/4 552/990/4 551/988/4 519/922/4
+f 490/862/4 522/928/4 552/990/4 520/925/4
+f 435/783/33 499/882/33 498/880/33 434/781/33
+f 464/833/34 528/942/34 529/944/34 465/834/34
+f 479/848/35 543/972/35 544/974/35 480/849/35
+f 450/813/47 514/913/47 513/911/47 449/811/47
+f 439/791/7 503/890/7 502/888/7 438/789/7
+f 458/827/37 522/929/37 521/927/37 457/826/37
+f 428/769/31 492/867/31 491/865/31 427/767/31
+f 472/841/10 536/958/10 537/960/10 473/842/10
+f 487/856/38 551/989/38 552/991/38 488/857/38
+f 454/821/23 518/921/23 517/919/23 453/819/23
+f 443/799/39 507/898/39 506/896/39 442/797/39
+f 465/834/36 529/944/36 530/946/36 466/835/36
+f 480/849/40 544/974/40 545/977/40 481/850/40
+f 432/777/35 496/876/35 495/873/35 431/775/35
+f 457/826/39 521/927/39 523/931/39 459/828/39
+f 447/807/20 511/906/20 510/904/20 446/805/20
+f 473/842/41 537/960/41 538/962/41 474/843/41
+f 488/858/26 552/992/26 522/929/26 458/827/26
+f 436/785/28 500/884/28 499/882/28 435/783/28
+f 466/835/42 530/946/42 531/948/42 467/836/42
+f 481/850/43 545/977/43 546/979/43 482/851/43
+f 451/815/42 515/915/42 514/913/42 450/813/42
+f 440/793/38 504/892/38 503/890/38 439/791/38
+f 459/828/44 523/931/44 524/933/44 460/829/44
+f 429/771/45 493/869/45 492/867/45 428/769/45
+f 474/843/17 538/962/17 539/964/17 475/844/17
+f 455/823/16 519/923/16 518/921/16 454/821/16
+f 426/765/41 489/860/41 490/863/41 425/763/41
+f 444/801/44 508/900/44 507/898/44 443/799/44
+f 467/836/27 531/948/27 532/950/27 468/837/27
+f 482/851/33 546/979/33 547/981/33 483/852/33
+f 433/779/46 497/878/46 496/876/46 432/777/46
diff --git a/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp0.png b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp0.png
new file mode 100644
index 0000000..6e8ca57
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp0.png
Binary files differ
diff --git a/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp1.png b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp1.png
new file mode 100644
index 0000000..d9fa346
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp1.png
Binary files differ
diff --git a/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp2.png b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp2.png
new file mode 100644
index 0000000..1fd1919
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp2.png
Binary files differ
diff --git a/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp3.png b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp3.png
new file mode 100644
index 0000000..8588b12
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_hp3.png
Binary files differ
diff --git a/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_template.png b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_template.png
new file mode 100755
index 0000000..0bab765
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_template.png
Binary files differ
diff --git a/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_vr0.png b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_vr0.png
new file mode 100644
index 0000000..d327bc3
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_vr0.png
Binary files differ
diff --git a/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_vr1.png b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_vr1.png
new file mode 100644
index 0000000..494e890
--- /dev/null
+++ b/advtrains_signals_muc_ubahn/textures/advtrains_signals_muc_ubahn_vr1.png
Binary files differ
diff --git a/advtrains_trackmap/mod.conf b/advtrains_trackmap/mod.conf
index 971bc26..633f1e2 100644
--- a/advtrains_trackmap/mod.conf
+++ b/advtrains_trackmap/mod.conf
@@ -3,4 +3,4 @@ title=Advanced Trains Track Map
description=Formspec-based map to display track layouts
author=orwell96
-depends=advtrains,ch_core
+depends=advtrains
diff --git a/advtrains_trackmap/viewer.lua b/advtrains_trackmap/viewer.lua
index c21d5e1..2ea54ce 100644
--- a/advtrains_trackmap/viewer.lua
+++ b/advtrains_trackmap/viewer.lua
@@ -6,7 +6,7 @@ local tm = advtrains.trackmap
local function node_left_click(pos, pname)
local node_ok, conns, rail_y=advtrains.get_rail_info_at(pos)
if not node_ok then
- minetest.chat_send_player(pname, "Toto není kolej!")
+ minetest.chat_send_player(pname, "Node is not a track!")
return
end
@@ -25,11 +25,10 @@ end
minetest.register_craftitem("advtrains_trackmap:tool",{
- description = "nástroj na mapování kolejí",
- _ch_help = "levý klik na kolej pro zobrazení „mapy“",
+ description = "Trackmap Tool\nPunch: Show map",
groups = {cracky=1}, -- key=name, value=rating; rating=1..3.
- inventory_image = "ch_core_white_pixel.png^[multiply:#dddddd^[resize:32x32^(at_il_tool.png^[resize:32x32)",
- wield_image = "ch_core_white_pixel.png^[multiply:#dddddd^[resize:32x32^(at_il_tool.png^[resize:32x32)",
+ inventory_image = "at_il_tool.png",
+ wield_image = "at_il_tool.png",
stack_max = 1,
on_use = function(itemstack, player, pointed_thing)
local pname = player:get_player_name()
@@ -42,15 +41,8 @@ minetest.register_craftitem("advtrains_trackmap:tool",{
end
end
})
-
-core.register_craft({
+minetest.register_craft({
output = "advtrains_trackmap:tool",
- recipe = {
- {"advtrains_interlocking:tool", "default:paper"},
- {"default:paper", "default:paper"},
- },
-})
-core.register_craft({
- output = "advtrains_interlocking:tool",
- recipe = {{"advtrains_trackmap:tool"}},
-})
+ type = "shapeless",
+ recipe = {"dye:green","advtrains:trackworker", "default:paper"}
+}) \ No newline at end of file
diff --git a/advtrains_train_track/init.lua b/advtrains_train_track/init.lua
index 608a8eb..35937bc 100644
--- a/advtrains_train_track/init.lua
+++ b/advtrains_train_track/init.lua
@@ -567,17 +567,6 @@ minetest.register_craft({
---- translate well to a block game.
-- END crossings
-advtrains.default_slope_formats = {t_30deg_slope = {
- vst1={true, false, true},
- vst2={true, false, true},
- vst31={true}, vst32={true}, vst33={true},
- vst41={true}, vst42={true}, vst43={true}, vst44={true},
- vst51={true}, vst52={true}, vst53={true}, vst54={true}, vst55={true},
- vst61={true}, vst62={true}, vst63={true}, vst64={true}, vst65={true}, vst66={true},
- vst71={true}, vst72={true}, vst73={true}, vst74={true}, vst75={true}, vst76={true}, vst77={true},
- vst81={true}, vst82={true}, vst83={true}, vst84={true}, vst85={true}, vst86={true}, vst87={true}, vst88={true},
-}}
-
--slopes
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack",
@@ -587,7 +576,7 @@ advtrains.register_tracks("default", {
shared_texture="advtrains_dtrack_shared.png",
second_texture="default_gravel.png",
description=attrans("Track"),
- formats=advtrains.default_slope_formats.t_30deg_slope,
+ formats={vst1={true, false, true}, vst2={true, false, true}, vst31={true}, vst32={true}, vst33={true}},
}, advtrains.ap.t_30deg_slope)
minetest.register_craft({
@@ -600,27 +589,6 @@ minetest.register_craft({
},
})
-advtrains.register_tracks("default", {
- nodename_prefix="advtrains:dtrack_rg",
- texture_prefix="advtrains_dtrack_rg",
- models_prefix="advtrains_dtrack",
- models_suffix=".obj",
- shared_texture="advtrains_dtrack_shared.png",
- second_texture="ch_extras_gravel.png",
- description=attrans("Track with Railway Gravel"),
- formats=advtrains.default_slope_formats.t_30deg_slope,
-}, advtrains.ap.t_30deg_slope)
-
-minetest.register_craft({
- type = "shapeless",
- output = 'advtrains:dtrack_rg_slopeplacer 2',
- recipe = {
- "advtrains:dtrack_placer",
- "advtrains:dtrack_placer",
- "ch_core:railway_gravel",
- },
-})
-
--bumpers
advtrains.register_tracks("default", {
@@ -689,9 +657,10 @@ advtrains.register_tracks("default", {
minetest.register_craft({
output = "advtrains:dtrack_atc_placer",
recipe = {
- {"mesecons_microcontroller:microcontroller0000", ""},
- {"advtrains:dtrack_placer", ""},
- },
+ {"","mesecons_microcontroller:microcontroller0000",""},
+ {"","advtrains:dtrack_placer",""},
+ {"","",""}
+ }
})
-- Tracks for loading and unloading trains
@@ -719,12 +688,12 @@ local function show_fc_formspec(pos,player)
local form = 'formspec_version[4]'..
'size[10,5]'..
- 'label[0.5,0.4;kolej nakládání/vykládání]'..
- 'label[0.5,1.1;Nastavte nákladní kód. Vagony se zadaným kódem budou naloženy/vyloženy.]'..
- 'label[0.5,1.6;Prázdné pole znamená všechny vagony.]'..
- 'label[0.5,2.1;Pro vypnutí zadejte kód #.]'..
- 'field[0.5,3;5.5,1;fc;kód:;'..minetest.formspec_escape(fc)..']'..
- 'button[6.5,3;3,1;save;Uložit]'
+ 'label[0.5,0.4;Advtrains Loading/Unloading Track]'..
+ 'label[0.5,1.1;Set the code to match against the wagon\'s freight code]'..
+ 'label[0.5,1.6;A blank field matches all wagons (default)]'..
+ 'label[0.5,2.1;Use code # to disable the track section]'..
+ 'field[0.5,3;5.5,1;fc;FC;'..minetest.formspec_escape(fc)..']'..
+ 'button[6.5,3;3,1;save;Submit]'
minetest.show_formspec(pname, "at_load_unload_"..advtrains.encode_pos(pos), form)
end
@@ -734,13 +703,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
local pos = advtrains.decode_pos(pe)
if pos then
if minetest.is_protected(pos, pname) then
- minetest.chat_send_player(pname, "Pozice je zastřežená!")
+ minetest.chat_send_player(pname, "Position is protected!")
return
end
if fields.save then
minetest.get_meta(pos):set_string("fc",tostring(fields.fc))
- minetest.chat_send_player(pname,"Nákladní kód nastaven: "..tostring(fields.fc))
+ minetest.chat_send_player(pname,"Freight code set: "..tostring(fields.fc))
show_fc_formspec(pos,player)
end
end
@@ -953,7 +922,7 @@ minetest.register_craft({
})
-if minetest.get_modpath("mesecons") then
+if mesecon then
advtrains.register_tracks("default", {
nodename_prefix="advtrains:dtrack_detector_off",
texture_prefix="advtrains_dtrack_detector",
@@ -1022,215 +991,7 @@ minetest.register_craft({
"mesecons:wire_00000000_off"
},
})
-
-local function swap_to_off(pos)
- local node = advtrains.ndb.get_node(pos)
- if node == nil then
- minetest.log("error", "Advtrains node at "..minetest.pos_to_string(pos).." expected, but not found!")
- else
- local old_node_name = node.name
- node.name = old_node_name:gsub("rdetector_on", "rdetector_off")
- assert(node.name)
- if node.name ~= old_node_name then
- advtrains.ndb.swap_node(pos, node)
- if advtrains.is_node_loaded(pos) then
- mesecon.receptor_off(pos, advtrains.meseconrules)
- end
- end
- end
-end
-
-local function swap_to_on(pos)
- local node = advtrains.ndb.get_node(pos)
- if node == nil then
- minetest.log("error", "Advtrains node at "..minetest.pos_to_string(pos).." expected, but not found!")
- else
- local old_node_name = node.name
- node.name = old_node_name:gsub("rdetector_off", "rdetector_on")
- assert(node.name)
- if node.name ~= old_node_name then
- advtrains.ndb.swap_node(pos, node)
- if advtrains.is_node_loaded(pos) then
- mesecon.receptor_on(pos, advtrains.meseconrules)
- end
- end
- end
-end
-
-local rdetector_data = {
- --[[
- [pos_hash] = {
- pos = pos,
- created = ...,
- trains = {
- [train_id] = {expiration = timestamp}}}
- ]]
-}
-
-local function watch_trains(pos_hash, created)
- assert(pos_hash)
- assert(created)
- local data = rdetector_data[pos_hash]
- if data == nil then
- return
- elseif created ~= data.created then
- return -- not my data
- else
- minetest.after(1, watch_trains, pos_hash, created)
- end
- local kept = 0
- local to_delete = {}
- local now = minetest.get_us_time()
- for train_id, traindata in pairs(data.trains) do
- local train = advtrains.trains[train_id]
- if train == nil or not train.last_pos then
- table.insert(to_delete, train_id) -- train does not exist
- elseif traindata.expiration ~= nil and traindata.expiration <= now then
- table.insert(to_delete, train_id) -- train expired
- else
- kept = kept + 1
- end
- end
- if kept == 0 then
- -- no kept trains => disable the node
- swap_to_off(data.pos)
- rdetector_data[pos_hash] = nil -- no trains remain, delete data
- elseif #to_delete > 0 then
- for _, train_id in ipairs(to_delete) do
- data.trains[train_id] = nil
- end
- end
-end
-
-local function on_train_approach(pos, train_id)
- local pos_hash = advtrains.encode_pos(pos)
- local data = rdetector_data[pos_hash]
- local now = minetest.get_us_time()
- local expiration = now + 30000000
- if data == nil then
- rdetector_data[pos_hash] = {
- pos = pos,
- created = now,
- trains = {[train_id] = {expiration = expiration}},
- }
- minetest.after(0.1, swap_to_on, pos)
- minetest.after(1, watch_trains, pos_hash, now)
- else
- data.trains[train_id] = {expiration = expiration}
- end
-end
-
-local function on_train_enter(pos, train_id)
- local pos_hash = advtrains.encode_pos(pos)
- local data = rdetector_data[pos_hash]
- local now = minetest.get_us_time()
- if data == nil then
- rdetector_data[pos_hash] = {
- pos = pos,
- created = now,
- trains = {[train_id] = {}},
- }
- minetest.after(0.1, swap_to_on, pos)
- minetest.after(1, watch_trains, pos_hash, now)
- else
- data.trains[train_id] = {}
- end
end
-
-local function on_train_leave(pos, train_id)
- local pos_hash = advtrains.encode_pos(pos)
- local data = rdetector_data[pos_hash]
- if data ~= nil then
- data.trains[train_id] = {expiration = minetest.get_us_time() - 1000000}
- end
-end
-
-local function after_dig_node(pos)
- rdetector_data[advtrains.encode_pos(pos)] = nil
-end
-
-advtrains.register_tracks("default", {
- nodename_prefix="advtrains:dtrack_rdetector_off",
- texture_prefix="advtrains_dtrack_detector",
- models_prefix="advtrains_dtrack",
- models_suffix=".b3d",
- shared_texture="advtrains_dtrack_shared_rdetector_off.png",
- description=attrans("Remote Detector Rail"),
- formats={},
- get_additional_definiton = function(def, preset, suffix, rotation)
- return {
- mesecons = {
- receptor = {
- state = mesecon.state.off,
- rules = advtrains.meseconrules
- }
- },
- after_dig_node = after_dig_node,
- drop = "advtrains:dtrack_rdetector_off_placer",
- advtrains = {
- on_updated_from_nodedb = function(pos, node)
- mesecon.receptor_off(pos, advtrains.meseconrules)
- end,
- on_train_approach = function(pos, train_id, train, index, has_entered)
- if has_entered then
- on_train_enter(pos, train_id)
- else
- on_train_approach(pos, train_id)
- end
- end,
- on_train_enter = on_train_enter,
- on_train_leave = on_train_leave,
- }
- }
- end
-}, advtrains.ap.t_30deg_straightonly)
-advtrains.register_tracks("default", {
- nodename_prefix="advtrains:dtrack_rdetector_on",
- texture_prefix="advtrains_dtrack",
- models_prefix="advtrains_dtrack",
- models_suffix=".b3d",
- shared_texture="advtrains_dtrack_shared_rdetector_on.png",
- description=attrans("Remote Detector Rail"),
- formats={},
- get_additional_definiton = function(def, preset, suffix, rotation)
- return {
- after_dig_node = after_dig_node,
- drop = "advtrains:dtrack_rdetector_off_placer",
- mesecons = {
- receptor = {
- state = mesecon.state.on,
- rules = advtrains.meseconrules
- }
- },
- advtrains = {
- on_updated_from_nodedb = function(pos, node)
- mesecon.receptor_on(pos, advtrains.meseconrules)
- end,
- on_train_approach = function(pos, train_id, train, index, has_entered)
- if has_entered then
- on_train_enter(pos, train_id)
- else
- on_train_approach(pos, train_id)
- end
- end,
- on_train_enter = on_train_enter,
- on_train_leave = on_train_leave,
- }
- }
- end
-}, advtrains.ap.t_30deg_straightonly_noplacer)
-minetest.register_craft({
-type="shapeless",
-output = 'advtrains:dtrack_rdetector_off_placer',
-recipe = {
- "advtrains:dtrack_detector_off_placer",
- "default:mese_crystal",
-},
-})
-
-end
-
-
--TODO legacy
--I know lbms are better for this purpose
for name,rep in pairs({swl_st="swlst", swr_st="swrst", swl_cr="swlcr", swr_cr="swrcr", }) do
diff --git a/assets/mm_trains_bvbg.png b/assets/mm_trains_bvbg.png
new file mode 100644
index 0000000..e1ac0ed
--- /dev/null
+++ b/assets/mm_trains_bvbg.png
Binary files differ
diff --git a/assets/muc_ubahn_uvs.png b/assets/muc_ubahn_uvs.png
new file mode 100644
index 0000000..b4292af
--- /dev/null
+++ b/assets/muc_ubahn_uvs.png
Binary files differ
diff --git a/assets/signal_wall.blend1 b/assets/signal_wall.blend1
new file mode 100644
index 0000000..7915a52
--- /dev/null
+++ b/assets/signal_wall.blend1
Binary files differ
diff --git a/assets/signal_wall_ceiling_muc_ubahn.blend b/assets/signal_wall_ceiling_muc_ubahn.blend
new file mode 100644
index 0000000..b4d8e06
--- /dev/null
+++ b/assets/signal_wall_ceiling_muc_ubahn.blend
Binary files differ
diff --git a/assets/signal_wall_muc_ubahn.blend b/assets/signal_wall_muc_ubahn.blend
new file mode 100644
index 0000000..6f40560
--- /dev/null
+++ b/assets/signal_wall_muc_ubahn.blend
Binary files differ