aboutsummaryrefslogtreecommitdiff
path: root/advtrains/couple.lua
diff options
context:
space:
mode:
Diffstat (limited to 'advtrains/couple.lua')
-rw-r--r--advtrains/couple.lua198
1 files changed, 153 insertions, 45 deletions
diff --git a/advtrains/couple.lua b/advtrains/couple.lua
index 336a6d4..3e6c432 100644
--- a/advtrains/couple.lua
+++ b/advtrains/couple.lua
@@ -11,17 +11,24 @@
-- When the initiating train has autocouple set, trains are immediately coupled
-- When not, a couple entity is spawned and coupling commences on click
-- Coupling MUST preserve the train ID of the initiating train, so it is done like this:
- -- initiating train is reversed
- -- stationary train is reversed if required, so that it points towards the initiating train
- -- do_connect_trains(initiating, stationary)
--- As a result, the coupled train is reversed in direction. Alternative way of doing things (might be considered later):
- -- stationary train is reversed if required, so that it points away from the initiating train
-- index of initiating train is set so that it matches the front pos of stationary train
- -- wagons of stationary train are inserted at the beginning of initiating train
-- remove stationary train
+ -- wagons of stationary train are inserted at the beginning of initiating train (considers direction of stat_train and inserts reverse if required)
-- 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
@@ -142,14 +149,22 @@ end
-- Called from train_step_b() when the current train (init_train) just stopped at one of the end indices of another train (stat_train)
-- Depending on autocouple, either couples immediately or spawns a couple entity
function advtrains.couple_initiate_with(init_train, stat_train, stat_is_front)
- --atdebug("Initiating couplign between init=",init_train.id,"stat=",stat_train.id,"backside=",stat_is_backside)
- if init_train.autocouple then
- advtrains.couple_trains(init_train, true, stat_train, stat_is_front)
- else
- local pos = advtrains.path_get_interpolated(init_train, init_train.index)
- create_couple_entity(pos, init_train, true, 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
+ 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
@@ -177,54 +192,147 @@ 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, 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
-- Actually performs the train coupling. Always retains train ID of train1
-function advtrains.couple_trains(train1, t1_is_front, train2, t2_is_front)
- --atdebug("Couple trains init=",init_train.id,"stat=",stat_train.id,"statreverse=",stat_must_reverse)
- -- see comment on top of file
- if t1_is_front then
- advtrains.invert_train(train1.id)
- end
- if not t2_is_front then
- advtrains.invert_train(train2.id)
- end
-
- advtrains.do_connect_trains(train1, train2)
-end
+function advtrains.couple_trains(init_train, invert_init_train, stat_train, stat_train_opposite)
+ --atdebug("Couple trains init=",init_train.id,"initinv=",invert_init_train,"stat=",stat_train.id,"statreverse=",stat_train_opposite)
--- Adds the wagons of first to second and deletes second_id afterwards
--- Assumes that second_id stands right behind first_id and both trains point to the same direction
-function advtrains.do_connect_trains(first, second)
-
- if not advtrains.train_ensure_init(first.id, first) then
- atwarn("Coupling: first train",first.id,"is not initialized! Operation aborted!")
+ if not advtrains.train_ensure_init(init_train.id, init_train) then
+ atwarn("Coupling: initiating train",init_train.id,"is not initialized! Operation aborted!")
return
end
- if not advtrains.train_ensure_init(second.id, second) then
- atwarn("Coupling: second train",second.id,"is not initialized! Operation aborted!")
+ if not advtrains.train_ensure_init(stat_train.id, stat_train) then
+ atwarn("Coupling: stationary train",stat_train.id,"is not initialized! Operation aborted!")
return
end
-
- local first_wagoncnt=#first.trainparts
- local second_wagoncnt=#second.trainparts
-
- for _,v in ipairs(second.trainparts) do
- table.insert(first.trainparts, v)
+
+ -- only used with the couple entity
+ if invert_init_train then
+ advtrains.invert_train(init_train.id)
end
-
- advtrains.remove_train(second.id)
- first.velocity = 0
+ local itp = init_train.trainparts
+ local init_wagoncnt = #itp
+ 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
+
+ if stat_train_opposite then
+ -- insert wagons in inverse order and set their wagon_flipped state
+ for i=1,stat_wagoncnt do
+ table.insert(itp, 1, stp[i])
+ local wdata = advtrains.wagons[stp[i]]
+ if wdata then
+ wdata.wagon_flipped = not wdata.wagon_flipped
+ else
+ atwarn("While coupling, wagon",stp[i],"of stationary train",stat_train.id,"not found!")
+ end
+ end
+ else
+ --insert wagons in normal order
+ for i=stat_wagoncnt,1,-1 do
+ table.insert(itp, 1, stp[i])
+ end
+ end
+
+ -- TODO: migrate some of the properties from stat_train to init_train?
- advtrains.update_trainpart_properties(first.id)
- advtrains.couple_invalidate(first)
+ advtrains.remove_train(stat_train.id)
+
+ -- Set train index forward
+ init_train.index = advtrains.path_get_index_by_offset(init_train, init_train.index, stat_trainlen)
+
+ advtrains.update_trainpart_properties(init_train.id)
+ advtrains.update_train_start_and_end(init_train)
+
+ advtrains.couple_invalidate(init_train)
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
+ if #t1_cplhr==0 then t1_cplhr[1]=attrans("<none>") 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
+ 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)