diff options
52 files changed, 4917 insertions, 553 deletions
@@ -3,6 +3,12 @@ packages: - git - lua5.1 - luarocks +- curl +- minetest-server +- unzip +- wget +- lua-busted +- luajit sources : - https://git.sr.ht/~gpcf/advtrains @@ -26,4 +32,37 @@ tasks: ~/.luarocks/bin/mineunit -r sed -n '/^File/,$p' luacov.report.out mv luacov.report.out ~/$i.luacov.report.out +- install_mt_game : | + curl -L https://github.com/minetest/minetest_game/archive/master.zip -o master.zip + mkdir -p .minetest/games/ + cd .minetest/games + unzip ../../master.zip + mv minetest_game-master minetest_game +- install_test_world: | + mkdir -p .minetest/worlds/ + curl https://lifomaps.de/advtrains-test/testworld.tar.gz -o ~/testworld.tar.gz + cd .minetest/worlds/ + tar xf ../../testworld.tar.gz +- run_unit_tests : | + cd advtrains/advtrains + busted + cd ../advtrains_interlocking + busted + cd ../serialize_lib + busted +- activate_test_env: | + cd advtrains + git merge --no-commit origin/luaatcdebug +- install_advtrains : | + mkdir .minetest/mods + cp -r advtrains .minetest/mods + cd .minetest/mods + git clone https://git.bananach.space/basic_trains.git/ +- run_test_world: | + echo "bind_address = 127.0.0.1" > minetest.conf + minetestserver --port 31111 --gameid minetest_game --config ~/minetest.conf --world ~/.minetest/worlds/advtrains_testworld --logfile ~/minetest.log +- test_po_files : | + cd advtrains/advtrains + for f in po/*.po; do + luajit -e 'require("poconvert").from_string("advtrains", io.input():read("*a"))' < $f done @@ -2,3 +2,5 @@ .project .settings luacov.* +advtrains/locale/*.tr +advtrains/po/*~ diff --git a/advtrains/atc.lua b/advtrains/atc.lua index c1ff218..b572cdc 100644 --- a/advtrains/atc.lua +++ b/advtrains/atc.lua @@ -106,7 +106,7 @@ local apn_func=function(pos) -- FIX for long-persisting ndb bug: there's no node in parameter 2 of this function! local meta=minetest.get_meta(pos) if meta then - meta:set_string("infotext", attrans("ATC controller, unconfigured.")) + meta:set_string("infotext", attrans("Unconfigured ATC controller")) meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta)) end end @@ -233,7 +233,7 @@ local matchptn={ advtrains.train_ensure_init(id, train) -- no one minds if this failed... this shouldn't even be called without train being initialized... else - atwarn(sid(id), attrans("ATC Reverse command warning: didn't reverse train, train moving!")) + atwarn(sid(id), attrans("ATC Reverse command warning: didn't reverse train, train moving.")) end return 1 end, @@ -245,11 +245,11 @@ local matchptn={ end, ["K"] = function(id, train) if train.door_open == 0 then - atwarn(sid(id), attrans("ATC Kick command warning: Doors closed")) + atwarn(sid(id), attrans("ATC Kick command warning: doors are closed.")) return 1 end if train.velocity > 0 then - atwarn(sid(id), attrans("ATC Kick command warning: Train moving")) + atwarn(sid(id), attrans("ATC Kick command warning: train moving.")) return 1 end local tp = train.trainparts diff --git a/advtrains/copytool.lua b/advtrains/copytool.lua index 8a6d2f7..c63551e 100644 --- a/advtrains/copytool.lua +++ b/advtrains/copytool.lua @@ -26,7 +26,7 @@ minetest.register_tool("advtrains:copytool", { return itemstack end if not minetest.check_player_privs(placer, {train_operator = true }) then - minetest.chat_send_player(pname, "You don't have the train_operator privilege.") + minetest.chat_send_player(pname, S("You do not have the @1 privilege.", "train_operator")) return itemstack end if not minetest.check_player_privs(placer, {train_admin = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then @@ -38,7 +38,7 @@ minetest.register_tool("advtrains:copytool", { local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid, {default=true}) if not prevpos then - minetest.chat_send_player(pname, "The track you are trying to place the wagon on is not long enough!") + minetest.chat_send_player(pname, attrans("The track you are trying to place the wagon on is not long enough.")) return end @@ -49,12 +49,12 @@ minetest.register_tool("advtrains:copytool", { end local clipboard = meta:get_string("clipboard") if (clipboard == "") then - minetest.chat_send_player(pname, "The clipboard is empty."); + minetest.chat_send_player(pname, attrans("The clipboard is empty.")); return end clipboard = minetest.deserialize(clipboard) if (clipboard.wagons == nil) then - minetest.chat_send_player(pname, "The clipboard is empty."); + minetest.chat_send_player(pname, attrans("The clipboard is empty.")); return end @@ -71,7 +71,7 @@ minetest.register_tool("advtrains:copytool", { local train = advtrains.trains[id] train.off_track = train.end_index<train.path_trk_b if (train.off_track) then - minetest.chat_send_player(pname, "Back of train would end up off track, cancelling.") + minetest.chat_send_player(pname, attrans("Back of train would end up off track, cancelling.")) advtrains.remove_train(id) return end @@ -89,19 +89,19 @@ minetest.register_tool("advtrains:copytool", { local le = pointed_thing.ref:get_luaentity() if (le == nil) then - minetest.chat_send_player(user:get_player_name(), "No such lua entity!") + minetest.chat_send_player(user:get_player_name(), attrans("No such lua entity.")) return end local wagon = advtrains.wagons[le.id] if (not (le.id and advtrains.wagons[le.id])) then - minetest.chat_send_player(user:get_player_name(), string.format("No such wagon: %s", le.id)) + minetest.chat_send_player(user:get_player_name(), attrans("No such wagon: @1.", le.id)) return end local train = advtrains.trains[wagon.train_id] if (not train) then - minetest.chat_send_player(user:get_player_name(), string.format("No such train: %s", wagon.train_id)) + minetest.chat_send_player(user:get_player_name(), attrans("No such train: @1.", wagon.train_id)) return end @@ -177,7 +177,7 @@ minetest.register_tool("advtrains:copytool", { return end meta:set_string("clipboard", minetest.serialize(clipboard)) - minetest.chat_send_player(user:get_player_name(), attrans("Train copied!")) + minetest.chat_send_player(user:get_player_name(), attrans("Train copied.")) return itemstack end }) diff --git a/advtrains/couple.lua b/advtrains/couple.lua index 49c8a5d..4933dd8 100644 --- a/advtrains/couple.lua +++ b/advtrains/couple.lua @@ -28,6 +28,20 @@ end advtrains.register_coupler_type("chain", attrans("Buffer and Chain Coupler")) advtrains.register_coupler_type("scharfenberg", attrans("Scharfenberg Coupler")) +for _, name in pairs {"couple", "decouple"} do + local t = {} + local function reg(f) + table.insert(t, f) + end + local function cb(...) + for _, f in ipairs(t) do + f(...) + end + end + advtrains["te_registered_on_" .. name] = t + advtrains["te_register_on_" .. name] = reg + advtrains["te_run_callbacks_on_" .. name] = cb +end local function create_couple_entity(pos, train1, t1_is_front, train2, t2_is_front) local id1 = train1.id @@ -79,8 +93,9 @@ function advtrains.train_check_couples(train) end if not train.cpl_front then -- recheck front couple - local front_trains, pos = advtrains.occ.get_occupations(train, atround(train.index) + CPL_CHK_DST) + local pos = advtrains.path_get(train, atround(train.index) + CPL_CHK_DST) if advtrains.is_node_loaded(pos) then -- if the position is loaded... + local front_trains = advtrains.occ.reverse_lookup_sel(pos, "in_train") for tid, idx in pairs(front_trains) do local other_train = advtrains.trains[tid] if not advtrains.train_ensure_init(tid, other_train) then @@ -109,8 +124,9 @@ function advtrains.train_check_couples(train) end if not train.cpl_back then -- recheck back couple - local back_trains, pos = advtrains.occ.get_occupations(train, atround(train.end_index) - CPL_CHK_DST) + local pos = advtrains.path_get(train, atround(train.end_index) - CPL_CHK_DST) if advtrains.is_node_loaded(pos) then -- if the position is loaded... + local back_trains = advtrains.occ.reverse_lookup_sel(pos, "in_train") for tid, idx in pairs(back_trains) do local other_train = advtrains.trains[tid] if not advtrains.train_ensure_init(tid, other_train) then @@ -182,8 +198,8 @@ end function advtrains.safe_couple_trains(train1, t1_is_front, train2, t2_is_front, pname) if pname and not minetest.check_player_privs(pname, "train_operator") then - minetest.chat_send_player(pname, "Missing train_operator privilege") - return false + minetest.chat_send_player(pname, S("You are not allowed to couple trains without the train_operator privilege.")) + return false end local wck_t1, wck_t2 @@ -225,6 +241,15 @@ function advtrains.couple_trains(init_train, invert_init_train, stat_train, stat local stp = stat_train.trainparts local stat_wagoncnt = #stp local stat_trainlen = stat_train.trainlen -- save the train length of stat train, to be added to index + + -- sanity check, prevent coupling if train would be longer than 20 after coupling + local tot_len = init_wagoncnt + stat_wagoncnt + if tot_len > advtrains.TRAIN_MAX_WAGONS then + atwarn("Cannot couple",stat_train.id,"and",init_train.id,"- train would have length",tot_len,"which is above the limit of",advtrains.TRAIN_MAX_WAGONS) + return + end + + advtrains.te_run_callbacks_on_couple(init_train, stat_train) if stat_train_opposite then -- insert wagons in inverse order and set their wagon_flipped state @@ -310,7 +335,7 @@ function advtrains.check_matching_coupler_types(t1, t1_front, t2, t2_front) --atdebug("CMCT: t1",t1_cplt,"t2",t2_cplt,"") -- if at least one of the trains has no couplers table, it always couples (fallback behavior and mode for universal shunters) - if not t1_cplt or not t2_cplt then + if minetest.settings:get_bool("advtrains_universal_couplers", false) or not t1_cplt or not t2_cplt then return true end @@ -326,11 +351,11 @@ function advtrains.check_matching_coupler_types(t1, t1_front, t2, t2_front) for typ,_ in pairs(t1_cplt) do table.insert(t1_cplhr, advtrains.coupler_types[typ] or typ) end - if #t1_cplhr==0 then t1_cplhr[1]=attrans("<none>") end + if #t1_cplhr==0 then t1_cplhr[1]=attrans("<No coupler>") end for typ,_ in pairs(t2_cplt) do table.insert(t2_cplhr, advtrains.coupler_types[typ] or typ) end - if #t2_cplhr==0 then t2_cplhr[1]=attrans("<none>") end + if #t2_cplhr==0 then t2_cplhr[1]=attrans("<No coupler>") end return false, attrans("Can not couple: The couplers of the trains do not match (@1 and @2).", table.concat(t1_cplhr, ","), table.concat(t2_cplhr, ",")) end @@ -428,7 +453,7 @@ minetest.register_entity("advtrains:discouple", { self.object:remove() return end - --getyaw seems to be a reliable method to check if an object is loaded...if it returns nil, it is not. + --get_yaw seems to be a reliable method to check if an object is loaded...if it returns nil, it is not. if not self.wagon.object:get_yaw() then self.object:remove() return diff --git a/advtrains/craft_items.lua b/advtrains/craft_items.lua index 0e693eb..1188b64 100644 --- a/advtrains/craft_items.lua +++ b/advtrains/craft_items.lua @@ -6,7 +6,7 @@ core.register_craftitem("advtrains:boiler", { core.register_craftitem("advtrains:driver_cab", { - description = attrans("driver's cab"), + description = attrans("Driver's cab"), inventory_image = "advtrains_driver_cab.png", }) diff --git a/advtrains/crafting.lua b/advtrains/crafting.lua index 7626d55..9f80456 100644 --- a/advtrains/crafting.lua +++ b/advtrains/crafting.lua @@ -22,6 +22,14 @@ minetest.register_craft({ }) --Wallmounted Signal minetest.register_craft({ + output = 'advtrains:signal_wall_l_off 2', + recipe = { + {'default:steel_ingot', 'default:steel_ingot', 'dye:red'}, + {'', 'default:steel_ingot', ''}, + {'default:steel_ingot', 'default:steel_ingot', 'dye:dark_green'}, + }, +}) +minetest.register_craft({ output = 'advtrains:signal_wall_r_off 2', recipe = { {'dye:red', 'default:steel_ingot', 'default:steel_ingot'}, @@ -29,6 +37,15 @@ minetest.register_craft({ {'dye:dark_green', 'default:steel_ingot', 'default:steel_ingot'}, }, }) +minetest.register_craft({ + output = 'advtrains:signal_wall_t_off 2', + recipe = { + {'default:steel_ingot', '', 'default:steel_ingot'}, + {'default:steel_ingot', 'default:steel_ingot', 'default:steel_ingot'}, + {'dye:dark_green', '', 'dye:red'}, + }, +}) + --Wallmounted Signals can be converted into every orientation by shapeless crafting minetest.register_craft({ diff --git a/advtrains/init.lua b/advtrains/init.lua index bca39df..3918ab3 100644 --- a/advtrains/init.lua +++ b/advtrains/init.lua @@ -51,6 +51,9 @@ advtrains.IGNORE_WORLD = false local NO_SAVE = false -- Do not save any data to advtrains save files +advtrains.TRAIN_MAX_WAGONS = 20 +-- Limit on the maximum number of wagons that may be in a train + -- ========================================================================== -- Use a global slowdown factor to slow down train movements. Now a setting @@ -181,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 = @@ -201,14 +204,20 @@ 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") advtrains.formspec = dofile(advtrains.modpath.."/formspec.lua") +advtrains.texture = dofile(advtrains.modpath.."/texture.lua") dofile(advtrains.modpath.."/path.lua") dofile(advtrains.modpath.."/trainlogic.lua") dofile(advtrains.modpath.."/trainhud.lua") dofile(advtrains.modpath.."/trackplacer.lua") dofile(advtrains.modpath.."/copytool.lua") +dofile(advtrains.modpath.."/wagonprop_tool.lua") dofile(advtrains.modpath.."/tracks.lua") dofile(advtrains.modpath.."/track_reg_helper.lua") dofile(advtrains.modpath.."/occupation.lua") @@ -479,6 +488,7 @@ 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", }) --then save it tmp_trains[id]=v @@ -742,6 +752,21 @@ minetest.register_chatcommand("at_whereis", end end, }) +minetest.register_chatcommand("at_tp", + { + params = "<train id>", + description = "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" + else + minetest.get_player_by_name(name):set_pos(train.last_pos) + return true, "Teleporting to train "..param + end + end, +}) minetest.register_chatcommand("at_disable_step", { params = "<yes/no>", @@ -763,6 +788,16 @@ minetest.register_chatcommand("at_disable_step", end, }) +minetest.register_chatcommand("at_status", + { + params = "", + description = "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),")"}) + end, +}) + advtrains.is_no_action = function() return no_action end 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/locale/advtrains.de.tr b/advtrains/locale/advtrains.de.tr deleted file mode 100644 index 6abbc12..0000000 --- a/advtrains/locale/advtrains.de.tr +++ /dev/null @@ -1,77 +0,0 @@ -# textdomain: advtrains -This wagon is owned by @1, you can't destroy it.=Dieser Waggon gehört @1, du kannst ihn nicht abbauen. -Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon.=Warnung: Du erhältst nur etwas Stahl zurück. Wenn du sicher bist, dass du den Waggon zerstören willst, halte 'Schleichen' und klicke links. -Show Inventory=Zeige Inventar -Select seat:=Wähle einen Sitzplatz aus: -ATC controller, unconfigured.=Zugbeeinflussungsschiene, nicht konfiguiert. -ATC controller=Zugbeeinflussungsschiene -ATC controller, mode @1@nChannel: @2=Zugbeeinflussungsschiene in Betriebsart "@1"@nKanal: @2 -ATC controller, mode @1@nCommand: @2=Zugbeeinflussungsschiene in Betriebsart "@1"@nBefehl: @2 -Command=Befehl -Command (on)=Befehl (wenn ein) -Digiline channel=Digiline-Kanal -Save=Speichern -ATC Reverse command warning: didn't reverse train, train moving!=Zugbeeinflussung - Warnung: Befehl 'R' nicht ausgeführt, Zug in Bewegung! -ATC command syntax error: I statement not closed: @1=Zugbeeinflussung - Syntaxfehler: I-Anweisung nicht geschlossen: @1 -ATC command parse error: Unknown command: @1=Zugbeeinflussung - Fehler: Unbekannter Befehl: @1 -This position is protected!=Diese Position ist geschützt! -You need to own at least one neighboring wagon to destroy this couple.=Du musst Besitzer eines angrenzenden Waggons sein, um hier abzukuppeln. -@1 Platform (low)=Niedriger @1-Bahnsteig -@1 Platform (high)=Hoher @1-Bahnsteig -off=aus -on=ein -Lampless Signal (@1)=Mechanisches Signal (@1) -Signal (@1)=Lichtsignal (@1) -Track Worker Tool@n@nLeft-click: change rail type (straight/curve/switch)@nRight-click: rotate rail/bumper/signal/etc.=Schienenwerkzeug@n@nLinksklick: Schienentyp ändern, Rechtsklick: Objekt drehen. -This node can't be rotated using the trackworker!=Kann diesen Block nicht mit dem Schienenwerkzeug drehen. -This node can't be changed using the trackworker!=Kann diesen Block nicht mit dem Schienenwerkzeug bearbeiten. -Can't place: not pointing at node=Kann nicht platzieren: Du zeigst nicht auf einen Block. -Can't place: space occupied!=Kann nicht platzieren: Platz besetzt. -Can't place: protected position!=Kann nicht platzieren: Position geschützt. -Can't place: Not enough slope items left (@1 required)=Kann nicht platzieren: nicht genug Steigungsblöcke, es werden insgesamt @1 benötigt. -Can't place: There's no slope of length @1=Kann nicht platzieren: Keine Steigung der Länge @1 definiert. -Can't place: no supporting node at upper end.=Kann nicht platzieren: kein unterstützender Block am Ende der Steigung. -Deprecated Track=ausrangierte Schiene, nicht verwenden. -Track=Schiene -Bumper=Prellbock -Detector Rail=Detektorschiene -Speed:=Geschw.: -Target:=Zielges.: -@1 Slope=@1 Steigung -Can't get on: wagon full or doors closed!=Kann nicht einsteigen: Waggon voll oder Türen geschlossen. -Use Sneak+rightclick to bypass closed doors!=Nutze Sneak+Rechtsklick, um die Türnotöffnung zu aktivieren und trotzdem einzusteigen. -Lock couples=Kupplungen sperren -Save wagon properties=Waggon-Einstellungen speichern -Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off!=Türen sind geschlossen! Sneak+Rechtsklick, um die Türnotöffnung zu aktivieren und trotzdem auszusteigen. -Wagon properties=Waggon-Einstellungen -Get off=Aussteigen -Get off (forced)=Aussteigen (erzwingen) -(Doors closed)=(Türen geschlossen) -Access to @1=Zugang zu @1 -Default Seat=Standardsitzplatz -Default Seat (driver stand)=Standardsitzplatz (Führerstand) -Driver Stand=Führerstand -Driver Stand (left)=Führerstand Links -Driver Stand (right)=Führerstand Rechts -Industrial Train Engine=Industrielle Lokomotive -Industrial tank wagon=Tankwaggon -Industrial wood wagon=Holztransportwaggon -Japanese Train Engine=Japanische Personenzug-Lokomotive -Japanese Train Wagon=Japanischer Personenzug-Passagierwaggon -Steam Engine=Dampflokomotive -Detailed Steam Engine=detaillierte Dampflokomotive -Passenger Wagon=Passagierwaggon -Box wagon=Güterwaggon -Subway Passenger Wagon=U-Bahn-Waggon -The wagon's inventory is not empty!=Das Inventar dieses Waggons ist nicht leer! -This track can not be changed!=Diese Schiene kann nicht geändert werden! -This track can not be rotated!=Diese Schiene kann nicht gedreht werden! -This track can not be removed!=Diese Schiene kann nicht entfernt werden! -Position is occupied by a train.=Ein Zug steht an dieser Position. -There's a Track Circuit Break here.=Hier ist eine Gleisabschnittsgrenze (TCB). -There's a Signal Influence Point here.=Hier ist ein Signal-Beeinflussungspunkt. -Buffer and Chain Coupler=Schraubenkupplung -Scharfenberg Coupler=Scharfenbergkupplung -Japanese Train Inter-Wagon Connection=Waggonzwischenverbindung Japanischer Personenzug -Can not couple: The couplers of the trains do not match (@1 and @2).=Kann nicht ankuppeln: Die Kupplungen der Züge passen nicht zueinander (@1 und @2) -<none>=<keine> diff --git a/advtrains/locale/advtrains.zh_CN.tr b/advtrains/locale/advtrains.zh_CN.tr deleted file mode 100644 index ef9c99b..0000000 --- a/advtrains/locale/advtrains.zh_CN.tr +++ /dev/null @@ -1,107 +0,0 @@ -# textdomain: advtrains - -# Advtrains Core (unorganized) -This wagon is owned by @1, you can't destroy it.=这是@1的车厢, 你不能摧毁它. -Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon.=警告: 如果你摧毁此车厢, 你只能拿到一些钢方块. 如果你确定要摧毁这个车厢,请按潜行键并左键单击此车厢. -ATC controller, unconfigured.=ATC控制器 (未配置) -ATC controller=ATC控制器 -ATC controller, mode @1@nChannel: @2=ATC控制器@n模式: @1@n频道: @2 -ATC controller, mode @1@nCommand: @2=ATC控制器@n模式: @1@n命令: @2 -Command=命令 -Command (on)=命令(激活时) -Digiline channel=Digiline 频道 -ATC Reverse command warning: didn't reverse train, train moving!=ATC警告:未执行“R”命令, 火车在移动 -ATC command syntax error: I statement not closed: @1=ATC语法错误: "I"命令不完整: @1 -ATC command parse error: Unknown command: @1=ATC语法错误: 未知命令: @1 -This position is protected!=这里已被保护. -You need to own at least one neighboring wagon to destroy this couple.=你必须至少拥有其中一个车厢才能解耦这两个车厢. -This node can't be rotated using the trackworker!=你不能使用铁路调整工具旋转这个方块. -This node can't be changed using the trackworker!=你不能使用铁路调整工具调整这个方块. -Can't place: not pointing at node=无法放置: 你没有选择任何方块. -Can't place: space occupied!=无法放置: 此区域已被占用. -Can't place: protected position!=无法放置: 此区域已被保护. -Can't place: Not enough slope items left (@1 required)=无法放置: 你没有足够的铁路斜坡放置工具 (你需要@1个) -Can't place: There's no slope of length @1=无法放置: advtrains不支持长度为@1m的斜坡. -Can't place: no supporting node at upper end.=无法放置: 较高端没有支撑方块. -Deprecated Track=请不要使用 -Can't get on: wagon full or doors closed!=无法上车: 车门已关闭或车厢已满 -Use Sneak+rightclick to bypass closed doors!=请使用潜行+右键上车 -Lock couples=锁定连接处 -Doors are closed! Use Sneak+rightclick to ignore the closed doors and get off!=车门已关闭, 请使用潜行+右键单击下车 -Access to @1=可前往@1 -The clipboard couldn't access the metadata. Paste failed.=无法粘贴: 剪贴板无法访问元数据 -The clipboard couldn't access the metadata. Copy failed.=无法复制: 剪贴板无法访问元数据 - -# Train HUD/Formspecs -Speed:=速度: -Target:=目标速度: -Show Inventory=显示物品栏 -Select seat:=请选择座位 -Wagon properties=车厢属性 -Save wagon properties=保存车厢属性 -Text displayed outside on train=车厢外部显示 -Text displayed inside train=车厢内部显示 -Line=火车线路 -Routingcode=路由码 -Get off=下车 -Get off (forced)=强制下车 -(Doors closed)=(车门已关闭) - -# General -Save=保存 -# "off" and "on" can be translated differently depending on the context and are therefore not translated. -off=off -on=on - -# Line automation -Station Code=车站代码 -Station Name=车站名称 -Door Delay=车门关闭时间 -Departure Speed=出发速度 -Stop Time=停站时间 - -# Items -Track Worker Tool@n@nLeft-click: change rail type (straight/curve/switch)@nRight-click: rotate rail/bumper/signal/etc.=铁路调整工具@n@n左键单击: 切换轨道类型@n右键单击: 旋转方块 -Passive Component Naming Tool@n@nRight-click to name a passive component.=被动元件命名工具@n@n右键单击命名所选元件. -Train copy/paste tool@n@nLeft-click: copy train@nRight-click: paste train=火车复制工具@n@n左键单击: 复制@n右键单击: 粘帖 -Track=铁轨 -Perpendicular Diamond Crossing Track=垂直交叉铁轨 -45/90 Degree Diamond Crossing Track=45度交叉铁轨 -Unloading Track=卸货铁轨 -Loading Track=装货铁轨 -Bumper=保险杠 -Detector Rail=探测铁轨 -@1 Slope=@1斜坡 -@1 Platform (low)=50cm高的@1站台 -@1 Platform (high)=1m高的@1站台 -@1 Platform (45 degree)=1m高的@1站台 (45度) -Lampless Signal (@1)=臂板信号机 (@1) -Signal (@1)=信号灯 (@1) -Wallmounted Signal (l)=壁挂式信号灯 (左侧) -Wallmounted Signal (r)=壁挂式信号灯 (右侧) -Wallmounted Signal (t)=悬挂式信号灯 -Andrew's Cross=铁路道口信号灯 -Boiler=锅炉 -driver's cab=驾驶室 -Wheel=车轮 -Chimney=烟囱 - -# Seats -Default Seat=默认座位 -Default Seat (driver stand)=默认座位 (司机座位) -Driver Stand=司机座位 -Driver Stand (left)=左侧司机座位 -Driver Stand (right)=右侧司机座位 - -# Wagon/engine types -Industrial Train Engine=工业用火车头 -Big Industrial Train Engine=大型工业用火车头 -Industrial tank wagon=液体运输车厢 -Industrial wood wagon=木材运输车厢 -Japanese Train Engine=高速列车车头 -Japanese Train Wagon=高速列车车厢 -Steam Engine=蒸汽机车 -Detailed Steam Engine=精细的蒸汽机车 -Passenger Wagon=客车 -Box Wagon=货运车厢 -Subway Passenger Wagon=地铁车厢 diff --git a/advtrains/occupation.lua b/advtrains/occupation.lua index db39991..26e1f79 100644 --- a/advtrains/occupation.lua +++ b/advtrains/occupation.lua @@ -86,9 +86,10 @@ end function o.set_item(train_id, pos, idx) local t = occgetcreate(pos) + assert(idx) local i = 1 while t[i] do - if t[i]==train_id then + if t[i]==train_id and t[i+1]==index then break end i = i + 2 @@ -98,25 +99,30 @@ function o.set_item(train_id, pos, idx) end -function o.clear_item(train_id, pos) +function o.clear_all_items(train_id, pos) local t = occget(pos) if not t then return end local i = 1 - local moving = false while t[i] do if t[i]==train_id then - if moving then - -- if, for some occasion, there should be a duplicate entry, erase this one too - atwarn("Duplicate occupation entry at",pos,"for train",train_id,":",t) - i = i - 2 - end - moving = true + table.remove(t, i) + table.remove(t, i) + else + i = i + 2 end - if moving then - t[i] = t[i+2] - t[i+1] = t[i+3] + end +end +function o.clear_specific_item(train_id, pos, index) + local t = occget(pos) + if not t then return end + local i = 1 + while t[i] do + if t[i]==train_id and t[i+1]==index then + table.remove(t, i) + table.remove(t, i) + else + i = i + 2 end - i = i + 2 end end @@ -143,64 +149,88 @@ function o.check_collision(pos, train_id) return false end --- Gets a mapping of train id's to indexes of trains that share this path item with this train --- The train itself will not be included. --- If the requested index position is off-track, returns {}. --- returns (table with train_id->index), position -function o.get_occupations(train, index) - local ppos, ontrack = advtrains.path_get(train, index) - if not ontrack then - atlog("Train",train.id,"get_occupations requested off-track",index) - return {}, ppos - end +-- Gets a mapping of train id's to indexes of trains that have a path item at this position +-- Note that the case where 2 or more indices are at a position only occurs if there is a track loop. +-- returns (table with train_id->{index1, index2...}) +function o.reverse_lookup(ppos) local pos = advtrains.round_vector_floor_y(ppos) local t = occget(pos) if not t then return {} end local r = {} local i = 1 - local train_id = train.id while t[i] do - if t[i]~=train_id then - r[t[i]] = t[i+1] - end + if not r[t[i]] then r[t[i]] = {} end + table.insert(r[t[i]], t[i+1]) i = i + 2 end - return r, pos + return r end --- Gets a mapping of train id's to indexes of trains that stand or drive over + +-- Gets a mapping of train id's to indexes of trains that have a path item at this position. +-- Quick variant: will only return one index per train (the latest one added) -- returns (table with train_id->index) -function o.get_trains_at(ppos) +function o.reverse_lookup_quick(ppos) local pos = advtrains.round_vector_floor_y(ppos) local t = occget(pos) if not t then return {} end local r = {} local i = 1 while t[i] do - local train = advtrains.trains[t[i]] - local idx = t[i+1] - if train.end_index - 0.5 <= idx and idx <= train.index + 0.5 then - r[t[i]] = idx - end + r[t[i]] = t[i+1] i = i + 2 end return r end --- Gets a mapping of train id's to indexes of trains that have a path --- generated over this node --- returns (table with train_id->index) -function o.get_trains_over(ppos) - local pos = advtrains.round_vector_floor_y(ppos) - local t = occget(pos) - if not t then return {} end +local OCC_CLOSE_PROXIMITY = 3 +-- Gets a mapping of train id's to index of trains that have a path item at this position. Selects at most one index based on a given heuristic, or even none if it does not match the heuristic criterion +-- returns (table with train_id->index), position +-- "in_train": first index that lies between train index and end index +-- "train_at_node": first index where the train is standing on that node (like in_train but with +-0.5 added to index) +-- "first_ahead": smallest index that is > current index +-- "before_end"(default): smallest index that is > end index +-- "close_proximity": within 3 indices close to the train index and end_index +-- "any": just output the first index found and do not check further (also occurs if both "in_train" and "first_ahead" heuristics have failed +function o.reverse_lookup_sel(pos, heuristic) + if not heuristic then heuristic = "before_end" end + local om = o.reverse_lookup(pos) local r = {} - local i = 1 - while t[i] do - local idx = t[i+1] - r[t[i]] = idx - i = i + 2 + for tid, idxs in pairs(om) do + r[tid] = idxs[1] + if heuristic~="any" then + --must run a heuristic + --atdebug("reverse_lookup_sel is running heuristic for", pos,heuristic,"idxs",table.concat(idxs,",")) + local otrn = advtrains.trains[tid] + advtrains.train_ensure_init(tid, otrn) + local h_value + for _,idx in ipairs(idxs) do + if heuristic == "first_ahead" and idx > otrn.index and (not h_value or h_value>idx) then + h_value = idx + end + if heuristic == "before_end" and idx > otrn.end_index and (not h_value or h_value>idx) then + h_value = idx + end + if heuristic == "in_train" and idx < otrn.index and idx > otrn.end_index then + h_value = idx + end + if heuristic == "train_at_node" and idx < (otrn.index+0.5) and idx > (otrn.end_index-0.5) then + h_value = idx + end + if heuristic == "close_proximity" and idx < (otrn.index + OCC_CLOSE_PROXIMITY) and idx > (otrn.end_index - OCC_CLOSE_PROXIMITY) then + h_value = idx + end + end + r[tid] = h_value + --atdebug(h_value,"chosen") + end end - return r + return r, pos +end +-- Gets a mapping of train id's to indexes of trains that stand or drive over +-- returns (table with train_id->index) +function o.get_trains_at(ppos) + local pos = advtrains.round_vector_floor_y(ppos) + return o.reverse_lookup_sel(pos, "train_at_node") end advtrains.occ = o diff --git a/advtrains/path.lua b/advtrains/path.lua index d54aebe..4807361 100644 --- a/advtrains/path.lua +++ b/advtrains/path.lua @@ -118,7 +118,7 @@ function advtrains.path_invalidate(train, ignore_lock) if train.path then for i,p in pairs(train.path) do - advtrains.occ.clear_item(train.id, advtrains.round_vector_floor_y(p)) + advtrains.occ.clear_all_items(train.id, advtrains.round_vector_floor_y(p)) end end train.path = nil @@ -161,7 +161,7 @@ function advtrains.path_invalidate_ahead(train, start_idx, ignore_when_passed) -- leave current node in path, it won't change. What might change is the path onward from here (e.g. switch) local i = idx + 1 while train.path[i] do - advtrains.occ.clear_item(train.id, advtrains.round_vector_floor_y(train.path[i])) + advtrains.occ.clear_specific_item(train.id, advtrains.round_vector_floor_y(train.path[i]), i) i = i+1 end train.path_ext_f=idx @@ -391,7 +391,7 @@ local PATH_CLEAR_KEEP = 4 function advtrains.path_clear_unused(train) local i for i = train.path_ext_b, train.path_req_b - PATH_CLEAR_KEEP do - advtrains.occ.clear_item(train.id, advtrains.round_vector_floor_y(train.path[i])) + advtrains.occ.clear_specific_item(train.id, advtrains.round_vector_floor_y(train.path[i]), i) train.path[i] = nil train.path_dist[i-1] = nil train.path_cp[i] = nil @@ -432,18 +432,19 @@ end -- Projects the path of "train" onto the path of "onto_train_id", and returns the index on onto_train's path -- that corresponds to "index" on "train"'s path, as well as whether both trains face each other -- index may be fractional +-- heuristic: see advtrains.occ.reverse_lookup_sel() -- returns: res_index, trains_facing -- returns nil when path can not be projected, either because trains are on different tracks or -- node at "index" happens to be on a turnout and it's the wrong direction -- Note - duplicate with similar functionality is in train_step_b() - that code combines train detection with projecting -function advtrains.path_project(train, index, onto_train_id) +function advtrains.path_project(train, index, onto_train_id, heuristic) local base_idx = atfloor(index) local frac_part = index - base_idx local base_pos = advtrains.path_get(train, base_idx) local base_cn = train.path_cn[base_idx] local otrn = advtrains.trains[onto_train_id] -- query occupation - local occ = advtrains.occ.get_trains_over(base_pos) + local occ = advtrains.occ.reverse_lookup_sel(base_pos, heuristic) -- is wanted train id contained? local ob_idx = occ[onto_train_id] if not ob_idx then 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..6fda1d7 --- /dev/null +++ b/advtrains/po/advtrains.pot @@ -0,0 +1,632 @@ +# 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: 2023-10-09 11:02+0200\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:109 +msgid "Unconfigured ATC controller" +msgstr "" + +#: advtrains/atc.lua:150 +msgid "" +"ATC controller, mode @1\n" +"Command: @2" +msgstr "" + +#: advtrains/atc.lua:180 +msgid "Command" +msgstr "" + +#: advtrains/atc.lua:184 +msgid "Command (on)" +msgstr "" + +#: advtrains/atc.lua:187 +msgid "Digiline channel" +msgstr "" + +#: advtrains/atc.lua:189 advtrains_line_automation/stoprail.lua:65 +#: advtrains_luaautomation/active_common.lua:48 +msgid "Save" +msgstr "" + +#: advtrains/atc.lua:236 +msgid "ATC Reverse command warning: didn't reverse train, train moving." +msgstr "" + +#: advtrains/atc.lua:248 +msgid "ATC Kick command warning: doors are closed." +msgstr "" + +#: advtrains/atc.lua:252 +msgid "ATC Kick command warning: train moving." +msgstr "" + +#: advtrains/atc.lua:322 +msgid "ATC command syntax error: I statement not closed: @1" +msgstr "" + +#: advtrains/atc.lua:385 +msgid "ATC command parse error: Unknown command: @1" +msgstr "" + +#: advtrains/copytool.lua:8 +msgid "" +"Train copy/paste tool\n" +"\n" +"Left-click: copy train\n" +"Right-click: paste train" +msgstr "" + +#: advtrains/copytool.lua:29 +msgid "You do not have the @1 privilege." +msgstr "" + +#: advtrains/copytool.lua:41 +msgid "The track you are trying to place the wagon on is not long enough." +msgstr "" + +#: advtrains/copytool.lua:47 +msgid "The clipboard couldn't access the metadata. Paste failed." +msgstr "" + +#: advtrains/copytool.lua:52 advtrains/copytool.lua:57 +msgid "The clipboard is empty." +msgstr "" + +#: advtrains/copytool.lua:74 +msgid "Back of train would end up off track, cancelling." +msgstr "" + +#: advtrains/copytool.lua:92 +msgid "No such lua entity." +msgstr "" + +#: advtrains/copytool.lua:98 +msgid "No such wagon: @1." +msgstr "" + +#: advtrains/copytool.lua:104 +msgid "No such train: @1." +msgstr "" + +#: advtrains/copytool.lua:176 +msgid "The clipboard couldn't access the metadata. Copy failed." +msgstr "" + +#: advtrains/copytool.lua:180 +msgid "Train copied." +msgstr "" + +#: advtrains/couple.lua:28 +msgid "Buffer and Chain Coupler" +msgstr "" + +#: advtrains/couple.lua:29 +msgid "Scharfenberg Coupler" +msgstr "" + +#: advtrains/couple.lua:185 +msgid "" +"You are not allowed to couple trains without the train_operator privilege." +msgstr "" + +#: advtrains/couple.lua:329 advtrains/couple.lua:333 +msgid "<No coupler>" +msgstr "" + +#: advtrains/couple.lua:334 +msgid "Can not couple: The couplers of the trains do not match (@1 and @2)." +msgstr "" + +#: advtrains/craft_items.lua:3 +msgid "Boiler" +msgstr "" + +#: advtrains/craft_items.lua:9 +msgid "Driver's cab" +msgstr "" + +#: advtrains/craft_items.lua:15 +msgid "Wheel" +msgstr "" + +#: advtrains/craft_items.lua:21 +msgid "Chimney" +msgstr "" + +#: advtrains/misc_nodes.lua:16 +msgid "@1 Platform (low)" +msgstr "" + +#: advtrains/misc_nodes.lua:33 +msgid "@1 Platform (high)" +msgstr "" + +#: advtrains/misc_nodes.lua:59 +msgid "@1 Platform (45 degree)" +msgstr "" + +#: advtrains/misc_nodes.lua:81 +msgid "@1 Platform (low, 45 degree)" +msgstr "" + +#: advtrains/protection.lua:7 +msgid "Can place, remove and operate trains" +msgstr "" + +#: advtrains/protection.lua:12 +msgid "" +"Can place, remove and operate any train, regardless of owner, whitelist, or " +"protection" +msgstr "" + +#: advtrains/protection.lua:18 +msgid "Can place and dig tracks in unprotected areas" +msgstr "" + +#: advtrains/protection.lua:24 +msgid "Can operate turnouts and signals in unprotected areas" +msgstr "" + +#: advtrains/protection.lua:148 +msgid "" +"You are not allowed to build near tracks without the track_builder privilege." +msgstr "" + +#: advtrains/protection.lua:148 +msgid "" +"You are not allowed to build tracks without the track_builder privilege." +msgstr "" + +#: advtrains/protection.lua:153 +msgid "You are not allowed to build near tracks at this protected position." +msgstr "" + +#: advtrains/protection.lua:153 +msgid "You are not allowed to build tracks at this protected position." +msgstr "" + +#: advtrains/protection.lua:184 +msgid "" +"You are not allowed to operate turnouts and signals without the " +"railway_operator privilege." +msgstr "" + +#: advtrains/signals.lua:63 +msgid "Lampless Signal" +msgstr "" + +#: advtrains/signals.lua:127 +msgid "Signal" +msgstr "" + +#: advtrains/signals.lua:191 +msgid "Wallmounted Signal (left)" +msgstr "" + +#: advtrains/signals.lua:192 +msgid "Wallmounted Signal (right)" +msgstr "" + +#: advtrains/signals.lua:193 +msgid "Wallmounted Signal (top)" +msgstr "" + +#: advtrains/signals.lua:281 advtrains/signals.lua:322 +msgid "Andrew's Cross" +msgstr "" + +#: advtrains/trackplacer.lua:313 +msgid "" +"Track Worker Tool\n" +"\n" +"Left-click: change rail type (straight/curve/switch)\n" +"Right-click: rotate object" +msgstr "" + +#: advtrains/trackplacer.lua:340 advtrains/trackplacer.lua:377 +msgid "This node can't be rotated using the trackworker." +msgstr "" + +#: advtrains/trackplacer.lua:350 +msgid "This track can not be rotated." +msgstr "" + +#: advtrains/trackplacer.lua:404 +msgid "This node can't be changed using the trackworker." +msgstr "" + +#: advtrains/trackplacer.lua:414 +msgid "This track can not be changed." +msgstr "" + +#: advtrains/tracks.lua:449 +msgid "This track can not be removed." +msgstr "" + +#: advtrains/tracks.lua:616 +msgid "Position is occupied by a train." +msgstr "" + +#: advtrains/tracks.lua:622 +msgid "There's a Track Circuit Break here." +msgstr "" + +#: advtrains/tracks.lua:626 +msgid "There's a Signal Influence Point here." +msgstr "" + +#: advtrains/tracks.lua:637 +msgid "@1 Slope" +msgstr "" + +#: advtrains/tracks.lua:648 advtrains/tracks.lua:653 +msgid "Can't place slope: not pointing at node." +msgstr "" + +#: advtrains/tracks.lua:658 +msgid "Can't place slope: space occupied." +msgstr "" + +#: advtrains/tracks.lua:711 +msgid "Can't place slope: Not enough slope items left (@1 required)." +msgstr "" + +#: advtrains/tracks.lua:714 +msgid "Can't place slope: There's no slope of length @1." +msgstr "" + +#: advtrains/tracks.lua:721 +msgid "Can't place slope: no supporting node at upper end." +msgstr "" + +#: advtrains/trainhud.lua:305 +msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again." +msgstr "" + +#: advtrains/wagons.lua:179 +msgid "This wagon is owned by @1, you can't destroy it." +msgstr "" + +#: advtrains/wagons.lua:203 +msgid "The wagon's inventory is not empty." +msgstr "" + +#: advtrains/wagons.lua:210 +msgid "Wagon needs to be decoupled from other wagons in order to destroy it." +msgstr "" + +#: advtrains/wagons.lua:216 +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:649 advtrains/wagons.lua:850 +msgid "Show Inventory" +msgstr "" + +#: advtrains/wagons.lua:652 +msgid "Onboard Computer" +msgstr "" + +#: advtrains/wagons.lua:655 advtrains/wagons.lua:1328 +msgid "Wagon properties" +msgstr "" + +#: advtrains/wagons.lua:658 +msgid "Get off" +msgstr "" + +#: advtrains/wagons.lua:661 +msgid "Get off (forced)" +msgstr "" + +#: advtrains/wagons.lua:663 +msgid "(Doors closed)" +msgstr "" + +#: advtrains/wagons.lua:692 +msgid "This wagon has no seats." +msgstr "" + +#: advtrains/wagons.lua:703 +msgid "This wagon is full." +msgstr "" + +#: advtrains/wagons.lua:706 +msgid "Doors are closed! (Try holding sneak key!)" +msgstr "" + +#: advtrains/wagons.lua:712 +msgid "You can't get on this wagon." +msgstr "" + +#: advtrains/wagons.lua:838 +msgid "Select seat:" +msgstr "" + +#: advtrains/wagons.lua:880 +msgid "Save wagon properties" +msgstr "" + +#: advtrains/wagons.lua:965 +msgid "Text displayed outside on train" +msgstr "" + +#: advtrains/wagons.lua:966 +msgid "Text displayed inside train" +msgstr "" + +#: advtrains/wagons.lua:967 +msgid "Line" +msgstr "" + +#: advtrains/wagons.lua:968 +msgid "Routingcode" +msgstr "" + +#: advtrains/wagons.lua:1241 +msgid "" +"Doors are closed. Use Sneak+rightclick to ignore the closed doors and get " +"off." +msgstr "" + +#: advtrains/wagons.lua:1250 +msgid "You are not allowed to access the driver stand." +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:13 +msgid "Point speed restriction: @1" +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:14 +msgid "Set point speed restriction:" +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:30 +msgid "You are not allowed to configure this track without the @1 privilege." +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:34 +#: advtrains_line_automation/stoprail.lua:31 +#: advtrains_line_automation/stoprail.lua:76 +msgid "You are not allowed to configure this track." +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:64 +msgid "Point Speed Restriction Track" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:54 +msgid "Station Code" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:55 +msgid "Station Name" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:56 +msgid "Door Delay" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:57 +msgid "Dep. Speed" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:58 advtrains_train_track/init.lua:11 +#: advtrains_train_track/init.lua:156 +msgid "Track" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:59 +msgid "Stop Time" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:60 +msgid "Door Side" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:62 +msgid "Reverse train" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:63 +msgid "Kick out passengers" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:97 +msgid "Station code \"@1\" already exists and is owned by @2." +msgstr "" + +#: advtrains_line_automation/stoprail.lua:111 +msgid "This station is owned by @1. You are not allowed to edit its name." +msgstr "" + +#: advtrains_line_automation/stoprail.lua:221 +msgid "Station/Stop Track" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:17 +msgid "Unconfigured LuaATC component" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:46 +msgid "LuaATC Environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:49 +msgid "Clear Local Environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:50 +msgid "Code" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:64 +msgid "" +"You are not allowed to configure this LuaATC component without the @1 " +"privilege." +msgstr "" + +#: advtrains_luaautomation/active_common.lua:94 +msgid "LuaATC component assigned to environment '@1'" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:96 +msgid "LuaATC component assigned to an invalid environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:171 +msgid "LuaATC component with error: @1" +msgstr "" + +#: advtrains_luaautomation/init.lua:13 +msgid "" +"Can place and configure LuaATC components, including execute potentially " +"harmful Lua code" +msgstr "" + +#: advtrains_luaautomation/mesecon_controller.lua:211 +msgid "LuaATC Mesecon Controller" +msgstr "" + +#: advtrains_luaautomation/operation_panel.lua:11 +msgid "LuaATC Operation Panel" +msgstr "" + +#: advtrains_luaautomation/pcnaming.lua:28 +msgid "" +"Passive Component Naming Tool\n" +"\n" +"Right-click to name a passive component." +msgstr "" + +#: advtrains_luaautomation/pcnaming.lua:39 +msgid "" +"You are not allowed to name LuaATC passive components without the @1 " +"privilege." +msgstr "" + +#: advtrains_luaautomation/pcnaming.lua:62 +msgid "Set name of component (empty to clear)" +msgstr "" + +#: advtrains_train_industrial/init.lua:10 +#: advtrains_train_industrial/init.lua:49 advtrains_train_steam/init.lua:20 +#: advtrains_train_steam/init.lua:91 +msgid "Driver Stand (right)" +msgstr "" + +#: advtrains_train_industrial/init.lua:17 +#: advtrains_train_industrial/init.lua:56 advtrains_train_steam/init.lua:14 +#: advtrains_train_steam/init.lua:85 +msgid "Driver Stand (left)" +msgstr "" + +#: advtrains_train_industrial/init.lua:40 +msgid "Industrial Train Engine" +msgstr "" + +#: advtrains_train_industrial/init.lua:79 +msgid "Big Industrial Train Engine" +msgstr "" + +#: advtrains_train_industrial/init.lua:98 +msgid "Industrial tank wagon" +msgstr "" + +#: advtrains_train_industrial/init.lua:116 +msgid "Industrial wood wagon" +msgstr "" + +#: advtrains_train_japan/init.lua:4 +msgid "Japanese Train Inter-Wagon Connection" +msgstr "" + +#: advtrains_train_japan/init.lua:37 +msgid "Driver stand" +msgstr "" + +#: advtrains_train_japan/init.lua:101 +msgid "Japanese Train Engine" +msgstr "" + +#: advtrains_train_japan/init.lua:176 +msgid "Japanese Train Wagon" +msgstr "" + +#: advtrains_train_steam/init.lua:75 +msgid "Steam Engine" +msgstr "" + +#: advtrains_train_steam/init.lua:159 +msgid "Detailed Steam Engine" +msgstr "" + +#: advtrains_train_steam/init.lua:206 +msgid "Passenger Wagon" +msgstr "" + +#: advtrains_train_steam/init.lua:226 +msgid "Box Wagon" +msgstr "" + +#: advtrains_train_subway/init.lua:144 +msgid "Subway Passenger Wagon" +msgstr "" + +#: advtrains_train_track/init.lua:31 +msgid "Y-turnout" +msgstr "" + +#: advtrains_train_track/init.lua:49 +msgid "3-way turnout" +msgstr "" + +#: advtrains_train_track/init.lua:69 +msgid "Perpendicular Diamond Crossing Track" +msgstr "" + +#: advtrains_train_track/init.lua:91 +msgid "90+Angle Diamond Crossing Track" +msgstr "" + +#: advtrains_train_track/init.lua:132 +msgid "Diagonal Diamond Crossing Track" +msgstr "" + +#: advtrains_train_track/init.lua:179 +msgid "Bumper" +msgstr "" + +#: advtrains_train_track/init.lua:201 +msgid "ATC controller" +msgstr "" + +#: advtrains_train_track/init.lua:317 +msgid "Unloading Track" +msgstr "" + +#: advtrains_train_track/init.lua:342 +msgid "Loading Track" +msgstr "" + +#: advtrains_train_track/init.lua:406 +msgid "Detector Rail" +msgstr "" diff --git a/advtrains/po/de.po b/advtrains/po/de.po new file mode 100644 index 0000000..8821fe3 --- /dev/null +++ b/advtrains/po/de.po @@ -0,0 +1,724 @@ +msgid "" +msgstr "" +"Project-Id-Version: advtrains\n" +"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n" +"POT-Creation-Date: 2023-10-09 11:02+0200\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:109 +msgid "Unconfigured ATC controller" +msgstr "Nicht konfiguiertes Zugbeeinflussungsgleis" + +#: advtrains/atc.lua:150 +msgid "" +"ATC controller, mode @1\n" +"Command: @2" +msgstr "" +"Zugbeeinflussungsgleis in Betriebsart „@1“\n" +"Befehl: @2" + +#: advtrains/atc.lua:180 +msgid "Command" +msgstr "Befehl" + +#: advtrains/atc.lua:184 +msgid "Command (on)" +msgstr "Befehl (wenn aktiviert)" + +#: advtrains/atc.lua:187 +msgid "Digiline channel" +msgstr "Digiline-Kanal" + +#: advtrains/atc.lua:189 advtrains_line_automation/stoprail.lua:65 +#: advtrains_luaautomation/active_common.lua:48 +msgid "Save" +msgstr "Speichern" + +#: advtrains/atc.lua:236 +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:248 +msgid "ATC Kick command warning: doors are closed." +msgstr "" +"Zugbeeinflussung: Wegen geschlossener Türen werden Fahrgäste nicht zum " +"Ausstieg gezwungen." + +#: advtrains/atc.lua:252 +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:322 +msgid "ATC command syntax error: I statement not closed: @1" +msgstr "Zugbeeinflussung: Unvollständiger I-Befehl: @1" + +#: advtrains/atc.lua:385 +msgid "ATC command parse error: Unknown command: @1" +msgstr "Zugbeeinflussung: Unbekannter Befehl: @1" + +#: advtrains/copytool.lua:8 +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:29 +msgid "You do not have the @1 privilege." +msgstr "Ihnen fehlt das „@1“-Privileg." + +#: advtrains/copytool.lua:41 +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:47 +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:52 advtrains/copytool.lua:57 +msgid "The clipboard is empty." +msgstr "Das Clipboard ist leer." + +#: advtrains/copytool.lua:74 +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:92 +msgid "No such lua entity." +msgstr "" +"Sie zeigen nicht auf einem Objekt, das mit diesem Werkzeug kopiert werden " +"kann." + +#: advtrains/copytool.lua:98 +msgid "No such wagon: @1." +msgstr "Es gibt keinen mit „@1“ identifizierbaren Waggon." + +#: advtrains/copytool.lua:104 +msgid "No such train: @1." +msgstr "Es gibt keinen mit „@1“ identifizierbaren Zug." + +#: advtrains/copytool.lua:176 +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:180 +msgid "Train copied." +msgstr "Der Zug wurde Kopiert." + +#: advtrains/couple.lua:28 +msgid "Buffer and Chain Coupler" +msgstr "Schraubenkupplung" + +#: advtrains/couple.lua:29 +msgid "Scharfenberg Coupler" +msgstr "Scharfenbergkupplung" + +#: advtrains/couple.lua:185 +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/couple.lua:329 advtrains/couple.lua:333 +msgid "<No coupler>" +msgstr "<Keine Kupplung vorhanden>" + +#: advtrains/couple.lua:334 +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/craft_items.lua:3 +msgid "Boiler" +msgstr "" + +#: advtrains/craft_items.lua:9 +msgid "Driver's cab" +msgstr "Führerstand" + +#: advtrains/craft_items.lua:15 +msgid "Wheel" +msgstr "" + +#: advtrains/craft_items.lua:21 +msgid "Chimney" +msgstr "" + +#: advtrains/misc_nodes.lua:16 +msgid "@1 Platform (low)" +msgstr "Niedriger @1-Bahnsteig" + +#: advtrains/misc_nodes.lua:33 +msgid "@1 Platform (high)" +msgstr "Hoher @1-Bahnsteig" + +#: advtrains/misc_nodes.lua:59 +msgid "@1 Platform (45 degree)" +msgstr "Hoher @1-Bahnsteig (45°)" + +#: advtrains/misc_nodes.lua:81 +msgid "@1 Platform (low, 45 degree)" +msgstr "Niedriger @1-Bahnsteig (45°)" + +#: advtrains/protection.lua:7 +msgid "Can place, remove and operate trains" +msgstr "" + +#: advtrains/protection.lua:12 +msgid "" +"Can place, remove and operate any train, regardless of owner, whitelist, or " +"protection" +msgstr "" + +#: advtrains/protection.lua:18 +msgid "Can place and dig tracks in unprotected areas" +msgstr "" + +#: advtrains/protection.lua:24 +msgid "Can operate turnouts and signals in unprotected areas" +msgstr "" + +#: advtrains/protection.lua:148 +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:148 +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:153 +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:153 +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:184 +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:63 +msgid "Lampless Signal" +msgstr "Mechanisches Signal" + +#: advtrains/signals.lua:127 +msgid "Signal" +msgstr "Lichtsignal" + +#: advtrains/signals.lua:191 +msgid "Wallmounted Signal (left)" +msgstr "An der linken Seite montiertes Signal" + +#: advtrains/signals.lua:192 +msgid "Wallmounted Signal (right)" +msgstr "An der rechten Seite montiertes Signal" + +#: advtrains/signals.lua:193 +msgid "Wallmounted Signal (top)" +msgstr "An der Decke montiertes Signal" + +#: advtrains/signals.lua:281 advtrains/signals.lua:322 +msgid "Andrew's Cross" +msgstr "Andreaskreuz" + +#: advtrains/trackplacer.lua:313 +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/trackplacer.lua:340 advtrains/trackplacer.lua:377 +msgid "This node can't be rotated using the trackworker." +msgstr "Dieser Block kann nicht mit dem Gleiswerkzeug gedreht werden." + +#: advtrains/trackplacer.lua:350 +msgid "This track can not be rotated." +msgstr "Dieses Gleis kann nicht gedreht werden." + +#: advtrains/trackplacer.lua:404 +msgid "This node can't be changed using the trackworker." +msgstr "Dieser Block kann nicht mit dem Gleiswerkzeug bearbeitet werden." + +#: advtrains/trackplacer.lua:414 +msgid "This track can not be changed." +msgstr "Dieses Gleis kann nicht geändert werden." + +#: advtrains/tracks.lua:449 +msgid "This track can not be removed." +msgstr "Dieses Gleis kann nicht entfernt werden." + +#: advtrains/tracks.lua:616 +msgid "Position is occupied by a train." +msgstr "Ein Zug steht an dieser Position." + +#: advtrains/tracks.lua:622 +msgid "There's a Track Circuit Break here." +msgstr "Hier ist eine Gleisabschnittsgrenze (TCB)." + +#: advtrains/tracks.lua:626 +msgid "There's a Signal Influence Point here." +msgstr "Hier ist ein Signal-Beeinflussungspunkt." + +#: advtrains/tracks.lua:637 +msgid "@1 Slope" +msgstr "@1 Steigung" + +#: advtrains/tracks.lua:648 advtrains/tracks.lua:653 +msgid "Can't place slope: not pointing at node." +msgstr "Es kann nicht platziert werden: Sie zeigen nicht auf einem Block." + +#: advtrains/tracks.lua:658 +msgid "Can't place slope: space occupied." +msgstr "Es kann nicht platziert werden: Diese Position ist besetzt." + +#: advtrains/tracks.lua:711 +msgid "Can't place slope: 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/tracks.lua:714 +msgid "Can't place slope: There's no slope of length @1." +msgstr "" +"Es kann nicht platziert werden: die Steigung der Länge @1 ist nicht " +"definiert." + +#: advtrains/tracks.lua:721 +msgid "Can't place slope: no supporting node at upper end." +msgstr "" +"Es kann nicht platziert werden: es gibt keinen unterstützenden Block am Ende " +"der Steigung." + +#: advtrains/trainhud.lua:305 +msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again." +msgstr "" + +#: advtrains/wagons.lua:179 +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:203 +msgid "The wagon's inventory is not empty." +msgstr "Das Inventar dieses Waggons ist nicht leer." + +#: advtrains/wagons.lua:210 +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:216 +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:649 advtrains/wagons.lua:850 +msgid "Show Inventory" +msgstr "Inventar Zeigen" + +#: advtrains/wagons.lua:652 +msgid "Onboard Computer" +msgstr "" + +#: advtrains/wagons.lua:655 advtrains/wagons.lua:1328 +msgid "Wagon properties" +msgstr "Waggon-Einstellungen" + +#: advtrains/wagons.lua:658 +msgid "Get off" +msgstr "Aussteigen" + +#: advtrains/wagons.lua:661 +msgid "Get off (forced)" +msgstr "Ausstieg zwingen" + +#: advtrains/wagons.lua:663 +msgid "(Doors closed)" +msgstr "(Türen geschlossen)" + +#: advtrains/wagons.lua:692 +msgid "This wagon has no seats." +msgstr "In diesem Waggon ist kein Sitzplatz vorhanden." + +#: advtrains/wagons.lua:703 +msgid "This wagon is full." +msgstr "Der Waggon ist voll." + +#: advtrains/wagons.lua:706 +msgid "Doors are closed! (Try holding sneak key!)" +msgstr "Die Türen sind geschlossen." + +#: advtrains/wagons.lua:712 +msgid "You can't get on this wagon." +msgstr "Sie können nicht in diesen Waggon einsteigen." + +#: advtrains/wagons.lua:838 +msgid "Select seat:" +msgstr "Wählen Sie einen Sitzplatz aus:" + +#: advtrains/wagons.lua:880 +msgid "Save wagon properties" +msgstr "Waggon-Einstellungen speichern" + +#: advtrains/wagons.lua:965 +msgid "Text displayed outside on train" +msgstr "Äußere Anzeige" + +#: advtrains/wagons.lua:966 +msgid "Text displayed inside train" +msgstr "Innere Anzeige" + +#: advtrains/wagons.lua:967 +msgid "Line" +msgstr "Linie" + +#: advtrains/wagons.lua:968 +msgid "Routingcode" +msgstr "" + +#: advtrains/wagons.lua:1241 +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:1250 +msgid "You are not allowed to access the driver stand." +msgstr "Sie haben keinen Zugang zum Führerstand." + +#: advtrains_interlocking/tsr_rail.lua:13 +msgid "Point speed restriction: @1" +msgstr "Geschwindigkeitskontrolle: @1" + +#: advtrains_interlocking/tsr_rail.lua:14 +msgid "Set point speed restriction:" +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:30 +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:34 +#: advtrains_line_automation/stoprail.lua:31 +#: advtrains_line_automation/stoprail.lua:76 +msgid "You are not allowed to configure this track." +msgstr "Sie dürfen dieses Gleis nicht konfigurieren." + +#: advtrains_interlocking/tsr_rail.lua:64 +msgid "Point Speed Restriction Track" +msgstr "Geschwindigkeitskontrollgleis" + +#: advtrains_line_automation/stoprail.lua:54 +msgid "Station Code" +msgstr "Kennzeichen der Haltestelle" + +#: advtrains_line_automation/stoprail.lua:55 +msgid "Station Name" +msgstr "Name der Haltestelle" + +#: advtrains_line_automation/stoprail.lua:56 +msgid "Door Delay" +msgstr "Zeit für die Türschließung" + +#: advtrains_line_automation/stoprail.lua:57 +msgid "Dep. Speed" +msgstr "Zielgeschwindigkeit bei Abfahrt" + +#: advtrains_line_automation/stoprail.lua:58 advtrains_train_track/init.lua:11 +#: advtrains_train_track/init.lua:156 +msgid "Track" +msgstr "Gleis" + +#: advtrains_line_automation/stoprail.lua:59 +msgid "Stop Time" +msgstr "Wartezeit" + +#: advtrains_line_automation/stoprail.lua:60 +msgid "Door Side" +msgstr "Türseite" + +#: advtrains_line_automation/stoprail.lua:62 +msgid "Reverse train" +msgstr "Zug Umkehren" + +#: advtrains_line_automation/stoprail.lua:63 +msgid "Kick out passengers" +msgstr "Fahrgäste zum Ausstieg zwingen" + +#: advtrains_line_automation/stoprail.lua:97 +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:111 +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:221 +msgid "Station/Stop Track" +msgstr "Gleis zur Kennzeichnung einer Haltestelle" + +#: advtrains_luaautomation/active_common.lua:17 +msgid "Unconfigured LuaATC component" +msgstr "Nicht konfiguierter LuaATC-Bauteil" + +#: advtrains_luaautomation/active_common.lua:46 +msgid "LuaATC Environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:49 +msgid "Clear Local Environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:50 +msgid "Code" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:64 +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/active_common.lua:94 +msgid "LuaATC component assigned to environment '@1'" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:96 +msgid "LuaATC component assigned to an invalid environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:171 +msgid "LuaATC component with error: @1" +msgstr "LuaATC-Bauteil mit Fehlermeldung: @1" + +#: advtrains_luaautomation/init.lua:13 +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:211 +msgid "LuaATC Mesecon Controller" +msgstr "" + +#: advtrains_luaautomation/operation_panel.lua:11 +msgid "LuaATC Operation Panel" +msgstr "" + +#: advtrains_luaautomation/pcnaming.lua:28 +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:39 +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_luaautomation/pcnaming.lua:62 +msgid "Set name of component (empty to clear)" +msgstr "" + +#: advtrains_train_industrial/init.lua:10 +#: advtrains_train_industrial/init.lua:49 advtrains_train_steam/init.lua:20 +#: advtrains_train_steam/init.lua:91 +msgid "Driver Stand (right)" +msgstr "Führerstand Rechts" + +#: advtrains_train_industrial/init.lua:17 +#: advtrains_train_industrial/init.lua:56 advtrains_train_steam/init.lua:14 +#: advtrains_train_steam/init.lua:85 +msgid "Driver Stand (left)" +msgstr "Führerstand Links" + +#: advtrains_train_industrial/init.lua:40 +msgid "Industrial Train Engine" +msgstr "Industrielle Lokomotive" + +#: advtrains_train_industrial/init.lua:79 +msgid "Big Industrial Train Engine" +msgstr "Große Industrielle Lokomotive" + +#: advtrains_train_industrial/init.lua:98 +msgid "Industrial tank wagon" +msgstr "Tankwaggon" + +#: advtrains_train_industrial/init.lua:116 +msgid "Industrial wood wagon" +msgstr "Holztransportwaggon" + +#: advtrains_train_japan/init.lua:4 +msgid "Japanese Train Inter-Wagon Connection" +msgstr "Waggonzwischenverbindung Japanischer Personenzüge" + +#: advtrains_train_japan/init.lua:37 +msgid "Driver stand" +msgstr "Führerstand" + +#: advtrains_train_japan/init.lua:101 +msgid "Japanese Train Engine" +msgstr "Japanische Personenzug-Lokomotive" + +#: advtrains_train_japan/init.lua:176 +msgid "Japanese Train Wagon" +msgstr "Japanischer Personenzug-Passagierwaggon" + +#: advtrains_train_steam/init.lua:75 +msgid "Steam Engine" +msgstr "Dampflokomotive" + +#: advtrains_train_steam/init.lua:159 +msgid "Detailed Steam Engine" +msgstr "Detaillierte Dampflokomotive" + +#: advtrains_train_steam/init.lua:206 +msgid "Passenger Wagon" +msgstr "Passagierwaggon" + +#: advtrains_train_steam/init.lua:226 +msgid "Box Wagon" +msgstr "Güterwaggon" + +#: advtrains_train_subway/init.lua:144 +msgid "Subway Passenger Wagon" +msgstr "U-Bahn-Waggon" + +#: advtrains_train_track/init.lua:31 +msgid "Y-turnout" +msgstr "Y-Weiche" + +#: advtrains_train_track/init.lua:49 +msgid "3-way turnout" +msgstr "Dreiwegweiche" + +#: advtrains_train_track/init.lua:69 +msgid "Perpendicular Diamond Crossing Track" +msgstr "Kreuzung mit zueinander orthogonalen Gleisen" + +#: advtrains_train_track/init.lua:91 +msgid "90+Angle Diamond Crossing Track" +msgstr "Kreuzung mit einem achsenparallelen Gleis" + +#: advtrains_train_track/init.lua:132 +msgid "Diagonal Diamond Crossing Track" +msgstr "Diagonale Gleiskreuzung" + +#: advtrains_train_track/init.lua:179 +msgid "Bumper" +msgstr "Prellbock" + +#: advtrains_train_track/init.lua:201 +msgid "ATC controller" +msgstr "Zugbeeinflussungsgleis" + +#: advtrains_train_track/init.lua:317 +msgid "Unloading Track" +msgstr "Abladungsgleis" + +#: advtrains_train_track/init.lua:342 +msgid "Loading Track" +msgstr "Beladungsgleis" + +#: advtrains_train_track/init.lua:406 +msgid "Detector Rail" +msgstr "Detektorgleis" + +#~ 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 "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..c744d2c --- /dev/null +++ b/advtrains/po/fr.po @@ -0,0 +1,728 @@ +msgid "" +msgstr "" +"Project-Id-Version: advtrains\n" +"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n" +"POT-Creation-Date: 2023-10-09 11:02+0200\n" +"PO-Revision-Date: 2024-11-02 21:31+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:109 +msgid "Unconfigured ATC controller" +msgstr "Controlleur ATC, non-configuré" + +#: advtrains/atc.lua:150 +msgid "" +"ATC controller, mode @1\n" +"Command: @2" +msgstr "" +"Controlleur ATC, mode @1\n" +"Commande : @2" + +#: advtrains/atc.lua:180 +msgid "Command" +msgstr "Commande" + +#: advtrains/atc.lua:184 +msgid "Command (on)" +msgstr "Commande (marche)" + +#: advtrains/atc.lua:187 +msgid "Digiline channel" +msgstr "Canal Digiline" + +#: advtrains/atc.lua:189 advtrains_line_automation/stoprail.lua:65 +#: advtrains_luaautomation/active_common.lua:48 +msgid "Save" +msgstr "Sauvegarder" + +#: advtrains/atc.lua:236 +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:248 +msgid "ATC Kick command warning: doors are closed." +msgstr "Avertissement commande ATC Éjecter : portes closes." + +#: advtrains/atc.lua:252 +msgid "ATC Kick command warning: train moving." +msgstr "Avertissement commande ATC Éjecter : train en mouvement." + +#: advtrains/atc.lua:322 +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:385 +msgid "ATC command parse error: Unknown command: @1" +msgstr "Erreur d'analyse de commande ATC : Commande inconnue : @1" + +#: advtrains/copytool.lua:8 +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:29 +msgid "You do not have the @1 privilege." +msgstr "Vous ne possédez pas le privilège \"@1\"." + +#: advtrains/copytool.lua:41 +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:47 +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:52 advtrains/copytool.lua:57 +msgid "The clipboard is empty." +msgstr "Le presse-papier est vide." + +#: advtrains/copytool.lua:74 +msgid "Back of train would end up off track, cancelling." +msgstr "La fin du train serait hors voie : annulation." + +#: advtrains/copytool.lua:92 +msgid "No such lua entity." +msgstr "Pas de telle entité lua." + +#: advtrains/copytool.lua:98 +msgid "No such wagon: @1." +msgstr "Pas de tel wagon : @1." + +#: advtrains/copytool.lua:104 +msgid "No such train: @1." +msgstr "Pas de tel train : @1." + +#: advtrains/copytool.lua:176 +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:180 +msgid "Train copied." +msgstr "Train copié." + +#: advtrains/couple.lua:28 +msgid "Buffer and Chain Coupler" +msgstr "Attelage à tampon et vis" + +#: advtrains/couple.lua:29 +msgid "Scharfenberg Coupler" +msgstr "Attelage Scharfenberg" + +#: advtrains/couple.lua:185 +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/couple.lua:329 advtrains/couple.lua:333 +msgid "<No coupler>" +msgstr "<Pas de coupleur>" + +#: advtrains/couple.lua:334 +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/craft_items.lua:3 +msgid "Boiler" +msgstr "Chaudière à vapeur" + +#: advtrains/craft_items.lua:9 +msgid "Driver's cab" +msgstr "Cabine de pilotage" + +#: advtrains/craft_items.lua:15 +msgid "Wheel" +msgstr "Roue" + +#: advtrains/craft_items.lua:21 +msgid "Chimney" +msgstr "Cheminée" + +#: advtrains/misc_nodes.lua:16 +msgid "@1 Platform (low)" +msgstr "Quai @1 (bas)" + +#: advtrains/misc_nodes.lua:33 +msgid "@1 Platform (high)" +msgstr "Quai @1 (haut)" + +#: advtrains/misc_nodes.lua:59 +msgid "@1 Platform (45 degree)" +msgstr "Quai @1 (haut, 45°)" + +#: advtrains/misc_nodes.lua:81 +msgid "@1 Platform (low, 45 degree)" +msgstr "Quai @1 (bas, 45°)" + +#: advtrains/protection.lua:7 +msgid "Can place, remove and operate trains" +msgstr "Possibilité de poser, retirer ou opérer les trains" + +#: advtrains/protection.lua:12 +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:18 +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:24 +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:148 +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:148 +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:153 +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:153 +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:184 +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:63 +msgid "Lampless Signal" +msgstr "Sémaphore" + +#: advtrains/signals.lua:127 +msgid "Signal" +msgstr "Signal" + +#: advtrains/signals.lua:191 +msgid "Wallmounted Signal (left)" +msgstr "Signal mural (gauche)" + +#: advtrains/signals.lua:192 +msgid "Wallmounted Signal (right)" +msgstr "Signal mural (droit)" + +#: advtrains/signals.lua:193 +msgid "Wallmounted Signal (top)" +msgstr "Signal mural (plafond)" + +#: advtrains/signals.lua:281 advtrains/signals.lua:322 +msgid "Andrew's Cross" +msgstr "Croix de Saint André" + +#: advtrains/trackplacer.lua:313 +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/trackplacer.lua:340 advtrains/trackplacer.lua:377 +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:350 +msgid "This track can not be rotated." +msgstr "Cette voie ne peut pas être tournée." + +#: advtrains/trackplacer.lua:404 +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:414 +msgid "This track can not be changed." +msgstr "Cette voie ne peut pas être modifiée." + +#: advtrains/tracks.lua:449 +msgid "This track can not be removed." +msgstr "Cette voie ne peut pas être enlevée." + +#: advtrains/tracks.lua:616 +msgid "Position is occupied by a train." +msgstr "Cet emplacement est occupé par un train." + +#: advtrains/tracks.lua:622 +msgid "There's a Track Circuit Break here." +msgstr "Il y a un \"Track Circuit Break\" ici." + +#: advtrains/tracks.lua:626 +msgid "There's a Signal Influence Point here." +msgstr "Il y a un \"Signal Influence Point\" ici." + +#: advtrains/tracks.lua:637 +msgid "@1 Slope" +msgstr "Pente @1" + +#: advtrains/tracks.lua:648 advtrains/tracks.lua:653 +msgid "Can't place slope: not pointing at node." +msgstr "Placement impossible : ne pointe pas un nœud." + +#: advtrains/tracks.lua:658 +msgid "Can't place slope: space occupied." +msgstr "Placement impossible : espace occupé." + +#: advtrains/tracks.lua:711 +msgid "Can't place slope: Not enough slope items left (@1 required)." +msgstr "" +"Placement impossible : quantité insuffisante de voie pentue (@1 manquant)." + +#: advtrains/tracks.lua:714 +msgid "Can't place slope: There's no slope of length @1." +msgstr "Placement impossible : il n'y a pas de voie pentue de longueur @1." + +#: advtrains/tracks.lua:721 +msgid "Can't place slope: no supporting node at upper end." +msgstr "Placement impossible : pas de nœud d'appui à l'extrémité supérieure." + +#: advtrains/trainhud.lua:305 +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/wagons.lua:179 +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:203 +msgid "The wagon's inventory is not empty." +msgstr "Le stock de ce wagon n'est pas vide." + +#: advtrains/wagons.lua:210 +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:216 +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:649 advtrains/wagons.lua:850 +msgid "Show Inventory" +msgstr "Montrer le stock" + +#: advtrains/wagons.lua:652 +msgid "Onboard Computer" +msgstr "Ordinateur embarqué" + +#: advtrains/wagons.lua:655 advtrains/wagons.lua:1328 +msgid "Wagon properties" +msgstr "Propriétés du wagon" + +#: advtrains/wagons.lua:658 +msgid "Get off" +msgstr "Débarquer" + +#: advtrains/wagons.lua:661 +msgid "Get off (forced)" +msgstr "Débarquer (de force)" + +#: advtrains/wagons.lua:663 +msgid "(Doors closed)" +msgstr "(Portes closes)" + +#: advtrains/wagons.lua:692 +msgid "This wagon has no seats." +msgstr "Ce wagon n'a pas de siège." + +#: advtrains/wagons.lua:703 +msgid "This wagon is full." +msgstr "Ce wagon est plein." + +#: advtrains/wagons.lua:706 +msgid "Doors are closed! (Try holding sneak key!)" +msgstr "Portes closes : (Essayez la \"sneak key\"!\")" + +#: advtrains/wagons.lua:712 +msgid "You can't get on this wagon." +msgstr "Montée impossible dans ce wagon." + +#: advtrains/wagons.lua:838 +msgid "Select seat:" +msgstr "Choisir le siège :" + +#: advtrains/wagons.lua:880 +msgid "Save wagon properties" +msgstr "Sauvegarder les propriétés du wagon" + +#: advtrains/wagons.lua:965 +msgid "Text displayed outside on train" +msgstr "Texte affiché à l'extérieur du train" + +#: advtrains/wagons.lua:966 +msgid "Text displayed inside train" +msgstr "Texte affiché à l'intérieur du train" + +#: advtrains/wagons.lua:967 +msgid "Line" +msgstr "Ligne" + +#: advtrains/wagons.lua:968 +msgid "Routingcode" +msgstr "Code de routage" + +#: advtrains/wagons.lua:1241 +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:1250 +msgid "You are not allowed to access the driver stand." +msgstr "Accès interdit au poste de pilotage." + +#: advtrains_interlocking/tsr_rail.lua:13 +msgid "Point speed restriction: @1" +msgstr "Point de limitation de vitesse : @1" + +#: advtrains_interlocking/tsr_rail.lua:14 +msgid "Set point speed restriction:" +msgstr "Placez un point de limitation de vitesse :" + +#: advtrains_interlocking/tsr_rail.lua:30 +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:34 +#: advtrains_line_automation/stoprail.lua:31 +#: advtrains_line_automation/stoprail.lua:76 +msgid "You are not allowed to configure this track." +msgstr "Vous n'êtes pas autorisé à configurer cette voie." + +#: advtrains_interlocking/tsr_rail.lua:64 +msgid "Point Speed Restriction Track" +msgstr "Voie de point de limitation de vitesse" + +#: advtrains_line_automation/stoprail.lua:54 +msgid "Station Code" +msgstr "Code de Station" + +#: advtrains_line_automation/stoprail.lua:55 +msgid "Station Name" +msgstr "Nom de Station" + +#: advtrains_line_automation/stoprail.lua:56 +msgid "Door Delay" +msgstr "Durée d'ouverture des portes" + +#: advtrains_line_automation/stoprail.lua:57 +msgid "Dep. Speed" +msgstr "Vitesse de départ" + +#: advtrains_line_automation/stoprail.lua:58 advtrains_train_track/init.lua:11 +#: advtrains_train_track/init.lua:156 +msgid "Track" +msgstr "Voie" + +#: advtrains_line_automation/stoprail.lua:59 +msgid "Stop Time" +msgstr "Durée d'arrêt" + +#: advtrains_line_automation/stoprail.lua:60 +msgid "Door Side" +msgstr "Coté d'ouvertures des portes" + +#: advtrains_line_automation/stoprail.lua:62 +msgid "Reverse train" +msgstr "Inversion du sens de marche" + +#: advtrains_line_automation/stoprail.lua:63 +msgid "Kick out passengers" +msgstr "Éjecter les passagers" + +#: advtrains_line_automation/stoprail.lua:97 +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:111 +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:221 +msgid "Station/Stop Track" +msgstr "Voie d'arrêt en station" + +#: advtrains_luaautomation/active_common.lua:17 +msgid "Unconfigured LuaATC component" +msgstr "Composant LuaATC non configuré" + +#: advtrains_luaautomation/active_common.lua:46 +msgid "LuaATC Environment" +msgstr "Environnement LuaATC" + +#: advtrains_luaautomation/active_common.lua:49 +msgid "Clear Local Environment" +msgstr "Effacer l'environnement LuaATC" + +#: advtrains_luaautomation/active_common.lua:50 +msgid "Code" +msgstr "Code" + +#: advtrains_luaautomation/active_common.lua:64 +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/active_common.lua:94 +msgid "LuaATC component assigned to environment '@1'" +msgstr "Composant LuaATC assigné à l'environnement '@1'" + +#: advtrains_luaautomation/active_common.lua:96 +msgid "LuaATC component assigned to an invalid environment" +msgstr "Composant LuaATC assigné à un environnement invalide" + +#: advtrains_luaautomation/active_common.lua:171 +msgid "LuaATC component with error: @1" +msgstr "Erreur @1 du composant LuaATC" + +#: advtrains_luaautomation/init.lua:13 +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:211 +msgid "LuaATC Mesecon Controller" +msgstr "Commande Mesecon de LuaATC" + +#: advtrains_luaautomation/operation_panel.lua:11 +msgid "LuaATC Operation Panel" +msgstr "Panneau de commande de LuaATC" + +#: advtrains_luaautomation/pcnaming.lua:28 +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:39 +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_luaautomation/pcnaming.lua:62 +msgid "Set name of component (empty to clear)" +msgstr "Nommer le composant (chaîne vide pour effacer)" + +#: advtrains_train_industrial/init.lua:10 +#: advtrains_train_industrial/init.lua:49 advtrains_train_steam/init.lua:20 +#: advtrains_train_steam/init.lua:91 +msgid "Driver Stand (right)" +msgstr "Poste de pilotage (droit)" + +#: advtrains_train_industrial/init.lua:17 +#: advtrains_train_industrial/init.lua:56 advtrains_train_steam/init.lua:14 +#: advtrains_train_steam/init.lua:85 +msgid "Driver Stand (left)" +msgstr "Poste de pilotage (gauche)" + +#: advtrains_train_industrial/init.lua:40 +msgid "Industrial Train Engine" +msgstr "Locomotive industrielle" + +#: advtrains_train_industrial/init.lua:79 +msgid "Big Industrial Train Engine" +msgstr "Grosse locomotive industrielle" + +#: advtrains_train_industrial/init.lua:98 +msgid "Industrial tank wagon" +msgstr "Wagon-citerne industriel" + +#: advtrains_train_industrial/init.lua:116 +msgid "Industrial wood wagon" +msgstr "Wagon grumier industriel" + +#: advtrains_train_japan/init.lua:4 +msgid "Japanese Train Inter-Wagon Connection" +msgstr "Passage inter-voiture de train Japonais" + +#: advtrains_train_japan/init.lua:37 +msgid "Driver stand" +msgstr "Poste de pilotage" + +#: advtrains_train_japan/init.lua:101 +msgid "Japanese Train Engine" +msgstr "Motrice Japonaise" + +#: advtrains_train_japan/init.lua:176 +msgid "Japanese Train Wagon" +msgstr "Voiture Japonaise" + +#: advtrains_train_steam/init.lua:75 +msgid "Steam Engine" +msgstr "Locomotive à vapeur" + +#: advtrains_train_steam/init.lua:159 +msgid "Detailed Steam Engine" +msgstr "Locomotive à vapeur complexe" + +#: advtrains_train_steam/init.lua:206 +msgid "Passenger Wagon" +msgstr "Voiture passager" + +#: advtrains_train_steam/init.lua:226 +msgid "Box Wagon" +msgstr "Wagon de frêt" + +#: advtrains_train_subway/init.lua:144 +msgid "Subway Passenger Wagon" +msgstr "Voiture de Métropolitain" + +#: advtrains_train_track/init.lua:31 +msgid "Y-turnout" +msgstr "Embranchement en Y" + +#: advtrains_train_track/init.lua:49 +msgid "3-way turnout" +msgstr "Embranchement triple" + +#: advtrains_train_track/init.lua:69 +msgid "Perpendicular Diamond Crossing Track" +msgstr "Croisement perpendiculaire" + +#: advtrains_train_track/init.lua:91 +msgid "90+Angle Diamond Crossing Track" +msgstr "Croisement perpendiculo-diagonal" + +#: advtrains_train_track/init.lua:132 +msgid "Diagonal Diamond Crossing Track" +msgstr "Croisement diagonal" + +#: advtrains_train_track/init.lua:179 +msgid "Bumper" +msgstr "Heurtoir" + +#: advtrains_train_track/init.lua:201 +msgid "ATC controller" +msgstr "Controlleur ATC" + +#: advtrains_train_track/init.lua:317 +msgid "Unloading Track" +msgstr "Voie de Déchargement" + +#: advtrains_train_track/init.lua:342 +msgid "Loading Track" +msgstr "Voie de Chargement" + +#: advtrains_train_track/init.lua:406 +msgid "Detector Rail" +msgstr "Voie détectrice" + +#~ 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 "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 "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..3a56c7c --- /dev/null +++ b/advtrains/po/update-translations.sh @@ -0,0 +1,28 @@ +#!/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 \ + --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..5bcc316 --- /dev/null +++ b/advtrains/po/zh_CN.po @@ -0,0 +1,696 @@ +msgid "" +msgstr "" +"Project-Id-Version: advtrains\n" +"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n" +"POT-Creation-Date: 2023-10-09 11:02+0200\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:109 +msgid "Unconfigured ATC controller" +msgstr "ATC 控制器 (未配置)" + +#: advtrains/atc.lua:150 +msgid "" +"ATC controller, mode @1\n" +"Command: @2" +msgstr "" +"ATC 控制器\n" +"模式:@1\n" +"命令:@2" + +#: advtrains/atc.lua:180 +msgid "Command" +msgstr "命令" + +#: advtrains/atc.lua:184 +msgid "Command (on)" +msgstr "命令 (激活时)" + +#: advtrains/atc.lua:187 +msgid "Digiline channel" +msgstr "Digiline 频道" + +#: advtrains/atc.lua:189 advtrains_line_automation/stoprail.lua:65 +#: advtrains_luaautomation/active_common.lua:48 +msgid "Save" +msgstr "保存" + +#: advtrains/atc.lua:236 +msgid "ATC Reverse command warning: didn't reverse train, train moving." +msgstr "ATC 警告:火车正在移动,无法改变行车方向。" + +#: advtrains/atc.lua:248 +msgid "ATC Kick command warning: doors are closed." +msgstr "ATC 警告:车门已关闭,无法踢出乘客。" + +#: advtrains/atc.lua:252 +msgid "ATC Kick command warning: train moving." +msgstr "ATC 警告:火车正在移动,无法踢出乘客。" + +#: advtrains/atc.lua:322 +msgid "ATC command syntax error: I statement not closed: @1" +msgstr "ATC 语法错误:“I”命令不完整:@1" + +#: advtrains/atc.lua:385 +msgid "ATC command parse error: Unknown command: @1" +msgstr "ATC 语法错误:未知命令:@1" + +#: advtrains/copytool.lua:8 +msgid "" +"Train copy/paste tool\n" +"\n" +"Left-click: copy train\n" +"Right-click: paste train" +msgstr "" +"火车复制工具\n" +"\n" +"左键单击:复制\n" +"右键单击:粘帖" + +#: advtrains/copytool.lua:29 +msgid "You do not have the @1 privilege." +msgstr "您没有“@1”权限。" + +#: advtrains/copytool.lua:41 +msgid "The track you are trying to place the wagon on is not long enough." +msgstr "轨道太短。" + +#: advtrains/copytool.lua:47 +msgid "The clipboard couldn't access the metadata. Paste failed." +msgstr "无法粘贴:剪贴板无法访问元数据。" + +#: advtrains/copytool.lua:52 advtrains/copytool.lua:57 +msgid "The clipboard is empty." +msgstr "剪贴板是空的。" + +#: advtrains/copytool.lua:74 +msgid "Back of train would end up off track, cancelling." +msgstr "火车后部不在轨道上。" + +#: advtrains/copytool.lua:92 +msgid "No such lua entity." +msgstr "您没有指向一个可以用火车复制工具复制的物体。" + +#: advtrains/copytool.lua:98 +msgid "No such wagon: @1." +msgstr "ID 为“@1”的车厢不存在。" + +#: advtrains/copytool.lua:104 +msgid "No such train: @1." +msgstr "ID 为“@1”的列车不存在。" + +#: advtrains/copytool.lua:176 +msgid "The clipboard couldn't access the metadata. Copy failed." +msgstr "无法复制:剪贴板无法访问元数据。" + +#: advtrains/copytool.lua:180 +msgid "Train copied." +msgstr "已复制列车。" + +#: advtrains/couple.lua:28 +msgid "Buffer and Chain Coupler" +msgstr "链式车钩" + +#: advtrains/couple.lua:29 +msgid "Scharfenberg Coupler" +msgstr "Scharfenberg 式车钩" + +#: advtrains/couple.lua:185 +msgid "" +"You are not allowed to couple trains without the train_operator privilege." +msgstr "您没有“train_operator”权限,不能连接这两节车厢。" + +#: advtrains/couple.lua:329 advtrains/couple.lua:333 +msgid "<No coupler>" +msgstr "<没有车钩>" + +#: advtrains/couple.lua:334 +msgid "Can not couple: The couplers of the trains do not match (@1 and @2)." +msgstr "您无法连接这两节车厢:这两节车厢使用不同的车钩 (@1和@2)。" + +#: advtrains/craft_items.lua:3 +msgid "Boiler" +msgstr "锅炉" + +#: advtrains/craft_items.lua:9 +msgid "Driver's cab" +msgstr "驾驶室" + +#: advtrains/craft_items.lua:15 +msgid "Wheel" +msgstr "车轮" + +#: advtrains/craft_items.lua:21 +msgid "Chimney" +msgstr "烟囱" + +#: advtrains/misc_nodes.lua:16 +msgid "@1 Platform (low)" +msgstr "较低的@1站台" + +#: advtrains/misc_nodes.lua:33 +msgid "@1 Platform (high)" +msgstr "较高的@1站台" + +#: advtrains/misc_nodes.lua:59 +msgid "@1 Platform (45 degree)" +msgstr "较高的@1站台 (45°)" + +#: advtrains/misc_nodes.lua:81 +msgid "@1 Platform (low, 45 degree)" +msgstr "较低的@1站台 (45°)" + +#: advtrains/protection.lua:7 +msgid "Can place, remove and operate trains" +msgstr "" + +#: advtrains/protection.lua:12 +msgid "" +"Can place, remove and operate any train, regardless of owner, whitelist, or " +"protection" +msgstr "" + +#: advtrains/protection.lua:18 +msgid "Can place and dig tracks in unprotected areas" +msgstr "" + +#: advtrains/protection.lua:24 +msgid "Can operate turnouts and signals in unprotected areas" +msgstr "" + +#: advtrains/protection.lua:148 +msgid "" +"You are not allowed to build near tracks without the track_builder privilege." +msgstr "您没有“train_operator”权限,不能在铁路附近建任何东西。" + +#: advtrains/protection.lua:148 +msgid "" +"You are not allowed to build tracks without the track_builder privilege." +msgstr "您没有“train_operator”权限,不能在这里建造铁路。" + +#: advtrains/protection.lua:153 +msgid "You are not allowed to build near tracks at this protected position." +msgstr "这里已被保护,您不能在这里的铁路附近建任何东西。" + +#: advtrains/protection.lua:153 +msgid "You are not allowed to build tracks at this protected position." +msgstr "这里已被保护,您不能在这里建造铁路。" + +#: advtrains/protection.lua:184 +msgid "" +"You are not allowed to operate turnouts and signals without the " +"railway_operator privilege." +msgstr "您没有“railway_operator”权限,不能控制铁路设施。" + +#: advtrains/signals.lua:63 +msgid "Lampless Signal" +msgstr "臂板信号机" + +#: advtrains/signals.lua:127 +msgid "Signal" +msgstr "信号灯" + +#: advtrains/signals.lua:191 +msgid "Wallmounted Signal (left)" +msgstr "壁挂式信号灯 (左侧)" + +#: advtrains/signals.lua:192 +msgid "Wallmounted Signal (right)" +msgstr "壁挂式信号灯 (右侧)" + +#: advtrains/signals.lua:193 +msgid "Wallmounted Signal (top)" +msgstr "悬挂式信号灯" + +#: advtrains/signals.lua:281 advtrains/signals.lua:322 +msgid "Andrew's Cross" +msgstr "铁路道口信号灯" + +#: advtrains/trackplacer.lua:313 +msgid "" +"Track Worker Tool\n" +"\n" +"Left-click: change rail type (straight/curve/switch)\n" +"Right-click: rotate object" +msgstr "" +"铁路调整工具\n" +"\n" +"左键单击:切换轨道类型\n" +"右键单击:旋转方块" + +#: advtrains/trackplacer.lua:340 advtrains/trackplacer.lua:377 +msgid "This node can't be rotated using the trackworker." +msgstr "您不能使用铁路调整工具旋转这个方块。" + +#: advtrains/trackplacer.lua:350 +msgid "This track can not be rotated." +msgstr "您不能旋转这段轨道。" + +#: advtrains/trackplacer.lua:404 +msgid "This node can't be changed using the trackworker." +msgstr "您不能使用铁路调整工具调整这个方块。" + +#: advtrains/trackplacer.lua:414 +msgid "This track can not be changed." +msgstr "您不能调整这段轨道。" + +#: advtrains/tracks.lua:449 +msgid "This track can not be removed." +msgstr "您不能移除这段轨道。" + +#: advtrains/tracks.lua:616 +msgid "Position is occupied by a train." +msgstr "" + +#: advtrains/tracks.lua:622 +msgid "There's a Track Circuit Break here." +msgstr "" + +#: advtrains/tracks.lua:626 +msgid "There's a Signal Influence Point here." +msgstr "" + +#: advtrains/tracks.lua:637 +msgid "@1 Slope" +msgstr "@1斜坡" + +#: advtrains/tracks.lua:648 advtrains/tracks.lua:653 +msgid "Can't place slope: not pointing at node." +msgstr "无法放置斜坡:您没有选择任何方块。" + +#: advtrains/tracks.lua:658 +msgid "Can't place slope: space occupied." +msgstr "无法放置斜坡:此区域已被占用。" + +#: advtrains/tracks.lua:711 +msgid "Can't place slope: Not enough slope items left (@1 required)." +msgstr "无法放置斜坡:您没有足够的铁路斜坡放置工具 (您总共需要@1个)" + +#: advtrains/tracks.lua:714 +msgid "Can't place slope: There's no slope of length @1." +msgstr "无法放置斜坡:advtrains 不支持长度为@1米的斜坡。" + +#: advtrains/tracks.lua:721 +msgid "Can't place slope: no supporting node at upper end." +msgstr "无法放置斜坡:较高端没有支撑方块。" + +#: advtrains/trainhud.lua:305 +msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again." +msgstr "" + +#: advtrains/wagons.lua:179 +msgid "This wagon is owned by @1, you can't destroy it." +msgstr "这是 @1 的车厢,您不能摧毁它。" + +#: advtrains/wagons.lua:203 +msgid "The wagon's inventory is not empty." +msgstr "" + +#: advtrains/wagons.lua:210 +msgid "Wagon needs to be decoupled from other wagons in order to destroy it." +msgstr "" + +#: advtrains/wagons.lua:216 +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:649 advtrains/wagons.lua:850 +msgid "Show Inventory" +msgstr "显示物品栏" + +#: advtrains/wagons.lua:652 +msgid "Onboard Computer" +msgstr "" + +#: advtrains/wagons.lua:655 advtrains/wagons.lua:1328 +msgid "Wagon properties" +msgstr "车厢属性" + +#: advtrains/wagons.lua:658 +msgid "Get off" +msgstr "下车" + +#: advtrains/wagons.lua:661 +msgid "Get off (forced)" +msgstr "强制下车" + +#: advtrains/wagons.lua:663 +msgid "(Doors closed)" +msgstr "(车门已关闭)" + +#: advtrains/wagons.lua:692 +msgid "This wagon has no seats." +msgstr "这节车厢没有座位。" + +#: advtrains/wagons.lua:703 +msgid "This wagon is full." +msgstr "车厢已满。" + +#: advtrains/wagons.lua:706 +msgid "Doors are closed! (Try holding sneak key!)" +msgstr "" + +#: advtrains/wagons.lua:712 +msgid "You can't get on this wagon." +msgstr "" + +#: advtrains/wagons.lua:838 +msgid "Select seat:" +msgstr "请选择座位:" + +#: advtrains/wagons.lua:880 +msgid "Save wagon properties" +msgstr "保存车厢属性" + +#: advtrains/wagons.lua:965 +msgid "Text displayed outside on train" +msgstr "车厢外部显示" + +#: advtrains/wagons.lua:966 +msgid "Text displayed inside train" +msgstr "车厢内部显示" + +#: advtrains/wagons.lua:967 +msgid "Line" +msgstr "火车线路" + +#: advtrains/wagons.lua:968 +msgid "Routingcode" +msgstr "路由码" + +#: advtrains/wagons.lua:1241 +msgid "" +"Doors are closed. Use Sneak+rightclick to ignore the closed doors and get " +"off." +msgstr "车门已关闭,请使用潜行+右键单击下车。" + +#: advtrains/wagons.lua:1250 +msgid "You are not allowed to access the driver stand." +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:13 +msgid "Point speed restriction: @1" +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:14 +msgid "Set point speed restriction:" +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:30 +msgid "You are not allowed to configure this track without the @1 privilege." +msgstr "您没有“@1”权限,不能调整这段轨道。" + +#: advtrains_interlocking/tsr_rail.lua:34 +#: advtrains_line_automation/stoprail.lua:31 +#: advtrains_line_automation/stoprail.lua:76 +msgid "You are not allowed to configure this track." +msgstr "您不能调整这段轨道。" + +#: advtrains_interlocking/tsr_rail.lua:64 +msgid "Point Speed Restriction Track" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:54 +msgid "Station Code" +msgstr "车站代码" + +#: advtrains_line_automation/stoprail.lua:55 +msgid "Station Name" +msgstr "车站名称" + +#: advtrains_line_automation/stoprail.lua:56 +msgid "Door Delay" +msgstr "车门关闭时间" + +#: advtrains_line_automation/stoprail.lua:57 +msgid "Dep. Speed" +msgstr "出发速度" + +#: advtrains_line_automation/stoprail.lua:58 advtrains_train_track/init.lua:11 +#: advtrains_train_track/init.lua:156 +msgid "Track" +msgstr "轨道" + +#: advtrains_line_automation/stoprail.lua:59 +msgid "Stop Time" +msgstr "停站时间" + +#: advtrains_line_automation/stoprail.lua:60 +msgid "Door Side" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:62 +msgid "Reverse train" +msgstr "改变行车方向" + +#: advtrains_line_automation/stoprail.lua:63 +msgid "Kick out passengers" +msgstr "踢出乘客" + +#: advtrains_line_automation/stoprail.lua:97 +msgid "Station code \"@1\" already exists and is owned by @2." +msgstr "" + +#: advtrains_line_automation/stoprail.lua:111 +msgid "This station is owned by @1. You are not allowed to edit its name." +msgstr "" + +#: advtrains_line_automation/stoprail.lua:221 +msgid "Station/Stop Track" +msgstr "车站轨道" + +#: advtrains_luaautomation/active_common.lua:17 +msgid "Unconfigured LuaATC component" +msgstr "LuaATC 部件 (未配置)" + +#: advtrains_luaautomation/active_common.lua:46 +msgid "LuaATC Environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:49 +msgid "Clear Local Environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:50 +msgid "Code" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:64 +msgid "" +"You are not allowed to configure this LuaATC component without the @1 " +"privilege." +msgstr "您没有“@1”权限,不能配置这个 LuaATC 部件。" + +#: advtrains_luaautomation/active_common.lua:94 +msgid "LuaATC component assigned to environment '@1'" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:96 +msgid "LuaATC component assigned to an invalid environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:171 +msgid "LuaATC component with error: @1" +msgstr "" + +#: advtrains_luaautomation/init.lua:13 +msgid "" +"Can place and configure LuaATC components, including execute potentially " +"harmful Lua code" +msgstr "" + +#: advtrains_luaautomation/mesecon_controller.lua:211 +msgid "LuaATC Mesecon Controller" +msgstr "" + +#: advtrains_luaautomation/operation_panel.lua:11 +msgid "LuaATC Operation Panel" +msgstr "" + +#: advtrains_luaautomation/pcnaming.lua:28 +msgid "" +"Passive Component Naming Tool\n" +"\n" +"Right-click to name a passive component." +msgstr "" +"被动元件命名工具\n" +"\n" +"右键单击命名所选元件。" + +#: advtrains_luaautomation/pcnaming.lua:39 +msgid "" +"You are not allowed to name LuaATC passive components without the @1 " +"privilege." +msgstr "您没有“@1”权限,不能命名被动元件。" + +#: advtrains_luaautomation/pcnaming.lua:62 +msgid "Set name of component (empty to clear)" +msgstr "" + +#: advtrains_train_industrial/init.lua:10 +#: advtrains_train_industrial/init.lua:49 advtrains_train_steam/init.lua:20 +#: advtrains_train_steam/init.lua:91 +msgid "Driver Stand (right)" +msgstr "右侧司机座位" + +#: advtrains_train_industrial/init.lua:17 +#: advtrains_train_industrial/init.lua:56 advtrains_train_steam/init.lua:14 +#: advtrains_train_steam/init.lua:85 +msgid "Driver Stand (left)" +msgstr "左侧司机座位" + +#: advtrains_train_industrial/init.lua:40 +msgid "Industrial Train Engine" +msgstr "工业用火车头" + +#: advtrains_train_industrial/init.lua:79 +msgid "Big Industrial Train Engine" +msgstr "大型工业用火车头" + +#: advtrains_train_industrial/init.lua:98 +msgid "Industrial tank wagon" +msgstr "液体运输车厢" + +#: advtrains_train_industrial/init.lua:116 +msgid "Industrial wood wagon" +msgstr "木材运输车厢" + +#: advtrains_train_japan/init.lua:4 +msgid "Japanese Train Inter-Wagon Connection" +msgstr "日本火车车钩" + +#: advtrains_train_japan/init.lua:37 +msgid "Driver stand" +msgstr "司机座位" + +#: advtrains_train_japan/init.lua:101 +msgid "Japanese Train Engine" +msgstr "高速列车车头" + +#: advtrains_train_japan/init.lua:176 +msgid "Japanese Train Wagon" +msgstr "高速列车车厢" + +#: advtrains_train_steam/init.lua:75 +msgid "Steam Engine" +msgstr "蒸汽机车" + +#: advtrains_train_steam/init.lua:159 +msgid "Detailed Steam Engine" +msgstr "精细的蒸汽机车" + +#: advtrains_train_steam/init.lua:206 +msgid "Passenger Wagon" +msgstr "客车" + +#: advtrains_train_steam/init.lua:226 +msgid "Box Wagon" +msgstr "货运车厢" + +#: advtrains_train_subway/init.lua:144 +msgid "Subway Passenger Wagon" +msgstr "地铁车厢" + +#: advtrains_train_track/init.lua:31 +msgid "Y-turnout" +msgstr "对称道岔" + +#: advtrains_train_track/init.lua:49 +msgid "3-way turnout" +msgstr "三开道岔" + +#: advtrains_train_track/init.lua:69 +msgid "Perpendicular Diamond Crossing Track" +msgstr "垂直交叉轨道" + +#: advtrains_train_track/init.lua:91 +msgid "90+Angle Diamond Crossing Track" +msgstr "交叉轨道 (其中一条轨道与坐标轴平行)" + +#: advtrains_train_track/init.lua:132 +msgid "Diagonal Diamond Crossing Track" +msgstr "交叉轨道" + +#: advtrains_train_track/init.lua:179 +msgid "Bumper" +msgstr "保险杠" + +#: advtrains_train_track/init.lua:201 +msgid "ATC controller" +msgstr "ATC 控制器" + +#: advtrains_train_track/init.lua:317 +msgid "Unloading Track" +msgstr "卸货轨道" + +#: advtrains_train_track/init.lua:342 +msgid "Loading Track" +msgstr "装货轨道" + +#: advtrains_train_track/init.lua:406 +msgid "Detector Rail" +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 "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..ece82c3 --- /dev/null +++ b/advtrains/po/zh_TW.po @@ -0,0 +1,696 @@ +msgid "" +msgstr "" +"Project-Id-Version: advtrains\n" +"Report-Msgid-Bugs-To: advtrains-discuss@lists.sr.ht\n" +"POT-Creation-Date: 2023-10-09 11:02+0200\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:109 +msgid "Unconfigured ATC controller" +msgstr "ATC 控制器 (未配置)" + +#: advtrains/atc.lua:150 +msgid "" +"ATC controller, mode @1\n" +"Command: @2" +msgstr "" +"ATC 控制器\n" +"模式:@1\n" +"命令:@2" + +#: advtrains/atc.lua:180 +msgid "Command" +msgstr "命令" + +#: advtrains/atc.lua:184 +msgid "Command (on)" +msgstr "命令 (啟用時)" + +#: advtrains/atc.lua:187 +msgid "Digiline channel" +msgstr "Digiline 頻道" + +#: advtrains/atc.lua:189 advtrains_line_automation/stoprail.lua:65 +#: advtrains_luaautomation/active_common.lua:48 +msgid "Save" +msgstr "儲存" + +#: advtrains/atc.lua:236 +msgid "ATC Reverse command warning: didn't reverse train, train moving." +msgstr "ATC 警告:火車正在移動,無法改變行車方向。" + +#: advtrains/atc.lua:248 +msgid "ATC Kick command warning: doors are closed." +msgstr "ATC 警告:車門已關閉,無法踢出乘客。" + +#: advtrains/atc.lua:252 +msgid "ATC Kick command warning: train moving." +msgstr "ATC 警告:火車正在移動,無法踢出乘客。" + +#: advtrains/atc.lua:322 +msgid "ATC command syntax error: I statement not closed: @1" +msgstr "ATC 語法錯誤:「I」命令不完整:@1" + +#: advtrains/atc.lua:385 +msgid "ATC command parse error: Unknown command: @1" +msgstr "ATC 語法錯誤:未知命令:@1" + +#: advtrains/copytool.lua:8 +msgid "" +"Train copy/paste tool\n" +"\n" +"Left-click: copy train\n" +"Right-click: paste train" +msgstr "" +"火車複製工具\n" +"\n" +"左鍵單擊:複製\n" +"右鍵單擊:粘帖" + +#: advtrains/copytool.lua:29 +msgid "You do not have the @1 privilege." +msgstr "您沒有「@1」許可權。" + +#: advtrains/copytool.lua:41 +msgid "The track you are trying to place the wagon on is not long enough." +msgstr "軌道太短。" + +#: advtrains/copytool.lua:47 +msgid "The clipboard couldn't access the metadata. Paste failed." +msgstr "無法貼上:剪貼簿無法訪問元資料。" + +#: advtrains/copytool.lua:52 advtrains/copytool.lua:57 +msgid "The clipboard is empty." +msgstr "剪貼簿是空的。" + +#: advtrains/copytool.lua:74 +msgid "Back of train would end up off track, cancelling." +msgstr "火車後部不在軌道上。" + +#: advtrains/copytool.lua:92 +msgid "No such lua entity." +msgstr "您沒有指向一個可以用火車複製工具複製的物體。" + +#: advtrains/copytool.lua:98 +msgid "No such wagon: @1." +msgstr "ID 為「@1」的車廂不存在。" + +#: advtrains/copytool.lua:104 +msgid "No such train: @1." +msgstr "ID 為「@1」的列車不存在。" + +#: advtrains/copytool.lua:176 +msgid "The clipboard couldn't access the metadata. Copy failed." +msgstr "無法複製:剪貼簿無法訪問元資料。" + +#: advtrains/copytool.lua:180 +msgid "Train copied." +msgstr "已複製火車。" + +#: advtrains/couple.lua:28 +msgid "Buffer and Chain Coupler" +msgstr "鏈式連結器" + +#: advtrains/couple.lua:29 +msgid "Scharfenberg Coupler" +msgstr "Scharfenberg 式連結器" + +#: advtrains/couple.lua:185 +msgid "" +"You are not allowed to couple trains without the train_operator privilege." +msgstr "您沒有「train_operator」許可權,不能連結這兩節車廂。" + +#: advtrains/couple.lua:329 advtrains/couple.lua:333 +msgid "<No coupler>" +msgstr "<無連結器>" + +#: advtrains/couple.lua:334 +msgid "Can not couple: The couplers of the trains do not match (@1 and @2)." +msgstr "您無法連結這兩節車廂:這兩節車廂使用不同的連結器 (@1和@2)。" + +#: advtrains/craft_items.lua:3 +msgid "Boiler" +msgstr "鍋爐" + +#: advtrains/craft_items.lua:9 +msgid "Driver's cab" +msgstr "駕駛室" + +#: advtrains/craft_items.lua:15 +msgid "Wheel" +msgstr "車輪" + +#: advtrains/craft_items.lua:21 +msgid "Chimney" +msgstr "煙囪" + +#: advtrains/misc_nodes.lua:16 +msgid "@1 Platform (low)" +msgstr "較低的@1月臺" + +#: advtrains/misc_nodes.lua:33 +msgid "@1 Platform (high)" +msgstr "較高的@1月臺" + +#: advtrains/misc_nodes.lua:59 +msgid "@1 Platform (45 degree)" +msgstr "較高的@1月臺 (45°)" + +#: advtrains/misc_nodes.lua:81 +msgid "@1 Platform (low, 45 degree)" +msgstr "較低的@1月臺 (45°)" + +#: advtrains/protection.lua:7 +msgid "Can place, remove and operate trains" +msgstr "" + +#: advtrains/protection.lua:12 +msgid "" +"Can place, remove and operate any train, regardless of owner, whitelist, or " +"protection" +msgstr "" + +#: advtrains/protection.lua:18 +msgid "Can place and dig tracks in unprotected areas" +msgstr "" + +#: advtrains/protection.lua:24 +msgid "Can operate turnouts and signals in unprotected areas" +msgstr "" + +#: advtrains/protection.lua:148 +msgid "" +"You are not allowed to build near tracks without the track_builder privilege." +msgstr "您沒有「train_operator」許可權,不能在鐵路附近建任何東西。" + +#: advtrains/protection.lua:148 +msgid "" +"You are not allowed to build tracks without the track_builder privilege." +msgstr "您沒有「train_operator」許可權,不能在這裡建造鐵路。" + +#: advtrains/protection.lua:153 +msgid "You are not allowed to build near tracks at this protected position." +msgstr "這裡已被保護,您不能在這裡的鐵路附近建任何東西。" + +#: advtrains/protection.lua:153 +msgid "You are not allowed to build tracks at this protected position." +msgstr "這裡已被保護,您不能在這裡建造鐵路。" + +#: advtrains/protection.lua:184 +msgid "" +"You are not allowed to operate turnouts and signals without the " +"railway_operator privilege." +msgstr "您沒有「railway_operator」許可權,不能控制鐵路設施。" + +#: advtrains/signals.lua:63 +msgid "Lampless Signal" +msgstr "臂木式號誌機" + +#: advtrains/signals.lua:127 +msgid "Signal" +msgstr "色燈號誌機" + +#: advtrains/signals.lua:191 +msgid "Wallmounted Signal (left)" +msgstr "壁掛式色燈號誌機 (左側)" + +#: advtrains/signals.lua:192 +msgid "Wallmounted Signal (right)" +msgstr "壁掛式色燈號誌機 (右側)" + +#: advtrains/signals.lua:193 +msgid "Wallmounted Signal (top)" +msgstr "懸掛式色燈號誌機" + +#: advtrains/signals.lua:281 advtrains/signals.lua:322 +msgid "Andrew's Cross" +msgstr "平交道號誌燈" + +#: advtrains/trackplacer.lua:313 +msgid "" +"Track Worker Tool\n" +"\n" +"Left-click: change rail type (straight/curve/switch)\n" +"Right-click: rotate object" +msgstr "" +"鐵路調整工具\n" +"\n" +"左鍵單擊:切換軌道型別\n" +"右鍵單擊:旋轉方塊" + +#: advtrains/trackplacer.lua:340 advtrains/trackplacer.lua:377 +msgid "This node can't be rotated using the trackworker." +msgstr "您不能使用鐵路調整工具旋轉這個方塊。" + +#: advtrains/trackplacer.lua:350 +msgid "This track can not be rotated." +msgstr "您不能旋轉這段軌道。" + +#: advtrains/trackplacer.lua:404 +msgid "This node can't be changed using the trackworker." +msgstr "您不能使用鐵路調整工具調整這個方塊。" + +#: advtrains/trackplacer.lua:414 +msgid "This track can not be changed." +msgstr "您不能調整這段軌道。" + +#: advtrains/tracks.lua:449 +msgid "This track can not be removed." +msgstr "您不能移除這段軌道。" + +#: advtrains/tracks.lua:616 +msgid "Position is occupied by a train." +msgstr "" + +#: advtrains/tracks.lua:622 +msgid "There's a Track Circuit Break here." +msgstr "" + +#: advtrains/tracks.lua:626 +msgid "There's a Signal Influence Point here." +msgstr "" + +#: advtrains/tracks.lua:637 +msgid "@1 Slope" +msgstr "@1斜坡" + +#: advtrains/tracks.lua:648 advtrains/tracks.lua:653 +msgid "Can't place slope: not pointing at node." +msgstr "無法放置斜坡:您沒有選擇任何方塊。" + +#: advtrains/tracks.lua:658 +msgid "Can't place slope: space occupied." +msgstr "無法放置斜坡:此區域已被佔用。" + +#: advtrains/tracks.lua:711 +msgid "Can't place slope: Not enough slope items left (@1 required)." +msgstr "無法放置斜坡:您沒有足夠的鐵路斜坡放置工具 (您總共需要@1個)" + +#: advtrains/tracks.lua:714 +msgid "Can't place slope: There's no slope of length @1." +msgstr "無法放置斜坡:advtrains 不支援長度為@1米的斜坡。" + +#: advtrains/tracks.lua:721 +msgid "Can't place slope: no supporting node at upper end." +msgstr "無法放置斜坡:較高階沒有支撐方塊。" + +#: advtrains/trainhud.lua:305 +msgid "OVERRUN RED SIGNAL! Examine situation and reverse train to move again." +msgstr "" + +#: advtrains/wagons.lua:179 +msgid "This wagon is owned by @1, you can't destroy it." +msgstr "這是 @1 的車廂,您不能摧毀它。" + +#: advtrains/wagons.lua:203 +msgid "The wagon's inventory is not empty." +msgstr "" + +#: advtrains/wagons.lua:210 +msgid "Wagon needs to be decoupled from other wagons in order to destroy it." +msgstr "" + +#: advtrains/wagons.lua:216 +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:649 advtrains/wagons.lua:850 +msgid "Show Inventory" +msgstr "顯示物品欄" + +#: advtrains/wagons.lua:652 +msgid "Onboard Computer" +msgstr "" + +#: advtrains/wagons.lua:655 advtrains/wagons.lua:1328 +msgid "Wagon properties" +msgstr "車廂屬性" + +#: advtrains/wagons.lua:658 +msgid "Get off" +msgstr "下車" + +#: advtrains/wagons.lua:661 +msgid "Get off (forced)" +msgstr "強制下車" + +#: advtrains/wagons.lua:663 +msgid "(Doors closed)" +msgstr "(車門已關閉)" + +#: advtrains/wagons.lua:692 +msgid "This wagon has no seats." +msgstr "這節車廂沒有座位。" + +#: advtrains/wagons.lua:703 +msgid "This wagon is full." +msgstr "車廂已滿。" + +#: advtrains/wagons.lua:706 +msgid "Doors are closed! (Try holding sneak key!)" +msgstr "" + +#: advtrains/wagons.lua:712 +msgid "You can't get on this wagon." +msgstr "" + +#: advtrains/wagons.lua:838 +msgid "Select seat:" +msgstr "請選擇座位:" + +#: advtrains/wagons.lua:880 +msgid "Save wagon properties" +msgstr "儲存車廂屬性" + +#: advtrains/wagons.lua:965 +msgid "Text displayed outside on train" +msgstr "車廂外部顯示" + +#: advtrains/wagons.lua:966 +msgid "Text displayed inside train" +msgstr "車廂內部顯示" + +#: advtrains/wagons.lua:967 +msgid "Line" +msgstr "火車線路" + +#: advtrains/wagons.lua:968 +msgid "Routingcode" +msgstr "路由碼" + +#: advtrains/wagons.lua:1241 +msgid "" +"Doors are closed. Use Sneak+rightclick to ignore the closed doors and get " +"off." +msgstr "車門已關閉,請使用潛行+右鍵單擊下車。" + +#: advtrains/wagons.lua:1250 +msgid "You are not allowed to access the driver stand." +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:13 +msgid "Point speed restriction: @1" +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:14 +msgid "Set point speed restriction:" +msgstr "" + +#: advtrains_interlocking/tsr_rail.lua:30 +msgid "You are not allowed to configure this track without the @1 privilege." +msgstr "您沒有「@1」許可權,不能調整這段軌道。" + +#: advtrains_interlocking/tsr_rail.lua:34 +#: advtrains_line_automation/stoprail.lua:31 +#: advtrains_line_automation/stoprail.lua:76 +msgid "You are not allowed to configure this track." +msgstr "您不能調整這段軌道。" + +#: advtrains_interlocking/tsr_rail.lua:64 +msgid "Point Speed Restriction Track" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:54 +msgid "Station Code" +msgstr "車站碼" + +#: advtrains_line_automation/stoprail.lua:55 +msgid "Station Name" +msgstr "車站名稱" + +#: advtrains_line_automation/stoprail.lua:56 +msgid "Door Delay" +msgstr "車門關閉時間" + +#: advtrains_line_automation/stoprail.lua:57 +msgid "Dep. Speed" +msgstr "出發速度" + +#: advtrains_line_automation/stoprail.lua:58 advtrains_train_track/init.lua:11 +#: advtrains_train_track/init.lua:156 +msgid "Track" +msgstr "軌道" + +#: advtrains_line_automation/stoprail.lua:59 +msgid "Stop Time" +msgstr "停站時間" + +#: advtrains_line_automation/stoprail.lua:60 +msgid "Door Side" +msgstr "" + +#: advtrains_line_automation/stoprail.lua:62 +msgid "Reverse train" +msgstr "改變行車方向" + +#: advtrains_line_automation/stoprail.lua:63 +msgid "Kick out passengers" +msgstr "踢出乘客" + +#: advtrains_line_automation/stoprail.lua:97 +msgid "Station code \"@1\" already exists and is owned by @2." +msgstr "" + +#: advtrains_line_automation/stoprail.lua:111 +msgid "This station is owned by @1. You are not allowed to edit its name." +msgstr "" + +#: advtrains_line_automation/stoprail.lua:221 +msgid "Station/Stop Track" +msgstr "車站軌道" + +#: advtrains_luaautomation/active_common.lua:17 +msgid "Unconfigured LuaATC component" +msgstr "LuaATC 元件 (未配置)" + +#: advtrains_luaautomation/active_common.lua:46 +msgid "LuaATC Environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:49 +msgid "Clear Local Environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:50 +msgid "Code" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:64 +msgid "" +"You are not allowed to configure this LuaATC component without the @1 " +"privilege." +msgstr "您沒有「@1」許可權,不能配置這個 LuaATC 元件。" + +#: advtrains_luaautomation/active_common.lua:94 +msgid "LuaATC component assigned to environment '@1'" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:96 +msgid "LuaATC component assigned to an invalid environment" +msgstr "" + +#: advtrains_luaautomation/active_common.lua:171 +msgid "LuaATC component with error: @1" +msgstr "" + +#: advtrains_luaautomation/init.lua:13 +msgid "" +"Can place and configure LuaATC components, including execute potentially " +"harmful Lua code" +msgstr "" + +#: advtrains_luaautomation/mesecon_controller.lua:211 +msgid "LuaATC Mesecon Controller" +msgstr "" + +#: advtrains_luaautomation/operation_panel.lua:11 +msgid "LuaATC Operation Panel" +msgstr "" + +#: advtrains_luaautomation/pcnaming.lua:28 +msgid "" +"Passive Component Naming Tool\n" +"\n" +"Right-click to name a passive component." +msgstr "" +"被動元件命名工具\n" +"\n" +"右鍵單擊命名所選元件。" + +#: advtrains_luaautomation/pcnaming.lua:39 +msgid "" +"You are not allowed to name LuaATC passive components without the @1 " +"privilege." +msgstr "您沒有「@1」許可權,不能命名這個元件。" + +#: advtrains_luaautomation/pcnaming.lua:62 +msgid "Set name of component (empty to clear)" +msgstr "" + +#: advtrains_train_industrial/init.lua:10 +#: advtrains_train_industrial/init.lua:49 advtrains_train_steam/init.lua:20 +#: advtrains_train_steam/init.lua:91 +msgid "Driver Stand (right)" +msgstr "右側司機座位" + +#: advtrains_train_industrial/init.lua:17 +#: advtrains_train_industrial/init.lua:56 advtrains_train_steam/init.lua:14 +#: advtrains_train_steam/init.lua:85 +msgid "Driver Stand (left)" +msgstr "左側司機座位" + +#: advtrains_train_industrial/init.lua:40 +msgid "Industrial Train Engine" +msgstr "工業用火車頭" + +#: advtrains_train_industrial/init.lua:79 +msgid "Big Industrial Train Engine" +msgstr "大型工業用火車頭" + +#: advtrains_train_industrial/init.lua:98 +msgid "Industrial tank wagon" +msgstr "液體運輸車廂" + +#: advtrains_train_industrial/init.lua:116 +msgid "Industrial wood wagon" +msgstr "木材運輸車廂" + +#: advtrains_train_japan/init.lua:4 +msgid "Japanese Train Inter-Wagon Connection" +msgstr "日本火車連結器" + +#: advtrains_train_japan/init.lua:37 +msgid "Driver stand" +msgstr "司機座位" + +#: advtrains_train_japan/init.lua:101 +msgid "Japanese Train Engine" +msgstr "高速列車車頭" + +#: advtrains_train_japan/init.lua:176 +msgid "Japanese Train Wagon" +msgstr "高速列車車廂" + +#: advtrains_train_steam/init.lua:75 +msgid "Steam Engine" +msgstr "蒸汽機車" + +#: advtrains_train_steam/init.lua:159 +msgid "Detailed Steam Engine" +msgstr "精細的蒸汽機車" + +#: advtrains_train_steam/init.lua:206 +msgid "Passenger Wagon" +msgstr "客車" + +#: advtrains_train_steam/init.lua:226 +msgid "Box Wagon" +msgstr "貨運車廂" + +#: advtrains_train_subway/init.lua:144 +msgid "Subway Passenger Wagon" +msgstr "地鐵車廂" + +#: advtrains_train_track/init.lua:31 +msgid "Y-turnout" +msgstr "對稱道岔" + +#: advtrains_train_track/init.lua:49 +msgid "3-way turnout" +msgstr "三開道岔" + +#: advtrains_train_track/init.lua:69 +msgid "Perpendicular Diamond Crossing Track" +msgstr "垂直交叉軌道" + +#: advtrains_train_track/init.lua:91 +msgid "90+Angle Diamond Crossing Track" +msgstr "交叉軌道 (其中一條軌道與座標軸平行)" + +#: advtrains_train_track/init.lua:132 +msgid "Diagonal Diamond Crossing Track" +msgstr "交叉軌道" + +#: advtrains_train_track/init.lua:179 +msgid "Bumper" +msgstr "保險槓" + +#: advtrains_train_track/init.lua:201 +msgid "ATC controller" +msgstr "ATC 控制器" + +#: advtrains_train_track/init.lua:317 +msgid "Unloading Track" +msgstr "卸貨軌道" + +#: advtrains_train_track/init.lua:342 +msgid "Loading Track" +msgstr "裝貨軌道" + +#: advtrains_train_track/init.lua:406 +msgid "Detector Rail" +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 "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 7474977..ac1cd66 100644 --- a/advtrains/protection.lua +++ b/advtrains/protection.lua @@ -4,24 +4,24 @@ -- Privileges to control TRAIN DRIVING/COUPLING minetest.register_privilege("train_operator", { - description = "Without this privilege, a player can't do anything about trains, neither place or remove them nor drive or couple them (but he can build tracks if he has track_builder)", + description = attrans("Can place, remove and operate trains"), give_to_singleplayer= true, }); minetest.register_privilege("train_admin", { - description = "Player may drive, place or remove any trains from/to anywhere, regardless of owner, whitelist or protection", + description = attrans("Can place, remove and operate any train, regardless of owner, whitelist, or protection"), give_to_singleplayer= true, }); -- Privileges to control TRACK BUILDING minetest.register_privilege("track_builder", { - description = "Player can place and/or dig rails not protected from him. If he also has protection_bypass, he can place/dig any rails", + description = attrans("Can place and dig tracks in unprotected areas"), give_to_singleplayer= true, }); -- Privileges to control OPERATING TURNOUTS/SIGNALS minetest.register_privilege("railway_operator", { - description = "Player can operate turnouts and signals not protected from him. If he also has protection_bypass, he can operate any turnouts/signals", + description = attrans("Can operate turnouts and signals in unprotected areas"), give_to_singleplayer= true, }); @@ -145,12 +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 - minetest.chat_send_player(pname, "You are not allowed to build "..nears.."tracks without track_builder privilege") + 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 - minetest.chat_send_player(pname, "You are not allowed to build "..nears.."tracks at protected position!") + 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 @@ -181,7 +181,7 @@ function advtrains.check_turnout_signal_protection(pos, pname) nocheck=false return true else - minetest.chat_send_player(pname, "You are not allowed to operate turnouts and signals (missing railway_operator privilege)") + 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/settingtypes.txt b/advtrains/settingtypes.txt index 79a1e4c..a09da71 100644 --- a/advtrains/settingtypes.txt +++ b/advtrains/settingtypes.txt @@ -65,3 +65,6 @@ advtrains_save_interval (Save Interval) int 60 20 3600 # If enabled, trains only collide with nodes with "normal" drawtype. advtrains_forgiving_collision (Forgiving Collision mode) bool false +# Enable universal couplers for wagons +# If enabled, wagons will bypass the checks that compare the coupler types when coupling. +advtrains_universal_couplers (Universal Couplers) bool false
\ No newline at end of file diff --git a/advtrains/signals.lua b/advtrains/signals.lua index 3f736c9..4dec7f5 100644 --- a/advtrains/signals.lua +++ b/advtrains/signals.lua @@ -59,7 +59,7 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", tiles = {"advtrains_retrosignal.png"}, 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, @@ -121,7 +121,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, @@ -174,6 +174,11 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", if r=="off" then crea=0 end --tunnel signals. no rotations. + 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", @@ -187,7 +192,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, @@ -287,7 +292,7 @@ minetest.register_node("advtrains:across_on", { mesh = "advtrains_across.obj", tiles = {{name="advtrains_across_anim.png", animation={type="vertical_frames", aspect_w=64, aspect_h=64, length=1.0}}}, drop="advtrains:across_off", - description=attrans("Andrew's Cross (on) (you hacker you)"), + description=attrans("Andrew's Cross"), groups = { cracky=3, not_blocking_trains=1, diff --git a/advtrains/sounds/advtrains_crossing_bell.ogg b/advtrains/sounds/advtrains_crossing_bell.ogg Binary files differindex 74df669..2b441ae 100644 --- a/advtrains/sounds/advtrains_crossing_bell.ogg +++ b/advtrains/sounds/advtrains_crossing_bell.ogg diff --git a/advtrains/spec/poconvert_spec.lua b/advtrains/spec/poconvert_spec.lua new file mode 100644 index 0000000..51f33e7 --- /dev/null +++ b/advtrains/spec/poconvert_spec.lua @@ -0,0 +1,70 @@ +package.path = "../?.lua;" .. package.path +advtrains = {} +_G.advtrains = advtrains +local poconvert = require("poconvert") + +describe("PO file converter", function() + it("should convert PO files", function() + assert.equals([[ +# textdomain: foo +foo=bar +baz= +#@=wh\at\\@n=@=w\as\\@n +multiline@nstrings=multiline@nresult +with context?=oder doch nicht]], poconvert.from_string("foo", [[ +msgid "" +msgstr "whatever metadata" + +msgid "foo" +msgstr "bar" + +msgid "baz" +msgstr "" + +#, fuzzy +msgid "=wh\\at\\\\\n" +msgstr "=w\\as\\\\\n" + +msgid "multi" +"line\n" +"strings" +msgstr "multi" +"line\n" +"result" + +msgctxt "i18n context" +msgid "with context?" +msgstr "oder doch nicht"]])) + end) + it("should reject invalid tokens", function() + assert.has.errors(function() + poconvert.from_string("", [[ +foo "" +bar ""]]) + end, "Invalid token: foo") + end) + it("should reject entries without a msgstr", function() + assert.has.errors(function() + poconvert.from_string("", [[msgid "foo"]]) + end, "Missing translated string") + end) + it("should reject entries without a msgid", function() + assert.has.errors(function() + poconvert.from_string("", [[msgstr "foo"]]) + end, "Missing untranslated string") + end) + it("should reject entries with improperly enclosed strings", function() + assert.has.errors(function() + poconvert.from_string("", [[ +msgid "foo" +msgstr "bar \]]) + end, "String extends beyond the end of input") + end) + it("should reject incomplete input", function() + assert.has.errors(function() + poconvert.from_string("", [[ +msgid "foo" +msgstr]]) + end, "No string provided for msgstr") + end) +end) diff --git a/advtrains/spec/texture_spec.lua b/advtrains/spec/texture_spec.lua new file mode 100644 index 0000000..2e3bd5d --- /dev/null +++ b/advtrains/spec/texture_spec.lua @@ -0,0 +1,19 @@ +package.path = "../?.lua;" .. package.path +local T = require "texture" + +describe("Texture creation", function() + it("works", function() + assert.same("^.png", tostring(T.raw"^.png")) + assert.same("foo\\:bar.png", tostring(T"foo:bar.png")) + end) +end) + +describe("Texture modifiers", function() + it("work", function() + assert.same("x^[colorize:c", tostring(T"x":colorize"c")) + assert.same("x^[colorize:c:alpha", tostring(T"x":colorize("c", "alpha"))) + assert.same("x^[multiply:c", tostring(T"x":multiply"c")) + assert.same("x^[resize:2x3", tostring(T"x":resize(2, 3))) + assert.same("x^[transformI", tostring(T"x":transform"I")) + end) +end) diff --git a/advtrains/spec/wagons_spec.lua b/advtrains/spec/wagons_spec.lua new file mode 100644 index 0000000..df0687b --- /dev/null +++ b/advtrains/spec/wagons_spec.lua @@ -0,0 +1,40 @@ +require "mineunit" +mineunit "core" + +_G.advtrains = { + wagon_load_range = 32 +} +sourcefile "wagons" + +local myproto = {_test = true} +advtrains.register_wagon(":mywagon", myproto, "My wagon", "", false) +advtrains.register_wagon_alias(":myalias", ":mywagon") +advtrains.register_wagon_alias(":myotheralias", ":myalias") + +local myotherproto = {_other = true} +advtrains.register_wagon(":noalias", myotherproto, "Not aliased wagon", "", false) +advtrains.register_wagon_alias(":noalias", ":mywagon") + +advtrains.register_wagon_alias(":nilalias", ":nil") + +advtrains.register_wagon_alias(":R1", ":R2") +advtrains.register_wagon_alias(":R2", ":R3") +advtrains.register_wagon_alias(":R3", ":R1") + +describe("wagon alias system", function() + it("should work", function() + assert.same({":mywagon", myproto}, {advtrains.resolve_wagon_alias(":myalias")}) + assert.equal(myproto, advtrains.wagon_prototypes[":myalias"]) + assert.same({":mywagon", myproto}, {advtrains.resolve_wagon_alias(":myotheralias")}) + end) + it("should respect wagon registration", function() + assert.same({":noalias", myotherproto}, {advtrains.resolve_wagon_alias(":noalias")}) + end) + it("should handle recursive loops", function() + assert.same({}, {advtrains.resolve_wagon_alias(":R1")}) + end) + it("should return nil for missing entries", function() + assert.same({}, {advtrains.resolve_wagon_alias(":what")}) + assert.same({}, {advtrains.resolve_wagon_alias(":nilalias")}) + end) +end) diff --git a/advtrains/texture.lua b/advtrains/texture.lua new file mode 100644 index 0000000..e6d83b0 --- /dev/null +++ b/advtrains/texture.lua @@ -0,0 +1,228 @@ +local tx = {} +setmetatable(tx, {__call = function(_, ...) return tx.base(...) end}) + +function tx.escape(str) + return (string.gsub(tostring(str), [[([%^:\])]], [[\%1]])) +end + +local function getargs(...) + return select("#", ...), {...} +end + +local function curry(f, x) + return function(...) + return f(x, ...) + end +end + +local function xmkmodifier(func) + return function(self, ...) + table.insert(self, (func(...))) + return self + end +end + +local function mkmodifier(fmt, spec) + return xmkmodifier(function(...) + local count = select("#", ...) + local args = {...} + for k, f in pairs(spec) do + args[k] = f(args[k]) + end + return string.format(fmt, unpack(args, 1, count)) + end) +end + +-- Texture object +local tx_lib = {} +local tx_mt = { + __index = tx_lib, + __tostring = function(self) + return table.concat(self, "^") + end, + __concat = function(a, b) + return tx.raw(("%s^%s"):format(tostring(a), tostring(b))) + end, +} + +function tx.raw(str) + return setmetatable({str}, tx_mt) +end +function tx.base(str) + return tx.raw(tx.escape(str)) +end +-- TODO: use [fill when 5.8.0 becomes widely used client-side +function tx.fill(w, h, color) + return tx"advtrains_hud_bg.png":resize(w, h):colorize(color) +end + +-- Most texture modifiers +tx_lib.colorize = xmkmodifier(function(c, a) + local str = ("[colorize:%s"):format(tx.escape(c)) + if a then + str = str .. ":" .. a + end + return str +end) +tx_lib.multiply = mkmodifier("[multiply:%s", {tx.escape}) +tx_lib.resize = mkmodifier("[resize:%dx%d", {}) +tx_lib.transform = mkmodifier("[transform%s", {tx.escape}) + +-- [combine + +local combine = {} + +function combine:add(x, y, ent) + table.insert(self.st, ([[%d,%d=%s]]):format(x, y, tx.escape(tostring(ent)))) + return self +end + +local combine_mt = { + __index = combine, + __tostring = function(self) + return table.concat(self.st, ":") + end, +} + +function tx.combine(w, h, bg) + local base = ("[combine:%dx%d"):format(w, h) + local obj = setmetatable({width = w, height = h, st = {base}}, combine_mt) + if bg then + obj:add_fill(0, 0, w, h, bg) + end + return obj +end + +function combine:add_fill(x, y, ...) + return self:add(x, y, tx.fill(...)) +end + +local function add_multicolor_fill(n, self, x, y, w, h, ...) + local argc, argv = getargs(...) + local t = 0 + for k = 1, argc, 2 do + t = t + argv[k] + end + local newargs = {x, y, w, h} + local sk, wk = n, n+2 + local s = newargs[wk]/t + for k = 1, argc, 2 do + local v = argv[k] * s + newargs[wk] = v + newargs[5] = argv[k+1] + self:add_fill(unpack(newargs)) + newargs[sk] = newargs[sk] + v + end + return self +end +combine.add_multicolor_fill_topdown = curry(add_multicolor_fill, 2) +combine.add_multicolor_fill_leftright = curry(add_multicolor_fill, 1) + +local function add_segmentbar(n, self, x, y, w, h, m, c, ...) + local argc, argv = getargs(...) + local baseargs = {x, y, w, h} + local ss = (baseargs[n+2]+m)/c + local bs = ss - m + for k = 1, argc, 3 do + local lower, upper, fill = argv[k], argv[k+1], argv[k+2] + lower = math.max(0, math.floor(lower))+1 + upper = math.min(c, math.floor(upper)) + if lower <= upper then + local args = {x, y, w, h, fill} + args[n+2] = bs + args[n] = args[n] + ss*(lower-1) + for i = lower, upper do + self:add_fill(unpack(args)) + args[n] = args[n] + ss + end + end + end + return self +end +combine.add_segmentbar_topdown = curry(add_segmentbar, 2) +combine.add_segmentbar_leftright = curry(add_segmentbar, 1) + +local function add_lever(n, self, x, y, w, h, hs, ss, val, hf, sf) + local baseargs = {x, y, w, h} + local sargs = {x, y, w, h, sf} + sargs[5-n] = ss + sargs[n+2] = baseargs[n+2] + ss - hs + for k = 1, 2 do + sargs[k] = baseargs[k] + (baseargs[k+2] - sargs[k+2])/2 + end + self:add_fill(unpack(sargs)) + local hargs = {x, y, w, h, hf} + hargs[n+2] = hs + hargs[n] = baseargs[n] + (baseargs[n+2]-hs)*val + self:add_fill(unpack(hargs)) + return self +end +combine.add_lever_topdown = curry(add_lever, 2) +combine.add_lever_leftright = curry(add_lever, 1) + +--[[ Seven-segment display + -1- +6 2 + -7- +5 3 + -4- +--]] +local sevenseg_digits = { + ["0"] = {1, 2, 3, 4, 5, 6}, + ["1"] = {2, 3}, + ["2"] = {1, 2, 4, 5, 7}, + ["3"] = {1, 2, 3, 4, 7}, + ["4"] = {2, 3, 6, 7}, + ["5"] = {1, 3, 4, 6, 7}, + ["6"] = {1, 3, 4, 5, 6, 7}, + ["7"] = {1, 2, 3}, + ["8"] = {1, 2, 3, 4, 5, 6, 7}, + ["9"] = {1, 2, 3, 4, 6, 7}, +} + +function combine:add_str7seg(x0, y0, tw, th, str, fill) + --[[ w and h (as width/height of individual (horizontal) segments) have the following properties: + tw = n(w+3h)-h + th = 2w+3h + --]] + local len = #str + local h = (2*tw-len*th)/(3*len-2) + local w = (th-3*h)/2 + local ws = w+3*h + local segs = { + {h, 0, w, h}, + {w+h, h, h, w}, + {w+h, w+2*h, h, w}, + {h, 2*(w+h), w, h}, + {0, w+2*h, h, w}, + {0, h, h, w}, + {h, w+h, w, h}, + } + for i = 1, len do + for _, k in pairs(sevenseg_digits[string.sub(str, i, i)] or {}) do + local s = segs[k] + self:add_fill(s[1]+x0, s[2]+y0, s[3], s[4], fill) + end + x0 = x0 + ws + end + return self +end + +function combine:add_n7seg(x, y, w, h, n, prec, ...) + if not (type(n) == "number" and type(prec) == "number") then + error("passed non-numeric value or precision to numeric display") + elseif prec < 0 then + error("negative length") + end + local pfx = "" + if n >= 0 then + n = math.min(10^prec-1, n) + else + n = math.min(10^(prec-1)-1, -n) + pfx = "-" + end + local str = ("%d"):format(n) + return self:add_str7seg(x, y, w, h, pfx .. ("0"):rep(prec-#str-#pfx) .. str, ...) +end + +return tx diff --git a/advtrains/textures/advtrains_wagon_prop_tool.png b/advtrains/textures/advtrains_wagon_prop_tool.png Binary files differnew file mode 100644 index 0000000..6352c55 --- /dev/null +++ b/advtrains/textures/advtrains_wagon_prop_tool.png diff --git a/advtrains/trackplacer.lua b/advtrains/trackplacer.lua index 597e8ec..6a2c7a8 100644 --- a/advtrains/trackplacer.lua +++ b/advtrains/trackplacer.lua @@ -230,10 +230,12 @@ function tp.place_track(pos, tpg, pname, yaw) return true end + -- TRACK WORKER -- + minetest.register_craftitem("advtrains:trackworker",{ - description = attrans("Track Worker Tool\n\nLeft-click: change rail type (straight/curve/switch)\nRight-click: rotate rail/bumper/signal/etc."), + description = attrans("Track Worker Tool\n\nLeft-click: change rail type (straight/curve/switch)\nRight-click: rotate object"), groups = {cracky=1}, -- key=name, value=rating; rating=1..3. inventory_image = "advtrains_trackworker.png", wield_image = "advtrains_trackworker.png", diff --git a/advtrains/trainhud.lua b/advtrains/trainhud.lua index 22aa6cf..ce4b913 100644 --- a/advtrains/trainhud.lua +++ b/advtrains/trainhud.lua @@ -1,5 +1,7 @@ --trainhud.lua: holds all the code for train controlling +local T = advtrains.texture + advtrains.hud = {} advtrains.hhud = {} @@ -8,6 +10,8 @@ advtrains.hud[player:get_player_name()] = nil advtrains.hhud[player:get_player_name()] = nil end) +local hud_type_key = minetest.features.hud_def_type_field and "type" or "hud_elem_type" + local mletter={[1]="F", [-1]="R", [0]="N"} function advtrains.on_control_change(pc, train, flip) @@ -101,19 +105,21 @@ function advtrains.set_trainhud(name, text, driver) if not player then return end + local drivertext = driver or "" local driverhud = { - hud_elem_type = "image", + [hud_type_key] = "image", name = "ADVTRAINS_DRIVER", position = {x=0.5, y=1}, offset = {x=0,y=-170}, - text = driver or "", + text = drivertext, alignment = {x=0,y=-1}, - scale = {x=1,y=1},} + scale = {x=1,y=1}, + } if not hud then - hud = {["driver"]={}} + hud = {} advtrains.hud[name] = hud hud.id = player:hud_add({ - hud_elem_type = "text", + [hud_type_key] = "text", name = "ADVTRAINS", number = 0xFFFFFF, position = {x=0.5, y=1}, @@ -122,17 +128,22 @@ function advtrains.set_trainhud(name, text, driver) scale = {x=200, y=60}, alignment = {x=0, y=-1}, }) - hud.oldText=text hud.driver = player:hud_add(driverhud) + hud.oldText = text + hud.oldDriver = drivertext else if hud.oldText ~= text then player:hud_change(hud.id, "text", text) hud.oldText=text end if hud.driver then - player:hud_change(hud.driver, "text", driver or "") + if hud.oldDriver ~= drivertext then + player:hud_change(hud.driver, "text", drivertext) + hud.oldDriver = drivertext + end elseif driver then hud.driver = player:hud_add(driverhud) + hud.oldDriver = drivertext end end end @@ -147,7 +158,7 @@ function advtrains.set_help_hud(name, text) hud = {} advtrains.hhud[name] = hud hud.id = player:hud_add({ - hud_elem_type = "text", + [hud_type_key] = "text", name = "ADVTRAINS_HELP", number = 0xFFFFFF, position = {x=1, y=0.3}, @@ -184,138 +195,94 @@ function advtrains.hud_train_format(train, flip) local vel = advtrains.abs_ceil(train.velocity) local vel_kmh=advtrains.abs_ceil(advtrains.ms_to_kmh(train.velocity)) - local tlev=train.lever or 1 + local tlev=train.lever or 3 if train.velocity==0 and not train.active_control then tlev=1 end if train.hud_lzb_effect_tmr then tlev=1 end - local ht = {"[combine:440x110:0,0=(advtrains_hud_bg.png^[resize\\:440x110)"} + local hud = T.combine(440, 110, "black") local st = {} if train.debug then st = {train.debug} end - -- seven-segment display - local function sevenseg(digit, x, y, w, h, m) - --[[ - -1- - 2 3 - -4- - 5 6 - -7- - ]] - local segs = { - {h, 0, w, h}, - {0, h, h, w}, - {w+h, h, h, w}, - {h, w+h, w, h}, - {0, w+2*h, h, w}, - {w+h, w+2*h, h, w}, - {h, 2*(w+h), w, h}} - local trans = { - [0] = {true, true, true, false, true, true, true}, - [1] = {false, false, true, false, false, true, false}, - [2] = {true, false, true, true, true, false, true}, - [3] = {true, false, true, true, false, true, true}, - [4] = {false, true, true, true, false, true, false}, - [5] = {true, true, false, true, false, true, true}, - [6] = {true, true, false, true, true, true, true}, - [7] = {true, false, true, false, false, true, false}, - [8] = {true, true, true, true, true, true, true}, - [9] = {true, true, true, true, false, true, true}} - local ent = trans[digit or 10] - if not ent then return end - for i = 1, 7, 1 do - if ent[i] then - local s = segs[i] - ht[#ht+1] = sformat("%d,%d=(advtrains_hud_bg.png^[resize\\:%dx%d^%s)",x+s[1], y+s[2], s[3], s[4], m) - end - end - end - -- lever - ht[#ht+1] = "275,10=(advtrains_hud_bg.png^[colorize\\:cyan^[resize\\:5x18)" - ht[#ht+1] = "275,28=(advtrains_hud_bg.png^[colorize\\:white^[resize\\:5x18)" - ht[#ht+1] = "275,46=(advtrains_hud_bg.png^[colorize\\:orange^[resize\\:5x36)" - ht[#ht+1] = "275,82=(advtrains_hud_bg.png^[colorize\\:red^[resize\\:5x18)" - ht[#ht+1] = "292,16=(advtrains_hud_bg.png^[colorize\\:darkslategray^[resize\\:6x78)" - ht[#ht+1] = sformat("280,%s=(advtrains_hud_bg.png^[colorize\\:gray^[resize\\:30x18)",18*(4-tlev)+10) + hud:add_multicolor_fill_topdown(275, 10, 5, 90, 1, "cyan", 1, "white", 2, "orange", 1, "red") + hud:add_lever_topdown(280, 10, 30, 90, 18, 6, (4-tlev)/4, "gray", "darkslategray") -- reverser - ht[#ht+1] = sformat("245,10=(advtrains_hud_arrow.png^[transformFY%s)", flip and "" or "^[multiply\\:cyan") - ht[#ht+1] = sformat("245,85=(advtrains_hud_arrow.png%s)", flip and "^[multiply\\:orange" or "") - ht[#ht+1] = "250,35=(advtrains_hud_bg.png^[colorize\\:darkslategray^[resize\\:5x40)" - ht[#ht+1] = sformat("240,%s=(advtrains_hud_bg.png^[resize\\:25x15^[colorize\\:gray)", flip and 65 or 30) + hud:add(245, 10, T"advtrains_hud_arrow.png":transform"FY":multiply(flip and "gray" or "cyan")) + hud:add(245, 85, T"advtrains_hud_arrow.png":multiply(flip and "orange" or "gray")) + hud:add_lever_topdown(240, 30, 25, 50, 15, 5, flip and 1 or 0, "gray", "darkslategray") -- train control/safety indication - if train.tarvelocity or train.atc_command then - ht[#ht+1] = "10,10=(advtrains_hud_atc.png^[resize\\:30x30^[multiply\\:cyan)" - end - if train.hud_lzb_effect_tmr then - ht[#ht+1] = "50,10=(advtrains_hud_lzb.png^[resize\\:30x30^[multiply\\:red)" - end - if train.is_shunt then - ht[#ht+1] = "90,10=(advtrains_hud_shunt.png^[resize\\:30x30^[multiply\\:orange)" - end + hud:add(10, 10, T"advtrains_hud_atc.png":resize(30, 30):multiply((train.tarvelocity or train.atc_command) and "cyan" or "darkslategray")) + hud:add(50, 10, T"advtrains_hud_lzb.png":resize(30, 30):multiply(train.hud_lzb_effect_tmr and "red" or "darkslategray")) + hud:add(90, 10, T"advtrains_hud_shunt.png":resize(30, 30):multiply(train.is_shunt and "orange" or "darkslategray")) -- door - ht[#ht+1] = "187,10=(advtrains_hud_bg.png^[resize\\:26x30^[colorize\\:white)" - ht[#ht+1] = "189,12=(advtrains_hud_bg.png^[resize\\:22x11)" - ht[#ht+1] = sformat("170,10=(advtrains_hud_bg.png^[resize\\:15x30^[colorize\\:%s)", train.door_open==-1 and "white" or "darkslategray") - ht[#ht+1] = "172,12=(advtrains_hud_bg.png^[resize\\:11x11)" - ht[#ht+1] = sformat("215,10=(advtrains_hud_bg.png^[resize\\:15x30^[colorize\\:%s)", train.door_open==1 and "white" or "darkslategray") - ht[#ht+1] = "217,12=(advtrains_hud_bg.png^[resize\\:11x11)" + hud:add_fill(187, 10, 26, 30, "white"):add_fill(189, 12, 22, 11, "black") + hud:add_fill(170, 10, 15, 30, train.door_open==-1 and "white" or "darkslategray"):add_fill(172, 12, 11, 11, "black") + hud:add_fill(215, 10, 15, 30, train.door_open==1 and "white" or "darkslategray"):add_fill(217, 12, 11, 11, "black") -- speed indication(s) - sevenseg(math.floor(vel/10), 320, 10, 30, 10, "[colorize\\:red\\:255") - sevenseg(vel%10, 380, 10, 30, 10, "[colorize\\:red\\:255") - for i = 1, vel, 1 do - ht[#ht+1] = sformat("%d,65=(advtrains_hud_bg.png^[resize\\:8x20^[colorize\\:white)", i*11-1) - end - for i = max+1, 20, 1 do - ht[#ht+1] = sformat("%d,65=(advtrains_hud_bg.png^[resize\\:8x20^[colorize\\:darkslategray)", i*11-1) - end + hud:add_n7seg(320, 10, 110, 90, vel, 2, "red") + hud:add_segmentbar_leftright(10, 65, 217, 20, 3, 20, max, 20, "darkslategray", 0, vel, "white") if res and res > 0 then - ht[#ht+1] = sformat("%d,60=(advtrains_hud_bg.png^[resize\\:3x30^[colorize\\:red\\:255)", 7+res*11) + hud:add_fill(7+res*11, 60, 3, 30, "red") end if train.tarvelocity then - ht[#ht+1] = sformat("%d,85=(advtrains_hud_arrow.png^[multiply\\:cyan^[transformFY^[makealpha\\:#000000)", 1+train.tarvelocity*11) + hud:add(1+train.tarvelocity*11, 85, T"advtrains_hud_arrow.png":transform"FY":multiply"cyan") end + local lzbdisp local lzb = train.lzb if lzb and lzb.checkpoints then local oc = lzb.checkpoints for i = 1, #oc do + if advtrains.interlocking then + local udata = oc[i].udata + if udata and udata.signal_pos then + local sigd = advtrains.interlocking.db.get_sigd_for_signal(udata.signal_pos) + if sigd then + local tcbs = advtrains.interlocking.db.get_tcbs(sigd) or {} + if tcbs.route_rsn then + table.insert(st, ("%s: %s"):format(minetest.pos_to_string(sigd.p), tcbs.route_rsn)) + end + end + end + end local spd = oc[i].speed spd = advtrains.speed.min(spd, train.speed_restriction) if spd == -1 then spd = nil end local c = not spd and "lime" or (type(spd) == "number" and (spd == 0) and "red" or "orange") or nil if c then - ht[#ht+1] = sformat("130,10=(advtrains_hud_bg.png^[resize\\:30x5^[colorize\\:%s)",c) - ht[#ht+1] = sformat("130,35=(advtrains_hud_bg.png^[resize\\:30x5^[colorize\\:%s)",c) if spd and spd~=0 then - ht[#ht+1] = sformat("%d,50=(advtrains_hud_arrow.png^[multiply\\:red^[makealpha\\:#000000)", 1+spd*11) + hud:add(1+spd*11, 50, T"advtrains_hud_arrow.png":multiply"red") end - local floor = math.floor - local dist = floor(((oc[i].index or train.index)-train.index)) + local dist = math.floor(((oc[i].index or train.index)-train.index)) dist = math.max(0, math.min(999, dist)) - for j = 1, 3, 1 do - sevenseg(floor((dist/10^(3-j))%10), 119+j*11, 18, 4, 2, "[colorize\\:"..c) - end + lzbdisp = {c = c, d = dist} break end end end + if not lzbdisp then + lzbdisp = {c = "darkslategray", d = 888} + end + hud:add_fill(130, 10, 30, 5, lzbdisp.c) + hud:add_fill(130, 35, 30, 5, lzbdisp.c) + hud:add_n7seg(131, 18, 28, 14, lzbdisp.d, 3, lzbdisp.c) if res and res == 0 then - st[#st+1] = attrans("OVERRUN RED SIGNAL! Examine situation and reverse train to move again.") + table.insert(st, attrans("OVERRUN RED SIGNAL! Examine situation and reverse train to move again.")) end if train.atc_command then - st[#st+1] = sformat("ATC: %s%s", train.atc_delay and advtrains.abs_ceil(train.atc_delay).."s " or "", train.atc_command or "") + table.insert(st, ("ATC: %s%s"):format(train.atc_delay and advtrains.abs_ceil(train.atc_delay).."s " or "", train.atc_command or "")) end - return table.concat(st,"\n"), table.concat(ht,":") + return table.concat(st,"\n"), tostring(hud) end local _, texture = advtrains.hud_train_format { -- dummy train object to demonstrate the train hud max_speed = 15, speed_restriction = 15, velocity = 15, tarvelocity = 12, active_control = true, lever = 3, ctrl = {lzb = true}, is_shunt = true, - door_open = 1, lzb = {oncoming = {{spd=6, idx=125.7}}}, index = 0, + door_open = 1, lzb = {checkpoints = {{speed=6, index=125.7}}}, index = 100, } minetest.register_node("advtrains:hud_demo",{ diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua index 9e9f214..1d44324 100644 --- a/advtrains/trainlogic.lua +++ b/advtrains/trainlogic.lua @@ -142,13 +142,8 @@ minetest.register_on_joinplayer(function(player) local pname = player:get_player_name() local id=advtrains.player_to_train_mapping[pname] if id then - for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.id then - local wdata = advtrains.wagons[wagon.id] - if wdata and wdata.train_id == id then - wagon:reattach_all() - end - end + for _, wagon in advtrains.wagon_entity_pairs_in_train(id) do + wagon:reattach_all() end end end) @@ -160,12 +155,10 @@ minetest.register_on_dieplayer(function(player) if id then local train=advtrains.trains[id] if not train then advtrains.player_to_train_mapping[pname]=nil return end - for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.train_id==id then - --when player dies, detach him from the train - --call get_off_plr on every wagon since we don't know which one he's on. - wagon:get_off_plr(pname) - end + for _, wagon in advtrains.wagon_entity_pairs_in_train(id) do + --when player dies, detach him from the train + --call get_off_plr on every wagon since we don't know which one he's on. + wagon:get_off_plr(pname) end -- just in case no wagon felt responsible for this player: clear train mapping advtrains.player_to_train_mapping[pname] = nil @@ -270,6 +263,10 @@ function advtrains.train_ensure_init(id, train) atwarn(debug.traceback()) return nil end + + if not train.staticdata then + train.staticdata = {} + end train.dirty = true if train.no_step then @@ -621,7 +618,7 @@ function advtrains.train_step_b(id, train, dtime) local base_cn = train.path_cn[base_idx] --atdebug(id,"Begin Checking for on-track collisions new_idx=",new_index_curr_tv,"base_idx=",base_idx,"base_pos=",base_pos,"base_cn=",base_cn) -- query occupation - local occ = advtrains.occ.get_trains_over(base_pos) + local occ = advtrains.occ.reverse_lookup_sel(base_pos, "close_proximity") -- iterate other trains for otid, ob_idx in pairs(occ) do if otid ~= id then @@ -651,7 +648,7 @@ function advtrains.train_step_b(id, train, dtime) -- Phase 2 - project ref_index back onto our path and check again (necessary because there might be a turnout on the way and we are driving into the flank if target_is_inside then - local our_index = advtrains.path_project(otrn, ref_index, id) + local our_index = advtrains.path_project(otrn, ref_index, id, "before_end") --atdebug("Backprojected our_index",our_index) if our_index and our_index <= new_index_curr_tv and our_index >= train.index then --FIX: If train was already past the collision point in the previous step, there is no collision! Fixes bug with split_at_index @@ -805,9 +802,12 @@ function advtrains.train_step_c(id, train, dtime) if is_loaded_area then local objs = minetest.get_objects_inside_radius(rcollpos, 2) for _,obj in ipairs(objs) do - if not obj:is_player() and obj:get_armor_groups().fleshy and obj:get_armor_groups().fleshy > 0 - and obj:get_luaentity() and obj:get_luaentity().name~="signs_lib:text" then - obj:punch(obj, 1, { full_punch_interval = 1.0, damage_groups = {fleshy = 1000}, }, nil) + if not obj:is_player() then + local armor = obj:get_armor_groups() + local luaentity = obj:get_luaentity() + if armor.fleshy and armor.fleshy > 0 and luaentity and luaentity.name ~= "signs_lib:text" then + obj:punch(obj, 1, { full_punch_interval = 1.0, damage_groups = {fleshy = 1000}, }, nil) + end end end end @@ -1101,8 +1101,17 @@ function advtrains.spawn_wagons(train_id) if advtrains.position_in_range(pos, ablkrng) then --atdebug("wagon",w_id,"spawning") local wt = advtrains.get_wagon_prototype(data) - local wagon = minetest.add_entity(pos, wt):get_luaentity() - wagon:set_id(w_id) + local wobj = minetest.add_entity(pos, wt) + if not wobj then + atwarn("Failed to spawn wagon", w_id, "of type", wt) + else + local wagon = wobj:get_luaentity() + if not wagon then + atwarn("Wagon", w_id, "of type", wt, "spawned with nil luaentity") + else + wagon:set_id(w_id) + end + end end end else @@ -1169,6 +1178,8 @@ function advtrains.split_train_at_index(train, index) newtrain.points_split = advtrains.merge_tables(train.points_split) newtrain.autocouple = train.autocouple + advtrains.te_run_callbacks_on_decouple(train, newtrain, index) + return newtrain_id -- return new train ID, so new train can be manipulated end @@ -1218,7 +1229,6 @@ function advtrains.invert_train(train_id) advtrains.update_trainpart_properties(train_id, true) -- recalculate path - advtrains.train_ensure_init(train_id, train) -- If interlocking present, check whether this train is in a section and then set as shunt move after reversion if advtrains.interlocking and train.il_sections and #train.il_sections > 0 then @@ -1244,7 +1254,7 @@ function advtrains.invalidate_all_paths(pos) local tab if pos then -- if position given, check occupation system - tab = advtrains.occ.get_trains_over(pos) + tab = advtrains.occ.reverse_lookup_quick(pos) else tab = advtrains.trains end @@ -1257,7 +1267,7 @@ end -- Calls invalidate_path_ahead on all trains occupying (having paths over) this node -- Can be called during train step. function advtrains.invalidate_all_paths_ahead(pos) - local tab = advtrains.occ.get_trains_over(pos) + local tab = advtrains.occ.reverse_lookup_sel(pos, "first_ahead") for id,index in pairs(tab) do local train = advtrains.trains[id] diff --git a/advtrains/wagonprop_tool.lua b/advtrains/wagonprop_tool.lua new file mode 100644 index 0000000..2a4a9e2 --- /dev/null +++ b/advtrains/wagonprop_tool.lua @@ -0,0 +1,43 @@ +minetest.register_craftitem("advtrains:wagon_prop_tool",{ --craftitem because it does nothing on its own + description = attrans("Wagon Properties Tool\nPunch a wagon to view and edit the Wagon Properties"), + short_description = attrans("Wagon Properties Tool"), + groups = {}, + inventory_image = "advtrains_wagon_prop_tool.png", + wield_image = "advtrains_wagon_prop_tool.png", + stack_max = 1, + on_use = function(itemstack, user, pointed_thing) + local pname = user:get_player_name() + if not pname or pname == "" then + return + end + + --sanity checks in case of clicking the wrong entity/node/nothing + if pointed_thing.type ~= "object" then return end --not an entity + local object = pointed_thing.ref:get_luaentity() + if not object.id then return end --entity doesn't have an id field + + local wagon = advtrains.wagons[object.id] --check if wagon exists in advtrains + if not wagon then --not a wagon + return + end --end sanity checks + + --whitelist protection check + if not advtrains.check_driving_couple_protection(pname,wagon.owner,wagon.whitelist) then + minetest.chat_send_player(pname, attrans("Insufficient privileges to use this!")) + return + end + object:show_wagon_properties(pname) + return itemstack + end, +}) + +if minetest.get_modpath("default") then --register recipe + minetest.register_craft({ + output = "advtrains:wagon_prop_tool", + recipe = { + {"advtrains:dtrack_placer","dye:black","default:paper"}, + {"screwdriver:screwdriver","default:paper","default:paper"}, + {"","","group:wood"}, + } + }) +end
\ No newline at end of file diff --git a/advtrains/wagons.lua b/advtrains/wagons.lua index f231546..ef057e5 100644 --- a/advtrains/wagons.lua +++ b/advtrains/wagons.lua @@ -13,7 +13,13 @@ local GETOFF_TP_DELAY = 0.5 local IGNORE_WORLD = advtrains.IGNORE_WORLD advtrains.wagons = {} -advtrains.wagon_prototypes = {} +advtrains.wagon_alias = {} +advtrains.wagon_prototypes = setmetatable({}, { + __index = function(t, k) + local _, proto = advtrains.resolve_wagon_alias(k) + return proto + end +}) advtrains.wagon_objects = {} local unload_wgn_range = advtrains.wagon_load_range + 32 @@ -200,7 +206,7 @@ function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direct 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(), attrans("The wagon's inventory is not empty.")); return end end @@ -280,7 +286,7 @@ function wagon:on_step(dtime) local data = advtrains.wagons[self.id] if not pos then - --atdebug("["..self.id.."][fatal] missing position (object:getpos() returned nil)") + --atdebug("["..self.id.."][fatal] missing position (object:get_pos() returned nil)") return end @@ -364,6 +370,15 @@ function wagon:on_step(dtime) outside = outside .."\n!!! 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 .."\nLiquid: "..data.techage_liquid.name..", "..data.techage_liquid.amount.." units" + else + outside = outside .."\nLiquid: empty" + end + end + if self.infotext_cache~=outside then self.object:set_properties({infotext=outside}) self.infotext_cache=outside @@ -689,7 +704,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, "Wagon has no seats!" + local allow, rsn=false, attrans("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 @@ -700,16 +715,16 @@ function wagon:on_rightclick(clicker) self:get_on(clicker, seatid) return else - rsn="Wagon is full." + rsn=attrans("This wagon is full.") end else - rsn="Doors are closed! (try holding sneak key!)" + rsn=attrans("Doors are closed! (Try holding sneak key!)") end end end end end - minetest.chat_send_player(pname, attrans("Can't get on: "..rsn)) + minetest.chat_send_player(pname, rsn or attrans("You can't get on this wagon.")) else self:show_get_on_form(pname) end @@ -805,8 +820,8 @@ function wagon:get_off(seatno) end --if not door_entry, or paths missing, fall back to old method --atdebug("using fallback") - local objpos=advtrains.round_vector_floor_y(self.object:getpos()) - local yaw=self.object:getyaw() + local objpos=advtrains.round_vector_floor_y(self.object:get_pos()) + local yaw=self.object:get_yaw() local isx=(yaw < math.pi/4) or (yaw > 3*math.pi/4 and yaw < 5*math.pi/4) or (yaw > 7*math.pi/4) local offp --abuse helper function @@ -859,6 +874,7 @@ 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;Allow these players to access your wagon:;"..minetest.formspec_escape(data.whitelist or "").."]" form = form .. "field[0.5,2;4.5,1;roadnumber;Wagon road number:;"..minetest.formspec_escape(data.roadnumber or "").."]" local fc = "" @@ -883,7 +899,7 @@ end --BordCom local function checkcouple(ent) - if not ent or not ent:getyaw() then + if not ent or not ent:get_yaw() then return nil end local le = ent:get_luaentity() @@ -962,6 +978,7 @@ 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 "")).."]" @@ -1079,12 +1096,11 @@ function wagon:handle_bordcom_fields(pname, formname, fields) for i, tpid in ipairs(train.trainparts) do if fields["dcpl_"..i] then advtrains.safe_decouple_wagon(tpid, pname) - elseif fields["wgprp"..i] then - for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.id==tpid and data.owner==pname then - wagon:show_wagon_properties(pname) - return - end + elseif fields["wgprp"..i] and data.owner==pname then + local wagon = advtrains.get_wagon_entity(tpid) + if wagon then + wagon:show_wagon_properties(pname) + return end end end @@ -1130,44 +1146,48 @@ end minetest.register_on_player_receive_fields(function(player, formname, fields) local uid=string.match(formname, "^advtrains_geton_(.+)$") if uid then - for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.id==uid then - local data = advtrains.wagons[wagon.id] - if fields.inv then - if wagon.has_inventory and wagon.get_inventory_formspec then - minetest.show_formspec(player:get_player_name(), "advtrains_inv_"..uid, wagon:get_inventory_formspec(player:get_player_name(), make_inv_name(uid))) - end - elseif fields.seat then - local val=minetest.explode_textlist_event(fields.seat) - if val and val.type~="INV" and not data.seatp[player:get_player_name()] then - --get on - wagon:get_on(player, val.index) - --will work with the new close_formspec functionality. close exactly this formspec. - minetest.show_formspec(player:get_player_name(), formname, "") - end + local wagon = advtrains.get_wagon_entity(uid) + if wagon then + local data = advtrains.wagons[wagon.id] + if fields.inv then + if wagon.has_inventory and wagon.get_inventory_formspec then + minetest.show_formspec(player:get_player_name(), "advtrains_inv_"..uid, wagon:get_inventory_formspec(player:get_player_name(), make_inv_name(uid))) + end + elseif fields.seat then + local val=minetest.explode_textlist_event(fields.seat) + if val and val.type~="INV" and not data.seatp[player:get_player_name()] then + --get on + wagon:get_on(player, val.index) + --will work with the new close_formspec functionality. close exactly this formspec. + minetest.show_formspec(player:get_player_name(), formname, "") end end end + return true end + uid=string.match(formname, "^advtrains_seating_(.+)$") if uid then - for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.id==uid then - local pname=player:get_player_name() - local no=wagon:get_seatno(pname) - if no then - if wagon.seat_groups then - wagon:seating_from_key_helper(pname, fields, no) - end + local wagon = advtrains.get_wagon_entity(uid) + if wagon then + local pname=player:get_player_name() + local no=wagon:get_seatno(pname) + if no then + if wagon.seat_groups then + wagon:seating_from_key_helper(pname, fields, no) end end end + return true end + uid=string.match(formname, "^advtrains_prop_(.+)$") if uid then local pname=player:get_player_name() local data = advtrains.wagons[uid] - if pname~=data.owner and not minetest.check_player_privs(pname, {train_admin = true}) then + if not data then + return true + elseif pname~=data.owner and not minetest.check_player_privs(pname, {train_admin = true}) then return true end if fields.save or not fields.quit then @@ -1189,29 +1209,32 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) wagon.show_wagon_properties({id=uid}, pname) end end + return true end uid=string.match(formname, "^advtrains_bordcom_(.+)$") if uid then - for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.id==uid then - wagon:handle_bordcom_fields(player:get_player_name(), formname, fields) - end + local wagon = advtrains.get_wagon_entity(uid) + if wagon then + wagon:handle_bordcom_fields(player:get_player_name(), formname, fields) end + return true end + uid=string.match(formname, "^advtrains_inv_(.+)$") if uid then local pname=player:get_player_name() local data = advtrains.wagons[uid] if fields.prop and data.owner==pname then - for _,wagon in pairs(minetest.luaentities) do - if wagon.is_wagon and wagon.initialized and wagon.id==uid and data.owner==pname then - wagon:show_wagon_properties(pname) - --wagon:handle_bordcom_fields(player:get_player_name(), formname, fields) - end + local wagon = advtrains.get_wagon_entity(uid) + if wagon then + wagon:show_wagon_properties(pname) + --wagon:handle_bordcom_fields(player:get_player_name(), formname, fields) end end + return true end end) + function wagon:seating_from_key_helper(pname, fields, no) local data = advtrains.wagons[self.id] local sgr=self.seats[no].group @@ -1238,7 +1261,7 @@ function wagon:seating_from_key_helper(pname, fields, no) 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, attrans("Doors are closed. Use Sneak+rightclick to ignore the closed doors and get off.")) end if fields.off then self:get_off(no) @@ -1247,10 +1270,10 @@ 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, "Not allowed to access a driver stand!" + return false, attrans("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:getpos(), self:train().text_outside) + advtrains.log("Drive", pname, self.object:get_pos(), self:train().text_outside) end return true end @@ -1308,11 +1331,33 @@ function advtrains.get_wagon_prototype(data) data.type = data.entity_name data.entity_name = nil end - if not wt or not advtrains.wagon_prototypes[wt] then + local rt, proto = advtrains.resolve_wagon_alias(wt) + if not rt then atwarn("Unable to load wagon type",wt,", using placeholder") - wt="advtrains:wagon_placeholder" + rt = "advtrains:wagon_placeholder" + proto = advtrains.wagon_prototypes[rt] + end + return rt, proto +end + +function advtrains.register_wagon_alias(src, dst) + advtrains.wagon_alias[src] = dst +end + +local function recursive_resolve_alias(name, seen) + local prototype = rawget(advtrains.wagon_prototypes, name) + if prototype then + return name, prototype end - return wt, advtrains.wagon_prototypes[wt] + local resolved = advtrains.wagon_alias[name] + if resolved and not seen[resolved] then + seen[name] = true + return recursive_resolve_alias(resolved, seen) + end +end + +function advtrains.resolve_wagon_alias(name) + return recursive_resolve_alias(name, {}) end function advtrains.standard_inventory_formspec(self, pname, invname) @@ -1359,13 +1404,23 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati groups = wagon_groups, on_place = function(itemstack, placer, pointed_thing) - if not pointed_thing.type == "node" then + if pointed_thing.type ~= "node" then return end + + local pos = pointed_thing.under + local node = minetest.get_node(pos) + local pointed_def = minetest.registered_nodes[node.name] + if pointed_def and pointed_def.on_rightclick then + local controls = placer:get_player_control() + if not controls.sneak then + return pointed_def.on_rightclick(pos, node, placer, itemstack, pointed_thing) + end + end + local pname = placer:get_player_name() - local node=minetest.get_node_or_nil(pointed_thing.under) - if not node then atprint("[advtrains]Ignore at placer position") return itemstack end + if node.name == "ignore" then atprint("[advtrains]Ignore at placer position") return itemstack end local nodename=node.name if(not advtrains.is_track(nodename)) then atprint("no track here, not placing.") @@ -1375,14 +1430,14 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati minetest.chat_send_player(pname, "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(pointed_thing.under, placer:get_player_name()) then + if not minetest.check_player_privs(placer, {train_admin = true }) and minetest.is_protected(pos, placer:get_player_name()) then return itemstack end local tconns=advtrains.get_track_connections(node.name, node.param2) local yaw = placer:get_look_horizontal() local plconnid = advtrains.yawToClosestConn(yaw, tconns) - local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid) + local prevpos = advtrains.get_adjacent_rail(pos, tconns, plconnid) if not prevpos then minetest.chat_send_player(pname, "The track you are trying to place the wagon on is not long enough!") return @@ -1390,7 +1445,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati local wid = advtrains.create_wagon(sysname, pname) - local id=advtrains.create_new_train_at(pointed_thing.under, plconnid, 0, {wid}) + local id=advtrains.create_new_train_at(pos, plconnid, 0, {wid}) if not advtrains.is_creative(pname) then itemstack:take_item() @@ -1477,4 +1532,28 @@ function advtrains.get_wagon_at_index(train_id, w_index) end -- nothing found, dist must be further back return nil -end
\ No newline at end of file +end + +function advtrains.get_wagon_entity(wagon_id) + if not advtrains.wagons[wagon_id] then return end + local object = advtrains.wagon_objects[wagon_id] + if object then + return object:get_luaentity() + end +end + +function advtrains.next_wagon_entity_in_train(train, i) + local wagon_id = train.trainparts[i + 1] + if wagon_id then + local wagon = advtrains.get_wagon_entity(wagon_id) + if wagon then + return i + 1, wagon + end + end +end + +function advtrains.wagon_entity_pairs_in_train(train_id) + local train = advtrains.trains[train_id] + if not train then return function() end end + return advtrains.next_wagon_entity_in_train, train, 0 +end diff --git a/advtrains_interlocking/route_prog.lua b/advtrains_interlocking/route_prog.lua index 37f751a..3ab5686 100644 --- a/advtrains_interlocking/route_prog.lua +++ b/advtrains_interlocking/route_prog.lua @@ -219,19 +219,32 @@ end local player_rte_prog = {} -function advtrains.interlocking.init_route_prog(pname, sigd) +function advtrains.interlocking.init_route_prog(pname, sigd, default_route) if not minetest.check_player_privs(pname, "interlocking") then minetest.chat_send_player(pname, "Insufficient privileges to use this!") return end - player_rte_prog[pname] = { + local rp = { origin = sigd, - route = { - name = "PROG["..pname.."]", - }, - tmp_lcks = {}, } - advtrains.interlocking.visualize_route(sigd, player_rte_prog[pname].route, "prog_"..pname, player_rte_prog[pname].tmp_lcks, pname) + if default_route then + rp.route = table.copy(default_route) + + -- "Step back one section", but keeping turnouts + local last_route = rp.route[#rp.route] + if last_route then + rp.tmp_lcks = last_route.locks + rp.route[#rp.route] = nil + end + rp.route.name = "PROG["..pname.."]" + else + rp.route = { + name = "PROG["..pname.."]" + } + rp.tmp_lcks = {} + end + player_rte_prog[pname] = rp + advtrains.interlocking.visualize_route(sigd, rp.route, "prog_"..pname, rp.tmp_lcks, pname) minetest.chat_send_player(pname, "Route programming mode active. Punch TCBs to add route segments, punch turnouts to lock them.") end diff --git a/advtrains_interlocking/route_ui.lua b/advtrains_interlocking/route_ui.lua index b01d449..478e8dc 100644 --- a/advtrains_interlocking/route_ui.lua +++ b/advtrains_interlocking/route_ui.lua @@ -25,7 +25,7 @@ function atil.show_route_edit_form(pname, sigd, routeid) local route = tcbs.routes[routeid] if not route then return end - local form = "size[9,10]label[0.5,0.2;Route overview]" + local form = "size[9,11]label[0.5,0.2;Route overview]" form = form.."field[0.8,1.2;6.5,1;name;Route name;"..minetest.formspec_escape(route.name).."]" form = form.."button[7.0,0.9;1.5,1;setname;Set]" @@ -114,11 +114,12 @@ function atil.show_route_edit_form(pname, sigd, routeid) form = form.."button[3.5,6;2,1;noautogen;Clr Autogen]" end form = form.."button[5.5,6;3,1;delete;Delete Route]" + form = form.."button[5.5,7;3,1;newfrom;New From Route]" --atdebug(route.ars) form = form.."style[ars;font=mono]" - form = form.."textarea[0.8,7.3;5,3;ars;ARS Rule List;"..atil.ars_to_text(route.ars).."]" - form = form.."button[5.5,7.23;3,1;savears;Save ARS List]" + form = form.."textarea[0.8,8.3;5,3;ars;ARS Rule List;"..atil.ars_to_text(route.ars).."]" + form = form.."button[5.5,8.23;3,1;savears;Save ARS List]" minetest.show_formspec(pname, "at_il_routeedit_"..minetest.pos_to_string(sigd.p).."_"..sigd.s.."_"..routeid, form) @@ -185,6 +186,13 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) table.remove(tcbs.routes, routeid) advtrains.interlocking.show_signalling_form(sigd, pname) end + + if fields.newfrom then + advtrains.interlocking.init_route_prog(pname, sigd, route) + minetest.close_formspec(pname, formname) + tcbs.ars_ignore_next = nil + return + end if fields.ars and fields.savears then route.ars = atil.text_to_ars(fields.ars) diff --git a/advtrains_interlocking/routesetting.lua b/advtrains_interlocking/routesetting.lua index 0207519..a72f644 100644 --- a/advtrains_interlocking/routesetting.lua +++ b/advtrains_interlocking/routesetting.lua @@ -365,7 +365,13 @@ function ilrs.update_route(sigd, tcbs, newrte, cancel) end if newrte then tcbs.routeset = newrte end --atdebug("Setting:",tcbs.routeset) - local succ, rsn, cbts, cblk = ilrs.set_route(sigd, tcbs.routes[tcbs.routeset]) + local succ, rsn, cbts, cblk + if tcbs.routes[tcbs.routeset] then + succ, rsn, cbts, cblk = ilrs.set_route(sigd, tcbs.routes[tcbs.routeset]) + else + succ = false + rsn = attrans("Route state changed.") + end if not succ then tcbs.route_rsn = rsn --atdebug("Routesetting failed:",rsn) diff --git a/advtrains_interlocking/tcb_ts_ui.lua b/advtrains_interlocking/tcb_ts_ui.lua index 82a57cf..e7ff685 100755 --- a/advtrains_interlocking/tcb_ts_ui.lua +++ b/advtrains_interlocking/tcb_ts_ui.lua @@ -494,6 +494,13 @@ minetest.register_entity("advtrains_interlocking:tcbmarker", { static_save = false, }) +function advtrains.interlocking.remove_tcb_marker_pts(pts) + if markerent[pts] then + markerent[pts]:remove() + markerent[pts] = nil + end +end + function advtrains.interlocking.show_tcb_marker(pos) --atdebug("showing tcb marker",pos) local tcb = ildb.get_tcb(pos) @@ -517,9 +524,7 @@ function advtrains.interlocking.show_tcb_marker(pos) end local pts = advtrains.roundfloorpts(pos) - if markerent[pts] then - markerent[pts]:remove() - end + advtrains.interlocking.remove_tcb_marker_pts(pts) local obj = minetest.add_entity(pos, "advtrains_interlocking:tcbmarker") if not obj then return end @@ -628,14 +633,22 @@ function advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, calle strtab[#strtab+1] = clr .. minetest.formspec_escape(route.name) end form = form.."label[0.5,2.5;Routes:]" - form = form.."textlist[0.5,3;5,3;rtelist;"..table.concat(strtab, ",").."]" + form = form.."textlist[0.5,3;5,3;rtelist;"..table.concat(strtab, ",") if sel_rte then + form = form .. ";" .. sel_rte .."]" form = form.."button[0.5,6; 5,1;setroute;Set Route]" form = form.."button[0.5,7;2,1;dsproute;Show]" if hasprivs then form = form.."button[3.5,7;2,1;editroute;Edit]" + if sel_rte > 1 then + form = form .. "button[5.5,4;0.5,0.3;moveup;↑]" + end + if sel_rte < #strtab then + form = form .. "button[5.5,4.7;0.5,0.3;movedown;↓]" + end end else + form = form .. "]" if tcbs.ars_disabled then form = form.."label[0.5,6 ;NOTE: ARS is disabled.]" form = form.."label[0.5,6.5;Routes are not automatically set.]" @@ -772,6 +785,20 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if fields.noauto then tcbs.route_auto = false end + + if sel_rte and tcbs.routes[sel_rte]and not tcbs.routeset then + if fields.moveup then + if tcbs.routes[sel_rte - 1] then + tcbs.routes[sel_rte - 1], tcbs.routes[sel_rte] = tcbs.routes[sel_rte], tcbs.routes[sel_rte - 1] + sel_rte = sel_rte - 1 + end + elseif fields.movedown then + if tcbs.routes[sel_rte + 1] then + tcbs.routes[sel_rte + 1], tcbs.routes[sel_rte] = tcbs.routes[sel_rte], tcbs.routes[sel_rte + 1] + sel_rte = sel_rte + 1 + end + end + end advtrains.interlocking.show_signalling_form(sigd, pname, sel_rte, true) return diff --git a/advtrains_interlocking/tsr_rail.lua b/advtrains_interlocking/tsr_rail.lua index f302540..c1e3c1c 100644 --- a/advtrains_interlocking/tsr_rail.lua +++ b/advtrains_interlocking/tsr_rail.lua @@ -3,13 +3,15 @@ -- Simple rail whose only purpose is to place a TSR on the position, as a temporary solution until the timetable system covers everything. -- This code resembles the code in lines/stoprail.lua +local S = attrans + local function updateform(pos) local meta = minetest.get_meta(pos) local pe = advtrains.encode_pos(pos) local npr = advtrains.interlocking.npr_rails[pe] or 2 - meta:set_string("infotext", "Point speed restriction: "..npr) - meta:set_string("formspec", "field[npr;Set point speed restriction:;"..npr.."]") + meta:set_string("infotext", S("Point speed restriction: @1",npr)) + meta:set_string("formspec", "field[npr;"..S("Set point speed restriction:")..";"..npr.."]") end @@ -25,11 +27,11 @@ local adefunc = function(def, preset, suffix, rotation) on_receive_fields = function(pos, formname, fields, player) local pname = player:get_player_name() if not minetest.check_player_privs(pname, {interlocking=true}) then - minetest.chat_send_player(pname, "Interlocking privilege required!") + minetest.chat_send_player(pname, S("You are not allowed to configure this track without the @1 privilege.", "interlocking")) return end if minetest.is_protected(pos, pname) then - minetest.chat_send_player(pname, "This rail is protected!") + minetest.chat_send_player(pname, S("You are not allowed to configure this track.")) minetest.record_protection_violation(pos, pname) return end @@ -59,7 +61,7 @@ if minetest.get_modpath("advtrains_train_track") ~= nil then models_prefix="advtrains_dtrack", models_suffix=".b3d", shared_texture="advtrains_dtrack_shared_npr.png", - description="Point Speed Restriction Rail", + description=S("Point Speed Restriction Track"), formats={}, get_additional_definiton = adefunc, }, advtrains.trackpresets.t_30deg_straightonly) diff --git a/advtrains_line_automation/stoprail.lua b/advtrains_line_automation/stoprail.lua index 55a4785..6c74a3d 100644 --- a/advtrains_line_automation/stoprail.lua +++ b/advtrains_line_automation/stoprail.lua @@ -28,7 +28,7 @@ local function show_stoprailform(pos, player) local pe = advtrains.encode_pos(pos) local pname = player:get_player_name() if minetest.is_protected(pos, pname) then - minetest.chat_send_player(pname, "Position is protected!") + minetest.chat_send_player(pname, attrans("You are not allowed to configure this track.")) return end @@ -73,7 +73,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) local pos = advtrains.decode_pos(pe) if pos then if minetest.is_protected(pos, pname) then - minetest.chat_send_player(pname, "Position is protected!") + minetest.chat_send_player(pname, attrans("You are not allowed to configure this track.")) return end @@ -94,7 +94,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if (stn.owner == pname or minetest.check_player_privs(pname, "train_admin")) then stdata.stn = fields.stn else - minetest.chat_send_player(pname, "Station code '"..fields.stn.."' does already exist and is owned by "..stn.owner) + minetest.chat_send_player(pname, attrans("Station code \"@1\" already exists and is owned by @2.", fields.stn, stn.owner)) show_stoprailform(pos,player) return end @@ -108,7 +108,7 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) if (stn.owner == pname or minetest.check_player_privs(pname, "train_admin")) then stn.name = fields.stnname else - minetest.chat_send_player(pname, "Not allowed to edit station name, owned by "..stn.owner) + minetest.chat_send_player(pname, attrans("This station is owned by @1. You are not allowed to edit its name.", stn.owner)) end end @@ -218,7 +218,7 @@ if minetest.get_modpath("advtrains_train_track") ~= nil then models_prefix="advtrains_dtrack", models_suffix=".b3d", shared_texture="advtrains_dtrack_shared_stop.png", - description="Station/Stop Rail", + description=attrans("Station/Stop Track"), formats={}, get_additional_definiton = adefunc, }, advtrains.trackpresets.t_30deg_straightonly) diff --git a/advtrains_luaautomation/README.md b/advtrains_luaautomation/README.md index a885075..275653c 100644 --- a/advtrains_luaautomation/README.md +++ b/advtrains_luaautomation/README.md @@ -93,6 +93,9 @@ Removes any pending interrupts of this node. Make this active component send a digiline message on the specified channel. Not available in init code. + - `trainparts(train_id)` + returns a table with the ids of the cars the train is composed of, or false if `train_id` is invalid. `train_id` can be replaced with `atc_id` when used in LuaATC Rails. + - `atc_send_to_train(<train_id>, <atc_command>)` Sends the specified ATC command to the train specified by its train id. This happens regardless of where the train is in the world, and can be used to remote-control trains. Returns true on success. If the train ID does not exist, returns false and does nothing. See [atc_command.txt](../atc_command.txt) for the ATC command syntax. @@ -142,22 +145,16 @@ asp = { -- the character of call_on and dead_end is purely informative call_on = <boolean>, -- Call-on route, expect train in track ahead (not implemented yet) dead_end = <boolean>, -- Route ends on a dead end (e.g. bumper) (not implemented yet) - - w_speed = <integer>, - -- "Warning speed restriction". Supposed for short-term speed - -- restrictions which always override any other restrictions - -- imposed by "speed" fields, until lifted by a value of -1 - -- (Example: german Langsamfahrstellen-Signale) } ``` -As of January 2020, the 'dst', 'call_on' and 'dead_end' fields are not used. +As of September 2024, the 'dst', 'call_on' and 'dead_end' fields are not used. #### Lines The advtrains_line_automation component adds a few contraptions that should make creating timeable systems easier. Part of its functionality is also available in LuaATC: -- `rwt.*` - all Railway Time functions are included as documented in [the wiki](https://advtrains.de/wiki/doku.php?id=dev:lines:rwt) +- `rwt.*` - all Railway Time functions are included as documented in [the wiki](https://advtrains.de/wiki/doku.php?id=dev:api:railway_time_api) - `schedule(rw_time, msg)`, `schedule_in(rw_dtime, msg)` Schedules an event of type {type="schedule", schedule=true, msg=msg} at (resp. after) the specified railway time (which can be in any format). You can only schedule one event this way. (uses the new lines-internal scheduler) @@ -273,10 +270,17 @@ Each wagon has a current FC, indicating its next destination. Returns a table with the entire FC list for each wagon in the train. Command: `get_fc()` Result: `{"", "foo!bar", "testing", "fc_1!fc_2!fc_3!?", "hello_world"}` + + - `get_fc_index()` + Returns a table with the current FC index for each wagon in the train. Use in conjunction with the result from `get_fc()` to find a the current FC for a wagon. + Command: `get_fc_index()` + Result: `{1, 1, 1, 2, 1}` - - `set_fc(fc_list)` + - `set_fc(fc_list, reset_index)` Overwrites the FC list according to a table `fc_list`. A false or nil entry will leave the wagon unaffected, however all others will be overwritten. - Useful for mass-programming freight trains that use FC-shunting instead of walking to each wagon individually. + Useful for mass-programming freight trains that use FC-shunting instead of walking to each wagon individually. If the new FC entry for a wagon is shorter than the old entry, the index will clip to the last FC in the new entry. + If `reset_index` is true, all Current FC values will reset to the first entry in the list, instead of remaining at the current index. + Example: train has FC lists: `"", "foo!bar", "testing", "fc_1!fc_2!fc_3!?", "hello_world"` Command: `set_fc({"", "foo!turtle", nil, "4tehlulz", false})` Result: `""` `"foo!turtle"` `"testing"` `"4tehlulz"` `"hello_world"` diff --git a/advtrains_luaautomation/active_common.lua b/advtrains_luaautomation/active_common.lua index 50fb2bc..074d3b3 100644 --- a/advtrains_luaautomation/active_common.lua +++ b/advtrains_luaautomation/active_common.lua @@ -1,4 +1,4 @@ - +local S = atltrans local ac = {nodes={}} @@ -14,7 +14,7 @@ end function ac.after_place_node(pos, player) local meta=minetest.get_meta(pos) meta:set_string("formspec", ac.getform(pos, meta)) - meta:set_string("infotext", "LuaATC component, unconfigured.") + meta:set_string("infotext", S("Unconfigured LuaATC component")) local ph=minetest.pos_to_string(pos) --just get first available key! for en,_ in pairs(atlatc.envs) do @@ -43,11 +43,11 @@ function ac.getform(pos, meta_p) end local form = "size["..atlatc.CODE_FORM_SIZE.."]" .."style[code;font=mono]" - .."label[0,-0.1;Environment]" + .."label[0,-0.1;"..S("LuaATC Environment").."]" .."dropdown[0,0.3;3;env;"..table.concat(envs_asvalues, ",")..";"..sel.."]" - .."button[5,0.2;2,1;save;Save]" - .."button[7,0.2;3,1;cle;Clear Local Env.]" - .."textarea[0.3,1.5;"..atlatc.CODE_FORM_SIZE..";code;Code;"..minetest.formspec_escape(code).."]" + .."button[5,0.2;2,1;save;"..S("Save").."]" + .."button[7,0.2;3,1;cle;"..S("Clear Local Environment").."]" + .."textarea[0.3,1.5;"..atlatc.CODE_FORM_SIZE..";code;"..S("Code")..";"..minetest.formspec_escape(code).."]" .."label["..atlatc.CODE_FORM_ERRLABELPOS..";"..err.."]" return form end @@ -55,13 +55,17 @@ end function ac.after_dig_node(pos, node, player) advtrains.invalidate_all_paths(pos) advtrains.ndb.clear(pos) + atlatc.interrupt.clear_ints_at_pos(pos) + if advtrains.lines and advtrains.lines.sched then + advtrains.lines.sched.discard_all(advtrains.encode_pos(pos)) + end local ph=minetest.pos_to_string(pos) ac.nodes[ph]=nil end function ac.on_receive_fields(pos, formname, fields, player) if not minetest.check_player_privs(player:get_player_name(), {atlatc=true}) then - minetest.chat_send_player(player:get_player_name(), "Missing privilege: atlatc - Operation cancelled!") + minetest.chat_send_player(player:get_player_name(), S("You are not allowed to configure this LuaATC component without the @1 privilege.", "atlatc")) return end @@ -91,9 +95,9 @@ function ac.on_receive_fields(pos, formname, fields, player) meta:set_string("formspec", ac.getform(pos, meta)) if nodetbl.env then - meta:set_string("infotext", "LuaATC component, assigned to environment '"..nodetbl.env.."'") + meta:set_string("infotext", S("LuaATC component assigned to environment '@1'", nodetbl.env)) else - meta:set_string("infotext", "LuaATC component, invalid enviroment set!") + meta:set_string("infotext", S("LuaATC component assigned to an invalid environment")) end end @@ -168,7 +172,7 @@ function ac.run_in_env(pos, evtdata, customfct_p, ignore_no_code) atlatc.active.nodes[ph].err=dataout env:log("error", "LuaATC component at",ph,": LUA Error:",dataout) if meta then - meta:set_string("infotext", "LuaATC component, ERROR:"..dataout) + meta:set_string("infotext", S("LuaATC component with error: @1", dataout)) end --TODO temporary --if customfct.atc_id then diff --git a/advtrains_luaautomation/atc_rail.lua b/advtrains_luaautomation/atc_rail.lua index aac11f0..dd26f51 100755..100644 --- a/advtrains_luaautomation/atc_rail.lua +++ b/advtrains_luaautomation/atc_rail.lua @@ -95,11 +95,19 @@ function r.fire_event(pos, evtdata, appr_internal) if not train_id then return end local fc_list = {} for index,wagon_id in ipairs(train.trainparts) do - fc_list[index] = table.concat(advtrains.wagons[wagon_id].fc,"!") or "" + fc_list[index] = table.concat(advtrains.wagons[wagon_id].fc or {},"!") end return fc_list end, - set_fc = function(fc_list) + get_fc_index = function() + if not train_id then return end + local fc_index_list = {} + for widx, wagon_id in ipars(train.trainparts) do + fc_index_list[widx] = advtrains.wagons[wagon_id].fcind or 1 + end + return fc_index_list + end, + set_fc = function(fc_list,reset_index) assertt(fc_list, "table") if not train_id then return false end -- safety type-check for entered values @@ -113,11 +121,12 @@ function r.fire_event(pos, evtdata, appr_internal) if fc_list[index] then -- has FC to enter to this wagon local data = advtrains.wagons[wagon_id] if data then -- wagon actually exists - for _,wagon in pairs(minetest.luaentities) do -- find wagon entity - if wagon.is_wagon and wagon.initialized and wagon.id==wagon_id then - wagon.set_fc(data,fc_list[index]) -- overwrite to new FC - break -- no point cycling through every other entity. we found our wagon - end + --effectively copyied from wagons.lua, allowing for the :split function and reset_index + data.fc = fc_list[index]:split("!") + if reset_index or not data.fcind then + data.fcind = 1 + elseif data.fcind > #data.fc then + data.fcind = #data.fc end end end @@ -219,7 +228,7 @@ advtrains.register_tracks("default", { models_prefix="advtrains_dtrack", models_suffix=".b3d", shared_texture="advtrains_dtrack_shared_atc.png", - description=atltrans("LuaATC Rail"), + description=atltrans("LuaATC Track"), formats={}, get_additional_definiton = function(def, preset, suffix, rotation) return { diff --git a/advtrains_luaautomation/environment.lua b/advtrains_luaautomation/environment.lua index d85bedc..b54d45c 100644 --- a/advtrains_luaautomation/environment.lua +++ b/advtrains_luaautomation/environment.lua @@ -153,6 +153,12 @@ local static_env = { local pos=atlatc.pcnaming.resolve_pos(parpos, "interrupt_pos") atlatc.interrupt.add(0, pos, {type="ext_int", ext_int=true, message=imesg}) end, + train_parts = function(train_id) + if not train_id then return false end + local train = advtrains.trains[train_id] + if not train then return false end + return table.copy(train.trainparts or {}) + end, -- sends an atc command to train regardless of where it is in the world atc_send_to_train = function(train_id, command) assertt(command, "string") @@ -164,6 +170,9 @@ local static_env = { return false end end, + get_slowdown = function() + return advtrains.global_slowdown + end } -- If interlocking is present, enable route setting functions @@ -221,7 +230,7 @@ if advtrains.interlocking then end static_env.set_aspect = function(signal, asp) local pos = atlatc.pcnaming.resolve_pos(signal) - return advtrains.interlocking.signal_set_aspect(pos) + return advtrains.interlocking.signal_set_aspect(pos,asp) end --section_occupancy() @@ -230,7 +239,7 @@ if advtrains.interlocking then ts_id = tostring(ts_id) local response = advtrains.interlocking.db.get_ts(ts_id) if not response then return false end - return table.copy(response.trains) + return (response.trains and table.copy(response.trains)) or {} end end @@ -259,6 +268,11 @@ if advtrains.lines then } end + +atlatc.register_function = function (name, f) + static_env[name] = f +end + for _, name in pairs(safe_globals) do static_env[name] = _G[name] end diff --git a/advtrains_luaautomation/init.lua b/advtrains_luaautomation/init.lua index c51aa71..b359142 100644 --- a/advtrains_luaautomation/init.lua +++ b/advtrains_luaautomation/init.lua @@ -2,15 +2,15 @@ -- Lua automation features for advtrains -- Uses global table 'atlatc' (AdvTrains_LuaATC) ---TODO: re-add localization (if merging localization, discard this hunk please) -atltrans = function(s,a,...)a={a,...}return s:gsub("@(%d+)",function(n)return a[tonumber(n)]end)end +atltrans = attrans +local S = atltrans --Privilege --Only trusted players should be enabled to build stuff which can break the server. atlatc = { envs = {}} -minetest.register_privilege("atlatc", { description = "Player can place and modify LUA ATC components. Grant with care! Allows to execute bad LUA code.", give_to_singleplayer = false, default= false }) +minetest.register_privilege("atlatc", { description = S("Can place and configure LuaATC components, including execute potentially harmful Lua code"), give_to_singleplayer = false, default= false }) --Size of code input forms in X,Y notation. Must be at least 10x10 atlatc.CODE_FORM_SIZE = "15,12" diff --git a/advtrains_luaautomation/mesecon_controller.lua b/advtrains_luaautomation/mesecon_controller.lua index bffff84..6981839 100644 --- a/advtrains_luaautomation/mesecon_controller.lua +++ b/advtrains_luaautomation/mesecon_controller.lua @@ -6,6 +6,7 @@ -- From Mesecons mod https://mesecons.net/ -- (c) Jeija and Contributors +local S = atltrans local BASENAME = "advtrains_luaautomation:mesecon_controller" local rules = { @@ -207,7 +208,7 @@ for d = 0, 1 do } minetest.register_node(node_name, { - description = "LuaATC Mesecon Controller", + description = S("LuaATC Mesecon Controller"), drawtype = "nodebox", tiles = { top, diff --git a/advtrains_luaautomation/operation_panel.lua b/advtrains_luaautomation/operation_panel.lua index c118ff3..8e12651 100755..100644 --- a/advtrains_luaautomation/operation_panel.lua +++ b/advtrains_luaautomation/operation_panel.lua @@ -1,3 +1,4 @@ +local S = atltrans local function on_punch(pos,node,player) atlatc.interrupt.add(0, pos, {type="punch", punch=true, name=player:get_player_name()}) @@ -7,7 +8,7 @@ end minetest.register_node("advtrains_luaautomation:oppanel", { drawtype = "normal", tiles={"atlatc_oppanel.png"}, - description = "LuaATC operation panel", + description = S("LuaATC Operation Panel"), groups = { cracky = 1, save_in_at_nodedb=1, diff --git a/advtrains_luaautomation/pcnaming.lua b/advtrains_luaautomation/pcnaming.lua index 71f4d9a..0089ae7 100644 --- a/advtrains_luaautomation/pcnaming.lua +++ b/advtrains_luaautomation/pcnaming.lua @@ -2,6 +2,8 @@ --a.k.a Passive component naming --Allows to assign names to passive components, so they can be called like: --setstate("iamasignal", "green") +local S = atltrans + atlatc.pcnaming={name_map={}} function atlatc.pcnaming.load(stuff) if type(stuff)=="table" then @@ -22,8 +24,11 @@ function atlatc.pcnaming.resolve_pos(pos, func_name) error("Invalid position supplied to " .. (func_name or "???")..": " .. dump(pos)) end + +local pcrename = {} + minetest.register_craftitem("advtrains_luaautomation:pcnaming",{ - description = attrans("Passive Component Naming Tool\n\nRight-click to name a passive component."), + description = S("Passive Component Naming Tool\n\nRight-click to name a passive component."), groups = {cracky=1}, -- key=name, value=rating; rating=1..3. inventory_image = "atlatc_pcnaming.png", wield_image = "atlatc_pcnaming.png", @@ -34,7 +39,7 @@ minetest.register_craftitem("advtrains_luaautomation:pcnaming",{ return end if not minetest.check_player_privs(pname, {atlatc=true}) then - minetest.chat_send_player(pname, "Missing privilege: atlatc") + minetest.chat_send_player(pname, S("You are not allowed to name LuaATC passive components without the @1 privilege.", "atlatc")) return end if pointed_thing.type=="node" then @@ -43,6 +48,7 @@ minetest.register_craftitem("advtrains_luaautomation:pcnaming",{ minetest.record_protection_violation(pos, pname) return end + local node = advtrains.ndb.get_node(pos) local ndef = minetest.registered_nodes[node.name] if node.name and ( @@ -57,16 +63,17 @@ minetest.register_craftitem("advtrains_luaautomation:pcnaming",{ pn=name end end - minetest.show_formspec(pname, "atlatc_naming_"..minetest.pos_to_string(pos), "field[pn;Set name of component (empty to clear);"..minetest.formspec_escape(pn).."]") + pcrename[pname] = pos + minetest.show_formspec(pname, "atlatc_naming", "field[pn;"..S("Set name of component (empty to clear)")..";"..minetest.formspec_escape(pn).."]") end end end, }) minetest.register_on_player_receive_fields(function(player, formname, fields) - local pts=string.match(formname, "^atlatc_naming_(.+)") - if pts then - local pos=minetest.string_to_pos(pts) - if fields.pn then + if formname == "atlatc_naming" then + local pname = player:get_player_name() + local pos=pcrename[pname] + if fields.pn and pos then --first remove all occurences for name, npos in pairs(atlatc.pcnaming.name_map) do if vector.equals(npos, pos) then diff --git a/advtrains_signals_ks/init.lua b/advtrains_signals_ks/init.lua index c449416..c0e74ea 100755 --- a/advtrains_signals_ks/init.lua +++ b/advtrains_signals_ks/init.lua @@ -333,6 +333,8 @@ for _, rtab in ipairs({ danger = {asp = { main = false, shunt = false }, n = "shuntd", ici=true}, shuntd = {asp = { main = false, shunt = true } , n = "danger"}, }) do + local sbox = table.copy(rtab.sbox) + sbox[5] = 0 minetest.register_node("advtrains_signals_ks:ra_"..typ.."_"..rot, { description = "Ks Shunting Signal", drawtype = "mesh", @@ -346,7 +348,11 @@ for _, rtab in ipairs({ paramtype2 = "facedir", selection_box = { type = "fixed", - fixed = {-1/4, -1/2, -1/4, 1/4, 0, 1/4} + fixed = {sbox, rotation_sbox} + }, + collision_box = { + type = "fixed", + fixed = sbox, }, groups = { cracky = 2, diff --git a/advtrains_train_track/init.lua b/advtrains_train_track/init.lua index 5065155..32e1235 100644 --- a/advtrains_train_track/init.lua +++ b/advtrains_train_track/init.lua @@ -678,8 +678,45 @@ minetest.register_on_player_receive_fields(function(player, formname, fields) end end) +local function load_wagon(wagon_id, node_inv, node_fc, unload) + local inv_modified = false + local w_inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..wagon_id}) + if w_inv and w_inv:get_list("box") then + + local wagon_data = advtrains.wagons[wagon_id] + local wagon_fc + if wagon_data.fc then + if not wagon_data.fcind then wagon_data.fcind = 1 end + wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or "" + end + + if node_fc == "" or wagon_fc == node_fc then + if not unload then + for _, item in ipairs(node_inv:get_list("main")) do + if w_inv:get_list("box") and w_inv:room_for_item("box", item) then + w_inv:add_item("box", item) + node_inv:remove_item("main", item) + if item.name ~= "" then inv_modified = true end + end + end + else + for _, item in ipairs(w_inv:get_list("box")) do + if node_inv:get_list("main") and node_inv:room_for_item("main", item) then + w_inv:remove_item("box", item) + node_inv:add_item("main", item) + if item.name ~= "" then inv_modified = true end + end + end + end + end + end + return inv_modified +end -local function train_load(pos, train_id, unload) +local function load_entire_train(pos, train_id, unload) -- flood load when not in an active area + if advtrains.is_node_loaded(pos) then -- leave the loading to the nodetimer if area is loaded + return + end local train=advtrains.trains[train_id] local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z}) if not string.match(below.name, "chest") then @@ -692,43 +729,60 @@ local function train_load(pos, train_id, unload) --track section is disabled return end - - local inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}}) - if inv and train.velocity < 2 then - for k, v in ipairs(train.trainparts) do - local i=minetest.get_inventory({type="detached", name="advtrains_wgn_"..v}) - if i and i:get_list("box") then - - local wagon_data = advtrains.wagons[v] - local wagon_fc - if wagon_data.fc then - if not wagon_data.fcind then wagon_data.fcind = 1 end - wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or "" - end - - if node_fc == "" or wagon_fc == node_fc then - if not unload then - for _, item in ipairs(inv:get_list("main")) do - if i:get_list("box") and i:room_for_item("box", item) then - i:add_item("box", item) - inv:remove_item("main", item) - end - end - else - for _, item in ipairs(i:get_list("box")) do - if inv:get_list("main") and inv:room_for_item("main", item) then - i:remove_item("box", item) - inv:add_item("main", item) - end + local node_inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}}) + if node_inv and train.velocity <= 2 then + for _, wagon_id in ipairs(train.trainparts) do + load_wagon(wagon_id, node_inv, node_fc, unload) + end + end +end + +local function load_wagon_on_timer(pos, unload) -- loading ramp when in an active area + if not advtrains.is_node_loaded(pos) then -- leave the loading for the flood load function. we're out of area + return true -- reset the nodetimer until the node is loaded again + end + local tid, tidx = advtrains.get_train_at_pos(pos) + if not tid or tid == "" then + return true + end -- no train to load. + + local train = advtrains.trains[tid] + local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z}) + if not string.match(below.name, "chest") then + atprint("this is not a chest! at "..minetest.pos_to_string(pos)) + return true + end + local node_fc = minetest.get_meta(pos):get_string("fc") or "" + if node_fc == "#" then + --track section is disabled + return true + end + local node_inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}}) + if node_inv and train.velocity <= 2 then + local _, wagon_id, wagon_data = advtrains.get_wagon_at_index(tid, tidx) + if wagon_id then + local inv_modified = load_wagon(wagon_id, node_inv, node_fc, unload) + if inv_modified then + if advtrains.wagon_prototypes[advtrains.get_wagon_prototype(wagon_data)].set_textures then + local wagon_object = advtrains.wagon_objects[wagon_id] + if wagon_object and wagon_data then + local ent = wagon_object:get_luaentity() + if ent and ent.set_textures then + ent:set_textures(wagon_data) end end end end end end + return true end - +local nodetimer_interval = minetest.settings:get("advtrains_loading_track_timer") or 1 +local function start_nodetimer(pos) + local timer = minetest.get_node_timer(pos) + timer:start(nodetimer_interval) +end advtrains.register_tracks("default", { nodename_prefix="advtrains:dtrack_unload", @@ -747,9 +801,16 @@ advtrains.register_tracks("default", { on_rightclick = function(pos, node, player) show_fc_formspec(pos, player) end, + after_place_node = function(pos) + advtrains.ndb.update(pos) + start_nodetimer(pos) + end, + on_timer = function(pos) + return load_wagon_on_timer(pos, true) + end, advtrains = { on_train_enter = function(pos, train_id) - train_load(pos, train_id, true) + load_entire_train(pos, train_id, true) end, }, } @@ -772,9 +833,16 @@ advtrains.register_tracks("default", { on_rightclick = function(pos, node, player) show_fc_formspec(pos, player) end, + after_place_node = function(pos) + advtrains.ndb.update(pos) + start_nodetimer(pos) + end, + on_timer = function(pos) + return load_wagon_on_timer(pos, false) + end, advtrains = { on_train_enter = function(pos, train_id) - train_load(pos, train_id, false) + load_entire_train(pos, train_id, false) end, }, } @@ -788,7 +856,6 @@ if minetest.get_modpath("basic_materials") then elseif minetest.get_modpath("technic") then loader_core = "technic:control_logic_unit" end ---print("Loader Core: "..loader_core) minetest.register_craft({ type="shapeless", diff --git a/advtrains_train_track/settingtypes.txt b/advtrains_train_track/settingtypes.txt new file mode 100644 index 0000000..0af0081 --- /dev/null +++ b/advtrains_train_track/settingtypes.txt @@ -0,0 +1,4 @@ +# Set the nodetimer delay for the loading tracks. +# A longer delay may cause wagons to be missed if the pass over too fast. +# A shorter delay may cause lag as wagons are checked multiple times as they pass over. +advtrains_loading_track_timer (Loading Track Timer) int 1
\ No newline at end of file |