aboutsummaryrefslogtreecommitdiff
path: root/advtrains/trainlogic.lua
Commit message (Collapse)AuthorAge
* add maximum length parameter to split_at_fc and split_off_locomotiveGabriel Pérez-Cerezo2020-08-21
|
* Add command to split off locomotiveGabriel Pérez-Cerezo2020-07-28
|
* Add function to step through freight codesGabriel Pérez-Cerezo2020-07-26
|
* add split_train_at_fc luaatc commandGabriel Pérez-Cerezo2020-07-26
| | | | | | This command splits the train at the second non-empty FC it encounters, taking with it the first few freight cars that all go to the same destination.
* Add workaround to unload wagons that are too far away from playersorwell962020-07-12
|
* Add autocouple modeGabriel Pérez-Cerezo2020-06-29
| | | | | | | The shunting mode no longer makes trains couple, since it was meant for other purposes. For autocoupling, the new autocoupling mode is used. If trains are in autocouple mode, they couple when they collide with another train.
* Workaround to handle split points (dt. aufgefahrene Weichen), fixing H#77orwell962020-06-10
|
* Fix trains flipping when autocouplingGabriel Pérez-Cerezo2020-06-08
|
* Simplify and optimize path_get_index_by_offset (cherrypicked)orwell962019-12-09
|
* Tentative fix for #31Gabriel Pérez-Cerezo2019-12-03
| | | | | This might fix #31 by clearing the HUD entry for the player when joining
* Don't spawn couple entities when not loadedorwell962019-11-26
|
* remove obsolete code/commentsorwell962019-11-26
|
* Shunting mode now couples trains on collision.Gabriel Pérez-Cerezo2019-08-11
| | | | Trains now get coupled when one of them is in coupling mode.
* Add decoupling to luaatcGabriel Pérez-Cerezo2019-08-11
|
* Change API to return the id of a newly created train when discouplingGabriel Pérez-Cerezo2019-08-09
|
* Run entity overrun checking only in loaded areasorwell962019-06-05
|
* Move LZB system to core and unify approach callback mechanismorwell962019-04-16
|
* Add setting for death behavior and implement damage checks betterorwell962019-03-09
|
* Prioritize LZB callback (possible bugfix for H#100)orwell962019-02-19
|
* Point speed restriction railsorwell962019-01-24
|
* Possible fix for braking problems + debug outputsorwell962019-01-23
|
* output step distance in train (debugging purposes)orwell962019-01-22
|
* Make "Can't restore train" a log message instead of atwarn()orwell962019-01-22
|
* Warn when something clears the path winthin train steporwell962019-01-22
|
* Revert "Correct last commit"orwell962019-01-22
| | | | This reverts commit 5f290819cdb78303396f9f89907ebbc66a9d74b3.
* Revert "Debugging code to trace down path_invalidate within callbacks error"orwell962019-01-22
| | | | This reverts commit 1965e846b6c61958063ea13e2ac88ae18b701d09.
* Revert "Index NaN check (tracking obscure error detected on LW migration)"orwell962019-01-22
| | | | This reverts commit e915b61da6f18efa49b6afacb7e9ca181d59cc5c.
* Correct last commitorwell962019-01-22
|
* Debugging code to trace down path_invalidate within callbacks errororwell962019-01-22
|
* Workaroundorwell962019-01-21
|
* Do not run train steps when path has been deletedorwell962019-01-21
|
* Avoid division through zero in get_accelerationorwell962019-01-21
|
* Index NaN check (tracking obscure error detected on LW migration)orwell962019-01-21
|
* Fix player_to_train_mapping (H#74)orwell962018-12-16
| | | | Entries were not inserted, thus neither damage protection nor teleport-to-train did work
* Fix crashes:orwell962018-12-10
| | | | | 1. when train hit a route, nil access to already cancelled route caused crash 2. fix crash when trying to ensure_init a train that doesn't exist
* Shunt signals (not exactly Ks), along with fixes in other components that ↵orwell962018-12-08
| | | | those rely on
* Apply speed restriction 0.5 indexes later, do not cap tarvelocity by ↵orwell962018-12-04
| | | | speed_restriction
* Remove superfluous "tarvelocity" assignmentsorwell962018-11-20
|
* Remove "couple locks" and apply protection to the actual coupling process, ↵orwell962018-11-10
| | | | and fix permissions on that
* Document fix 0a982b6356b2f4b6a28e74f9f90c4f584169a96dorwell962018-10-29
| | | | Add comment that explains why fix was necessary
* Actually set last_connid to 1, to prevent warningorwell962018-10-29
|
* Handle the case that a train is not initialized (train_ensure_init returns ↵orwell962018-10-29
| | | | | | nil/false) Fixes H#72
* Small fixes which do not have any effectorwell962018-10-29
|
* Improve ATC-LZB-User control interaction, smoothen LZB control operationsorwell962018-10-17
| | | | (prevent flickering view when atc battles against lzb)
* Address H#60, H#17, M#18 and M#7orwell962018-10-17
| | | | | | | duplicate "message" to "msg" make operation panel "cracky" remove inexistent dtime_s parameter add bones:bones to the list of not_blocking_trains nodes
* Properly handle speed restrictionsorwell962018-10-10
|
* Remote Routesetting from Onboard Computerorwell962018-10-10
| | | | + Fix lzb oncoming item deletion/speed restriction
* Properly implement invalidate_all_paths, recheck lzb on aspect changeorwell962018-10-10
|
* Add signal safety control override, restructure control systemorwell962018-10-10
|
* Teleport player to their train every 2 seconds instead of just on_joinplayerorwell962018-08-12
| | | | Solves problem of wagon being unloaded while player sitting inside it because of network lag
change did not happen through a call to advtrains.interlocking.signal_set_aspect(pos, asp), you are *required* to call this function: advtrains.interlocking.signal_on_aspect_changed(pos) in order to notify trains about the aspect change. This function will query get_aspect to retrieve the new aspect. ]]-- local DANGER = { main = { free = false, speed = 0, }, shunt = { free = false, }, dst = { free = false, speed = 0, }, info = {} } advtrains.interlocking.DANGER = DANGER local function fillout_aspect(asp) if not asp.main then asp.main = { free = true, } end if not asp.dst then asp.dst = { free = true, } end if not asp.shunt then asp.shunt = { free = false, proceed_as_main = false, } end if not asp.info then asp.info = {} end end function advtrains.interlocking.update_signal_aspect(tcbs) if tcbs.signal then local asp = tcbs.aspect or DANGER advtrains.interlocking.signal_set_aspect(tcbs.signal, asp) end end function advtrains.interlocking.signal_can_dig(pos) return not advtrains.interlocking.db.get_sigd_for_signal(pos) end function advtrains.interlocking.signal_after_dig(pos) -- clear influence point advtrains.interlocking.db.clear_ip_by_signalpos(pos) end function advtrains.interlocking.signal_set_aspect(pos, asp) fillout_aspect(asp) local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] if ndef and ndef.advtrains and ndef.advtrains.set_aspect then ndef.advtrains.set_aspect(pos, node, asp) advtrains.interlocking.signal_on_aspect_changed(pos) end end -- should be called when aspect has changed on this signal. function advtrains.interlocking.signal_on_aspect_changed(pos) local ipts, iconn = advtrains.interlocking.db.get_ip_by_signalpos(pos) if not ipts then return end local ipos = minetest.string_to_pos(ipts) local tns = advtrains.occ.get_trains_over(ipos) for id, sidx in pairs(tns) do local train = advtrains.trains[id] --if train.index <= sidx then advtrains.interlocking.lzb_invalidate(train) --end end end function advtrains.interlocking.signal_rc_handler(pos, node, player, itemstack, pointed_thing) local pname = player:get_player_name() local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos) if sigd then advtrains.interlocking.show_signalling_form(sigd, pname) else local ndef = minetest.registered_nodes[node.name] if ndef.advtrains and ndef.advtrains.set_aspect then -- permit to set aspect manually minetest.show_formspec(pname, "at_il_sigasp_"..minetest.pos_to_string(pos), "field[aspect;Set Aspect ('A' to assign IP);D0D0D]") else --static signal - only IP advtrains.interlocking.show_ip_form(pos, pname) end end end minetest.register_on_player_receive_fields(function(player, formname, fields) local pname = player:get_player_name() local pts = string.match(formname, "^at_il_sigasp_(.+)$") local pos if pts then pos = minetest.string_to_pos(pts) end if pos and fields.aspect then if fields.aspect == "A" then advtrains.interlocking.show_ip_form(pos, pname) return end local mfs, msps, dfs, dsps, shs = string.match(fields.aspect, "^([FD])([-0-9]+)([FD])([-0-9]+)([FD])$") local asp = { main = { free = mfs=="F", speed = tonumber(msps), }, shunt = { free = shs=="F", }, dst = { free = dfs=="F", speed = tonumber(dsps), }, info = { call_on = false, -- Call-on route, expect train in track ahead dead_end = false, -- Route ends on a dead end (e.g. bumper) } } advtrains.interlocking.signal_set_aspect(pos, asp) end end) -- Returns the aspect the signal at pos is supposed to show function advtrains.interlocking.signal_get_supposed_aspect(pos) local sigd = advtrains.interlocking.db.get_sigd_for_signal(pos) if sigd then local tcbs = advtrains.interlocking.db.get_tcbs(sigd) if tcbs.aspect then return tcbs.aspect end end return DANGER; end -- Returns the actual aspect of the signal at position, as returned by the nodedef. -- returns nil when there's no signal at the position function advtrains.interlocking.signal_get_aspect(pos) local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] if ndef and ndef.advtrains and ndef.advtrains.get_aspect then local asp = ndef.advtrains.get_aspect(pos, node) if not asp then asp = DANGER end fillout_aspect(asp) return asp end return nil end -- Returns the "supported_aspects" of the signal at position, as returned by the nodedef. -- returns nil when there's no signal at the position function advtrains.interlocking.signal_get_supported_aspects(pos) local node=advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] if ndef and ndef.advtrains and ndef.advtrains.supported_aspects then local asp = ndef.advtrains.supported_aspects return asp end return nil end local players_assign_ip = {} local function ipmarker(ipos, connid) local node_ok, conns, rhe = advtrains.get_rail_info_at(ipos, advtrains.all_tracktypes) if not node_ok then return end local yaw = advtrains.dir_to_angle(conns[connid].c) -- using tcbmarker here local obj = minetest.add_entity(vector.add(ipos, {x=0, y=0.2, z=0}), "advtrains_interlocking:tcbmarker") if not obj then return end obj:set_yaw(yaw) obj:set_properties({ textures = { "at_il_signal_ip.png" }, }) end -- shows small info form for signal IP state/assignment -- only_notset: show only if it is not set yet (used by signal tcb assignment) function advtrains.interlocking.show_ip_form(pos, pname, only_notset) if not minetest.check_player_privs(pname, "interlocking") then return end local form = "size[7,5]label[0.5,0.5;Signal at "..minetest.pos_to_string(pos).."]" local pts, connid = advtrains.interlocking.db.get_ip_by_signalpos(pos) if pts then form = form.."label[0.5,1.5;Influence point is set at "..pts.."/"..connid.."]" form = form.."button_exit[0.5,2.5; 5,1;set;Move]" form = form.."button_exit[0.5,3.5; 5,1;clear;Clear]" local ipos = minetest.string_to_pos(pts) ipmarker(ipos, connid) else form = form.."label[0.5,1.5;Influence point is not set.]" form = form.."label[0.5,2.0;It is recommended to set an influence point.]" form = form.."label[0.5,2.5;This is the point where trains will obey the signal.]" form = form.."button_exit[0.5,3.5; 5,1;set;Set]" end if not only_notset or not pts then minetest.show_formspec(pname, "at_il_ipassign_"..minetest.pos_to_string(pos), form) end end minetest.register_on_player_receive_fields(function(player, formname, fields) local pname = player:get_player_name() if not minetest.check_player_privs(pname, {train_operator=true, interlocking=true}) then return end local pts = string.match(formname, "^at_il_ipassign_([^_]+)$") local pos if pts then pos = minetest.string_to_pos(pts) end if pos then if fields.set then advtrains.interlocking.signal_init_ip_assign(pos, pname) elseif fields.clear then advtrains.interlocking.db.clear_ip_by_signalpos(pos) end end end) -- inits the signal IP assignment process function advtrains.interlocking.signal_init_ip_assign(pos, pname) if not minetest.check_player_privs(pname, "interlocking") then minetest.chat_send_player(pname, "Insufficient privileges to use this!") return end --remove old IP --advtrains.interlocking.db.clear_ip_by_signalpos(pos) minetest.chat_send_player(pname, "Configuring Signal: Please look in train's driving direction and punch rail to set influence point.") players_assign_ip[pname] = pos end minetest.register_on_punchnode(function(pos, node, player, pointed_thing) local pname = player:get_player_name() if not minetest.check_player_privs(pname, "interlocking") then return end -- IP assignment local signalpos = players_assign_ip[pname] if signalpos then if vector.distance(pos, signalpos)<=50 then local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, advtrains.all_tracktypes) if node_ok and #conns == 2 then local yaw = player:get_look_horizontal() local plconnid = advtrains.yawToClosestConn(yaw, conns) -- add assignment if not already present. local pts = advtrains.roundfloorpts(pos) if not advtrains.interlocking.db.get_ip_signal_asp(pts, plconnid) then advtrains.interlocking.db.set_ip_signal(pts, plconnid, signalpos) ipmarker(pos, plconnid) minetest.chat_send_player(pname, "Configuring Signal: Successfully set influence point") else minetest.chat_send_player(pname, "Configuring Signal: Influence point of another signal is already present!") end else minetest.chat_send_player(pname, "Configuring Signal: This is not a normal two-connection rail! Aborted.") end else minetest.chat_send_player(pname, "Configuring Signal: Node is too far away. Aborted.") end players_assign_ip[pname] = nil end end) --== aspect selector ==-- local players_aspsel = {} --[[ suppasp: "supported_aspects" table purpose: form title string callback: func(pname, aspect) called on form submit ]] function advtrains.interlocking.show_signal_aspect_selector(pname, p_suppasp, p_purpose, callback, p_isasp) local suppasp = p_suppasp or { main = {}, dst = {}, shunt = {}, info = {}, } local purpose = p_purpose or "" local isasp = p_isasp and fillout_aspect(p_isasp) local form = "size[7,5]label[0.5,0.5;Select Signal Aspect:]" form = form.."label[0.5,1;"..purpose.."]" form = form.."label[0.5,1.5;== Main Signal ==]" if suppasp.main.free == nil then local st = 2 if isasp and not isasp.main.free then st=1 end form = form.."dropdown[0.5,2;2;main_free;danger,free;"..st.."]" end if suppasp.main.speed then local selid = 1 if isasp and isasp.main.speed then for idx, spv in ipairs(suppasp.main.speed) do if spv == isasp.main.speed then selid = idx break end end end form = form.."label[2.3,1;Speed:]"