Merge nocrash branch into master and merging it with the unified functions so that restoring works how it should
Also fix minor bugs and an occasional crash with couplesmaster
commit
0c7144bcc4
BIN
advtrains.zip
BIN
advtrains.zip
Binary file not shown.
|
@ -92,49 +92,53 @@ advtrains.register_tracks("default", {
|
|||
return {
|
||||
after_place_node=apn_func,
|
||||
after_dig_node=function(pos)
|
||||
advtrains.invalidate_all_paths()
|
||||
advtrains.ndb.clear(pos)
|
||||
local pts=minetest.pos_to_string(pos)
|
||||
atc.controllers[pts]=nil
|
||||
return advtrains.pcall(function()
|
||||
advtrains.invalidate_all_paths()
|
||||
advtrains.ndb.clear(pos)
|
||||
local pts=minetest.pos_to_string(pos)
|
||||
atc.controllers[pts]=nil
|
||||
end)
|
||||
end,
|
||||
on_receive_fields = function(pos, formname, fields, player)
|
||||
if advtrains.is_protected(pos, player:get_player_name()) then
|
||||
minetest.record_protection_violation(pos, player:get_player_name())
|
||||
return
|
||||
end
|
||||
local meta=minetest.get_meta(pos)
|
||||
if meta then
|
||||
if not fields.save then
|
||||
--maybe only the dropdown changed
|
||||
if fields.mode then
|
||||
meta:set_string("mode", idxtrans[fields.mode])
|
||||
if fields.mode=="digiline" then
|
||||
meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) )
|
||||
else
|
||||
meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) )
|
||||
end
|
||||
meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta))
|
||||
end
|
||||
return advtrains.pcall(function()
|
||||
if advtrains.is_protected(pos, player:get_player_name()) then
|
||||
minetest.record_protection_violation(pos, player:get_player_name())
|
||||
return
|
||||
end
|
||||
meta:set_string("mode", idxtrans[fields.mode])
|
||||
meta:set_string("command", fields.command)
|
||||
meta:set_string("command_on", fields.command_on)
|
||||
meta:set_string("channel", fields.channel)
|
||||
if fields.mode=="digiline" then
|
||||
meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) )
|
||||
else
|
||||
meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) )
|
||||
local meta=minetest.get_meta(pos)
|
||||
if meta then
|
||||
if not fields.save then
|
||||
--maybe only the dropdown changed
|
||||
if fields.mode then
|
||||
meta:set_string("mode", idxtrans[fields.mode])
|
||||
if fields.mode=="digiline" then
|
||||
meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) )
|
||||
else
|
||||
meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) )
|
||||
end
|
||||
meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta))
|
||||
end
|
||||
return
|
||||
end
|
||||
meta:set_string("mode", idxtrans[fields.mode])
|
||||
meta:set_string("command", fields.command)
|
||||
meta:set_string("command_on", fields.command_on)
|
||||
meta:set_string("channel", fields.channel)
|
||||
if fields.mode=="digiline" then
|
||||
meta:set_string("infotext", attrans("ATC controller, mode @1\nChannel: @2", fields.mode, meta:get_string("command")) )
|
||||
else
|
||||
meta:set_string("infotext", attrans("ATC controller, mode @1\nCommand: @2", fields.mode, meta:get_string("command")) )
|
||||
end
|
||||
meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta))
|
||||
|
||||
local pts=minetest.pos_to_string(pos)
|
||||
local _, conn1=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
|
||||
atc.controllers[pts]={command=fields.command, arrowconn=conn1}
|
||||
if advtrains.detector.on_node[pts] then
|
||||
atc.send_command(pos)
|
||||
end
|
||||
end
|
||||
meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta))
|
||||
|
||||
local pts=minetest.pos_to_string(pos)
|
||||
local _, conn1=advtrains.get_rail_info_at(pos, advtrains.all_tracktypes)
|
||||
atc.controllers[pts]={command=fields.command, arrowconn=conn1}
|
||||
if advtrains.detector.on_node[pts] then
|
||||
atc.send_command(pos)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
advtrains = {
|
||||
on_train_enter = function(pos, train_id)
|
||||
|
|
|
@ -31,52 +31,56 @@ minetest.register_entity("advtrains:discouple", {
|
|||
end,
|
||||
get_staticdata=function() return "DISCOUPLE" end,
|
||||
on_punch=function(self, player)
|
||||
--only if player owns at least one wagon next to this
|
||||
local own=player:get_player_name()
|
||||
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 nextwgn_id=train.trainparts[self.wagon.pos_in_trainparts-1]
|
||||
for aoi, le in pairs(minetest.luaentities) do
|
||||
if le and le.is_wagon then
|
||||
if le.unique_id==nextwgn_id then
|
||||
if le.owner and le.owner~=own then
|
||||
minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple."))
|
||||
return
|
||||
return advtrains.pcall(function()
|
||||
--only if player owns at least one wagon next to this
|
||||
local own=player:get_player_name()
|
||||
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 nextwgn_id=train.trainparts[self.wagon.pos_in_trainparts-1]
|
||||
for aoi, le in pairs(minetest.luaentities) do
|
||||
if le and le.is_wagon then
|
||||
if le.unique_id==nextwgn_id then
|
||||
if le.owner and le.owner~=own then
|
||||
minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple."))
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
atprint("Discouple punched. Splitting train", self.wagon.train_id)
|
||||
advtrains.split_train_at_wagon(self.wagon)--found in trainlogic.lua
|
||||
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
|
||||
minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple."))
|
||||
end
|
||||
atprint("Discouple punched. Splitting train", self.wagon.train_id)
|
||||
advtrains.split_train_at_wagon(self.wagon)--found in trainlogic.lua
|
||||
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
|
||||
minetest.chat_send_player(own, attrans("You need to own at least one neighboring wagon to destroy this couple."))
|
||||
end
|
||||
end)
|
||||
end,
|
||||
on_step=function(self, dtime)
|
||||
local t=os.clock()
|
||||
if not self.wagon then
|
||||
self.object:remove()
|
||||
atprint("Discouple: no wagon, destroying")
|
||||
return
|
||||
end
|
||||
--getyaw seems to be a reliable method to check if an object is loaded...if it returns nil, it is not.
|
||||
if not self.wagon.object:getyaw() then
|
||||
atprint("Discouple: wagon no longer loaded, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
local velocityvec=self.wagon.object:getvelocity()
|
||||
self.updatepct_timer=(self.updatepct_timer or 0)-dtime
|
||||
if not self.old_velocity_vector or not vector.equals(velocityvec, self.old_velocity_vector) or self.updatepct_timer<=0 then--only send update packet if something changed
|
||||
local flipsign=self.wagon.wagon_flipped and -1 or 1
|
||||
self.object:setpos(vector.add(self.wagon.object:getpos(), {y=0, x=-math.sin(self.wagon.object:getyaw())*self.wagon.wagon_span*flipsign, z=math.cos(self.wagon.object:getyaw())*self.wagon.wagon_span*flipsign}))
|
||||
self.object:setvelocity(velocityvec)
|
||||
self.updatepct_timer=2
|
||||
end
|
||||
atprintbm("discouple_step", t)
|
||||
return advtrains.pcall(function()
|
||||
local t=os.clock()
|
||||
if not self.wagon then
|
||||
self.object:remove()
|
||||
atprint("Discouple: no wagon, destroying")
|
||||
return
|
||||
end
|
||||
--getyaw seems to be a reliable method to check if an object is loaded...if it returns nil, it is not.
|
||||
if not self.wagon.object:getyaw() then
|
||||
atprint("Discouple: wagon no longer loaded, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
local velocityvec=self.wagon.object:getvelocity()
|
||||
self.updatepct_timer=(self.updatepct_timer or 0)-dtime
|
||||
if not self.old_velocity_vector or not vector.equals(velocityvec, self.old_velocity_vector) or self.updatepct_timer<=0 then--only send update packet if something changed
|
||||
local flipsign=self.wagon.wagon_flipped and -1 or 1
|
||||
self.object:setpos(vector.add(self.wagon.object:getpos(), {y=0, x=-math.sin(self.wagon.object:getyaw())*self.wagon.wagon_span*flipsign, z=math.cos(self.wagon.object:getyaw())*self.wagon.wagon_span*flipsign}))
|
||||
self.object:setvelocity(velocityvec)
|
||||
self.updatepct_timer=2
|
||||
end
|
||||
atprintbm("discouple_step", t)
|
||||
end)
|
||||
end,
|
||||
})
|
||||
|
||||
|
@ -98,74 +102,79 @@ minetest.register_entity("advtrains:couple", {
|
|||
initial_sprite_basepos = {x=0, y=0},
|
||||
|
||||
is_couple=true,
|
||||
on_activate=function(self, staticdata)
|
||||
if staticdata=="COUPLE" then
|
||||
--couple entities have no right to exist further...
|
||||
atprint("Couple loaded from staticdata, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
on_activate=function(self, staticdata)
|
||||
return advtrains.pcall(function()
|
||||
if staticdata=="COUPLE" then
|
||||
--couple entities have no right to exist further...
|
||||
atprint("Couple loaded from staticdata, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
end)
|
||||
end,
|
||||
get_staticdata=function(self) return "COUPLE" end,
|
||||
on_rightclick=function(self, clicker)
|
||||
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
|
||||
|
||||
if self.train1_is_backpos and not self.train2_is_backpos then
|
||||
advtrains.do_connect_trains(id1, id2, clicker)
|
||||
--case 2 (second train is front)
|
||||
elseif self.train2_is_backpos and not self.train1_is_backpos then
|
||||
advtrains.do_connect_trains(id2, id1, clicker)
|
||||
--case 3
|
||||
elseif self.train1_is_backpos and self.train2_is_backpos then
|
||||
advtrains.invert_train(id2)
|
||||
advtrains.do_connect_trains(id1, id2, clicker)
|
||||
--case 4
|
||||
elseif not self.train1_is_backpos and not self.train2_is_backpos then
|
||||
advtrains.invert_train(id1)
|
||||
advtrains.do_connect_trains(id1, id2, clicker)
|
||||
end
|
||||
atprint("Coupled trains", id1, id2)
|
||||
self.object:remove()
|
||||
return advtrains.pcall(function()
|
||||
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
|
||||
if self.train1_is_backpos and not self.train2_is_backpos then
|
||||
advtrains.do_connect_trains(id1, id2, clicker)
|
||||
--case 2 (second train is front)
|
||||
elseif self.train2_is_backpos and not self.train1_is_backpos then
|
||||
advtrains.do_connect_trains(id2, id1, clicker)
|
||||
--case 3
|
||||
elseif self.train1_is_backpos and self.train2_is_backpos then
|
||||
advtrains.invert_train(id2)
|
||||
advtrains.do_connect_trains(id1, id2, clicker)
|
||||
--case 4
|
||||
elseif not self.train1_is_backpos and not self.train2_is_backpos then
|
||||
advtrains.invert_train(id1)
|
||||
advtrains.do_connect_trains(id1, id2, clicker)
|
||||
end
|
||||
atprint("Coupled trains", id1, id2)
|
||||
self.object:remove()
|
||||
end)
|
||||
end,
|
||||
on_step=function(self, dtime)
|
||||
local t=os.clock()
|
||||
if not self.train_id_1 or not self.train_id_2 then atprint("Couple: train ids not set!") self.object:remove() return end
|
||||
local train1=advtrains.trains[self.train_id_1]
|
||||
local train2=advtrains.trains[self.train_id_2]
|
||||
if not train1 or not train2 then
|
||||
atprint("Couple: trains missing, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
if not train1.path or not train2.path or not train1.index or not train2.index or not train1.end_index or not train2.end_index then
|
||||
atprint("Couple: paths or end_index missing. Might happen when paths got cleared")
|
||||
return
|
||||
end
|
||||
|
||||
local tp1
|
||||
if not self.train1_is_backpos then
|
||||
tp1=advtrains.get_real_index_position(train1.path, train1.index)
|
||||
else
|
||||
tp1=advtrains.get_real_index_position(train1.path, train1.end_index)
|
||||
end
|
||||
local tp2
|
||||
if not self.train2_is_backpos then
|
||||
tp2=advtrains.get_real_index_position(train2.path, train2.index)
|
||||
else
|
||||
tp2=advtrains.get_real_index_position(train2.path, train2.end_index)
|
||||
end
|
||||
if not tp1 or not tp2 or not (vector.distance(tp1,tp2)<couple_max_dist) then
|
||||
atprint("Couple: train end positions too distanced, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
else
|
||||
local pos_median=advtrains.pos_median(tp1, tp2)
|
||||
if not vector.equals(pos_median, self.object:getpos()) then
|
||||
self.object:setpos(pos_median)
|
||||
return advtrains.pcall(function()
|
||||
local t=os.clock()
|
||||
if not self.train_id_1 or not self.train_id_2 then atprint("Couple: train ids not set!") self.object:remove() return end
|
||||
local train1=advtrains.trains[self.train_id_1]
|
||||
local train2=advtrains.trains[self.train_id_2]
|
||||
if not train1 or not train2 then
|
||||
atprint("Couple: trains missing, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
end
|
||||
atprintbm("couple step", t)
|
||||
if not train1.path or not train2.path or not train1.index or not train2.index or not train1.end_index or not train2.end_index then
|
||||
atprint("Couple: paths or end_index missing. Might happen when paths got cleared")
|
||||
return
|
||||
end
|
||||
|
||||
local tp1
|
||||
if not self.train1_is_backpos then
|
||||
tp1=advtrains.get_real_index_position(train1.path, train1.index)
|
||||
else
|
||||
tp1=advtrains.get_real_index_position(train1.path, train1.end_index)
|
||||
end
|
||||
local tp2
|
||||
if not self.train2_is_backpos then
|
||||
tp2=advtrains.get_real_index_position(train2.path, train2.index)
|
||||
else
|
||||
tp2=advtrains.get_real_index_position(train2.path, train2.end_index)
|
||||
end
|
||||
if not tp1 or not tp2 or not (vector.distance(tp1,tp2)<couple_max_dist) then
|
||||
atprint("Couple: train end positions too distanced, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
else
|
||||
local pos_median=advtrains.pos_median(tp1, tp2)
|
||||
if not vector.equals(pos_median, self.object:getpos()) then
|
||||
self.object:setpos(pos_median)
|
||||
end
|
||||
end
|
||||
atprintbm("couple step", t)
|
||||
end)
|
||||
end,
|
||||
})
|
||||
|
|
|
@ -9,6 +9,29 @@ end
|
|||
|
||||
advtrains = {trains={}, wagon_save={}, player_to_train_mapping={}}
|
||||
|
||||
--pcall
|
||||
local no_action=false
|
||||
function advtrains.pcall(fun)
|
||||
if no_action then return end
|
||||
|
||||
local succ, err, return1, return2, return3, return4=pcall(fun)
|
||||
if not succ then
|
||||
atwarn("Lua Error occured: ", err)
|
||||
atwarn("Restoring saved state in 1 second...")
|
||||
no_action=true
|
||||
--read last save state and continue, as if server was restarted
|
||||
for aoi, le in pairs(minetest.luaentities) do
|
||||
if le.is_wagon then
|
||||
le.object:remove()
|
||||
end
|
||||
end
|
||||
minetest.after(1, advtrains.load)
|
||||
else
|
||||
return err, return1, return2, return3, return4
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
advtrains.modpath = minetest.get_modpath("advtrains")
|
||||
|
||||
function advtrains.print_concat_table(a)
|
||||
|
@ -94,6 +117,7 @@ dofile(advtrains.modpath.."/craft_items.lua")
|
|||
--load/save
|
||||
|
||||
advtrains.fpath=minetest.get_worldpath().."/advtrains"
|
||||
|
||||
function advtrains.avt_load()
|
||||
local file, err = io.open(advtrains.fpath, "r")
|
||||
if not file then
|
||||
|
@ -197,44 +221,47 @@ end
|
|||
|
||||
--## MAIN LOOP ##--
|
||||
--Calls all subsequent main tasks of both advtrains and atlatc
|
||||
local init_load
|
||||
local init_load=false
|
||||
local save_interval=20
|
||||
local save_timer=save_interval
|
||||
|
||||
minetest.register_globalstep(function(dtime_mt)
|
||||
--call load once. see advtrains.load() comment
|
||||
if not init_load then
|
||||
advtrains.load()
|
||||
end
|
||||
--limit dtime: if trains move too far in one step, automation may cause stuck and wrongly braking trains
|
||||
local dtime=dtime_mt
|
||||
if dtime>0.2 then
|
||||
atprint("Limiting dtime to 0.2!")
|
||||
dtime=0.2
|
||||
end
|
||||
|
||||
advtrains.mainloop_trainlogic(dtime)
|
||||
if advtrains_itm_mainloop then
|
||||
advtrains_itm_mainloop(dtime)
|
||||
end
|
||||
if atlatc then
|
||||
atlatc.mainloop_stepcode(dtime)
|
||||
atlatc.interrupt.mainloop(dtime)
|
||||
end
|
||||
|
||||
|
||||
--trigger a save when necessary
|
||||
save_timer=save_timer-dtime
|
||||
if save_timer<=0 then
|
||||
local t=os.clock()
|
||||
--save
|
||||
advtrains.save()
|
||||
save_timer=save_interval
|
||||
atprintbm("saving", t)
|
||||
end
|
||||
|
||||
return advtrains.pcall(function()
|
||||
--call load once. see advtrains.load() comment
|
||||
if not init_load then
|
||||
advtrains.load()
|
||||
end
|
||||
--limit dtime: if trains move too far in one step, automation may cause stuck and wrongly braking trains
|
||||
local dtime=dtime_mt
|
||||
if dtime>0.2 then
|
||||
atprint("Limiting dtime to 0.2!")
|
||||
dtime=0.2
|
||||
end
|
||||
|
||||
advtrains.mainloop_trainlogic(dtime)
|
||||
if advtrains_itm_mainloop then
|
||||
advtrains_itm_mainloop(dtime)
|
||||
end
|
||||
if atlatc then
|
||||
atlatc.mainloop_stepcode(dtime)
|
||||
atlatc.interrupt.mainloop(dtime)
|
||||
end
|
||||
|
||||
|
||||
--trigger a save when necessary
|
||||
save_timer=save_timer-dtime
|
||||
if save_timer<=0 then
|
||||
local t=os.clock()
|
||||
--save
|
||||
advtrains.save()
|
||||
save_timer=save_interval
|
||||
atprintbm("saving", t)
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
--if something goes wrong in these functions, there is no help. no pcall here.
|
||||
|
||||
--## MAIN LOAD ROUTINE ##
|
||||
-- Causes the loading of everything
|
||||
-- first time called in main loop (after the init phase) because luaautomation has to initialize first.
|
||||
|
@ -247,6 +274,8 @@ function advtrains.load()
|
|||
advtrains_itm_init()
|
||||
end
|
||||
init_load=true
|
||||
no_action=false
|
||||
atprint("[load_all]Loaded advtrains save files")
|
||||
end
|
||||
|
||||
--## MAIN SAVE ROUTINE ##
|
||||
|
@ -261,5 +290,6 @@ function advtrains.save()
|
|||
if atlatc then
|
||||
atlatc.save()
|
||||
end
|
||||
atprint("[save_all]Saved advtrains save files")
|
||||
end
|
||||
minetest.register_on_shutdown(advtrains.save)
|
||||
|
|
|
@ -203,37 +203,41 @@ minetest.register_abm({
|
|||
nodenames = {"group:save_in_nodedb"},
|
||||
run_at_every_load = true,
|
||||
action = function(pos, node)
|
||||
local cid=ndbget(pos.x, pos.y, pos.z)
|
||||
if cid then
|
||||
--if in database, detect changes and apply.
|
||||
local nodeid = ndb_nodeids[u14b(cid)]
|
||||
local param2 = l2b(cid)
|
||||
if not nodeid then
|
||||
--something went wrong
|
||||
atprint("nodedb: lbm nid not found", pos, "with nid", u14b(cid), "param2", param2, "cid is", cid)
|
||||
ndb.update(pos, node)
|
||||
else
|
||||
if (nodeid~=node.name or param2~=node.param2) then
|
||||
atprint("nodedb: lbm replaced", pos, "with nodeid", nodeid, "param2", param2, "cid is", cid)
|
||||
minetest.swap_node(pos, {name=nodeid, param2 = param2})
|
||||
local ndef=minetest.registered_nodes[nodeid]
|
||||
if ndef and ndef.on_updated_from_nodedb then
|
||||
ndef.on_updated_from_nodedb(pos, node)
|
||||
return advtrains.pcall(function()
|
||||
local cid=ndbget(pos.x, pos.y, pos.z)
|
||||
if cid then
|
||||
--if in database, detect changes and apply.
|
||||
local nodeid = ndb_nodeids[u14b(cid)]
|
||||
local param2 = l2b(cid)
|
||||
if not nodeid then
|
||||
--something went wrong
|
||||
atprint("nodedb: lbm nid not found", pos, "with nid", u14b(cid), "param2", param2, "cid is", cid)
|
||||
ndb.update(pos, node)
|
||||
else
|
||||
if (nodeid~=node.name or param2~=node.param2) then
|
||||
atprint("nodedb: lbm replaced", pos, "with nodeid", nodeid, "param2", param2, "cid is", cid)
|
||||
minetest.swap_node(pos, {name=nodeid, param2 = param2})
|
||||
local ndef=minetest.registered_nodes[nodeid]
|
||||
if ndef and ndef.on_updated_from_nodedb then
|
||||
ndef.on_updated_from_nodedb(pos, node)
|
||||
end
|
||||
end
|
||||
end
|
||||
else
|
||||
--if not in database, take it.
|
||||
atprint("nodedb: ", pos, "not in database")
|
||||
ndb.update(pos, node)
|
||||
end
|
||||
else
|
||||
--if not in database, take it.
|
||||
atprint("nodedb: ", pos, "not in database")
|
||||
ndb.update(pos, node)
|
||||
end
|
||||
end)
|
||||
end,
|
||||
interval=10,
|
||||
chance=1,
|
||||
})
|
||||
|
||||
minetest.register_on_dignode(function(pos, oldnode, digger)
|
||||
ndb.clear(pos)
|
||||
return advtrains.pcall(function()
|
||||
ndb.clear(pos)
|
||||
end)
|
||||
end)
|
||||
|
||||
function ndb.get_nodes()
|
||||
|
|
|
@ -187,26 +187,28 @@ function tp.register_track_placer(nnprefix, imgprefix, dispname)
|
|||
wield_image = imgprefix.."_placer.png",
|
||||
groups={},
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local name = placer:get_player_name()
|
||||
if not name then
|
||||
return itemstack
|
||||
end
|
||||
if pointed_thing.type=="node" then
|
||||
local pos=pointed_thing.above
|
||||
local upos=vector.subtract(pointed_thing.above, {x=0, y=1, z=0})
|
||||
if advtrains.is_protected(pos,name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return itemstack
|
||||
return advtrains.pcall(function()
|
||||
local name = placer:get_player_name()
|
||||
if not name then
|
||||
return itemstack
|
||||
end
|
||||
if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to
|
||||
and minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable then
|
||||
tp.placetrack(pos, nnprefix, placer, itemstack, pointed_thing)
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
itemstack:take_item()
|
||||
if pointed_thing.type=="node" then
|
||||
local pos=pointed_thing.above
|
||||
local upos=vector.subtract(pointed_thing.above, {x=0, y=1, z=0})
|
||||
if advtrains.is_protected(pos,name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return itemstack
|
||||
end
|
||||
if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to
|
||||
and minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable then
|
||||
tp.placetrack(pos, nnprefix, placer, itemstack, pointed_thing)
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
itemstack:take_item()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return itemstack
|
||||
return itemstack
|
||||
end)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
@ -220,78 +222,82 @@ minetest.register_craftitem("advtrains:trackworker",{
|
|||
wield_image = "advtrains_trackworker.png",
|
||||
stack_max = 1,
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
local name = placer:get_player_name()
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
if pointed_thing.type=="node" then
|
||||
local pos=pointed_thing.under
|
||||
if advtrains.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return advtrains.pcall(function()
|
||||
local name = placer:get_player_name()
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
local node=minetest.get_node(pos)
|
||||
if pointed_thing.type=="node" then
|
||||
local pos=pointed_thing.under
|
||||
if advtrains.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return
|
||||
end
|
||||
local node=minetest.get_node(pos)
|
||||
|
||||
--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end
|
||||
if advtrains.get_train_at_pos(pos) then return end
|
||||
--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end
|
||||
if advtrains.get_train_at_pos(pos) then return end
|
||||
|
||||
local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$")
|
||||
--atprint(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation)
|
||||
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then
|
||||
nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$")
|
||||
rotation = ""
|
||||
local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$")
|
||||
--atprint(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation)
|
||||
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then
|
||||
minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!"))
|
||||
return
|
||||
end
|
||||
end
|
||||
local modext=tp.tracks[nnprefix].twrotate[suffix]
|
||||
|
||||
if rotation==modext[#modext] then --increase param2
|
||||
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4})
|
||||
return
|
||||
else
|
||||
local modpos
|
||||
for k,v in pairs(modext) do if v==rotation then modpos=k end end
|
||||
if not modpos then
|
||||
nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$")
|
||||
rotation = ""
|
||||
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then
|
||||
minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!"))
|
||||
return
|
||||
return
|
||||
end
|
||||
end
|
||||
local modext=tp.tracks[nnprefix].twrotate[suffix]
|
||||
|
||||
if rotation==modext[#modext] then --increase param2
|
||||
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[1], param2=(node.param2+1)%4})
|
||||
return
|
||||
else
|
||||
local modpos
|
||||
for k,v in pairs(modext) do if v==rotation then modpos=k end end
|
||||
if not modpos then
|
||||
minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!"))
|
||||
return
|
||||
end
|
||||
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2})
|
||||
end
|
||||
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2})
|
||||
end
|
||||
end
|
||||
end)
|
||||
end,
|
||||
on_use=function(itemstack, user, pointed_thing)
|
||||
local name = user:get_player_name()
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
if pointed_thing.type=="node" then
|
||||
local pos=pointed_thing.under
|
||||
local node=minetest.get_node(pos)
|
||||
if advtrains.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return
|
||||
return advtrains.pcall(function()
|
||||
local name = user:get_player_name()
|
||||
if not name then
|
||||
return
|
||||
end
|
||||
|
||||
--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end
|
||||
if advtrains.get_train_at_pos(pos) then return end
|
||||
local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$")
|
||||
--atprint(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation)
|
||||
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then
|
||||
nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$")
|
||||
rotation = ""
|
||||
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then
|
||||
minetest.chat_send_player(user:get_player_name(), attrans("This node can't be changed using the trackworker!"))
|
||||
return
|
||||
end
|
||||
end
|
||||
local nextsuffix=tp.tracks[nnprefix].twcycle[suffix]
|
||||
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2})
|
||||
|
||||
else
|
||||
atprint(name, dump(tp.tracks))
|
||||
end
|
||||
if pointed_thing.type=="node" then
|
||||
local pos=pointed_thing.under
|
||||
local node=minetest.get_node(pos)
|
||||
if advtrains.is_protected(pos, name) then
|
||||
minetest.record_protection_violation(pos, name)
|
||||
return
|
||||
end
|
||||
|
||||
--if not advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then return end
|
||||
if advtrains.get_train_at_pos(pos) then return end
|
||||
local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$")
|
||||
--atprint(node.name.."\npattern recognizes:"..nodeprefix.." / "..railtype.." / "..rotation)
|
||||
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then
|
||||
nnprefix, suffix=string.match(node.name, "^(.+)_([^_]+)$")
|
||||
rotation = ""
|
||||
if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twcycle[suffix] then
|
||||
minetest.chat_send_player(user:get_player_name(), attrans("This node can't be changed using the trackworker!"))
|
||||
return
|
||||
end
|
||||
end
|
||||
local nextsuffix=tp.tracks[nnprefix].twcycle[suffix]
|
||||
advtrains.ndb.swap_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2})
|
||||
|
||||
else
|
||||
atprint(name, dump(tp.tracks))
|
||||
end
|
||||
end)
|
||||
end,
|
||||
})
|
||||
|
||||
|
|
|
@ -37,8 +37,7 @@ advtrains.train_roll_force=0.5--per second, not divided by number of wagons, acc
|
|||
advtrains.train_emerg_force=10--for emergency brakes(when going off track)
|
||||
|
||||
|
||||
advtrains.mainloop_trainlogic(function(dtime)
|
||||
|
||||
advtrains.mainloop_trainlogic=function(dtime)
|
||||
--build a table of all players indexed by pts. used by damage and door system.
|
||||
advtrains.playersbypts={}
|
||||
for _, player in pairs(minetest.get_connected_players()) do
|
||||
|
@ -67,39 +66,43 @@ advtrains.mainloop_trainlogic(function(dtime)
|
|||
end
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
local pname=player:get_player_name()
|
||||
local id=advtrains.player_to_train_mapping[pname]
|
||||
if id then
|
||||
local train=advtrains.trains[id]
|
||||
if not train then advtrains.player_to_train_mapping[pname]=nil return end
|
||||
--set the player to the train position.
|
||||
--minetest will emerge the area and load the objects, which then will call reattach_all().
|
||||
--because player is in mapping, it will not be subject to dying.
|
||||
player:setpos(train.last_pos_prev)
|
||||
--independent of this, cause all wagons of the train which are loaded to reattach their players
|
||||
--needed because already loaded wagons won't call reattach_all()
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.train_id==id then
|
||||
wagon:reattach_all()
|
||||
return advtrains.pcall(function()
|
||||
local pname=player:get_player_name()
|
||||
local id=advtrains.player_to_train_mapping[pname]
|
||||
if id then
|
||||
local train=advtrains.trains[id]
|
||||
if not train then advtrains.player_to_train_mapping[pname]=nil return end
|
||||
--set the player to the train position.
|
||||
--minetest will emerge the area and load the objects, which then will call reattach_all().
|
||||
--because player is in mapping, it will not be subject to dying.
|
||||
player:setpos(train.last_pos_prev)
|
||||
--independent of this, cause all wagons of the train which are loaded to reattach their players
|
||||
--needed because already loaded wagons won't call reattach_all()
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.train_id==id then
|
||||
wagon:reattach_all()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
|
||||
minetest.register_on_dieplayer(function(player)
|
||||
local pname=player:get_player_name()
|
||||
local id=advtrains.player_to_train_mapping[pname]
|
||||
if id then
|
||||
local train=advtrains.trains[id]
|
||||
if not train then advtrains.player_to_train_mapping[pname]=nil return end
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.train_id==id then
|
||||
--when player dies, detach him from the train
|
||||
--call get_off_plr on every wagon since we don't know which one he's on.
|
||||
wagon:get_off_plr(pname)
|
||||
return advtrains.pcall(function()
|
||||
local pname=player:get_player_name()
|
||||
local id=advtrains.player_to_train_mapping[pname]
|
||||
if id then
|
||||
local train=advtrains.trains[id]
|
||||
if not train then advtrains.player_to_train_mapping[pname]=nil return end
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.train_id==id then
|
||||
--when player dies, detach him from the train
|
||||
--call get_off_plr on every wagon since we don't know which one he's on.
|
||||
wagon:get_off_plr(pname)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
--[[
|
||||
train step structure:
|
||||
|
@ -797,6 +800,10 @@ end
|
|||
function advtrains.do_connect_trains(first_id, second_id, player)
|
||||
local first, second=advtrains.trains[first_id], advtrains.trains[second_id]
|
||||
|
||||
if not first or not second or not first.index or not second.index or not first.end_index or not second.end_index then
|
||||
return false
|
||||
end
|
||||
|
||||
if first.couple_lock_back or second.couple_lock_front then
|
||||
-- trains are ordered correctly!
|
||||
if player then
|
||||
|
@ -817,6 +824,7 @@ function advtrains.do_connect_trains(first_id, second_id, player)
|
|||
advtrains.update_trainpart_properties(first_id)
|
||||
advtrains.trains[first_id].velocity=new_velocity
|
||||
advtrains.trains[first_id].tarvelocity=0
|
||||
return true
|
||||
end
|
||||
|
||||
function advtrains.invert_train(train_id)
|
||||
|
|
|
@ -50,19 +50,21 @@ function wagon:on_activate(sd_uid, dtime_s)
|
|||
end
|
||||
|
||||
function wagon:get_staticdata()
|
||||
if not self:ensure_init() then return end
|
||||
atprint("[wagon "..((self.unique_id and self.unique_id~="" and self.unique_id) or "no-id").."]: saving to wagon_save")
|
||||
--serialize inventory, if it has one
|
||||
if self.has_inventory then
|
||||
local inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..self.unique_id})
|
||||
self.ser_inv=advtrains.serialize_inventory(inv)
|
||||
end
|
||||
--save to table before being unloaded
|
||||
advtrains.wagon_save[self.unique_id]=advtrains.merge_tables(self)
|
||||
advtrains.wagon_save[self.unique_id].entity_name=self.name
|
||||
advtrains.wagon_save[self.unique_id].name=nil
|
||||
advtrains.wagon_save[self.unique_id].object=nil
|
||||
return self.unique_id
|
||||
return advtrains.pcall(function()
|
||||
if not self:ensure_init() then return end
|
||||
atprint("[wagon "..((self.unique_id and self.unique_id~="" and self.unique_id) or "no-id").."]: saving to wagon_save")
|
||||
--serialize inventory, if it has one
|
||||
if self.has_inventory then
|
||||
local inv=minetest.get_inventory({type="detached", name="advtrains_wgn_"..self.unique_id})
|
||||
self.ser_inv=advtrains.serialize_inventory(inv)
|
||||
end
|
||||
--save to table before being unloaded
|
||||
advtrains.wagon_save[self.unique_id]=advtrains.merge_tables(self)
|
||||
advtrains.wagon_save[self.unique_id].entity_name=self.name
|
||||
advtrains.wagon_save[self.unique_id].name=nil
|
||||
advtrains.wagon_save[self.unique_id].object=nil
|
||||
return self.unique_id
|
||||
end)
|
||||
end
|
||||
--returns: uid of wagon
|
||||
function wagon:init_new_instance(train_id, properties)
|
||||
|
@ -147,36 +149,38 @@ end
|
|||
|
||||
-- Remove the wagon
|
||||
function wagon:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
|
||||
if not self:ensure_init() then return end
|
||||
if not puncher or not puncher:is_player() then
|
||||
return
|
||||
end
|
||||
if self.owner and puncher:get_player_name()~=self.owner and (not minetest.check_player_privs(puncher, {train_remove = true })) then
|
||||
minetest.chat_send_player(puncher:get_player_name(), attrans("This wagon is owned by @1, you can't destroy it.", self.owner));
|
||||
return
|
||||
end
|
||||
|
||||
if minetest.setting_getbool("creative_mode") then
|
||||
if not self:destroy() then return end
|
||||
|
||||
local inv = puncher:get_inventory()
|
||||
if not inv:contains_item("main", self.name) then
|
||||
inv:add_item("main", self.name)
|
||||
end
|
||||
else
|
||||
local pc=puncher:get_player_control()
|
||||
if not pc.sneak then
|
||||
minetest.chat_send_player(puncher:get_player_name(), attrans("Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon."))
|
||||
return advtrains.pcall(function()
|
||||
if not self:ensure_init() then return end
|
||||
if not puncher or not puncher:is_player() then
|
||||
return
|
||||
end
|
||||
|
||||
if not self:destroy() then return end
|
||||
|
||||
local inv = puncher:get_inventory()
|
||||
for _,item in ipairs(self.drops or {self.name}) do
|
||||
inv:add_item("main", item)
|
||||
if self.owner and puncher:get_player_name()~=self.owner and (not minetest.check_player_privs(puncher, {train_remove = true })) then
|
||||
minetest.chat_send_player(puncher:get_player_name(), attrans("This wagon is owned by @1, you can't destroy it.", self.owner));
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
if minetest.setting_getbool("creative_mode") then
|
||||
if not self:destroy() then return end
|
||||
|
||||
local inv = puncher:get_inventory()
|
||||
if not inv:contains_item("main", self.name) then
|
||||
inv:add_item("main", self.name)
|
||||
end
|
||||
else
|
||||
local pc=puncher:get_player_control()
|
||||
if not pc.sneak then
|
||||
minetest.chat_send_player(puncher:get_player_name(), attrans("Warning: If you destroy this wagon, you only get some steel back! If you are sure, hold Sneak and left-click the wagon."))
|
||||
return
|
||||
end
|
||||
|
||||
if not self:destroy() then return end
|
||||
|
||||
local inv = puncher:get_inventory()
|
||||
for _,item in ipairs(self.drops or {self.name}) do
|
||||
inv:add_item("main", item)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
function wagon:destroy()
|
||||
--some rules:
|
||||
|
@ -211,260 +215,262 @@ end
|
|||
|
||||
|
||||
function wagon:on_step(dtime)
|
||||
if not self:ensure_init() then return end
|
||||
|
||||
local t=os.clock()
|
||||
local pos = self.object:getpos()
|
||||
|
||||
if not pos then
|
||||
atprint("["..self.unique_id.."][fatal] missing position (object:getpos() returned nil)")
|
||||
return
|
||||
end
|
||||
|
||||
self.entity_name=self.name
|
||||
|
||||
--is my train still here
|
||||
if not self.train_id or not self:train() then
|
||||
atprint("[wagon "..self.unique_id.."] missing train_id, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
if not self.seatp then
|
||||
self.seatp={}
|
||||
end
|
||||
if not self.seatpc then
|
||||
self.seatpc={}
|
||||
end
|
||||
|
||||
--Legacy: remove infotext since it does not work this way anyways
|
||||
self.infotext=nil
|
||||
|
||||
--custom on_step function
|
||||
if self.custom_on_step then
|
||||
self:custom_on_step(self, dtime)
|
||||
end
|
||||
|
||||
--driver control
|
||||
for seatno, seat in ipairs(self.seats) do
|
||||
local driver=self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
|
||||
local has_driverstand=seat.driving_ctrl_access and self.seatp[seatno] and minetest.check_player_privs(self.seatp[seatno], {train_operator=true})
|
||||
if has_driverstand and driver then
|
||||
advtrains.update_driver_hud(driver:get_player_name(), self:train(), self.wagon_flipped)
|
||||
elseif driver then
|
||||
--only show the inside text
|
||||
local inside=self:train().text_inside or ""
|
||||
advtrains.set_trainhud(driver:get_player_name(), inside)
|
||||
return advtrains.pcall(function()
|
||||
if not self:ensure_init() then return end
|
||||
|
||||
local t=os.clock()
|
||||
local pos = self.object:getpos()
|
||||
|
||||
if not pos then
|
||||
atprint("["..self.unique_id.."][fatal] missing position (object:getpos() returned nil)")
|
||||
return
|
||||
end
|
||||
if driver and driver:get_player_control_bits()~=self.seatpc[seatno] then
|
||||
local pc=driver:get_player_control()
|
||||
self.seatpc[seatno]=driver:get_player_control_bits()
|
||||
|
||||
if has_driverstand then
|
||||
--regular driver stand controls
|
||||
advtrains.on_control_change(pc, self:train(), self.wagon_flipped)
|
||||
else
|
||||
-- If on a passenger seat and doors are open, get off when W or D pressed.
|
||||
local pass = self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
|
||||
if pass and self:train().door_open~=0 then
|
||||
local pc=pass:get_player_control()
|
||||
if pc.up or pc.down then
|
||||
self:get_off(seatno)
|
||||
end
|
||||
end
|
||||
end
|
||||
if pc.aux1 and pc.sneak then
|
||||
self:get_off(seatno)
|
||||
end
|
||||
|
||||
self.entity_name=self.name
|
||||
|
||||
--is my train still here
|
||||
if not self.train_id or not self:train() then
|
||||
atprint("[wagon "..self.unique_id.."] missing train_id, destroying")
|
||||
self.object:remove()
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
--check infotext
|
||||
local outside=self:train().text_outside or ""
|
||||
if self.object:get_properties().infotext~=outside then
|
||||
self.object:set_properties({infotext=outside})
|
||||
end
|
||||
|
||||
local gp=self:train()
|
||||
local fct=self.wagon_flipped and -1 or 1
|
||||
--door animation
|
||||
if self.doors then
|
||||
if (self.door_anim_timer or 0)<=0 then
|
||||
local dstate = (gp.door_open or 0) * fct
|
||||
if dstate ~= self.door_state then
|
||||
local at
|
||||
--meaning of the train.door_open field:
|
||||
-- -1: left doors (rel. to train orientation)
|
||||
-- 0: closed
|
||||
-- 1: right doors
|
||||
--this code produces the following behavior:
|
||||
-- if changed from 0 to +-1, play open anim. if changed from +-1 to 0, play close.
|
||||
-- if changed from +-1 to -+1, first close and set 0, then it will detect state change again and run open.
|
||||
if self.door_state == 0 then
|
||||
at=self.doors.open[dstate]
|
||||
self.object:set_animation(at.frames, at.speed or 15, at.blend or 0, false)
|
||||
self.door_state = dstate
|
||||
if not self.seatp then
|
||||
self.seatp={}
|
||||
end
|
||||
if not self.seatpc then
|
||||
self.seatpc={}
|
||||
end
|
||||
|
||||
--Legacy: remove infotext since it does not work this way anyways
|
||||
self.infotext=nil
|
||||
|
||||
--custom on_step function
|
||||
if self.custom_on_step then
|
||||
self:custom_on_step(self, dtime)
|
||||
end
|
||||
|
||||
--driver control
|
||||
for seatno, seat in ipairs(self.seats) do
|
||||
local driver=self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
|
||||
local has_driverstand=seat.driving_ctrl_access and self.seatp[seatno] and minetest.check_player_privs(self.seatp[seatno], {train_operator=true})
|
||||
if has_driverstand and driver then
|
||||
advtrains.update_driver_hud(driver:get_player_name(), self:train(), self.wagon_flipped)
|
||||
elseif driver then
|
||||
--only show the inside text
|
||||
local inside=self:train().text_inside or ""
|
||||
advtrains.set_trainhud(driver:get_player_name(), inside)
|
||||
end
|
||||
if driver and driver:get_player_control_bits()~=self.seatpc[seatno] then
|
||||
local pc=driver:get_player_control()
|
||||
self.seatpc[seatno]=driver:get_player_control_bits()
|
||||
|
||||
if has_driverstand then
|
||||
--regular driver stand controls
|
||||
advtrains.on_control_change(pc, self:train(), self.wagon_flipped)
|
||||
else
|
||||
at=self.doors.close[self.door_state or 1]--in case it has not been set yet
|
||||
self.object:set_animation(at.frames, at.speed or 15, at.blend or 0, false)
|
||||
self.door_state = 0
|
||||
-- If on a passenger seat and doors are open, get off when W or D pressed.
|
||||
local pass = self.seatp[seatno] and minetest.get_player_by_name(self.seatp[seatno])
|
||||
if pass and self:train().door_open~=0 then
|
||||
local pc=pass:get_player_control()
|
||||
if pc.up or pc.down then
|
||||
self:get_off(seatno)
|
||||
end
|
||||
end
|
||||
end
|
||||
self.door_anim_timer = at.time
|
||||
end
|
||||
else
|
||||
self.door_anim_timer = (self.door_anim_timer or 0) - dtime
|
||||
end
|
||||
end
|
||||
|
||||
--DisCouple
|
||||
if self.pos_in_trainparts and self.pos_in_trainparts>1 then
|
||||
if gp.velocity==0 and not self.lock_couples then
|
||||
if not self.discouple or not self.discouple.object:getyaw() then
|
||||
local object=minetest.add_entity(pos, "advtrains:discouple")
|
||||
if object then
|
||||
local le=object:get_luaentity()
|
||||
le.wagon=self
|
||||
--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})
|
||||
self.discouple=le
|
||||
else
|
||||
atprint("Couldn't spawn DisCouple")
|
||||
if pc.aux1 and pc.sneak then
|
||||
self:get_off(seatno)
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.discouple and self.discouple.object:getyaw() then
|
||||
self.discouple.object:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
--for path to be available. if not, skip step
|
||||
if not gp.path then
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
return
|
||||
end
|
||||
if not self.pos_in_train then
|
||||
--why ever. but better continue next step...
|
||||
advtrains.update_trainpart_properties(self.train_id)
|
||||
return
|
||||
end
|
||||
|
||||
local index=advtrains.get_real_path_index(self:train(), self.pos_in_train)
|
||||
--atprint("trainindex "..gp.index.." wagonindex "..index)
|
||||
|
||||
--automatic get_on
|
||||
--needs to know index and path
|
||||
if self.door_entry and gp.door_open and gp.door_open~=0 and gp.velocity==0 then
|
||||
--using the mapping created by the trainlogic globalstep
|
||||
for i, ino in ipairs(self.door_entry) do
|
||||
--fct is the flipstate flag from door animation above
|
||||
local aci = index + ino*fct
|
||||
local ix1=gp.path[math.floor(aci)]
|
||||
local ix2=gp.path[math.floor(aci+1)]
|
||||
-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
|
||||
-- (x z) rotated by 90deg is (-z x) (http://stackoverflow.com/a/4780141)
|
||||
local add = { x = (ix2.z-ix1.z)*gp.door_open, y = 0, z = (ix1.x-ix2.x)*gp.door_open }
|
||||
local pts1=vector.round(vector.add(ix1, add))
|
||||
local pts2=vector.round(vector.add(ix2, add))
|
||||
if minetest.get_item_group(minetest.get_node(pts1).name, "platform")>0 then
|
||||
local ckpts={
|
||||
pts1,
|
||||
pts2,
|
||||
vector.add(pts1, {x=0, y=1, z=0}),
|
||||
vector.add(pts2, {x=0, y=1, z=0}),
|
||||
}
|
||||
for _,ckpos in ipairs(ckpts) do
|
||||
local cpp=minetest.pos_to_string(ckpos)
|
||||
if advtrains.playersbypts[cpp] then
|
||||
self:on_rightclick(advtrains.playersbypts[cpp])
|
||||
|
||||
--check infotext
|
||||
local outside=self:train().text_outside or ""
|
||||
if self.object:get_properties().infotext~=outside then
|
||||
self.object:set_properties({infotext=outside})
|
||||
end
|
||||
|
||||
local gp=self:train()
|
||||
local fct=self.wagon_flipped and -1 or 1
|
||||
--door animation
|
||||
if self.doors then
|
||||
if (self.door_anim_timer or 0)<=0 then
|
||||
local dstate = (gp.door_open or 0) * fct
|
||||
if dstate ~= self.door_state then
|
||||
local at
|
||||
--meaning of the train.door_open field:
|
||||
-- -1: left doors (rel. to train orientation)
|
||||
-- 0: closed
|
||||
-- 1: right doors
|
||||
--this code produces the following behavior:
|
||||
-- if changed from 0 to +-1, play open anim. if changed from +-1 to 0, play close.
|
||||
-- if changed from +-1 to -+1, first close and set 0, then it will detect state change again and run open.
|
||||
if self.door_state == 0 then
|
||||
at=self.doors.open[dstate]
|
||||
self.object:set_animation(at.frames, at.speed or 15, at.blend or 0, false)
|
||||
self.door_state = dstate
|
||||
else
|
||||
at=self.doors.close[self.door_state or 1]--in case it has not been set yet
|
||||
self.object:set_animation(at.frames, at.speed or 15, at.blend or 0, false)
|
||||
self.door_state = 0
|
||||
end
|
||||
self.door_anim_timer = at.time
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--position recalculation
|
||||
local first_pos=gp.path[math.floor(index)]
|
||||
local second_pos=gp.path[math.floor(index)+1]
|
||||
if not first_pos or not second_pos then
|
||||
--atprint(" object "..self.unique_id.." path end reached!")
|
||||
self.object:setvelocity({x=0,y=0,z=0})
|
||||
return
|
||||
end
|
||||
|
||||
--checking for environment collisions(a 3x3 cube around the center)
|
||||
if not gp.recently_collided_with_env then
|
||||
local collides=false
|
||||
for x=-1,1 do
|
||||
for y=0,2 do
|
||||
for z=-1,1 do
|
||||
local node=minetest.get_node_or_nil(vector.add(first_pos, {x=x, y=y, z=z}))
|
||||
if (advtrains.train_collides(node)) then
|
||||
collides=true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if collides then
|
||||
if self.collision_count and self.collision_count>10 then
|
||||
--enable collision mercy to get trains stuck in walls out of walls
|
||||
--actually do nothing except limiting the velocity to 1
|
||||
gp.velocity=math.min(gp.velocity, 1)
|
||||
gp.tarvelocity=math.min(gp.tarvelocity, 1)
|
||||
else
|
||||
gp.recently_collided_with_env=true
|
||||
gp.velocity=2*gp.velocity
|
||||
gp.movedir=-gp.movedir
|
||||
gp.tarvelocity=0
|
||||
self.collision_count=(self.collision_count or 0)+1
|
||||
self.door_anim_timer = (self.door_anim_timer or 0) - dtime
|
||||
end
|
||||
end
|
||||
|
||||
--DisCouple
|
||||
if self.pos_in_trainparts and self.pos_in_trainparts>1 then
|
||||
if gp.velocity==0 and not self.lock_couples then
|
||||
if not self.discouple or not self.discouple.object:getyaw() then
|
||||
local object=minetest.add_entity(pos, "advtrains:discouple")
|
||||
if object then
|
||||
local le=object:get_luaentity()
|
||||
le.wagon=self
|
||||
--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})
|
||||
self.discouple=le
|
||||
else
|
||||
atprint("Couldn't spawn DisCouple")
|
||||
end
|
||||
end
|
||||
else
|
||||
if self.discouple and self.discouple.object:getyaw() then
|
||||
self.discouple.object:remove()
|
||||
end
|
||||
end
|
||||
end
|
||||
--for path to be available. if not, skip step
|
||||
if not gp.path then
|
||||
self.object:setvelocity({x=0, y=0, z=0})
|
||||
return
|
||||
end
|
||||
if not self.pos_in_train then
|
||||
--why ever. but better continue next step...
|
||||
advtrains.update_trainpart_properties(self.train_id)
|
||||
return
|
||||
end
|
||||
|
||||
local index=advtrains.get_real_path_index(self:train(), self.pos_in_train)
|
||||
--atprint("trainindex "..gp.index.." wagonindex "..index)
|
||||
|
||||
--automatic get_on
|
||||
--needs to know index and path
|
||||
if self.door_entry and gp.door_open and gp.door_open~=0 and gp.velocity==0 then
|
||||
--using the mapping created by the trainlogic globalstep
|
||||
for i, ino in ipairs(self.door_entry) do
|
||||
--fct is the flipstate flag from door animation above
|
||||
local aci = index + ino*fct
|
||||
local ix1=gp.path[math.floor(aci)]
|
||||
local ix2=gp.path[math.floor(aci+1)]
|
||||
-- the two wanted positions are ix1 and ix2 + (2nd-1st rotated by 90deg)
|
||||
-- (x z) rotated by 90deg is (-z x) (http://stackoverflow.com/a/4780141)
|
||||
local add = { x = (ix2.z-ix1.z)*gp.door_open, y = 0, z = (ix1.x-ix2.x)*gp.door_open }
|
||||
local pts1=vector.round(vector.add(ix1, add))
|
||||
local pts2=vector.round(vector.add(ix2, add))
|
||||
if minetest.get_item_group(minetest.get_node(pts1).name, "platform")>0 then
|
||||
local ckpts={
|
||||
pts1,
|
||||
pts2,
|
||||
vector.add(pts1, {x=0, y=1, z=0}),
|
||||
vector.add(pts2, {x=0, y=1, z=0}),
|
||||
}
|
||||
for _,ckpos in ipairs(ckpts) do
|
||||
local cpp=minetest.pos_to_string(ckpos)
|
||||
if advtrains.playersbypts[cpp] then
|
||||
self:on_rightclick(advtrains.playersbypts[cpp])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--position recalculation
|
||||
local first_pos=gp.path[math.floor(index)]
|
||||
local second_pos=gp.path[math.floor(index)+1]
|
||||
if not first_pos or not second_pos then
|
||||
--atprint(" object "..self.unique_id.." path end reached!")
|
||||
self.object:setvelocity({x=0,y=0,z=0})
|
||||
return
|
||||
end
|
||||
|
||||
--checking for environment collisions(a 3x3 cube around the center)
|
||||
if not gp.recently_collided_with_env then
|
||||
local collides=false
|
||||
for x=-1,1 do
|
||||
for y=0,2 do
|
||||
for z=-1,1 do
|
||||
local node=minetest.get_node_or_nil(vector.add(first_pos, {x=x, y=y, z=z}))
|
||||
if (advtrains.train_collides(node)) then
|
||||
collides=true
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
if collides then
|
||||
if self.collision_count and self.collision_count>10 then
|
||||
--enable collision mercy to get trains stuck in walls out of walls
|
||||
--actually do nothing except limiting the velocity to 1
|
||||
gp.velocity=math.min(gp.velocity, 1)
|
||||
gp.tarvelocity=math.min(gp.tarvelocity, 1)
|
||||
else
|
||||
gp.recently_collided_with_env=true
|
||||
gp.velocity=2*gp.velocity
|
||||
gp.movedir=-gp.movedir
|
||||
gp.tarvelocity=0
|
||||
self.collision_count=(self.collision_count or 0)+1
|
||||
end
|
||||
else
|
||||
self.collision_count=nil
|
||||
end
|
||||
end
|
||||
|
||||
--FIX: use index of the wagon, not of the train.
|
||||
local velocity=(gp.velocity*gp.movedir)/(gp.path_dist[math.floor(index)] or 1)
|
||||
local acceleration=(gp.last_accel or 0)/(gp.path_dist[math.floor(index)] or 1)
|
||||
local factor=index-math.floor(index)
|
||||
local actual_pos={x=first_pos.x-(first_pos.x-second_pos.x)*factor, y=first_pos.y-(first_pos.y-second_pos.y)*factor, z=first_pos.z-(first_pos.z-second_pos.z)*factor,}
|
||||
local velocityvec={x=(first_pos.x-second_pos.x)*velocity*-1, z=(first_pos.z-second_pos.z)*velocity*-1, y=(first_pos.y-second_pos.y)*velocity*-1}
|
||||
local accelerationvec={x=(first_pos.x-second_pos.x)*acceleration*-1, z=(first_pos.z-second_pos.z)*acceleration*-1, y=(first_pos.y-second_pos.y)*acceleration*-1}
|
||||
|
||||
--some additional positions to determine orientation
|
||||
local aposfwd=gp.path[math.floor(index+2)]
|
||||
local aposbwd=gp.path[math.floor(index-1)]
|
||||
|
||||
local yaw
|
||||
if aposfwd and aposbwd then
|
||||
yaw=advtrains.get_wagon_yaw(aposfwd, second_pos, first_pos, aposbwd, factor)+math.pi--TODO remove when cleaning up
|
||||
else
|
||||
self.collision_count=nil
|
||||
yaw=math.atan2((first_pos.x-second_pos.x), (second_pos.z-first_pos.z))
|
||||
end
|
||||
end
|
||||
|
||||
--FIX: use index of the wagon, not of the train.
|
||||
local velocity=(gp.velocity*gp.movedir)/(gp.path_dist[math.floor(index)] or 1)
|
||||
local acceleration=(gp.last_accel or 0)/(gp.path_dist[math.floor(index)] or 1)
|
||||
local factor=index-math.floor(index)
|
||||
local actual_pos={x=first_pos.x-(first_pos.x-second_pos.x)*factor, y=first_pos.y-(first_pos.y-second_pos.y)*factor, z=first_pos.z-(first_pos.z-second_pos.z)*factor,}
|
||||
local velocityvec={x=(first_pos.x-second_pos.x)*velocity*-1, z=(first_pos.z-second_pos.z)*velocity*-1, y=(first_pos.y-second_pos.y)*velocity*-1}
|
||||
local accelerationvec={x=(first_pos.x-second_pos.x)*acceleration*-1, z=(first_pos.z-second_pos.z)*acceleration*-1, y=(first_pos.y-second_pos.y)*acceleration*-1}
|
||||
|
||||
--some additional positions to determine orientation
|
||||
local aposfwd=gp.path[math.floor(index+2)]
|
||||
local aposbwd=gp.path[math.floor(index-1)]
|
||||
|
||||
local yaw
|
||||
if aposfwd and aposbwd then
|
||||
yaw=advtrains.get_wagon_yaw(aposfwd, second_pos, first_pos, aposbwd, factor)+math.pi--TODO remove when cleaning up
|
||||
else
|
||||
yaw=math.atan2((first_pos.x-second_pos.x), (second_pos.z-first_pos.z))
|
||||
end
|
||||
if self.wagon_flipped then
|
||||
yaw=yaw+math.pi
|
||||
end
|
||||
|
||||
self.updatepct_timer=(self.updatepct_timer or 0)-dtime
|
||||
if not self.old_velocity_vector
|
||||
or not vector.equals(velocityvec, self.old_velocity_vector)
|
||||
or not self.old_acceleration_vector
|
||||
or not vector.equals(accelerationvec, self.old_acceleration_vector)
|
||||
or self.old_yaw~=yaw
|
||||
or self.updatepct_timer<=0 then--only send update packet if something changed
|
||||
self.object:setpos(actual_pos)
|
||||
self.object:setvelocity(velocityvec)
|
||||
self.object:setacceleration(accelerationvec)
|
||||
self.object:setyaw(yaw)
|
||||
self.updatepct_timer=2
|
||||
if self.update_animation then
|
||||
self:update_animation(gp.velocity)
|
||||
if self.wagon_flipped then
|
||||
yaw=yaw+math.pi
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self.old_velocity_vector=velocityvec
|
||||
self.old_acceleration_vector=accelerationvec
|
||||
self.old_yaw=yaw
|
||||
atprintbm("wagon step", t)
|
||||
|
||||
self.updatepct_timer=(self.updatepct_timer or 0)-dtime
|
||||
if not self.old_velocity_vector
|
||||
or not vector.equals(velocityvec, self.old_velocity_vector)
|
||||
or not self.old_acceleration_vector
|
||||
or not vector.equals(accelerationvec, self.old_acceleration_vector)
|
||||
or self.old_yaw~=yaw
|
||||
or self.updatepct_timer<=0 then--only send update packet if something changed
|
||||
self.object:setpos(actual_pos)
|
||||
self.object:setvelocity(velocityvec)
|
||||
self.object:setacceleration(accelerationvec)
|
||||
self.object:setyaw(yaw)
|
||||
self.updatepct_timer=2
|
||||
if self.update_animation then
|
||||
self:update_animation(gp.velocity)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
self.old_velocity_vector=velocityvec
|
||||
self.old_acceleration_vector=accelerationvec
|
||||
self.old_yaw=yaw
|
||||
atprintbm("wagon step", t)
|
||||
end)
|
||||
end
|
||||
|
||||
function advtrains.get_real_path_index(train, pit)
|
||||
|
@ -485,85 +491,87 @@ function advtrains.get_real_path_index(train, pit)
|
|||
end
|
||||
|
||||
function wagon:on_rightclick(clicker)
|
||||
if not self:ensure_init() then return end
|
||||
if not clicker or not clicker:is_player() then
|
||||
return
|
||||
end
|
||||
if clicker:get_player_control().aux1 then
|
||||
--advtrains.dumppath(self:train().path)
|
||||
--minetest.chat_send_all("at index "..(self:train().index or "nil"))
|
||||
--advtrains.invert_train(self.train_id)
|
||||
atprint(dump(self))
|
||||
return
|
||||
end
|
||||
local pname=clicker:get_player_name()
|
||||
local no=self:get_seatno(pname)
|
||||
if no then
|
||||
if self.seat_groups then
|
||||
local poss={}
|
||||
local sgr=self.seats[no].group
|
||||
for _,access in ipairs(self.seat_groups[sgr].access_to) do
|
||||
if self:check_seat_group_access(pname, access) then
|
||||
poss[#poss+1]={name=self.seat_groups[access].name, key="sgr_"..access}
|
||||
return advtrains.pcall(function()
|
||||
if not self:ensure_init() then return end
|
||||
if not clicker or not clicker:is_player() then
|
||||
return
|
||||
end
|
||||
if clicker:get_player_control().aux1 then
|
||||
--advtrains.dumppath(self:train().path)
|
||||
--minetest.chat_send_all("at index "..(self:train().index or "nil"))
|
||||
--advtrains.invert_train(self.train_id)
|
||||
atprint(dump(self))
|
||||
return
|
||||
end
|
||||
local pname=clicker:get_player_name()
|
||||
local no=self:get_seatno(pname)
|
||||
if no then
|
||||
if self.seat_groups then
|
||||
local poss={}
|
||||
local sgr=self.seats[no].group
|
||||
for _,access in ipairs(self.seat_groups[sgr].access_to) do
|
||||
if self:check_seat_group_access(pname, access) then
|
||||
poss[#poss+1]={name=self.seat_groups[access].name, key="sgr_"..access}
|
||||
end
|
||||
end
|
||||
end
|
||||
if self.has_inventory and self.get_inventory_formspec then
|
||||
poss[#poss+1]={name=attrans("Show Inventory"), key="inv"}
|
||||
end
|
||||
if self.owner==pname then
|
||||
poss[#poss+1]={name=attrans("Wagon properties"), key="prop"}
|
||||
end
|
||||
if not self.seat_groups[sgr].require_doors_open or self:train().door_open~=0 then
|
||||
poss[#poss+1]={name=attrans("Get off"), key="off"}
|
||||
else
|
||||
if clicker:get_player_control().sneak then
|
||||
poss[#poss+1]={name=attrans("Get off (forced)"), key="off"}
|
||||
if self.has_inventory and self.get_inventory_formspec then
|
||||
poss[#poss+1]={name=attrans("Show Inventory"), key="inv"}
|
||||
end
|
||||
if self.owner==pname then
|
||||
poss[#poss+1]={name=attrans("Wagon properties"), key="prop"}
|
||||
end
|
||||
if not self.seat_groups[sgr].require_doors_open or self:train().door_open~=0 then
|
||||
poss[#poss+1]={name=attrans("Get off"), key="off"}
|
||||
else
|
||||
poss[#poss+1]={name=attrans("(Doors closed)"), key="dcwarn"}
|
||||
if clicker:get_player_control().sneak then
|
||||
poss[#poss+1]={name=attrans("Get off (forced)"), key="off"}
|
||||
else
|
||||
poss[#poss+1]={name=attrans("(Doors closed)"), key="dcwarn"}
|
||||
end
|
||||
end
|
||||
if #poss==0 then
|
||||
--can't do anything.
|
||||
elseif #poss==1 then
|
||||
self:seating_from_key_helper(pname, {[poss[1].key]=true}, no)
|
||||
else
|
||||
local form = "size[5,"..1+(#poss).."]"
|
||||
for pos,ent in ipairs(poss) do
|
||||
form = form .. "button_exit[0.5,"..(pos-0.5)..";4,1;"..ent.key..";"..ent.name.."]"
|
||||
end
|
||||
minetest.show_formspec(pname, "advtrains_seating_"..self.unique_id, form)
|
||||
end
|
||||
end
|
||||
if #poss==0 then
|
||||
--can't do anything.
|
||||
elseif #poss==1 then
|
||||
self:seating_from_key_helper(pname, {[poss[1].key]=true}, no)
|
||||
else
|
||||
local form = "size[5,"..1+(#poss).."]"
|
||||
for pos,ent in ipairs(poss) do
|
||||
form = form .. "button_exit[0.5,"..(pos-0.5)..";4,1;"..ent.key..";"..ent.name.."]"
|
||||
end
|
||||
minetest.show_formspec(pname, "advtrains_seating_"..self.unique_id, form)
|
||||
self:get_off(no)
|
||||
end
|
||||
else
|
||||
self:get_off(no)
|
||||
end
|
||||
else
|
||||
--do not attach if already on a train
|
||||
if advtrains.player_to_train_mapping[pname] then return end
|
||||
if self.seat_groups then
|
||||
if #self.seats==0 then
|
||||
if self.has_inventory and self.get_inventory_formspec then
|
||||
minetest.show_formspec(pname, "advtrains_inv_"..self.unique_id, self:get_inventory_formspec(pname))
|
||||
--do not attach if already on a train
|
||||
if advtrains.player_to_train_mapping[pname] then return end
|
||||
if self.seat_groups then
|
||||
if #self.seats==0 then
|
||||
if self.has_inventory and self.get_inventory_formspec then
|
||||
minetest.show_formspec(pname, "advtrains_inv_"..self.unique_id, self:get_inventory_formspec(pname))
|
||||
end
|
||||
return
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local doors_open = self:train().door_open~=0 or clicker:get_player_control().sneak
|
||||
for _,sgr in ipairs(self.assign_to_seat_group) do
|
||||
if self:check_seat_group_access(pname, sgr) then
|
||||
for seatid, seatdef in ipairs(self.seats) do
|
||||
if seatdef.group==sgr and not self.seatp[seatid] and (not self.seat_groups[sgr].require_doors_open or doors_open) then
|
||||
self:get_on(clicker, seatid)
|
||||
return
|
||||
|
||||
local doors_open = self:train().door_open~=0 or clicker:get_player_control().sneak
|
||||
for _,sgr in ipairs(self.assign_to_seat_group) do
|
||||
if self:check_seat_group_access(pname, sgr) then
|
||||
for seatid, seatdef in ipairs(self.seats) do
|
||||
if seatdef.group==sgr and not self.seatp[seatid] and (not self.seat_groups[sgr].require_doors_open or doors_open) then
|
||||
self:get_on(clicker, seatid)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
minetest.chat_send_player(pname, attrans("Can't get on: wagon full or doors closed!"))
|
||||
minetest.chat_send_player(pname, attrans("Use Sneak+rightclick to bypass closed doors!"))
|
||||
else
|
||||
self:show_get_on_form(pname)
|
||||
end
|
||||
minetest.chat_send_player(pname, attrans("Can't get on: wagon full or doors closed!"))
|
||||
minetest.chat_send_player(pname, attrans("Use Sneak+rightclick to bypass closed doors!"))
|
||||
else
|
||||
self:show_get_on_form(pname)
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
function wagon:get_on(clicker, seatno)
|
||||
|
@ -708,77 +716,79 @@ function wagon:show_wagon_properties(pname)
|
|||
minetest.show_formspec(pname, "advtrains_prop_"..self.unique_id, form)
|
||||
end
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
local uid=string.match(formname, "^advtrains_geton_(.+)$")
|
||||
if uid then
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
|
||||
if fields.inv then
|
||||
if wagon.has_inventory and wagon.get_inventory_formspec then
|
||||
minetest.show_formspec(player:get_player_name(), "advtrains_inv_"..uid, wagon:get_inventory_formspec(player:get_player_name()))
|
||||
end
|
||||
elseif fields.seat then
|
||||
local val=minetest.explode_textlist_event(fields.seat)
|
||||
if val and val.type~="INV" and not wagon.seatp[player:get_player_name()] then
|
||||
--get on
|
||||
wagon:get_on(player, val.index)
|
||||
--will work with the new close_formspec functionality. close exactly this formspec.
|
||||
minetest.show_formspec(player:get_player_name(), formname, "")
|
||||
return advtrains.pcall(function()
|
||||
local uid=string.match(formname, "^advtrains_geton_(.+)$")
|
||||
if uid then
|
||||
for _,wagon in pairs(minetest.luaentities) do
|
||||
if wagon.is_wagon and wagon.initialized and wagon.unique_id==uid then
|
||||
if fields.inv then
|
||||
if wagon.has_inventory and wagon.get_inventory_formspec then
|
||||
minetest.show_formspec(player:get_player_name(), "advtrains_inv_"..uid, wagon:get_inventory_formspec(player:get_player_name()))
|
||||
end
|
||||
elseif fields.seat then
|
||||
local val=minetest.explode_textlist_event(fields.seat)
|
||||
if val and val.type~="INV" and not wagon.seatp[player:get_player_name()] then
|
||||
--get on
|
||||
wagon:get_on(player, val.index)
|
||||
--will work with the new close_formspec functionality. close exactly this formspec.
|
||||
minetest.show_formspec(player:get_player_name(), formname, "")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
uid=string.match(formname, "^advtrains_seating_(.+)$")
|
||||
if uid then
|
||||
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()
|
||||
local no=wagon:get_seatno(pname)
|
||||
if no then
|
||||
if wagon.seat_groups then
|
||||
wagon:seating_from_key_helper(pname, fields, no)
|
||||
uid=string.match(formname, "^advtrains_seating_(.+)$")
|
||||
if uid then
|
||||
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()
|
||||
local no=wagon:get_seatno(pname)
|
||||
if no then
|
||||
if wagon.seat_groups then
|
||||
wagon:seating_from_key_helper(pname, fields, no)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
uid=string.match(formname, "^advtrains_prop_(.+)$")
|
||||
if uid then
|
||||
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 fields.save or 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
|
||||
uid=string.match(formname, "^advtrains_prop_(.+)$")
|
||||
if uid then
|
||||
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 fields.save or 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
|
||||
end
|
||||
if fields.lock_couples then
|
||||
wagon.lock_couples = fields.lock_couples == "true"
|
||||
end
|
||||
if fields.text_outside then
|
||||
if fields.text_outside~="" then
|
||||
wagon:train().text_outside=fields.text_outside
|
||||
else
|
||||
wagon:train().text_outside=nil
|
||||
if fields.lock_couples then
|
||||
wagon.lock_couples = fields.lock_couples == "true"
|
||||
end
|
||||
end
|
||||
if fields.text_inside then
|
||||
if fields.text_inside~="" then
|
||||
wagon:train().text_inside=fields.text_inside
|
||||
else
|
||||
wagon:train().text_inside=nil
|
||||
if fields.text_outside then
|
||||
if fields.text_outside~="" then
|
||||
wagon:train().text_outside=fields.text_outside
|
||||
else
|
||||
wagon:train().text_outside=nil
|
||||
end
|
||||
end
|
||||
if fields.text_inside then
|
||||
if fields.text_inside~="" then
|
||||
wagon:train().text_inside=fields.text_inside
|
||||
else
|
||||
wagon:train().text_inside=nil
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end)
|
||||
end)
|
||||
function wagon:seating_from_key_helper(pname, fields, no)
|
||||
local sgr=self.seats[no].group
|
||||
|
@ -841,41 +851,43 @@ function advtrains.register_wagon(sysname, prototype, desc, inv_img)
|
|||
stack_max = 1,
|
||||
|
||||
on_place = function(itemstack, placer, pointed_thing)
|
||||
if not pointed_thing.type == "node" then
|
||||
return
|
||||
end
|
||||
|
||||
return advtrains.pcall(function()
|
||||
if not pointed_thing.type == "node" then
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local node=minetest.get_node_or_nil(pointed_thing.under)
|
||||
if not node then atprint("[advtrains]Ignore at placer position") return itemstack end
|
||||
local nodename=node.name
|
||||
if(not advtrains.is_track_and_drives_on(nodename, prototype.drives_on)) then
|
||||
atprint("no track here, not placing.")
|
||||
local node=minetest.get_node_or_nil(pointed_thing.under)
|
||||
if not node then atprint("[advtrains]Ignore at placer position") return itemstack end
|
||||
local nodename=node.name
|
||||
if(not advtrains.is_track_and_drives_on(nodename, prototype.drives_on)) then
|
||||
atprint("no track here, not placing.")
|
||||
return itemstack
|
||||
end
|
||||
if not minetest.check_player_privs(placer, {train_place = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then
|
||||
minetest.record_protection_violation(pointed_thing.under, placer:get_player_name())
|
||||
return
|
||||
end
|
||||
local conn1=advtrains.get_track_connections(node.name, node.param2)
|
||||
local id=advtrains.create_new_train_at(pointed_thing.under, advtrains.dirCoordSet(pointed_thing.under, conn1))
|
||||
|
||||
local ob=minetest.add_entity(pointed_thing.under, "advtrains:"..sysname)
|
||||
if not ob then
|
||||
atprint("couldn't add_entity, aborting")
|
||||
end
|
||||
local le=ob:get_luaentity()
|
||||
|
||||
le.owner=placer:get_player_name()
|
||||
|
||||
local wagon_uid=le:init_new_instance(id, {})
|
||||
|
||||
advtrains.add_wagon_to_train(le, id)
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack
|
||||
end
|
||||
if not minetest.check_player_privs(placer, {train_place = true }) and minetest.is_protected(pointed_thing.under, placer:get_player_name()) then
|
||||
minetest.record_protection_violation(pointed_thing.under, placer:get_player_name())
|
||||
return
|
||||
end
|
||||
local conn1=advtrains.get_track_connections(node.name, node.param2)
|
||||
local id=advtrains.create_new_train_at(pointed_thing.under, advtrains.dirCoordSet(pointed_thing.under, conn1))
|
||||
|
||||
local ob=minetest.add_entity(pointed_thing.under, "advtrains:"..sysname)
|
||||
if not ob then
|
||||
atprint("couldn't add_entity, aborting")
|
||||
end
|
||||
local le=ob:get_luaentity()
|
||||
|
||||
le.owner=placer:get_player_name()
|
||||
|
||||
local wagon_uid=le:init_new_instance(id, {})
|
||||
|
||||
advtrains.add_wagon_to_train(le, id)
|
||||
if not minetest.setting_getbool("creative_mode") then
|
||||
itemstack:take_item()
|
||||
end
|
||||
return itemstack
|
||||
|
||||
|
||||
end)
|
||||
end,
|
||||
})
|
||||
end
|
||||
|
|
|
@ -136,7 +136,7 @@ function advtrains_itm_mainloop(dtime)
|
|||
end
|
||||
timer=2
|
||||
end
|
||||
end)
|
||||
end
|
||||
minetest.register_on_player_receive_fields(function(player, formname, fields)
|
||||
if formname=="itrainmap" and fields.quit then
|
||||
itm_pdata[player:get_player_name()]=nil
|
||||
|
|
|
@ -62,10 +62,10 @@ function atlatc.load()
|
|||
end
|
||||
file:close()
|
||||
end
|
||||
-- run init code of all environments
|
||||
atlatc.run_initcode()
|
||||
end
|
||||
|
||||
-- run init code of all environments
|
||||
atlatc.run_initcode()
|
||||
|
||||
atlatc.save = function()
|
||||
--versions:
|
||||
|
@ -107,4 +107,4 @@ function atlatc.mainloop_stepcode(dtime)
|
|||
timer=0
|
||||
atlatc.run_stepcode()
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
|
|
@ -22,26 +22,24 @@ function iq.add(t, pos, evtdata)
|
|||
end
|
||||
|
||||
function iq.mainloop(dtime)
|
||||
if run then
|
||||
timer=timer + math.min(dtime, 0.2)
|
||||
for i=1,#queue do
|
||||
local qe=queue[i]
|
||||
if not qe then
|
||||
table.remove(queue, i)
|
||||
i=i-1
|
||||
elseif timer>qe.t then
|
||||
local pos, evtdata=queue[i].p, queue[i].e
|
||||
local node=advtrains.ndb.get_node(pos)
|
||||
local ndef=minetest.registered_nodes[node.name]
|
||||
if ndef and ndef.luaautomation and ndef.luaautomation.fire_event then
|
||||
ndef.luaautomation.fire_event(pos, evtdata)
|
||||
end
|
||||
table.remove(queue, i)
|
||||
i=i-1
|
||||
timer=timer + math.min(dtime, 0.2)
|
||||
for i=1,#queue do
|
||||
local qe=queue[i]
|
||||
if not qe then
|
||||
table.remove(queue, i)
|
||||
i=i-1
|
||||
elseif timer>qe.t then
|
||||
local pos, evtdata=queue[i].p, queue[i].e
|
||||
local node=advtrains.ndb.get_node(pos)
|
||||
local ndef=minetest.registered_nodes[node.name]
|
||||
if ndef and ndef.luaautomation and ndef.luaautomation.fire_event then
|
||||
ndef.luaautomation.fire_event(pos, evtdata)
|
||||
end
|
||||
table.remove(queue, i)
|
||||
i=i-1
|
||||
end
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue