--atc.lua --registers and controls the ATC system local atc={} -- ATC persistence table atc.controllers = {} --contents: {command="...", arrowconn=0-15 where arrow points} advtrains.fpath_atc=minetest.get_worldpath().."/advtrains_atc" local file, err = io.open(advtrains.fpath_atc, "r") if not file then local er=err or "Unknown Error" print("[advtrains]Failed loading advtrains atc save file "..er) else local tbl = minetest.deserialize(file:read("*a")) if type(tbl) == "table" then atc.controllers=tbl.controllers end file:close() end function atc.save() --leave space for more save data. local datastr = minetest.serialize({controllers = atc.controllers}) if not datastr then minetest.log("error", "[advtrains] Failed to serialize trackdb data!") return end local file, err = io.open(advtrains.fpath_atc, "w") if err then return err end file:write(datastr) file:close() end --call from advtrains.detector subprogram function atc.trigger_controller_train_enter(pos, train_id) atc.send_command(pos) end --general function atc.send_command(pos) local pts=minetest.pos_to_string(pos) if atc.controllers[pts] then print("Called send_command at "..pts) local train_id = advtrains.detector.on_node[pts] if train_id then if advtrains.trains[train_id] then print("send_command inside if: "..sid(train_id)) 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 print("Sending ATC Command: "..atc.controllers[pts].command) end end end end 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} local apn_func=function(pos) advtrains.reset_trackdb_position(pos) local meta=minetest.get_meta(pos) if meta then meta:set_string("infotext", "ATC controller, unconfigured.") 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", models_prefix="advtrains_dtrack_detector", models_suffix=".b3d", shared_texture="advtrains_dtrack_rail_atc.png", description="ATC controller", formats={}, get_additional_definiton = function(def, preset, suffix, rotation) return { after_place_node=apn_func, on_place_rail=apn_func, after_dig_node=function(pos) advtrains.invalidate_all_paths() advtrains.reset_trackdb_position(pos) local pts=minetest.pos_to_string(pos) atc.controllers[pts]=nil end, on_receive_fields = function(pos, formname, fields, player) if minetest.is_protected(pos, player:get_player_name()) then minetest.chat_send_player(player:get_player_name(), "This position is protected!") 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]) meta:set_string("infotext", "ATC controller, mode "..fields.mode.."\n"..( fields.mode=="digiline" and "Channel: "..meta:get_string("channel") or "Command: "..meta:get_string("command") ) ) 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) meta:set_string("infotext", "ATC controller, mode "..fields.mode.."\n"..( fields.mode=="digiline" and "Channel: "..meta:get_string("channel") or "Command: "..meta:get_string("command") ) ) 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} atc.send_command(pos) end end, } 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 formspec=formspec.."field[0.5,1.5;7,1;command;Command;"..minetest.formspec_escape(command).."]" if tonumber(mode)==2 then formspec=formspec.."field[0.5,3;7,1;command_on;Command (on);"..minetest.formspec_escape(command_on).."]" end else formspec=formspec.."field[0.5,1.5;7,1;channel;Digiline channel;"..minetest.formspec_escape(channel).."]" end return formspec.."button_exit[0.5,4.5;7,1;save;Save]" end --from trainlogic.lua train step local matchptn={ ["SM"]=function(id, train) train.tarvelocity=train.max_speed return 2 end, ["S([0-9]+)"]=function(id, train, match) 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 print("ATC Reverse command warning: didn't reverse train!") end return 1 end, } 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? local is_cond, cond_applies 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" 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 print("Evaluating if statement: "..command) print("Cond: "..(cond or "nil")) print("Applies: "..(cond_applies and "true" or "false")) print("Rest: "..rest) --find end of conditional statement local nest, pos, elsepos=0, 1 while nest>=0 do if pos>#rest then print("ATC command syntax error: I statement not closed: "..command) 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 print("Result: "..command) 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) print("Executing: "..string.sub(command, 1, patlen)) 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 print("ATC command parse error: "..command) atc.train_reset_command(id) end --move table to desired place advtrains.atc=atc