2016-11-10 13:58:27 -08:00
|
|
|
--atc.lua
|
|
|
|
--registers and controls the ATC system
|
|
|
|
|
2017-01-04 03:02:00 -08:00
|
|
|
local atc={}
|
2017-01-12 08:33:43 -08:00
|
|
|
-- ATC persistence table. advtrains.atc is created by init.lua when it loads the save file.
|
2017-01-16 11:07:04 -08:00
|
|
|
atc.controllers = {}
|
|
|
|
function atc.load_data(data)
|
2017-01-31 11:52:02 -08:00
|
|
|
local temp = data and data.controllers or {}
|
|
|
|
--transcode atc controller data to node hashes: table access times for numbers are far less than for strings
|
|
|
|
for pts, data in pairs(temp) do
|
2017-02-03 11:40:30 -08:00
|
|
|
if type(pts)=="number" then
|
|
|
|
pts=minetest.pos_to_string(minetest.get_position_from_hash(pts))
|
2017-01-31 11:52:02 -08:00
|
|
|
end
|
|
|
|
atc.controllers[pts] = data
|
|
|
|
end
|
2017-01-16 11:07:04 -08:00
|
|
|
end
|
|
|
|
function atc.save_data()
|
2017-01-18 10:03:27 -08:00
|
|
|
return {controllers = atc.controllers}
|
2017-01-16 11:07:04 -08:00
|
|
|
end
|
2017-01-04 03:02:00 -08:00
|
|
|
--contents: {command="...", arrowconn=0-15 where arrow points}
|
|
|
|
|
|
|
|
--general
|
|
|
|
|
2017-02-04 12:07:18 -08:00
|
|
|
function atc.send_command(pos, par_tid)
|
2017-02-03 11:40:30 -08:00
|
|
|
local pts=minetest.pos_to_string(pos)
|
2017-01-04 03:02:00 -08:00
|
|
|
if atc.controllers[pts] then
|
2017-01-17 06:29:37 -08:00
|
|
|
--atprint("Called send_command at "..pts)
|
2017-02-04 12:07:18 -08:00
|
|
|
local train_id = par_tid or advtrains.detector.on_node[pts]
|
2017-01-04 03:02:00 -08:00
|
|
|
if train_id then
|
|
|
|
if advtrains.trains[train_id] then
|
2017-01-17 06:29:37 -08:00
|
|
|
--atprint("send_command inside if: "..sid(train_id))
|
2017-01-04 03:02:00 -08:00
|
|
|
atc.train_reset_command(train_id)
|
|
|
|
local arrowconn=atc.controllers[pts].arrowconn
|
|
|
|
local train=advtrains.trains[train_id]
|
|
|
|
for index, ppos in pairs(train.path) do
|
|
|
|
if vector.equals(advtrains.round_vector_floor_y(ppos), pos) then
|
|
|
|
advtrains.trains[train_id].atc_arrow =
|
|
|
|
vector.equals(
|
|
|
|
advtrains.dirCoordSet(pos, arrowconn),
|
|
|
|
advtrains.round_vector_floor_y(train.path[index+train.movedir])
|
|
|
|
)
|
|
|
|
advtrains.trains[train_id].atc_command=atc.controllers[pts].command
|
2017-02-20 02:14:37 -08:00
|
|
|
atprint("Sending ATC Command: ", atc.controllers[pts].command)
|
2017-02-04 09:35:34 -08:00
|
|
|
return true
|
2017-01-04 03:02:00 -08:00
|
|
|
end
|
|
|
|
end
|
2017-02-04 09:35:34 -08:00
|
|
|
atwarn("ATC rail at", pos, ": Rail not on train's path! Can't determine arrow direction. Assuming +!")
|
|
|
|
advtrains.trains[train_id].atc_arrow=true
|
|
|
|
advtrains.trains[train_id].atc_command=atc.controllers[pts].command
|
2017-02-20 02:14:37 -08:00
|
|
|
atprint("Sending ATC Command: ", atc.controllers[pts].command)
|
2017-02-04 09:35:34 -08:00
|
|
|
else
|
|
|
|
atwarn("ATC rail at", pos, ": Sending command failed: The train",train_id,"does not exist. This seems to be a bug.")
|
2017-01-04 03:02:00 -08:00
|
|
|
end
|
2017-02-04 09:35:34 -08:00
|
|
|
else
|
|
|
|
atwarn("ATC rail at", pos, ": Sending command failed: There's no train at this position. This seems to be a bug.")
|
2017-01-04 03:02:00 -08:00
|
|
|
end
|
2017-02-04 09:35:34 -08:00
|
|
|
else
|
|
|
|
atwarn("ATC rail at", pos, ": Sending command failed: Entry for controller not found.")
|
|
|
|
atwarn("ATC rail at", pos, ": Please visit controller and click 'Save'")
|
2017-01-04 03:02:00 -08:00
|
|
|
end
|
|
|
|
return false
|
|
|
|
end
|
|
|
|
|
|
|
|
function atc.train_reset_command(train_id)
|
|
|
|
advtrains.trains[train_id].atc_command=nil
|
|
|
|
advtrains.trains[train_id].atc_delay=0
|
|
|
|
advtrains.trains[train_id].atc_brake_target=nil
|
|
|
|
advtrains.trains[train_id].atc_wait_finish=nil
|
|
|
|
advtrains.trains[train_id].atc_arrow=nil
|
|
|
|
end
|
|
|
|
|
|
|
|
--nodes
|
|
|
|
local idxtrans={static=1, mesecon=2, digiline=3}
|
2017-01-16 11:07:04 -08:00
|
|
|
local apn_func=function(pos, node)
|
|
|
|
advtrains.ndb.update(pos, node)
|
2017-01-04 03:02:00 -08:00
|
|
|
local meta=minetest.get_meta(pos)
|
|
|
|
if meta then
|
2017-01-23 12:29:59 -08:00
|
|
|
meta:set_string("infotext", attrans("ATC controller, unconfigured."))
|
2017-01-04 03:02:00 -08:00
|
|
|
meta:set_string("formspec", atc.get_atc_controller_formspec(pos, meta))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
advtrains.register_tracks("default", {
|
|
|
|
nodename_prefix="advtrains:dtrack_atc",
|
|
|
|
texture_prefix="advtrains_dtrack_atc",
|
2017-03-09 02:09:01 -08:00
|
|
|
models_prefix="advtrains_dtrack",
|
2017-01-04 03:02:00 -08:00
|
|
|
models_suffix=".b3d",
|
2017-03-09 02:09:01 -08:00
|
|
|
shared_texture="advtrains_dtrack_shared_atc.png",
|
2017-01-23 12:29:59 -08:00
|
|
|
description=attrans("ATC controller"),
|
2017-01-04 03:02:00 -08:00
|
|
|
formats={},
|
|
|
|
get_additional_definiton = function(def, preset, suffix, rotation)
|
|
|
|
return {
|
|
|
|
after_place_node=apn_func,
|
|
|
|
after_dig_node=function(pos)
|
2017-04-29 10:44:43 -07:00
|
|
|
return advtrains.pcall(function()
|
2017-05-03 07:31:13 -07:00
|
|
|
advtrains.invalidate_all_paths(pos)
|
2017-04-29 10:44:43 -07:00
|
|
|
advtrains.ndb.clear(pos)
|
|
|
|
local pts=minetest.pos_to_string(pos)
|
|
|
|
atc.controllers[pts]=nil
|
|
|
|
end)
|
2017-01-04 03:02:00 -08:00
|
|
|
end,
|
|
|
|
on_receive_fields = function(pos, formname, fields, player)
|
2017-04-29 10:44:43 -07:00
|
|
|
return advtrains.pcall(function()
|
|
|
|
if advtrains.is_protected(pos, player:get_player_name()) then
|
|
|
|
minetest.record_protection_violation(pos, player:get_player_name())
|
2017-01-04 03:02:00 -08:00
|
|
|
return
|
|
|
|
end
|
2017-04-29 10:44:43 -07:00
|
|
|
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
|
2017-02-04 12:07:18 -08:00
|
|
|
end
|
2017-04-29 10:44:43 -07:00
|
|
|
end)
|
2017-01-04 03:02:00 -08:00
|
|
|
end,
|
2017-02-03 11:40:30 -08:00
|
|
|
advtrains = {
|
|
|
|
on_train_enter = function(pos, train_id)
|
|
|
|
atc.send_command(pos)
|
|
|
|
end,
|
|
|
|
},
|
2017-01-04 03:02:00 -08:00
|
|
|
}
|
|
|
|
end
|
|
|
|
}, advtrains.trackpresets.t_30deg_straightonly)
|
|
|
|
|
|
|
|
|
|
|
|
function atc.get_atc_controller_formspec(pos, meta)
|
|
|
|
local mode=tonumber(meta:get_string("mode")) or 1
|
|
|
|
local command=meta:get_string("command")
|
|
|
|
local command_on=meta:get_string("command_on")
|
|
|
|
local channel=meta:get_string("channel")
|
|
|
|
local formspec="size[8,6]"..
|
|
|
|
"dropdown[0,0;3;mode;static,mesecon,digiline;"..mode.."]"
|
|
|
|
if mode<3 then
|
2017-01-23 12:29:59 -08:00
|
|
|
formspec=formspec.."field[0.5,1.5;7,1;command;"..attrans("Command")..";"..minetest.formspec_escape(command).."]"
|
2017-01-04 03:02:00 -08:00
|
|
|
if tonumber(mode)==2 then
|
2017-01-23 12:29:59 -08:00
|
|
|
formspec=formspec.."field[0.5,3;7,1;command_on;"..attrans("Command (on)")..";"..minetest.formspec_escape(command_on).."]"
|
2017-01-04 03:02:00 -08:00
|
|
|
end
|
|
|
|
else
|
2017-01-23 12:29:59 -08:00
|
|
|
formspec=formspec.."field[0.5,1.5;7,1;channel;"..attrans("Digiline channel")..";"..minetest.formspec_escape(channel).."]"
|
2017-01-04 03:02:00 -08:00
|
|
|
end
|
2017-01-23 12:29:59 -08:00
|
|
|
return formspec.."button_exit[0.5,4.5;7,1;save;"..attrans("Save").."]"
|
2017-01-04 03:02:00 -08:00
|
|
|
end
|
|
|
|
|
|
|
|
--from trainlogic.lua train step
|
|
|
|
local matchptn={
|
|
|
|
["SM"]=function(id, train)
|
|
|
|
train.tarvelocity=train.max_speed
|
|
|
|
return 2
|
|
|
|
end,
|
2017-01-24 12:10:53 -08:00
|
|
|
["S([0-9]+)"]=function(id, train, match)
|
2017-01-04 03:02:00 -08:00
|
|
|
train.tarvelocity=tonumber(match)
|
|
|
|
return #match+1
|
|
|
|
end,
|
|
|
|
["B([0-9]+)"]=function(id, train, match)
|
|
|
|
if train.velocity>tonumber(match) then
|
|
|
|
train.atc_brake_target=tonumber(match)
|
|
|
|
if train.tarvelocity>train.atc_brake_target then
|
|
|
|
train.tarvelocity=train.atc_brake_target
|
|
|
|
end
|
|
|
|
end
|
|
|
|
return #match+1
|
|
|
|
end,
|
|
|
|
["W"]=function(id, train)
|
|
|
|
train.atc_wait_finish=true
|
|
|
|
return 1
|
|
|
|
end,
|
|
|
|
["D([0-9]+)"]=function(id, train, match)
|
|
|
|
train.atc_delay=tonumber(match)
|
|
|
|
return #match+1
|
|
|
|
end,
|
|
|
|
["R"]=function(id, train)
|
|
|
|
if train.velocity<=0 then
|
|
|
|
train.movedir=train.movedir*-1
|
|
|
|
train.atc_arrow = not train.atc_arrow
|
|
|
|
else
|
2017-02-04 09:35:34 -08:00
|
|
|
atwarn(sid(id), attrans("ATC Reverse command warning: didn't reverse train, train moving!"))
|
2017-01-04 03:02:00 -08:00
|
|
|
end
|
|
|
|
return 1
|
|
|
|
end,
|
2017-01-18 10:03:27 -08:00
|
|
|
["O([LRC])"]=function(id, train, match)
|
|
|
|
local tt={L=-1, R=1, C=0}
|
|
|
|
local arr=train.atc_arrow and 1 or -1
|
|
|
|
train.door_open = tt[match]*arr*train.movedir
|
|
|
|
return 2
|
|
|
|
end,
|
2017-01-04 03:02:00 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
function atc.execute_atc_command(id, train)
|
|
|
|
--strip whitespaces
|
|
|
|
local command=string.match(train.atc_command, "^%s*(.*)$")
|
|
|
|
|
|
|
|
|
|
|
|
if string.match(command, "^%s*$") then
|
|
|
|
train.atc_command=nil
|
|
|
|
return
|
|
|
|
end
|
|
|
|
--conditional statement?
|
2017-01-27 14:43:01 -08:00
|
|
|
local is_cond, cond_applies, compare
|
2017-01-04 03:02:00 -08:00
|
|
|
local cond, rest=string.match(command, "^I([%+%-])(.+)$")
|
|
|
|
if cond then
|
|
|
|
is_cond=true
|
|
|
|
if cond=="+" then
|
|
|
|
cond_applies=train.atc_arrow
|
|
|
|
end
|
|
|
|
if cond=="-" then
|
|
|
|
cond_applies=not train.atc_arrow
|
|
|
|
end
|
|
|
|
else
|
|
|
|
cond, compare, rest=string.match(command, "^I([<>]=?)([0-9]+)(.+)$")
|
|
|
|
if cond and compare then
|
|
|
|
is_cond=true
|
|
|
|
if cond=="<" then
|
|
|
|
cond_applies=train.velocity<tonumber(compare)
|
|
|
|
end
|
|
|
|
if cond==">" then
|
|
|
|
cond_applies=train.velocity>tonumber(compare)
|
|
|
|
end
|
|
|
|
if cond=="<=" then
|
|
|
|
cond_applies=train.velocity<=tonumber(compare)
|
|
|
|
end
|
|
|
|
if cond==">=" then
|
|
|
|
cond_applies=train.velocity>=tonumber(compare)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if is_cond then
|
2017-01-04 12:34:18 -08:00
|
|
|
atprint("Evaluating if statement: "..command)
|
|
|
|
atprint("Cond: "..(cond or "nil"))
|
|
|
|
atprint("Applies: "..(cond_applies and "true" or "false"))
|
|
|
|
atprint("Rest: "..rest)
|
2017-01-04 03:02:00 -08:00
|
|
|
--find end of conditional statement
|
|
|
|
local nest, pos, elsepos=0, 1
|
|
|
|
while nest>=0 do
|
|
|
|
if pos>#rest then
|
2017-02-04 09:35:34 -08:00
|
|
|
atwarn(sid(id), attrans("ATC command syntax error: I statement not closed: @1",command))
|
2017-01-04 03:02:00 -08:00
|
|
|
atc.train_reset_command(id)
|
|
|
|
return
|
|
|
|
end
|
|
|
|
local char=string.sub(rest, pos, pos)
|
|
|
|
if char=="I" then
|
|
|
|
nest=nest+1
|
|
|
|
end
|
|
|
|
if char==";" then
|
|
|
|
nest=nest-1
|
|
|
|
end
|
|
|
|
if nest==0 and char=="E" then
|
|
|
|
elsepos=pos+0
|
|
|
|
end
|
|
|
|
pos=pos+1
|
|
|
|
end
|
|
|
|
if not elsepos then elsepos=pos-1 end
|
|
|
|
if cond_applies then
|
|
|
|
command=string.sub(rest, 1, elsepos-1)..string.sub(rest, pos)
|
|
|
|
else
|
|
|
|
command=string.sub(rest, elsepos+1, pos-2)..string.sub(rest, pos)
|
|
|
|
end
|
2017-01-04 12:34:18 -08:00
|
|
|
atprint("Result: "..command)
|
2017-01-04 03:02:00 -08:00
|
|
|
train.atc_command=command
|
|
|
|
atc.execute_atc_command(id, train)
|
|
|
|
return
|
|
|
|
else
|
|
|
|
for pattern, func in pairs(matchptn) do
|
|
|
|
local match=string.match(command, "^"..pattern)
|
|
|
|
if match then
|
|
|
|
local patlen=func(id, train, match)
|
|
|
|
|
2017-01-04 12:34:18 -08:00
|
|
|
atprint("Executing: "..string.sub(command, 1, patlen))
|
2017-01-04 03:02:00 -08:00
|
|
|
|
|
|
|
train.atc_command=string.sub(command, patlen+1)
|
|
|
|
if train.atc_delay<=0 and not train.atc_wait_finish then
|
|
|
|
--continue (recursive, cmds shouldn't get too long, and it's a end-recursion.)
|
|
|
|
atc.execute_atc_command(id, train)
|
|
|
|
end
|
|
|
|
return
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-02-04 09:35:34 -08:00
|
|
|
atwarn(sid(id), attrans("ATC command parse error: Unknown command: @1", command))
|
2017-01-04 03:02:00 -08:00
|
|
|
atc.train_reset_command(id)
|
|
|
|
end
|
|
|
|
|
2017-01-12 08:33:43 -08:00
|
|
|
|
|
|
|
|
2017-01-04 03:02:00 -08:00
|
|
|
--move table to desired place
|
|
|
|
advtrains.atc=atc
|