Multiple major changes:
- implement wagon properties and seat group access check - fix a server warning about unassigned variable - refill advtrains.detector.on_node every step - reorder train step function(s): - fixed bug that some atc rails were not recognized - saving some extra calculations - integrate path prediction directly to step functions and separate it (also see comment directly above train_step_a()) - add couple lock feature (can't couple or discouple from wagon with locked couples) - ...master
parent
262f425966
commit
83c859b13a
|
@ -198,7 +198,7 @@ function atc.execute_atc_command(id, train)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
--conditional statement?
|
--conditional statement?
|
||||||
local is_cond, cond_applies
|
local is_cond, cond_applies, compare
|
||||||
local cond, rest=string.match(command, "^I([%+%-])(.+)$")
|
local cond, rest=string.match(command, "^I([%+%-])(.+)$")
|
||||||
if cond then
|
if cond then
|
||||||
is_cond=true
|
is_cond=true
|
||||||
|
|
|
@ -31,7 +31,7 @@ minetest.register_entity("advtrains:discouple", {
|
||||||
on_punch=function(self, player)
|
on_punch=function(self, player)
|
||||||
--only if player owns at least one wagon next to this
|
--only if player owns at least one wagon next to this
|
||||||
local own=player:get_player_name()
|
local own=player:get_player_name()
|
||||||
if self.wagon.owner and self.wagon.owner==own then
|
if self.wagon.owner and self.wagon.owner==own and not self.wagon.lock_couples then
|
||||||
local train=advtrains.trains[self.wagon.train_id]
|
local train=advtrains.trains[self.wagon.train_id]
|
||||||
local nextwgn_id=train.trainparts[self.wagon.pos_in_trainparts-1]
|
local nextwgn_id=train.trainparts[self.wagon.pos_in_trainparts-1]
|
||||||
for aoi, le in pairs(minetest.luaentities) do
|
for aoi, le in pairs(minetest.luaentities) do
|
||||||
|
@ -46,6 +46,8 @@ minetest.register_entity("advtrains:discouple", {
|
||||||
end
|
end
|
||||||
advtrains.split_train_at_wagon(self.wagon)--found in trainlogic.lua
|
advtrains.split_train_at_wagon(self.wagon)--found in trainlogic.lua
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
|
elseif self.wagon.lock_couples then
|
||||||
|
minetest.chat_send_player(own, "Couples of one of the wagons are locked, can't discouple!")
|
||||||
else
|
else
|
||||||
minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple."))
|
minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple."))
|
||||||
end
|
end
|
||||||
|
@ -99,24 +101,24 @@ minetest.register_entity("advtrains:couple", {
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
get_staticdata=function(self) return "COUPLE" end,
|
get_staticdata=function(self) return "COUPLE" end,
|
||||||
on_rightclick=function(self)
|
on_rightclick=function(self, clicker)
|
||||||
if not self.train_id_1 or not self.train_id_2 then return end
|
if not self.train_id_1 or not self.train_id_2 then return end
|
||||||
|
|
||||||
local id1, id2=self.train_id_1, self.train_id_2
|
local id1, id2=self.train_id_1, self.train_id_2
|
||||||
|
|
||||||
if self.train1_is_backpos and not self.train2_is_backpos then
|
if self.train1_is_backpos and not self.train2_is_backpos then
|
||||||
advtrains.do_connect_trains(id1, id2)
|
advtrains.do_connect_trains(id1, id2, clicker)
|
||||||
--case 2 (second train is front)
|
--case 2 (second train is front)
|
||||||
elseif self.train2_is_backpos and not self.train1_is_backpos then
|
elseif self.train2_is_backpos and not self.train1_is_backpos then
|
||||||
advtrains.do_connect_trains(id2, id1)
|
advtrains.do_connect_trains(id2, id1, clicker)
|
||||||
--case 3
|
--case 3
|
||||||
elseif self.train1_is_backpos and self.train2_is_backpos then
|
elseif self.train1_is_backpos and self.train2_is_backpos then
|
||||||
advtrains.invert_train(id2)
|
advtrains.invert_train(id2)
|
||||||
advtrains.do_connect_trains(id1, id2)
|
advtrains.do_connect_trains(id1, id2, clicker)
|
||||||
--case 4
|
--case 4
|
||||||
elseif not self.train1_is_backpos and not self.train2_is_backpos then
|
elseif not self.train1_is_backpos and not self.train2_is_backpos then
|
||||||
advtrains.invert_train(id1)
|
advtrains.invert_train(id1)
|
||||||
advtrains.do_connect_trains(id1, id2)
|
advtrains.do_connect_trains(id1, id2, clicker)
|
||||||
end
|
end
|
||||||
self.object:remove()
|
self.object:remove()
|
||||||
end,
|
end,
|
||||||
|
|
|
@ -386,76 +386,27 @@ end
|
||||||
|
|
||||||
advtrains.detector = {}
|
advtrains.detector = {}
|
||||||
advtrains.detector.on_node = {}
|
advtrains.detector.on_node = {}
|
||||||
advtrains.detector.on_node_restore = {}
|
|
||||||
--set if paths were invalidated before. tells trainlogic.lua to call advtrains.detector.finalize_restore()
|
|
||||||
advtrains.detector.clean_step_before = false
|
|
||||||
|
|
||||||
--when train enters a node, call this
|
|
||||||
--The entry already being contained in advtrains.detector.on_node_restore will not trigger an on_train_enter event on the node. (when path is reset, this is saved).
|
|
||||||
function advtrains.detector.enter_node(pos, train_id)
|
function advtrains.detector.enter_node(pos, train_id)
|
||||||
local pts = minetest.pos_to_string(advtrains.round_vector_floor_y(pos))
|
local ppos=advtrains.round_vector_floor_y(pos)
|
||||||
--atprint("enterNode "..pts.." "..sid(train_id))
|
local pts=minetest.pos_to_string(ppos)
|
||||||
if advtrains.detector.on_node[pts] then
|
|
||||||
if advtrains.trains[advtrains.detector.on_node[pts]] then
|
|
||||||
--atprint(""..pts.." already occupied")
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
advtrains.detector.leave_node(pos, advtrains.detector.on_node[pts])
|
|
||||||
end
|
|
||||||
end
|
|
||||||
advtrains.detector.on_node[pts]=train_id
|
advtrains.detector.on_node[pts]=train_id
|
||||||
if advtrains.detector.on_node_restore[pts]==train_id then
|
advtrains.detector.call_enter_callback(ppos, train_id)
|
||||||
advtrains.detector.on_node_restore[pts]=nil
|
|
||||||
else
|
|
||||||
advtrains.detector.call_enter_callback(advtrains.round_vector_floor_y(pos), train_id)
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
function advtrains.detector.leave_node(pos, train_id)
|
function advtrains.detector.leave_node(pos, train_id)
|
||||||
local pts = minetest.pos_to_string(advtrains.round_vector_floor_y(pos))
|
local ppos=advtrains.round_vector_floor_y(pos)
|
||||||
--atprint("leaveNode "..pts.." "..sid(train_id))
|
local pts=minetest.pos_to_string(ppos)
|
||||||
if not advtrains.detector.on_node[pts] then
|
advtrains.detector.on_node[pts]=nil
|
||||||
--atprint(""..pts.." leave: nothing here")
|
advtrains.detector.call_leave_callback(ppos, train_id)
|
||||||
return false
|
|
||||||
end
|
|
||||||
if advtrains.detector.on_node[pts]==train_id then
|
|
||||||
advtrains.detector.call_leave_callback(advtrains.round_vector_floor_y(pos), train_id)
|
|
||||||
advtrains.detector.on_node[pts]=nil
|
|
||||||
else
|
|
||||||
if advtrains.trains[advtrains.detector.on_node[pts]] then
|
|
||||||
--atprint(""..pts.." occupied by another train")
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
advtrains.detector.leave_node(pos, advtrains.detector.on_node[pts])
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
end
|
||||||
--called immediately before invalidating paths
|
function advtrains.detector.stay_node(pos, train_id)
|
||||||
function advtrains.detector.setup_restore()
|
local ppos=advtrains.round_vector_floor_y(pos)
|
||||||
--atprint("setup_restore")
|
local pts=minetest.pos_to_string(ppos)
|
||||||
-- don't execute if it already has been called. For some reason it gets called twice...
|
advtrains.detector.on_node[pts]=train_id
|
||||||
if advtrains.detector.clean_step_before then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
advtrains.detector.on_node_restore={}
|
|
||||||
for k, v in pairs(advtrains.detector.on_node) do
|
|
||||||
advtrains.detector.on_node_restore[k]=v
|
|
||||||
end
|
|
||||||
advtrains.detector.on_node = {}
|
|
||||||
advtrains.detector.clean_step_before = true
|
|
||||||
end
|
|
||||||
--called one step after invalidating paths, when all trains have restored their path and called enter_node for their contents.
|
|
||||||
function advtrains.detector.finalize_restore()
|
|
||||||
--atprint("finalize_restore")
|
|
||||||
for pts, train_id in pairs(advtrains.detector.on_node_restore) do
|
|
||||||
--atprint("called leave callback "..pts.." "..train_id)
|
|
||||||
advtrains.detector.call_leave_callback(minetest.string_to_pos(pts), train_id)
|
|
||||||
end
|
|
||||||
advtrains.detector.on_node_restore = {}
|
|
||||||
advtrains.detector.clean_step_before = false
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function advtrains.detector.call_enter_callback(pos, train_id)
|
function advtrains.detector.call_enter_callback(pos, train_id)
|
||||||
--atprint("instructed to call enter calback")
|
--atprint("instructed to call enter calback")
|
||||||
|
|
||||||
|
|
|
@ -50,22 +50,47 @@ minetest.register_globalstep(function(dtime)
|
||||||
atprintbm("saving", t)
|
atprintbm("saving", t)
|
||||||
end
|
end
|
||||||
--regular train step
|
--regular train step
|
||||||
|
-- do in two steps:
|
||||||
|
-- a: predict path and add all nodes to the advtrains.detector.on_node table
|
||||||
|
-- b: check for collisions based on these data
|
||||||
|
-- (and more)
|
||||||
local t=os.clock()
|
local t=os.clock()
|
||||||
|
advtrains.detector.on_node={}
|
||||||
for k,v in pairs(advtrains.trains) do
|
for k,v in pairs(advtrains.trains) do
|
||||||
advtrains.train_step(k, v, dtime)
|
advtrains.train_step_a(k, v, dtime)
|
||||||
end
|
end
|
||||||
|
for k,v in pairs(advtrains.trains) do
|
||||||
--see tracks.lua
|
advtrains.train_step_b(k, v, dtime)
|
||||||
if advtrains.detector.clean_step_before then
|
|
||||||
advtrains.detector.finalize_restore()
|
|
||||||
end
|
end
|
||||||
|
|
||||||
atprintbm("trainsteps", t)
|
atprintbm("trainsteps", t)
|
||||||
endstep()
|
endstep()
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function advtrains.train_step(id, train, dtime)
|
--[[
|
||||||
--Legacy: set drives_on and max_speed
|
train step structure:
|
||||||
|
|
||||||
|
|
||||||
|
- legacy stuff
|
||||||
|
- preparing the initial path and creating index
|
||||||
|
- setting node coverage old indices
|
||||||
|
- handle velocity influences:
|
||||||
|
- off-track
|
||||||
|
- atc
|
||||||
|
- player controls
|
||||||
|
- environment collision
|
||||||
|
- update index = move
|
||||||
|
- create path
|
||||||
|
- update node coverage
|
||||||
|
- do less important stuff such as checking trainpartload or removing
|
||||||
|
|
||||||
|
-- break --
|
||||||
|
- handle train collisions
|
||||||
|
|
||||||
|
]]
|
||||||
|
|
||||||
|
function advtrains.train_step_a(id, train, dtime)
|
||||||
|
--- 1. LEGACY STUFF ---
|
||||||
if not train.drives_on or not train.max_speed then
|
if not train.drives_on or not train.max_speed then
|
||||||
advtrains.update_trainpart_properties(id)
|
advtrains.update_trainpart_properties(id)
|
||||||
end
|
end
|
||||||
|
@ -76,258 +101,7 @@ function advtrains.train_step(id, train, dtime)
|
||||||
if not train.movedir or (train.movedir~=1 and train.movedir~=-1) then
|
if not train.movedir or (train.movedir~=1 and train.movedir~=-1) then
|
||||||
train.movedir=1
|
train.movedir=1
|
||||||
end
|
end
|
||||||
--very unimportant thing: check if couple is here
|
--- 2. prepare initial path and index if needed ---
|
||||||
if train.couple_eid_front and (not minetest.luaentities[train.couple_eid_front] or not minetest.luaentities[train.couple_eid_front].is_couple) then train.couple_eid_front=nil end
|
|
||||||
if train.couple_eid_back and (not minetest.luaentities[train.couple_eid_back] or not minetest.luaentities[train.couple_eid_back].is_couple) then train.couple_eid_back=nil end
|
|
||||||
|
|
||||||
--skip certain things (esp. collision) when not moving
|
|
||||||
local train_moves=(train.velocity~=0)
|
|
||||||
|
|
||||||
--if not train.last_pos then advtrains.trains[id]=nil return end
|
|
||||||
|
|
||||||
if not advtrains.pathpredict(id, train) then
|
|
||||||
atprint("pathpredict failed(returned false)")
|
|
||||||
train.velocity=0
|
|
||||||
train.tarvelocity=0
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local path=advtrains.get_or_create_path(id, train)
|
|
||||||
if not path then
|
|
||||||
train.velocity=0
|
|
||||||
train.tarvelocity=0
|
|
||||||
atprint("train has no path for whatever reason")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local train_end_index=advtrains.get_train_end_index(train)
|
|
||||||
--apply off-track handling:
|
|
||||||
local front_off_track=train.max_index_on_track and train.index>train.max_index_on_track
|
|
||||||
local back_off_track=train.min_index_on_track and train_end_index<train.min_index_on_track
|
|
||||||
if front_off_track and back_off_track then--allow movement in both directions
|
|
||||||
if train.tarvelocity>1 then train.tarvelocity=1 end
|
|
||||||
elseif front_off_track then--allow movement only backward
|
|
||||||
if train.movedir==1 and train.tarvelocity>0 then train.tarvelocity=0 end
|
|
||||||
if train.movedir==-1 and train.tarvelocity>1 then train.tarvelocity=1 end
|
|
||||||
elseif back_off_track then--allow movement only forward
|
|
||||||
if train.movedir==-1 and train.tarvelocity>0 then train.tarvelocity=0 end
|
|
||||||
if train.movedir==1 and train.tarvelocity>1 then train.tarvelocity=1 end
|
|
||||||
end
|
|
||||||
|
|
||||||
--update advtrains.detector
|
|
||||||
if not train.detector_old_index then
|
|
||||||
train.detector_old_index = math.floor(train_end_index)
|
|
||||||
train.detector_old_end_index = math.floor(train_end_index)
|
|
||||||
end
|
|
||||||
local ifo, ifn, ibo, ibn = train.detector_old_index, math.floor(train.index), train.detector_old_end_index, math.floor(train_end_index)
|
|
||||||
if ifn>ifo then
|
|
||||||
for i=ifo, ifn do
|
|
||||||
if path[i] then
|
|
||||||
advtrains.detector.enter_node(path[i], id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif ifn<ifo then
|
|
||||||
for i=ifn, ifo do
|
|
||||||
if path[i] then
|
|
||||||
advtrains.detector.leave_node(path[i], id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if ibn<ibo then
|
|
||||||
for i=ibn, ibn do
|
|
||||||
if path[i] then
|
|
||||||
advtrains.detector.enter_node(path[i], id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif ibn>ibo then
|
|
||||||
for i=ibo, ibn do
|
|
||||||
if path[i] then
|
|
||||||
advtrains.detector.leave_node(path[i], id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
train.detector_old_index = math.floor(train.index)
|
|
||||||
train.detector_old_end_index = math.floor(train_end_index)
|
|
||||||
|
|
||||||
--remove?
|
|
||||||
if #train.trainparts==0 then
|
|
||||||
atprint("[train "..sid(id).."] has empty trainparts, removing.")
|
|
||||||
advtrains.detector.leave_node(path[train.detector_old_index], id)
|
|
||||||
advtrains.trains[id]=nil
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
if train_moves then
|
|
||||||
--check for collisions by finding objects
|
|
||||||
|
|
||||||
--heh, new collision again.
|
|
||||||
--this time, based on NODES and the advtrains.detector.on_node table.
|
|
||||||
local collpos
|
|
||||||
local coll_grace=1
|
|
||||||
if train.movedir==1 then
|
|
||||||
collpos=advtrains.get_real_index_position(path, train.index-coll_grace)
|
|
||||||
else
|
|
||||||
collpos=advtrains.get_real_index_position(path, train_end_index+coll_grace)
|
|
||||||
end
|
|
||||||
if collpos then
|
|
||||||
local rcollpos=advtrains.round_vector_floor_y(collpos)
|
|
||||||
for x=-1,1 do
|
|
||||||
for z=-1,1 do
|
|
||||||
local testpos=vector.add(rcollpos, {x=x, y=0, z=z})
|
|
||||||
local testpts=minetest.pos_to_string(testpos)
|
|
||||||
if advtrains.detector.on_node[testpts] and advtrains.detector.on_node[testpts]~=id then
|
|
||||||
if advtrains.trains[advtrains.detector.on_node[testpts]] then
|
|
||||||
--collides
|
|
||||||
advtrains.spawn_couple_on_collide(id, testpos, advtrains.detector.on_node[testpts], train.movedir==-1)
|
|
||||||
|
|
||||||
train.recently_collided_with_env=true
|
|
||||||
train.velocity=0.5*train.velocity
|
|
||||||
train.movedir=train.movedir*-1
|
|
||||||
train.tarvelocity=0
|
|
||||||
else
|
|
||||||
--unexistant train left in this place
|
|
||||||
advtrains.detector.on_node[testpts]=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
--check for any trainpart entities if they have been unloaded. do this only if train is near a player, to not spawn entities into unloaded areas
|
|
||||||
--todo function will be taken by update_trainpart_properties
|
|
||||||
train.check_trainpartload=(train.check_trainpartload or 0)-dtime
|
|
||||||
local node_range=(math.max((minetest.setting_get("active_block_range") or 0),1)*16)
|
|
||||||
if train.check_trainpartload<=0 then
|
|
||||||
local ori_pos=advtrains.get_real_index_position(path, train.index) --not much to calculate
|
|
||||||
--atprint("[train "..id.."] at "..minetest.pos_to_string(vector.round(ori_pos)))
|
|
||||||
|
|
||||||
local should_check=false
|
|
||||||
for _,p in ipairs(minetest.get_connected_players()) do
|
|
||||||
should_check=should_check or ((vector.distance(ori_pos, p:getpos())<node_range))
|
|
||||||
end
|
|
||||||
if should_check then
|
|
||||||
advtrains.update_trainpart_properties(id)
|
|
||||||
end
|
|
||||||
train.check_trainpartload=2
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--handle collided_with_env
|
|
||||||
if train.recently_collided_with_env then
|
|
||||||
train.tarvelocity=0
|
|
||||||
if not train_moves then
|
|
||||||
train.recently_collided_with_env=false--reset status when stopped
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if train.locomotives_in_train==0 then
|
|
||||||
train.tarvelocity=0
|
|
||||||
end
|
|
||||||
|
|
||||||
--interpret ATC command
|
|
||||||
if train.atc_brake_target and train.atc_brake_target>=train.velocity then
|
|
||||||
train.atc_brake_target=nil
|
|
||||||
end
|
|
||||||
if train.atc_wait_finish then
|
|
||||||
if not train.atc_brake_target and train.velocity==train.tarvelocity then
|
|
||||||
train.atc_wait_finish=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if train.atc_command then
|
|
||||||
if train.atc_delay<=0 and not train.atc_wait_finish then
|
|
||||||
advtrains.atc.execute_atc_command(id, train)
|
|
||||||
else
|
|
||||||
train.atc_delay=train.atc_delay-dtime
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--make brake adjust the tarvelocity if necessary
|
|
||||||
if train.brake and (math.ceil(train.velocity)-1)<train.tarvelocity then
|
|
||||||
train.tarvelocity=math.max((math.ceil(train.velocity)-1), 0)
|
|
||||||
end
|
|
||||||
--apply tarvel(but with physics in mind!)
|
|
||||||
if train.velocity~=train.tarvelocity then
|
|
||||||
local applydiff=0
|
|
||||||
local mass=#train.trainparts
|
|
||||||
local diff=train.tarvelocity-train.velocity
|
|
||||||
if diff>0 then--accelerating, force will be brought on only by locomotives.
|
|
||||||
--atprint("accelerating with default force")
|
|
||||||
applydiff=(math.min((advtrains.train_accel_force*train.locomotives_in_train*dtime)/mass, math.abs(diff)))
|
|
||||||
else--decelerating
|
|
||||||
if front_off_track or back_off_track or train.recently_collided_with_env then --every wagon has a brake, so not divided by mass.
|
|
||||||
--atprint("braking with emergency force")
|
|
||||||
applydiff= -(math.min((advtrains.train_emerg_force*dtime), math.abs(diff)))
|
|
||||||
elseif train.brake or (train.atc_brake_target and train.atc_brake_target<train.velocity) then
|
|
||||||
--atprint("braking with default force")
|
|
||||||
--no math.min, because it can grow beyond tarvelocity, see up there
|
|
||||||
--dont worry, it will never fall below zero.
|
|
||||||
applydiff= -((advtrains.train_brake_force*dtime))
|
|
||||||
else
|
|
||||||
--atprint("roll")
|
|
||||||
applydiff= -(math.min((advtrains.train_roll_force*dtime), math.abs(diff)))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
train.last_accel=(applydiff*train.movedir)
|
|
||||||
train.velocity=math.min(math.max( train.velocity+applydiff , 0), train.max_speed or 10)
|
|
||||||
else
|
|
||||||
train.last_accel=0
|
|
||||||
end
|
|
||||||
|
|
||||||
--move
|
|
||||||
--TODO 3,5 + 0.7
|
|
||||||
train.index=train.index and train.index+(((train.velocity*train.movedir)/(train.path_dist[math.floor(train.index)] or 1))*dtime) or 0
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
--structure of train table:
|
|
||||||
--[[
|
|
||||||
trains={
|
|
||||||
[train_id]={
|
|
||||||
trainparts={
|
|
||||||
[n]=wagon_id
|
|
||||||
}
|
|
||||||
path={path}
|
|
||||||
velocity
|
|
||||||
tarvelocity
|
|
||||||
index
|
|
||||||
trainlen
|
|
||||||
path_inv_level
|
|
||||||
last_pos |
|
|
||||||
last_dir | for pathpredicting.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
--a wagon itself has the following properties:
|
|
||||||
wagon={
|
|
||||||
unique_id
|
|
||||||
train_id
|
|
||||||
pos_in_train (is index difference, including train_span stuff)
|
|
||||||
pos_in_trainparts (is index in trainparts tabel of trains)
|
|
||||||
}
|
|
||||||
inherited by metatable:
|
|
||||||
wagon_proto={
|
|
||||||
wagon_span
|
|
||||||
}
|
|
||||||
]]
|
|
||||||
|
|
||||||
--returns new id
|
|
||||||
function advtrains.create_new_train_at(pos, pos_prev)
|
|
||||||
local newtrain_id=os.time()..os.clock()
|
|
||||||
while advtrains.trains[newtrain_id] do newtrain_id=os.time()..os.clock() end--ensure uniqueness(will be unneccessary)
|
|
||||||
|
|
||||||
advtrains.trains[newtrain_id]={}
|
|
||||||
advtrains.trains[newtrain_id].last_pos=pos
|
|
||||||
advtrains.trains[newtrain_id].last_pos_prev=pos_prev
|
|
||||||
advtrains.trains[newtrain_id].tarvelocity=0
|
|
||||||
advtrains.trains[newtrain_id].velocity=0
|
|
||||||
advtrains.trains[newtrain_id].trainparts={}
|
|
||||||
return newtrain_id
|
|
||||||
end
|
|
||||||
|
|
||||||
--returns false on failure. handle this case!
|
|
||||||
function advtrains.pathpredict(id, train)
|
|
||||||
|
|
||||||
--atprint("pos ",x,y,z)
|
|
||||||
--::rerun::
|
|
||||||
if not train.index then train.index=0 end
|
if not train.index then train.index=0 end
|
||||||
if not train.path or #train.path<2 then
|
if not train.path or #train.path<2 then
|
||||||
if not train.last_pos then
|
if not train.last_pos then
|
||||||
|
@ -376,21 +150,112 @@ function advtrains.pathpredict(id, train)
|
||||||
train.path[0]=train.last_pos
|
train.path[0]=train.last_pos
|
||||||
train.path[-1]=train.last_pos_prev
|
train.path[-1]=train.last_pos_prev
|
||||||
train.path_dist[-1]=vector.distance(train.last_pos, train.last_pos_prev)
|
train.path_dist[-1]=vector.distance(train.last_pos, train.last_pos_prev)
|
||||||
|
train.path_extent_min=-1
|
||||||
|
train.path_extent_max=0
|
||||||
end
|
end
|
||||||
|
|
||||||
local pregen_front=2
|
--- 2a. set train.end_index which is required in different places, IF IT IS NOT SET YET by STMT afterwards. ---
|
||||||
local pregen_back=2
|
--- table entry to avoid triple recalculation ---
|
||||||
if train.velocity>0 then
|
if not train.end_index then
|
||||||
if train.movedir>0 then
|
train.end_index=advtrains.get_train_end_index(train)
|
||||||
pregen_front=2+math.ceil(train.velocity*0.15) --assumes server step of 0.1 seconds, +50% tolerance
|
end
|
||||||
|
|
||||||
|
--- 2b. set node coverage old indices ---
|
||||||
|
|
||||||
|
train.detector_old_index = math.floor(train.index)
|
||||||
|
train.detector_old_end_index = math.floor(train.end_index)
|
||||||
|
|
||||||
|
--- 3. handle velocity influences ---
|
||||||
|
local train_moves=(train.velocity~=0)
|
||||||
|
|
||||||
|
if train.recently_collided_with_env then
|
||||||
|
train.tarvelocity=0
|
||||||
|
if not train_moves then
|
||||||
|
train.recently_collided_with_env=false--reset status when stopped
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if train.locomotives_in_train==0 then
|
||||||
|
train.tarvelocity=0
|
||||||
|
end
|
||||||
|
|
||||||
|
--apply off-track handling:
|
||||||
|
--won't take any effect immediately after path reset because index_on_track not set, but that's not severe.
|
||||||
|
local front_off_track=train.max_index_on_track and train.index>train.max_index_on_track
|
||||||
|
local back_off_track=train.min_index_on_track and train.end_index<train.min_index_on_track
|
||||||
|
if front_off_track and back_off_track then--allow movement in both directions
|
||||||
|
if train.tarvelocity>1 then train.tarvelocity=1 end
|
||||||
|
elseif front_off_track then--allow movement only backward
|
||||||
|
if train.movedir==1 and train.tarvelocity>0 then train.tarvelocity=0 end
|
||||||
|
if train.movedir==-1 and train.tarvelocity>1 then train.tarvelocity=1 end
|
||||||
|
elseif back_off_track then--allow movement only forward
|
||||||
|
if train.movedir==-1 and train.tarvelocity>0 then train.tarvelocity=0 end
|
||||||
|
if train.movedir==1 and train.tarvelocity>1 then train.tarvelocity=1 end
|
||||||
|
end
|
||||||
|
|
||||||
|
--interpret ATC command
|
||||||
|
if train.atc_brake_target and train.atc_brake_target>=train.velocity then
|
||||||
|
train.atc_brake_target=nil
|
||||||
|
end
|
||||||
|
if train.atc_wait_finish then
|
||||||
|
if not train.atc_brake_target and train.velocity==train.tarvelocity then
|
||||||
|
train.atc_wait_finish=nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if train.atc_command then
|
||||||
|
if train.atc_delay<=0 and not train.atc_wait_finish then
|
||||||
|
advtrains.atc.execute_atc_command(id, train)
|
||||||
else
|
else
|
||||||
pregen_back=2+math.ceil(train.velocity*0.15)
|
train.atc_delay=train.atc_delay-dtime
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
--make brake adjust the tarvelocity if necessary
|
||||||
|
if train.brake and (math.ceil(train.velocity)-1)<train.tarvelocity then
|
||||||
|
train.tarvelocity=math.max((math.ceil(train.velocity)-1), 0)
|
||||||
|
end
|
||||||
|
|
||||||
local maxn=train.max_index_on_track or 0
|
--- 3a. actually calculate new velocity ---
|
||||||
while (maxn-train.index) < pregen_front do--pregenerate
|
if train.velocity~=train.tarvelocity then
|
||||||
|
local applydiff=0
|
||||||
|
local mass=#train.trainparts
|
||||||
|
local diff=train.tarvelocity-train.velocity
|
||||||
|
if diff>0 then--accelerating, force will be brought on only by locomotives.
|
||||||
|
--atprint("accelerating with default force")
|
||||||
|
applydiff=(math.min((advtrains.train_accel_force*train.locomotives_in_train*dtime)/mass, math.abs(diff)))
|
||||||
|
else--decelerating
|
||||||
|
if front_off_track or back_off_track or train.recently_collided_with_env then --every wagon has a brake, so not divided by mass.
|
||||||
|
--atprint("braking with emergency force")
|
||||||
|
applydiff= -(math.min((advtrains.train_emerg_force*dtime), math.abs(diff)))
|
||||||
|
elseif train.brake or (train.atc_brake_target and train.atc_brake_target<train.velocity) then
|
||||||
|
--atprint("braking with default force")
|
||||||
|
--no math.min, because it can grow beyond tarvelocity, see up there
|
||||||
|
--dont worry, it will never fall below zero.
|
||||||
|
applydiff= -((advtrains.train_brake_force*dtime))
|
||||||
|
else
|
||||||
|
--atprint("roll")
|
||||||
|
applydiff= -(math.min((advtrains.train_roll_force*dtime), math.abs(diff)))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
train.last_accel=(applydiff*train.movedir)
|
||||||
|
train.velocity=math.min(math.max( train.velocity+applydiff , 0), train.max_speed or 10)
|
||||||
|
else
|
||||||
|
train.last_accel=0
|
||||||
|
end
|
||||||
|
|
||||||
|
--- 4. move train ---
|
||||||
|
|
||||||
|
train.index=train.index and train.index+(((train.velocity*train.movedir)/(train.path_dist[math.floor(train.index)] or 1))*dtime) or 0
|
||||||
|
|
||||||
|
--- 4a. update train.end_index to the new position ---
|
||||||
|
train.end_index=advtrains.get_train_end_index(train)
|
||||||
|
|
||||||
|
--- 5. extend path as necessary ---
|
||||||
|
|
||||||
|
local gen_front=math.max(train.index, train.detector_old_index) + 2
|
||||||
|
local gen_back=math.min(train.end_index, train.detector_old_end_index) - 2
|
||||||
|
|
||||||
|
local maxn=train.path_extent_max or 0
|
||||||
|
while maxn < gen_front do--pregenerate
|
||||||
--atprint("maxn conway for ",maxn,minetest.pos_to_string(path[maxn]),maxn-1,minetest.pos_to_string(path[maxn-1]))
|
--atprint("maxn conway for ",maxn,minetest.pos_to_string(path[maxn]),maxn-1,minetest.pos_to_string(path[maxn-1]))
|
||||||
local conway=advtrains.conway(train.path[maxn], train.path[maxn-1], train.drives_on)
|
local conway=advtrains.conway(train.path[maxn], train.path[maxn-1], train.drives_on)
|
||||||
if conway then
|
if conway then
|
||||||
|
@ -405,9 +270,10 @@ function advtrains.pathpredict(id, train)
|
||||||
train.path_dist[maxn]=vector.distance(train.path[maxn+1], train.path[maxn])
|
train.path_dist[maxn]=vector.distance(train.path[maxn+1], train.path[maxn])
|
||||||
maxn=advtrains.maxN(train.path)
|
maxn=advtrains.maxN(train.path)
|
||||||
end
|
end
|
||||||
|
train.path_extent_max=maxn
|
||||||
|
|
||||||
local minn=train.min_index_on_track or -1
|
local minn=train.path_extent_min or -1
|
||||||
while (train.index-minn) < (train.trainlen or 0) + pregen_back do --post_generate. has to be at least trainlen. (we let go of the exact calculation here since this would be unuseful here)
|
while minn > gen_back do
|
||||||
--atprint("minn conway for ",minn,minetest.pos_to_string(path[minn]),minn+1,minetest.pos_to_string(path[minn+1]))
|
--atprint("minn conway for ",minn,minetest.pos_to_string(path[minn]),minn+1,minetest.pos_to_string(path[minn+1]))
|
||||||
local conway=advtrains.conway(train.path[minn], train.path[minn+1], train.drives_on)
|
local conway=advtrains.conway(train.path[minn], train.path[minn+1], train.drives_on)
|
||||||
if conway then
|
if conway then
|
||||||
|
@ -422,7 +288,8 @@ function advtrains.pathpredict(id, train)
|
||||||
train.path_dist[minn-1]=vector.distance(train.path[minn], train.path[minn-1])
|
train.path_dist[minn-1]=vector.distance(train.path[minn], train.path[minn-1])
|
||||||
minn=advtrains.minN(train.path)
|
minn=advtrains.minN(train.path)
|
||||||
end
|
end
|
||||||
if not train.min_index_on_track then train.min_index_on_track=0 end
|
train.path_extent_min=minn
|
||||||
|
if not train.min_index_on_track then train.min_index_on_track=-1 end
|
||||||
if not train.max_index_on_track then train.max_index_on_track=0 end
|
if not train.max_index_on_track then train.max_index_on_track=0 end
|
||||||
|
|
||||||
--make pos/yaw available for possible recover calls
|
--make pos/yaw available for possible recover calls
|
||||||
|
@ -441,15 +308,160 @@ function advtrains.pathpredict(id, train)
|
||||||
train.last_pos=train.path[math.floor(train.index+0.5)]
|
train.last_pos=train.path[math.floor(train.index+0.5)]
|
||||||
train.last_pos_prev=train.path[math.floor(train.index-0.5)]
|
train.last_pos_prev=train.path[math.floor(train.index-0.5)]
|
||||||
end
|
end
|
||||||
return train.path
|
|
||||||
end
|
--- 6. update node coverage ---
|
||||||
function advtrains.get_train_end_index(train)
|
|
||||||
return advtrains.get_real_path_index(train, train.trainlen or 2)--this function can be found inside wagons.lua since it's more related to wagons. we just set trainlen as pos_in_train
|
-- when paths get cleared, the old indices set above will be up-to-date and represent the state in which the last run of this code was made
|
||||||
|
local ifo, ifn, ibo, ibn = train.detector_old_index, math.floor(train.index), train.detector_old_end_index, math.floor(train.end_index)
|
||||||
|
local path=train.path
|
||||||
|
|
||||||
|
for i=ibn, ifn do
|
||||||
|
if path[i] then
|
||||||
|
advtrains.detector.stay_node(path[i], id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if ifn>ifo then
|
||||||
|
for i=ifo+1, ifn do
|
||||||
|
if path[i] then
|
||||||
|
advtrains.detector.enter_node(path[i], id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif ifn<ifo then
|
||||||
|
for i=ifn, ifo-1 do
|
||||||
|
if path[i] then
|
||||||
|
advtrains.detector.leave_node(path[i], id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if ibn<ibo then
|
||||||
|
for i=ibn, ibo-1 do
|
||||||
|
if path[i] then
|
||||||
|
advtrains.detector.enter_node(path[i], id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif ibn>ibo then
|
||||||
|
for i=ibo+1, ibn do
|
||||||
|
if path[i] then
|
||||||
|
advtrains.detector.leave_node(path[i], id)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
--- 7. do less important stuff ---
|
||||||
|
--check for any trainpart entities if they have been unloaded. do this only if train is near a player, to not spawn entities into unloaded areas
|
||||||
|
|
||||||
|
train.check_trainpartload=(train.check_trainpartload or 0)-dtime
|
||||||
|
local node_range=(math.max((minetest.setting_get("active_block_range") or 0),1)*16)
|
||||||
|
if train.check_trainpartload<=0 then
|
||||||
|
local ori_pos=advtrains.get_real_index_position(path, train.index) --not much to calculate
|
||||||
|
--atprint("[train "..id.."] at "..minetest.pos_to_string(vector.round(ori_pos)))
|
||||||
|
|
||||||
|
local should_check=false
|
||||||
|
for _,p in ipairs(minetest.get_connected_players()) do
|
||||||
|
should_check=should_check or ((vector.distance(ori_pos, p:getpos())<node_range))
|
||||||
|
end
|
||||||
|
if should_check then
|
||||||
|
advtrains.update_trainpart_properties(id)
|
||||||
|
end
|
||||||
|
train.check_trainpartload=2
|
||||||
|
end
|
||||||
|
--remove?
|
||||||
|
if #train.trainparts==0 then
|
||||||
|
atprint("[train "..sid(id).."] has empty trainparts, removing.")
|
||||||
|
advtrains.detector.leave_node(path[train.detector_old_index], id)
|
||||||
|
advtrains.trains[id]=nil
|
||||||
|
return
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function advtrains.get_or_create_path(id, train)
|
function advtrains.train_step_b(id, train, dtime)
|
||||||
if not train.path then return advtrains.pathpredict(id, train) end
|
|
||||||
return train.path
|
--- 8. check for collisions with other trains ---
|
||||||
|
|
||||||
|
local train_moves=(train.velocity~=0)
|
||||||
|
|
||||||
|
if train_moves then
|
||||||
|
|
||||||
|
--heh, new collision again.
|
||||||
|
--this time, based on NODES and the advtrains.detector.on_node table.
|
||||||
|
local collpos
|
||||||
|
local coll_grace=1
|
||||||
|
if train.movedir==1 then
|
||||||
|
collpos=advtrains.get_real_index_position(train.path, train.index-coll_grace)
|
||||||
|
else
|
||||||
|
collpos=advtrains.get_real_index_position(train.path, train.end_index+coll_grace)
|
||||||
|
end
|
||||||
|
if collpos then
|
||||||
|
local rcollpos=advtrains.round_vector_floor_y(collpos)
|
||||||
|
for x=-1,1 do
|
||||||
|
for z=-1,1 do
|
||||||
|
local testpos=vector.add(rcollpos, {x=x, y=0, z=z})
|
||||||
|
local testpts=minetest.pos_to_string(testpos)
|
||||||
|
if advtrains.detector.on_node[testpts] and advtrains.detector.on_node[testpts]~=id then
|
||||||
|
--collides
|
||||||
|
advtrains.spawn_couple_on_collide(id, testpos, advtrains.detector.on_node[testpts], train.movedir==-1)
|
||||||
|
|
||||||
|
train.recently_collided_with_env=true
|
||||||
|
train.velocity=0.5*train.velocity
|
||||||
|
train.movedir=train.movedir*-1
|
||||||
|
train.tarvelocity=0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
--structure of train table:
|
||||||
|
--[[
|
||||||
|
trains={
|
||||||
|
[train_id]={
|
||||||
|
trainparts={
|
||||||
|
[n]=wagon_id
|
||||||
|
}
|
||||||
|
path={path}
|
||||||
|
velocity
|
||||||
|
tarvelocity
|
||||||
|
index
|
||||||
|
trainlen
|
||||||
|
path_inv_level
|
||||||
|
last_pos |
|
||||||
|
last_dir | for pathpredicting.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
--a wagon itself has the following properties:
|
||||||
|
wagon={
|
||||||
|
unique_id
|
||||||
|
train_id
|
||||||
|
pos_in_train (is index difference, including train_span stuff)
|
||||||
|
pos_in_trainparts (is index in trainparts tabel of trains)
|
||||||
|
}
|
||||||
|
inherited by metatable:
|
||||||
|
wagon_proto={
|
||||||
|
wagon_span
|
||||||
|
}
|
||||||
|
]]
|
||||||
|
|
||||||
|
--returns new id
|
||||||
|
function advtrains.create_new_train_at(pos, pos_prev)
|
||||||
|
local newtrain_id=os.time()..os.clock()
|
||||||
|
while advtrains.trains[newtrain_id] do newtrain_id=os.time()..os.clock() end--ensure uniqueness(will be unneccessary)
|
||||||
|
|
||||||
|
advtrains.trains[newtrain_id]={}
|
||||||
|
advtrains.trains[newtrain_id].last_pos=pos
|
||||||
|
advtrains.trains[newtrain_id].last_pos_prev=pos_prev
|
||||||
|
advtrains.trains[newtrain_id].tarvelocity=0
|
||||||
|
advtrains.trains[newtrain_id].velocity=0
|
||||||
|
advtrains.trains[newtrain_id].trainparts={}
|
||||||
|
return newtrain_id
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function advtrains.get_train_end_index(train)
|
||||||
|
return advtrains.get_real_path_index(train, train.trainlen or 2)--this function can be found inside wagons.lua since it's more related to wagons. we just set trainlen as pos_in_train
|
||||||
end
|
end
|
||||||
|
|
||||||
function advtrains.add_wagon_to_train(wagon, train_id, index)
|
function advtrains.add_wagon_to_train(wagon, train_id, index)
|
||||||
|
@ -508,7 +520,6 @@ function advtrains.update_trainpart_properties(train_id, invert_flipstate)
|
||||||
wagon.wagon_flipped = not wagon.wagon_flipped
|
wagon.wagon_flipped = not wagon.wagon_flipped
|
||||||
end
|
end
|
||||||
rel_pos=rel_pos+wagon.wagon_span
|
rel_pos=rel_pos+wagon.wagon_span
|
||||||
any_loaded=true
|
|
||||||
|
|
||||||
if wagon.drives_on then
|
if wagon.drives_on then
|
||||||
for k,_ in pairs(train.drives_on) do
|
for k,_ in pairs(train.drives_on) do
|
||||||
|
@ -518,6 +529,13 @@ function advtrains.update_trainpart_properties(train_id, invert_flipstate)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
train.max_speed=math.min(train.max_speed, wagon.max_speed)
|
train.max_speed=math.min(train.max_speed, wagon.max_speed)
|
||||||
|
if i==1 then
|
||||||
|
train.couple_lock_front=wagon.lock_couples
|
||||||
|
end
|
||||||
|
if i==#train.trainparts then
|
||||||
|
train.couple_lock_back=wagon.lock_couples
|
||||||
|
end
|
||||||
|
|
||||||
else
|
else
|
||||||
atprint(w_id.." not loaded and no save available")
|
atprint(w_id.." not loaded and no save available")
|
||||||
--what the hell...
|
--what the hell...
|
||||||
|
@ -531,9 +549,11 @@ end
|
||||||
function advtrains.split_train_at_wagon(wagon)
|
function advtrains.split_train_at_wagon(wagon)
|
||||||
--get train
|
--get train
|
||||||
local train=advtrains.trains[wagon.train_id]
|
local train=advtrains.trains[wagon.train_id]
|
||||||
|
if not train.path then return end
|
||||||
|
|
||||||
local real_pos_in_train=advtrains.get_real_path_index(train, wagon.pos_in_train)
|
local real_pos_in_train=advtrains.get_real_path_index(train, wagon.pos_in_train)
|
||||||
local pos_for_new_train=advtrains.get_or_create_path(wagon.train_id, train)[math.floor(real_pos_in_train+wagon.wagon_span)]
|
local pos_for_new_train=train.path[math.floor(real_pos_in_train+wagon.wagon_span)]
|
||||||
local pos_for_new_train_prev=advtrains.get_or_create_path(wagon.train_id, train)[math.floor(real_pos_in_train-1+wagon.wagon_span)]
|
local pos_for_new_train_prev=train.path[math.floor(real_pos_in_train-1+wagon.wagon_span)]
|
||||||
|
|
||||||
--before doing anything, check if both are rails. else do not allow
|
--before doing anything, check if both are rails. else do not allow
|
||||||
if not pos_for_new_train then
|
if not pos_for_new_train then
|
||||||
|
@ -683,15 +703,25 @@ end
|
||||||
--pos1 and pos2 are just needed to form a median.
|
--pos1 and pos2 are just needed to form a median.
|
||||||
|
|
||||||
|
|
||||||
function advtrains.do_connect_trains(first_id, second_id)
|
function advtrains.do_connect_trains(first_id, second_id, player)
|
||||||
local first_wagoncnt=#advtrains.trains[first_id].trainparts
|
local first, second=advtrains.trains[first_id], advtrains.trains[second_id]
|
||||||
local second_wagoncnt=#advtrains.trains[second_id].trainparts
|
|
||||||
|
|
||||||
for _,v in ipairs(advtrains.trains[second_id].trainparts) do
|
if first.couple_lock_back or second.couple_lock_front then
|
||||||
table.insert(advtrains.trains[first_id].trainparts, v)
|
-- trains are ordered correctly!
|
||||||
|
if player then
|
||||||
|
minetest.chat_send_player(player:get_player_name(), "Can't couple: couples locked!")
|
||||||
|
end
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local first_wagoncnt=#first.trainparts
|
||||||
|
local second_wagoncnt=#second.trainparts
|
||||||
|
|
||||||
|
for _,v in ipairs(second.trainparts) do
|
||||||
|
table.insert(first.trainparts, v)
|
||||||
end
|
end
|
||||||
--kick it like physics (with mass being #wagons)
|
--kick it like physics (with mass being #wagons)
|
||||||
local new_velocity=((advtrains.trains[first_id].velocity*first_wagoncnt)+(advtrains.trains[second_id].velocity*second_wagoncnt))/(first_wagoncnt+second_wagoncnt)
|
local new_velocity=((first.velocity*first_wagoncnt)+(second.velocity*second_wagoncnt))/(first_wagoncnt+second_wagoncnt)
|
||||||
advtrains.trains[second_id]=nil
|
advtrains.trains[second_id]=nil
|
||||||
advtrains.update_trainpart_properties(first_id)
|
advtrains.update_trainpart_properties(first_id)
|
||||||
advtrains.trains[first_id].velocity=new_velocity
|
advtrains.trains[first_id].velocity=new_velocity
|
||||||
|
@ -751,10 +781,12 @@ function advtrains.invalidate_all_paths()
|
||||||
v.path=nil
|
v.path=nil
|
||||||
v.path_dist=nil
|
v.path_dist=nil
|
||||||
v.index=nil
|
v.index=nil
|
||||||
|
v.end_index=nil
|
||||||
v.min_index_on_track=nil
|
v.min_index_on_track=nil
|
||||||
v.max_index_on_track=nil
|
v.max_index_on_track=nil
|
||||||
|
v.path_extent_min=nil
|
||||||
|
v.path_extent_max=nil
|
||||||
|
|
||||||
advtrains.detector.setup_restore()
|
|
||||||
v.detector_old_index=nil
|
v.detector_old_index=nil
|
||||||
v.detector_old_end_index=nil
|
v.detector_old_end_index=nil
|
||||||
end
|
end
|
||||||
|
|
|
@ -92,7 +92,6 @@ function wagon:init_from_wagon_save(uid)
|
||||||
self.initialized=true
|
self.initialized=true
|
||||||
minetest.after(1, function() self:reattach_all() end)
|
minetest.after(1, function() self:reattach_all() end)
|
||||||
atprint("init_from_wagon_save "..self.unique_id.." ("..self.train_id..")")
|
atprint("init_from_wagon_save "..self.unique_id.." ("..self.train_id..")")
|
||||||
advtrains.update_trainpart_properties(self.train_id)
|
|
||||||
end
|
end
|
||||||
function wagon:init_shared()
|
function wagon:init_shared()
|
||||||
if self.has_inventory then
|
if self.has_inventory then
|
||||||
|
@ -294,7 +293,7 @@ function wagon:on_step(dtime)
|
||||||
end
|
end
|
||||||
--DisCouple
|
--DisCouple
|
||||||
if self.pos_in_trainparts and self.pos_in_trainparts>1 then
|
if self.pos_in_trainparts and self.pos_in_trainparts>1 then
|
||||||
if gp.velocity==0 then
|
if gp.velocity==0 and not self.lock_couples then
|
||||||
if not self.discouple or not self.discouple.object:getyaw() then
|
if not self.discouple or not self.discouple.object:getyaw() then
|
||||||
local object=minetest.add_entity(pos, "advtrains:discouple")
|
local object=minetest.add_entity(pos, "advtrains:discouple")
|
||||||
if object then
|
if object then
|
||||||
|
@ -314,7 +313,7 @@ function wagon:on_step(dtime)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
--for path to be available. if not, skip step
|
--for path to be available. if not, skip step
|
||||||
if not advtrains.get_or_create_path(self.train_id, gp) then
|
if not gp.path then
|
||||||
self.object:setvelocity({x=0, y=0, z=0})
|
self.object:setvelocity({x=0, y=0, z=0})
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
@ -593,6 +592,28 @@ function wagon:show_get_on_form(pname)
|
||||||
end
|
end
|
||||||
minetest.show_formspec(pname, "advtrains_geton_"..self.unique_id, form)
|
minetest.show_formspec(pname, "advtrains_geton_"..self.unique_id, form)
|
||||||
end
|
end
|
||||||
|
function wagon:show_wagon_properties(pname)
|
||||||
|
if not self.seat_groups then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
if not self.seat_access then
|
||||||
|
self.seat_access={}
|
||||||
|
end
|
||||||
|
--[[
|
||||||
|
fields: seat access: empty: everyone
|
||||||
|
checkbox: lock couples
|
||||||
|
button: save
|
||||||
|
]]
|
||||||
|
local form="size[5,"..(#self.seat_groups*1.5+5).."]"
|
||||||
|
local at=0
|
||||||
|
for sgr,sgrdef in pairs(self.seat_groups) do
|
||||||
|
form=form.."field[0.5,"..(0.5+at*1.5)..";4,1;sgr_"..sgr..";"..sgrdef.name..";"..(self.seat_access[sgr] or "").."]"
|
||||||
|
at=at+1
|
||||||
|
end
|
||||||
|
form=form.."checkbox[0,"..(at*1.5)..";lock_couples;Lock couples;"..(self.lock_couples and "true" or "false").."]"
|
||||||
|
form=form.."button_exit[0.5,"..(1+at*1.5)..";4,1;save;Save wagon properties]"
|
||||||
|
minetest.show_formspec(pname, "advtrains_prop_"..self.unique_id, form)
|
||||||
|
end
|
||||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
local uid=string.match(formname, "^advtrains_geton_(.+)$")
|
local uid=string.match(formname, "^advtrains_geton_(.+)$")
|
||||||
if uid then
|
if uid then
|
||||||
|
@ -628,6 +649,27 @@ minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
uid=string.match(formname, "^advtrains_prop_(.+)$")
|
||||||
|
if uid then
|
||||||
|
atprint(fields)
|
||||||
|
for _,wagon in pairs(minetest.luaentities) do
|
||||||
|
if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
|
||||||
|
local pname=player:get_player_name()
|
||||||
|
if pname~=wagon.owner then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
if not fields.quit then
|
||||||
|
for sgr,sgrdef in pairs(wagon.seat_groups) do
|
||||||
|
if fields["sgr_"..sgr] then
|
||||||
|
local fcont = fields["sgr_"..sgr]
|
||||||
|
wagon.seat_access[sgr] = fcont~="" and fcont or nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
wagon.lock_couples = fields.lock_couples == "true"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end)
|
end)
|
||||||
function wagon:seating_from_key_helper(pname, fields, no)
|
function wagon:seating_from_key_helper(pname, fields, no)
|
||||||
local sgr=self.seats[no].group
|
local sgr=self.seats[no].group
|
||||||
|
@ -648,15 +690,26 @@ function wagon:seating_from_key_helper(pname, fields, no)
|
||||||
self:show_wagon_properties(pname)
|
self:show_wagon_properties(pname)
|
||||||
end
|
end
|
||||||
if fields.dcwarn then
|
if fields.dcwarn then
|
||||||
minetest.chat_send_player(pname, "Use shift-rightclick to open doors with force and get off!")
|
minetest.chat_send_player(pname, "Doors are closed! Use shift-rightclick to open doors with force and get off!")
|
||||||
end
|
end
|
||||||
if fields.off then
|
if fields.off then
|
||||||
self:get_off(no)
|
self:get_off(no)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
function wagon:check_seat_group_access(pname, sgr)
|
function wagon:check_seat_group_access(pname, sgr)
|
||||||
--TODO implement
|
if not self.seat_access then
|
||||||
return sgr~="driverstand" or pname=="orwell"
|
return true
|
||||||
|
end
|
||||||
|
local sae=self.seat_access[sgr]
|
||||||
|
if not sae or sae=="" then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
for name in string.gmatch(sae, "%S+") do
|
||||||
|
if name==pname then
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return false
|
||||||
end
|
end
|
||||||
function wagon:reattach_all()
|
function wagon:reattach_all()
|
||||||
if not self.seatp then self.seatp={} end
|
if not self.seatp then self.seatp={} end
|
||||||
|
|
Loading…
Reference in New Issue