Remove "couple locks" and apply protection to the actual coupling process, and fix permissions on that
This commit is contained in:
parent
88aee2aecb
commit
b872bdae82
|
@ -65,7 +65,7 @@ minetest.register_entity("advtrains:discouple", {
|
||||||
-- advtrains:couple
|
-- advtrains:couple
|
||||||
-- Couple entity
|
-- Couple entity
|
||||||
local function lockmarker(obj)
|
local function lockmarker(obj)
|
||||||
minetest.spawn_entity(obj:get_pos(), "advtrains.lockmarker")
|
minetest.add_entity(obj:get_pos(), "advtrains:lockmarker")
|
||||||
obj:remove()
|
obj:remove()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -96,63 +96,12 @@ minetest.register_entity("advtrains:couple", {
|
||||||
|
|
||||||
local pname=clicker
|
local pname=clicker
|
||||||
if type(clicker)~="string" then pname=clicker:get_player_name() end
|
if type(clicker)~="string" then pname=clicker:get_player_name() end
|
||||||
if not minetest.check_player_privs(pname, "train_operator") then return end
|
|
||||||
|
|
||||||
local train1=advtrains.trains[self.train_id_1]
|
if advtrains.safe_couple_trains(self.train_id_1, self.train_id_2, self.t1_is_front, self.t2_is_front, pname) then
|
||||||
local train2=advtrains.trains[self.train_id_2]
|
self.object:remove()
|
||||||
if not advtrains.train_ensure_init(self.train_id_1, train1) then
|
|
||||||
atwarn("Train",self.train_id_1,"is not initialized! Operation aborted!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if not advtrains.train_ensure_init(self.train_id_2, train2) then
|
|
||||||
atwarn("Train",self.train_id_2,"is not initialized! Operation aborted!")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local id1, id2=self.train_id_1, self.train_id_2
|
|
||||||
local bp1, bp2 = self.t1_is_front, self.t2_is_front
|
|
||||||
if bp1 then
|
|
||||||
if train1.couple_lock_front then
|
|
||||||
lockmarker(self.object)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if bp2 then
|
|
||||||
if train2.couple_lock_front then
|
|
||||||
lockmarker(self.object)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
advtrains.invert_train(id1)
|
|
||||||
advtrains.do_connect_trains(id1, id2, clicker)
|
|
||||||
else
|
|
||||||
if train2.couple_lock_back then
|
|
||||||
lockmarker(self.object)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
advtrains.do_connect_trains(id2, id1, clicker)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
if train1.couple_lock_back then
|
lockmarker(self.object)
|
||||||
lockmarker(self.object)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
if bp2 then
|
|
||||||
if train2.couple_lock_front then
|
|
||||||
lockmarker(self.object)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
advtrains.do_connect_trains(id1, id2, clicker)
|
|
||||||
else
|
|
||||||
if train2.couple_lock_back then
|
|
||||||
lockmarker(self.object)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
advtrains.invert_train(id2)
|
|
||||||
advtrains.do_connect_trains(id1, id2, clicker)
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
atprint("Coupled trains", id1, id2)
|
|
||||||
self.object:remove()
|
|
||||||
end)
|
end)
|
||||||
end,
|
end,
|
||||||
on_step=function(self, dtime)
|
on_step=function(self, dtime)
|
||||||
|
|
|
@ -287,7 +287,7 @@ advtrains.avt_save = function(remove_players_from_wagons)
|
||||||
"last_pos", "last_connid", "last_frac", "velocity", "tarvelocity",
|
"last_pos", "last_connid", "last_frac", "velocity", "tarvelocity",
|
||||||
"trainparts", "recently_collided_with_env",
|
"trainparts", "recently_collided_with_env",
|
||||||
"atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open",
|
"atc_brake_target", "atc_wait_finish", "atc_command", "atc_delay", "door_open",
|
||||||
"text_outside", "text_inside", "couple_lck_front", "couple_lck_back", "line",
|
"text_outside", "text_inside", "line",
|
||||||
"il_sections", "speed_restriction",
|
"il_sections", "speed_restriction",
|
||||||
})
|
})
|
||||||
--then save it
|
--then save it
|
||||||
|
@ -308,6 +308,8 @@ advtrains.avt_save = function(remove_players_from_wagons)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
-- TODO apply save-keys here too
|
-- TODO apply save-keys here too
|
||||||
|
-- TODO temp
|
||||||
|
wdata.dcpl_lock = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
--versions:
|
--versions:
|
||||||
|
|
|
@ -736,22 +736,7 @@ function advtrains.add_wagon_to_train(wagon_id, train_id, index)
|
||||||
run_callbacks_update(train_id, train)
|
run_callbacks_update(train_id, train)
|
||||||
end
|
end
|
||||||
|
|
||||||
function advtrains.safe_decouple_wagon(w_id, pname)
|
-- Note: safe_decouple_wagon() has been moved to wagons.lua
|
||||||
if not minetest.check_player_privs(pname, "train_operator") then
|
|
||||||
minetest.chat_send_player(pname, "Missing train_operator privilege")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
local data = advtrains.wagons[w_id]
|
|
||||||
if data.dcpl_lock then
|
|
||||||
minetest.chat_send_player(pname, "Couple is locked (ask owner or admin to unlock it)")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
atprint("wagon:discouple() Splitting train", data.train_id)
|
|
||||||
local train = advtrains.trains[data.train_id]
|
|
||||||
advtrains.log("Discouple", pname, train.last_pos, train.text_outside)
|
|
||||||
advtrains.split_train_at_wagon(w_id)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
-- this function sets wagon's pos_in_train(parts) properties and train's max_speed and drives_on (and more)
|
-- this function sets wagon's pos_in_train(parts) properties and train's max_speed and drives_on (and more)
|
||||||
function advtrains.update_trainpart_properties(train_id, invert_flipstate)
|
function advtrains.update_trainpart_properties(train_id, invert_flipstate)
|
||||||
|
@ -881,13 +866,7 @@ function advtrains.split_train_at_wagon(wagon_id)
|
||||||
local newtrain_id=advtrains.create_new_train_at(pos, connid, frac, tp)
|
local newtrain_id=advtrains.create_new_train_at(pos, connid, frac, tp)
|
||||||
local newtrain=advtrains.trains[newtrain_id]
|
local newtrain=advtrains.trains[newtrain_id]
|
||||||
|
|
||||||
train.tarvelocity=0
|
|
||||||
newtrain.velocity=train.velocity
|
newtrain.velocity=train.velocity
|
||||||
newtrain.tarvelocity=0
|
|
||||||
|
|
||||||
newtrain.couple_lck_back=train.couple_lck_back
|
|
||||||
newtrain.couple_lck_front=false
|
|
||||||
train.couple_lck_back=false
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1013,12 +992,6 @@ function advtrains.do_connect_trains(first_id, second_id)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
if first.couple_lck_back or second.couple_lck_front then
|
|
||||||
-- trains are ordered correctly!
|
|
||||||
-- Note, this is already checked in the rightclick step of the couple entity before trains are actually reversed
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local first_wagoncnt=#first.trainparts
|
local first_wagoncnt=#first.trainparts
|
||||||
local second_wagoncnt=#second.trainparts
|
local second_wagoncnt=#second.trainparts
|
||||||
|
|
||||||
|
@ -1026,13 +999,10 @@ function advtrains.do_connect_trains(first_id, second_id)
|
||||||
table.insert(first.trainparts, v)
|
table.insert(first.trainparts, v)
|
||||||
end
|
end
|
||||||
|
|
||||||
local tmp_cpl_lck=second.couple_lck_back
|
|
||||||
|
|
||||||
advtrains.remove_train(second_id)
|
advtrains.remove_train(second_id)
|
||||||
|
|
||||||
first.velocity=0
|
first.velocity=0
|
||||||
first.tarvelocity=0
|
first.tarvelocity=0
|
||||||
first.couple_lck_back=tmp_cpl_lck
|
|
||||||
|
|
||||||
advtrains.update_trainpart_properties(first_id)
|
advtrains.update_trainpart_properties(first_id)
|
||||||
advtrains.couple_invalidate(first)
|
advtrains.couple_invalidate(first)
|
||||||
|
@ -1050,7 +1020,6 @@ function advtrains.invert_train(train_id)
|
||||||
advtrains.path_setrestore(train, true)
|
advtrains.path_setrestore(train, true)
|
||||||
|
|
||||||
-- rotate some other stuff
|
-- rotate some other stuff
|
||||||
train.couple_lck_back, train.couple_lck_front = train.couple_lck_front, train.couple_lck_back
|
|
||||||
if train.door_open then
|
if train.door_open then
|
||||||
train.door_open = - train.door_open
|
train.door_open = - train.door_open
|
||||||
end
|
end
|
||||||
|
|
|
@ -300,7 +300,7 @@ function wagon:on_step(dtime)
|
||||||
--check infotext
|
--check infotext
|
||||||
local outside=self:train().text_outside or ""
|
local outside=self:train().text_outside or ""
|
||||||
if setting_show_ids then
|
if setting_show_ids then
|
||||||
outside = outside .. "\nT:" .. data.train_id .. " W:" .. self.id
|
outside = outside .. "\nT:" .. data.train_id .. " W:" .. self.id .. " O:" .. data.owner
|
||||||
end
|
end
|
||||||
|
|
||||||
local train=self:train()
|
local train=self:train()
|
||||||
|
@ -361,7 +361,7 @@ function wagon:on_step(dtime)
|
||||||
|
|
||||||
--DisCouple
|
--DisCouple
|
||||||
if data.pos_in_trainparts and data.pos_in_trainparts>1 then
|
if data.pos_in_trainparts and data.pos_in_trainparts>1 then
|
||||||
if train.velocity==0 and not data.dcpl_lock then
|
if train.velocity==0 then
|
||||||
if not self.discouple or not self.discouple.object:getyaw() then
|
if not self.discouple or not self.discouple.object:getyaw() then
|
||||||
atprint(self.id,"trying to spawn discouple")
|
atprint(self.id,"trying to spawn discouple")
|
||||||
local yaw = self.object:getyaw()
|
local yaw = self.object:getyaw()
|
||||||
|
@ -374,9 +374,6 @@ function wagon:on_step(dtime)
|
||||||
--box is hidden when attached, so unuseful.
|
--box is hidden when attached, so unuseful.
|
||||||
--object:set_attach(self.object, "", {x=0, y=0, z=self.wagon_span*10}, {x=0, y=0, z=0})
|
--object:set_attach(self.object, "", {x=0, y=0, z=self.wagon_span*10}, {x=0, y=0, z=0})
|
||||||
self.discouple=le
|
self.discouple=le
|
||||||
atprint(self.id,"success")
|
|
||||||
else
|
|
||||||
atprint("Couldn't spawn DisCouple")
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
@ -474,12 +471,13 @@ function wagon:on_step(dtime)
|
||||||
end
|
end
|
||||||
|
|
||||||
self.updatepct_timer=(self.updatepct_timer or 0)-dtime
|
self.updatepct_timer=(self.updatepct_timer or 0)-dtime
|
||||||
|
local updatepct_timer_elapsed = self.updatepct_timer<=0
|
||||||
if not self.old_velocity_vector
|
if not self.old_velocity_vector
|
||||||
or not vector.equals(velocityvec, self.old_velocity_vector)
|
or not vector.equals(velocityvec, self.old_velocity_vector)
|
||||||
or not self.old_acceleration_vector
|
or not self.old_acceleration_vector
|
||||||
or not vector.equals(accelerationvec, self.old_acceleration_vector)
|
or not vector.equals(accelerationvec, self.old_acceleration_vector)
|
||||||
or self.old_yaw~=yaw
|
or self.old_yaw~=yaw
|
||||||
or self.updatepct_timer<=0 then--only send update packet if something changed
|
or updatepct_timer_elapsed then--only send update packet if something changed
|
||||||
|
|
||||||
self.object:setpos(pos)
|
self.object:setpos(pos)
|
||||||
self.object:setvelocity(velocityvec)
|
self.object:setvelocity(velocityvec)
|
||||||
|
@ -518,7 +516,7 @@ function wagon:on_step(dtime)
|
||||||
self:custom_on_velocity_change(train.velocity, self.old_velocity or 0, dtime)
|
self:custom_on_velocity_change(train.velocity, self.old_velocity or 0, dtime)
|
||||||
end
|
end
|
||||||
-- remove discouple object, because it will be in a wrong location
|
-- remove discouple object, because it will be in a wrong location
|
||||||
if self.discouple then
|
if not updatepct_timer_elapsed and self.discouple then
|
||||||
self.discouple.object:remove()
|
self.discouple.object:remove()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -792,13 +790,8 @@ function wagon:show_bordcom(pname)
|
||||||
local ename = ent.type
|
local ename = ent.type
|
||||||
form = form .. "item_image["..i..","..linhei..";1,1;"..ename.."]"
|
form = form .. "item_image["..i..","..linhei..";1,1;"..ename.."]"
|
||||||
if i~=1 then
|
if i~=1 then
|
||||||
if not ent.dcpl_lock then
|
if checklock(pname, ent.owner, pre_own, ent.whitelist, pre_wl) then
|
||||||
form = form .. "image_button["..(i-0.5)..","..(linhei+1)..";1,1;advtrains_discouple.png;dcpl_"..i..";]"
|
form = form .. "image_button["..(i-0.5)..","..(linhei+1)..";1,1;advtrains_discouple.png;dcpl_"..i..";]"
|
||||||
if checklock(pname, ent.owner, pre_own, ent.whitelist, pre_wl) then
|
|
||||||
form = form .. "image_button["..(i-0.5)..","..(linhei+2)..";1,1;advtrains_cpl_unlock.png;dcpl_lck_"..i..";]"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
form = form .. "image_button["..(i-0.5)..","..(linhei+2)..";1,1;advtrains_cpl_lock.png;dcpl_ulck_"..i..";]"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if i == data.pos_in_trainparts then
|
if i == data.pos_in_trainparts then
|
||||||
|
@ -824,18 +817,6 @@ function wagon:show_bordcom(pname)
|
||||||
if couple_back then
|
if couple_back then
|
||||||
form = form .. "image_button["..(#train.trainparts+0.5)..","..(linhei+1)..";1,1;advtrains_couple.png;cpl_b;]"
|
form = form .. "image_button["..(#train.trainparts+0.5)..","..(linhei+1)..";1,1;advtrains_couple.png;cpl_b;]"
|
||||||
end
|
end
|
||||||
if owns_any then
|
|
||||||
if train.couple_lck_front then
|
|
||||||
form = form .. "image_button[0.5,"..(linhei+2)..";1,1;advtrains_cpl_lock.png;cpl_ulck_f;]"
|
|
||||||
else
|
|
||||||
form = form .. "image_button[0.5,"..(linhei+2)..";1,1;advtrains_cpl_unlock.png;cpl_lck_f;]"
|
|
||||||
end
|
|
||||||
if train.couple_lck_back then
|
|
||||||
form = form .. "image_button["..(#train.trainparts+0.5)..","..(linhei+2)..";1,1;advtrains_cpl_lock.png;cpl_ulck_b;]"
|
|
||||||
else
|
|
||||||
form = form .. "image_button["..(#train.trainparts+0.5)..","..(linhei+2)..";1,1;advtrains_cpl_unlock.png;cpl_lck_b;]"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
else
|
else
|
||||||
form=form.."label[0.5,4.5;Train overview / coupling control is only shown when the train stands.]"
|
form=form.."label[0.5,4.5;Train overview / coupling control is only shown when the train stands.]"
|
||||||
|
@ -887,24 +868,6 @@ function wagon:handle_bordcom_fields(pname, formname, fields)
|
||||||
if fields["dcpl_"..i] then
|
if fields["dcpl_"..i] then
|
||||||
advtrains.safe_decouple_wagon(tpid, pname)
|
advtrains.safe_decouple_wagon(tpid, pname)
|
||||||
end
|
end
|
||||||
if i>1 and fields["dcpl_lck_"..i] then
|
|
||||||
local ent = advtrains.wagons[tpid]
|
|
||||||
local pent = advtrains.wagons[train.trainparts[i-1]]
|
|
||||||
if ent and pent then
|
|
||||||
if checklock(pname, ent.owner, pent.owner, ent.whitelist, pent.whitelist) then
|
|
||||||
ent.dcpl_lock = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if i>1 and fields["dcpl_ulck_"..i] then
|
|
||||||
local ent = advtrains.wagons[tpid]
|
|
||||||
local pent = advtrains.wagons[train.trainparts[i-1]]
|
|
||||||
if ent and pent then
|
|
||||||
if checklock(pname, ent.owner, pent.owner, ent.whitelist, pent.whitelist) then
|
|
||||||
ent.dcpl_lock = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
--check cpl_eid_front and _back of train
|
--check cpl_eid_front and _back of train
|
||||||
local couple_front = checkcouple(train.cpl_front)
|
local couple_front = checkcouple(train.cpl_front)
|
||||||
|
@ -917,29 +880,6 @@ function wagon:handle_bordcom_fields(pname, formname, fields)
|
||||||
couple_back:on_rightclick(pname)
|
couple_back:on_rightclick(pname)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function chkownsany()
|
|
||||||
local owns_any = minetest.check_player_privs(pname, "train_admin")
|
|
||||||
for i, tpid in ipairs(train.trainparts) do
|
|
||||||
local ent = advtrains.wagons[tpid]
|
|
||||||
if ent then
|
|
||||||
owns_any = owns_any or advtrains.check_driving_couple_protection(pname, ent.owner, ent.whitelist)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return owns_any
|
|
||||||
end
|
|
||||||
if fields.cpl_lck_f and chkownsany() then
|
|
||||||
train.couple_lck_front=true
|
|
||||||
end
|
|
||||||
if fields.cpl_lck_b and chkownsany() then
|
|
||||||
train.couple_lck_back=true
|
|
||||||
end
|
|
||||||
if fields.cpl_ulck_f and chkownsany() then
|
|
||||||
train.couple_lck_front=false
|
|
||||||
end
|
|
||||||
if fields.cpl_ulck_b and chkownsany() then
|
|
||||||
train.couple_lck_back=false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Interlocking functionality: If the interlocking module is loaded, you can set the signal aspect
|
-- Interlocking functionality: If the interlocking module is loaded, you can set the signal aspect
|
||||||
-- from inside the train
|
-- from inside the train
|
||||||
if fields.ilrs and advtrains.interlocking and train.lzb and #train.lzb.oncoming > 0 then
|
if fields.ilrs and advtrains.interlocking and train.lzb and #train.lzb.oncoming > 0 then
|
||||||
|
@ -1073,6 +1013,97 @@ function wagon:reattach_all()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function check_twagon_owner(train, b_first, pname)
|
||||||
|
local wtp = b_first and 1 or #train.trainparts
|
||||||
|
atdebug("wtp",wtp)
|
||||||
|
local wid = train.trainparts[wtp]
|
||||||
|
local wdata = advtrains.wagons[wid]
|
||||||
|
if wdata then
|
||||||
|
return advtrains.check_driving_couple_protection(pname, wdata.owner, wdata.whitelist)
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
function advtrains.safe_couple_trains(id1, id2, t1f, t2f, pname, try_run)
|
||||||
|
|
||||||
|
if not minetest.check_player_privs(pname, "train_operator") then
|
||||||
|
minetest.chat_send_player(pname, "Missing train_operator privilege")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local train1=advtrains.trains[id1]
|
||||||
|
local train2=advtrains.trains[id2]
|
||||||
|
|
||||||
|
if not advtrains.train_ensure_init(id1, train1)
|
||||||
|
or not advtrains.train_ensure_init(id2, train2) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
local wck_t1 = check_twagon_owner(train1, t1f, pname)
|
||||||
|
local wck_t2 = check_twagon_owner(train2, t2f, pname)
|
||||||
|
|
||||||
|
if wck_t1 or wck_t2 then
|
||||||
|
if try_run then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if t1f then
|
||||||
|
if t2f then
|
||||||
|
advtrains.invert_train(id1)
|
||||||
|
advtrains.do_connect_trains(id1, id2)
|
||||||
|
else
|
||||||
|
advtrains.do_connect_trains(id2, id1)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if t2f then
|
||||||
|
advtrains.do_connect_trains(id1, id2)
|
||||||
|
else
|
||||||
|
advtrains.invert_train(id2)
|
||||||
|
advtrains.do_connect_trains(id1, id2)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
else
|
||||||
|
minetest.chat_send_player(pname, "You must be authorized for at least one wagon.")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function advtrains.safe_decouple_wagon(w_id, pname, try_run)
|
||||||
|
if not minetest.check_player_privs(pname, "train_operator") then
|
||||||
|
minetest.chat_send_player(pname, "Missing train_operator privilege")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local data = advtrains.wagons[w_id]
|
||||||
|
|
||||||
|
local dpt = data.pos_in_trainparts
|
||||||
|
if not dpt or dpt <= 1 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
local train = advtrains.trains[data.train_id]
|
||||||
|
local owid = train.trainparts[dpt-1]
|
||||||
|
local owdata = advtrains.wagons[owid]
|
||||||
|
|
||||||
|
if not owdata then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if not checklock(pname, data.owner, owdata.owner, data.whitelist, owdata.whitelist) then
|
||||||
|
minetest.chat_send_player(pname, "Not allowed to do this.")
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
if try_run then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
advtrains.log("Discouple", pname, train.last_pos, train.text_outside)
|
||||||
|
advtrains.split_train_at_wagon(w_id)
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function advtrains.get_wagon_prototype(data)
|
function advtrains.get_wagon_prototype(data)
|
||||||
local wt = data.type
|
local wt = data.type
|
||||||
if not wt then
|
if not wt then
|
||||||
|
|
Loading…
Reference in New Issue