From 5f5d28af1b92218022eaa14f1fd801ac98c57805 Mon Sep 17 00:00:00 2001 From: orwell96 Date: Mon, 25 Oct 2021 21:08:42 +0200 Subject: Coupling: Add concept of coupler types, allow coupling only when coupler types match --- advtrains/api_doc.txt | 7 +++ advtrains/couple.lua | 114 +++++++++++++++++++++++++++++++++++---- advtrains/locale/advtrains.de.tr | 4 ++ 3 files changed, 115 insertions(+), 10 deletions(-) diff --git a/advtrains/api_doc.txt b/advtrains/api_doc.txt index 8ac4986..1e49df3 100644 --- a/advtrains/api_doc.txt +++ b/advtrains/api_doc.txt @@ -75,6 +75,13 @@ advtrains.register_wagon(name, prototype, description, inventory_image) ^- Getting on by walking in then takes effect. ^- Positive values mean front, negative ones back. Resulting position is automatically shifted to the right side. + coupler_types_front = {scharfenberg=true}, + coupler_types_back = {chain=true}, + ^- Defines the available coupler types on this wagon on the front and back side. Wagon will only couple to wagons that have a matching coupler. (this property does not have any visual impact) + ^- Default: not given (nil) - causes the wagon to couple to any other wagon regardless of coupler type. + ^- Empty table ({}): This wagon does not couple to any other wagon (e.g. for Linetrack vehicles) + ^- Register coupler types using ''advtrains.register_coupler_type(type, name)''. advtrains defines the default types "chain" (Buffer and Chain) and "scharfenberg" (Scharfenberg coupler). + wagon_span=2, ^- How far this wagon extends from its base position. Is the half of the wagon length. ^- Used to determine in which distance the other wagons have to be positioned. Will require tweaking. diff --git a/advtrains/couple.lua b/advtrains/couple.lua index 149584b..b812dec 100644 --- a/advtrains/couple.lua +++ b/advtrains/couple.lua @@ -17,6 +17,18 @@ -- train.couple_* contain references to ObjectRefs of couple objects, which contain all relevant information -- These objectRefs will delete themselves once the couples no longer match (see below) + +advtrains.coupler_types = {} + +function advtrains.register_coupler_type(code, name) + advtrains.coupler_types[code] = name +end + +-- Register some default couplers +advtrains.register_coupler_type("chain", attrans("Buffer and Chain Coupler")) +advtrains.register_coupler_type("scharfenberg", attrans("Scharfenberg Coupler")) + + local function create_couple_entity(pos, train1, t1_is_front, train2, t2_is_front) local id1 = train1.id local id2 = train2.id @@ -139,16 +151,20 @@ end function advtrains.couple_initiate_with(init_train, stat_train, stat_is_front) --atdebug("Couple init autocouple=",init_train.autocouple,"atc_w_acpl=",init_train.atc_wait_autocouple) if init_train.autocouple or init_train.atc_wait_autocouple then - advtrains.couple_trains(init_train, false, stat_train, stat_is_front) - -- clear atc couple waiting blocker - init_train.atc_wait_autocouple = nil - else - local pos = advtrains.path_get_interpolated(init_train, init_train.index) - create_couple_entity(pos, init_train, true, stat_train, stat_is_front) - -- clear ATC command on collision - advtrains.atc.train_reset_command(init_train) + local cplmatch, msg = advtrains.check_matching_coupler_types(init_train, true, stat_train, stat_is_front) + if cplmatch then + advtrains.couple_trains(init_train, false, stat_train, stat_is_front) + -- clear atc couple waiting blocker + init_train.atc_wait_autocouple = nil + return + end end - + -- get here if either autocouple is not on or couples dont match + local pos = advtrains.path_get_interpolated(init_train, init_train.index) + create_couple_entity(pos, init_train, true, stat_train, stat_is_front) + -- clear ATC command on collision + advtrains.atc.train_reset_command(init_train) + end -- check if the player has permission for the first/last wagon of the train @@ -176,7 +192,13 @@ function advtrains.safe_couple_trains(train1, t1_is_front, train2, t2_is_front, wck_t2 = check_twagon_owner(train2, t2_is_front, pname) end if (wck_t1 or wck_t2) or not pname then - advtrains.couple_trains(train1, not t1_is_front, train2, t2_is_front) + + local cplmatch, msg = advtrains.check_matching_coupler_types(train1, t1_is_front, train2, t2_is_front) + if cplmatch then + advtrains.couple_trains(train1, not t1_is_front, train2, t2_is_front) + else + minetest.chat_send_player(pname, msg) + end end end @@ -234,7 +256,79 @@ function advtrains.couple_trains(init_train, invert_init_train, stat_train, stat return true end +-- Couple types matching check +-- returns: true, nil if OK +-- false, errmsg if there is an error +function advtrains.check_matching_coupler_types(t1, t1_front, t2, t2_front) + -- 1. get wagons + local t1_wid + if t1_front then + t1_wid = t1.trainparts[1] + else + t1_wid = t1.trainparts[#t1.trainparts] + end + local t2_wid + if t2_front then + t2_wid = t2.trainparts[1] + else + t2_wid = t2.trainparts[#t2.trainparts] + end + --atdebug("CMCT: t1_wid",t1_wid,"t2_wid",t2_wid,"") + + if not t1_wid or not t2_wid then + return false, "Unable to retrieve wagons from train"--note: no translation needed, case should not occur + end + + local t1_wagon = advtrains.wagons[t1_wid] + local t2_wagon = advtrains.wagons[t2_wid] + + if not t1_wagon or not t2_wagon then + return false, "At least one of wagons "..t1_wagon.." or "..t2_wagon.." does not exist"--note: no translation needed, case should not occur + end + + -- these calls do not fail, they may return placeholder - doesn't matter + local _,t1_wpro = advtrains.get_wagon_prototype(t1_wagon) + local _,t2_wpro = advtrains.get_wagon_prototype(t2_wagon) + + -- get correct couplers table (front/back) + local t1_cplt + if not t1_front == not t1_wagon.wagon_flipped then --fancy XOR + t1_cplt = t1_wpro.coupler_types_back + else + t1_cplt = t1_wpro.coupler_types_front + end + local t2_cplt + if not t2_front == not t2_wagon.wagon_flipped then --fancy XOR + t2_cplt = t2_wpro.coupler_types_back + else + t2_cplt = t2_wpro.coupler_types_front + end + + --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 + return true + end + + -- have common coupler? + for typ,_ in pairs(t1_cplt) do + if t2_cplt[typ] then + --atdebug("CMCT: Matching type",typ) + return true + end + end + --no match, give user an info + local t1_cplhr, t2_cplhr = {},{} + for typ,_ in pairs(t1_cplt) do + table.insert(t1_cplhr, advtrains.coupler_types[typ] or typ) + end + for typ,_ in pairs(t2_cplt) do + table.insert(t2_cplhr, advtrains.coupler_types[typ] or typ) + 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 -- DECOUPLING -- function advtrains.split_train_at_fc(train, count_empty, length_limit) diff --git a/advtrains/locale/advtrains.de.tr b/advtrains/locale/advtrains.de.tr index cd43eed..7566aa4 100644 --- a/advtrains/locale/advtrains.de.tr +++ b/advtrains/locale/advtrains.de.tr @@ -70,3 +70,7 @@ 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) -- cgit v1.2.3