aboutsummaryrefslogtreecommitdiff
path: root/advtrains
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 /advtrains
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
Diffstat (limited to 'advtrains')
-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
16 files changed, 5979 insertions, 646 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