Train Coupling: Change behavior so that train direction of initiating train is kept, add ATC Cpl command

This commit is contained in:
orwell96 2021-10-25 19:54:58 +02:00
parent 4989da3663
commit e7d0a5fac2
5 changed files with 85 additions and 54 deletions

View File

@ -199,10 +199,16 @@ local matchptn={
return #match+1
end,
["B([0-9]+)"]=function(id, train, match)
if train.velocity>tonumber(match) then
train.atc_brake_target=tonumber(match)
if not train.tarvelocity or train.tarvelocity>train.atc_brake_target then
train.tarvelocity=train.atc_brake_target
local btar = tonumber(match)
if train.velocity>btar then
train.atc_brake_target=btar
if not train.tarvelocity or train.tarvelocity>btar then
train.tarvelocity=btar
end
else
-- independent of brake target, must make sure that tarvelocity is not greater than it
if train.tarvelocity and train.tarvelocity>btar then
train.tarvelocity=btar
end
end
return #match+1
@ -267,6 +273,10 @@ local matchptn={
advtrains.interlocking.ars_set_disable(train, match=="0")
return 2
end,
["Cpl"]=function(id, train)
train.atc_wait_autocouple=true
return 3
end,
}
eval_conditional = function(command, arrow, speed)
@ -358,11 +368,13 @@ function atc.execute_atc_command(id, train)
local match=string.match(command, "^"..pattern)
if match then
local patlen=func(id, train, match)
atprint("Executing: "..string.sub(command, 1, patlen))
--atdebug("Executing: "..string.sub(command, 1, patlen))
--atdebug("Train ATC State: tvel=",train.tarvelocity,"brktar=",train.atc_brake_target,"delay=",train.atc_delay,"wfinish=",train.atc_wait_finish,"wacpl=",train.atc_wait_autocouple)
train.atc_command=string.sub(command, patlen+1)
if train.atc_delay<=0 and not train.atc_wait_finish then
if train.atc_delay<=0
and not train.atc_wait_finish
and not train.atc_wait_autocouple then
--continue (recursive, cmds shouldn't get too long, and it's a end-recursion.)
atc.execute_atc_command(id, train)
end

View File

@ -11,14 +11,9 @@
-- 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)
@ -142,12 +137,16 @@ 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)
--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)
end
end
@ -177,50 +176,61 @@ 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)
advtrains.couple_trains(train1, not t1_is_front, train2, t2_is_front)
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
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)
advtrains.do_connect_trains(train1, train2)
end
-- 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)
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
first.velocity = 0
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
advtrains.update_trainpart_properties(first.id)
advtrains.couple_invalidate(first)
-- TODO: migrate some of the properties from stat_train to init_train?
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.couple_invalidate(init_train)
return true
end

View File

@ -468,7 +468,7 @@ advtrains.avt_save = function(remove_players_from_wagons)
"atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open",
"text_outside", "text_inside", "line", "routingcode",
"il_sections", "speed_restriction", "is_shunt",
"points_split", "autocouple", "ars_disable",
"points_split", "autocouple", "atc_wait_autocouple", "ars_disable",
})
--then save it
tmp_trains[id]=v

View File

@ -418,9 +418,11 @@ function advtrains.train_step_b(id, train, dtime)
ctrl_lever = userc
else
if train.atc_command then
if (not train.atc_delay or train.atc_delay<=0) and not train.atc_wait_finish then
if (not train.atc_delay or train.atc_delay<=0)
and not train.atc_wait_finish
and not train.atc_wait_autocouple then
advtrains.atc.execute_atc_command(id, train)
else
elseif train.atc_delay and train.atc_delay > 0 then
train.atc_delay=train.atc_delay-dtime
end
elseif train.atc_delay then
@ -711,12 +713,15 @@ function advtrains.train_step_c(id, train, dtime)
if train.ontrack_collision_info then
train.velocity = 0
train.acceleration = 0
advtrains.atc.train_reset_command(train)
--advtrains.atc.train_reset_command(train) will occur in couple_initiate_with if required
local otrn = advtrains.trains[train.ontrack_collision_info.otid]
if otrn.velocity == 0 then -- other train must be standing, else don't initiate coupling
advtrains.couple_initiate_with(train, otrn, not train.ontrack_collision_info.same_dir)
else
-- other collision - stop any ATC control
advtrains.atc.train_reset_command(train)
end
train.ontrack_collision_info = nil

View File

@ -51,6 +51,10 @@ Kick all passengers out of the trains
This command kicks all passengers (non-driving players) off the train. This command works only
if the train is stopped and its doors are open.
Cpl
Temporarily switch the train to "Autocouple" mode and wait for coupling.
This command makes the train continue at its current speed until it hits another standing wagon or train. Then, it couples to this train and ATC command execution continues.
# conditional statements:
I<condition><code>;