aboutsummaryrefslogtreecommitdiff
path: root/advtrains/trainlogic.lua
Commit message (Expand)AuthorAge
* Get door closing time from wagon definition, no longer user configurable, and...orwell2025-06-23
* Remove attrans, unify translation strings with Sorwell2025-06-10
* ATC: add "G" command to wait for green signal, improve ATC hud, potentially f...orwell2025-01-28
* Various bugfixes found in lunixforks debugorwell2025-01-09
* Node Callbacks: Call Enter/Leave at center of rail (.0 index)orwell2024-11-25
* Merge branch 'master' into route_prog_reworkorwell2024-11-11
|\
| * Implement staticdata for trainsY. Wang2024-11-09
| * Address wagon aliasing issuesY. Wang2024-11-09
| * Fix crashing when train hitting objects without armor group1F616EMO2024-11-09
| * Wagon iterator, lookup by id, and use them in code1F616EMO2024-11-09
| * Occupation system: store multiple indices for the same train, introduce rever...orwell962023-06-24
* | ARS supports triggering distant signal, other bugfixesorwell2024-07-20
* | Re-implement point origin handling (replace old points_split hack by proper s...orwell2023-10-15
* | Begin major rework of track registration systemorwell962023-09-04
|/
* Report coordinates of wagons with unregistered prototypesY. Wang2023-04-12
* On_Joinplayer: fix train ID check for attachment updateorwell962022-06-13
* Fix speed sign allowing v>max_speedY. Wang2021-12-16
* Trivial fixup for train decoupling regressionrelease-2.4.1ywang2021-11-20
* Support different types of speed restrictions; add documentationywang2021-11-07
* On-Track Collision system: Fix train teleportation when using split_at_index(...orwell962021-11-04
* Train Coupling: Change behavior so that train direction of initiating train i...orwell962021-10-25
* Disable position-based collision and coupling system for very short trains (s...orwell962021-07-07
* Rework train same-track collision system and deterministic couplingorwell962021-07-07
* Make the collision mode configurableGabriel Pérez-Cerezo2021-06-30
* Train-World collisions: Collide only with 'normal'-drawtype nodes.orwell962021-06-29
* Entity Damage: Correct sign entity nameorwell962021-06-29
* Trains splitting: retain important properties (door state, line, texts etc)orwell962021-05-22
* Deregister player from train on death in all cases (fixes #119)release-2.3.0orwell962021-04-25
* Prevent splitting trains when they're off track (fixes #178)orwell962021-04-25
* Fix undeclared globals warnings (#176)orwell962021-04-25
* LZB: Look ahead before movement, not afterorwell962021-02-12
* Fix hud and trainlogic to work togetherorwell962021-02-10
* Replace deprecated object:getxxx()/setxxx() by get_xxx()/set_xxx()orwell962021-02-10
* Remove debug facilitiesorwell962021-02-10
* Rewrite movement logic againorwell962021-02-10
* Add debug prints, modify LZB to fix problems with look_aheadorwell962021-02-10
* Start using path_invalidate_ahead()orwell962021-02-10
* More debug info to hopefully gain more info on the bugorwell962021-02-10
* Fix things, rework signal aspect select dialog, transform old aspects on-the-flyorwell962021-02-10
* Always do zero-barrier check and prevent LZB 0 overruns in movement logicorwell962021-02-10
* Fix lots of things around new LZBorwell962021-02-10
* Remove pcall wrappers completely, add command to disable advtrains mainlooporwell962021-02-10
* Implement a LZB speed lookup table for the path and rewrite velocity controlsorwell962021-02-10
* Discard get_node_or_nil() for area-loaded check and use either a distance-bas...orwell962021-02-03
* 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
* Add workaround to unload wagons that are too far away from playersorwell962020-07-12
* Add autocouple modeGabriel Pérez-Cerezo2020-06-29
an>i} end tp.tracks[nnprefix].modify[nodename]=true end function tp.add_worked(nnprefix, suffix, rotation, cycle_follows) tp.tracks[nnprefix].twcycle[suffix]=cycle_follows if not tp.tracks[nnprefix].twrotate[suffix] then tp.tracks[nnprefix].twrotate[suffix]={} end table.insert(tp.tracks[nnprefix].twrotate[suffix], rotation) end --[[ rewrite algorithm. selection criteria: these will never be changed or even selected: - tracks being already connected on both sides - tracks that are already connected on one side but are not bendable to the desired position the following situations can occur: 1. there are two more than two rails around 1.1 there is one or more subset(s) that can be directly connected -> choose the first possibility 2.2 not -> choose the first one and orient straight 2. there's exactly 1 rail around -> choose and orient straight 3. there's no rail around -> set straight ]] function tp.find_already_connected(pos)--TODO vertical calculations(check node below) local function istrackandbc(pos, conn) local cnode=minetest.get_node(advtrains.dirCoordSet(pos, conn)) local bconn=(conn+8)%16 if advtrains.is_track_and_drives_on(cnode.name, advtrains.all_tracktypes) then local cconn1, cconn2=advtrains.get_track_connections(cnode.name, cnode.param2) return cconn1==bconn or cconn2==bconn end return false end local dnode=minetest.get_node(pos) local dconn1, dconn2=advtrains.get_track_connections(dnode.name, dnode.param2) local t={[true]="true", [false]="false"} if istrackandbc(pos, dconn1) and istrackandbc(pos, dconn2) then return dconn1, dconn2 elseif istrackandbc(pos, dconn1) then return dconn1 elseif istrackandbc(pos, dconn2) then return dconn2 end return nil end function tp.rail_and_can_be_bent(originpos, conn, nnpref) local pos=advtrains.dirCoordSet(originpos, conn) local newdir=(conn+8)%16 local node=minetest.get_node(pos) local tr=tp.tracks[nnpref] if not advtrains.is_track_and_drives_on(node.name, advtrains.all_tracktypes) then return false end --rail at other end? local adj1, adj2=tp.find_already_connected(pos) if adj1 and adj2 then return false--dont destroy existing track elseif adj1 and not adj2 then if tr.double_conn[adj1.."_"..newdir] then return true--if exists, connect new rail and old end end return false else if tr.single_conn[newdir] then--just rotate old rail to right orientation return true end return false end end function tp.bend_rail(originpos, conn, nnpref) local pos=advtrains.dirCoordSet(originpos, conn) local newdir=(conn+8)%16 local node=minetest.get_node(pos) local tr=tp.tracks[nnpref] --is rail already connected? no need to bend. local conn1, conn2=advtrains.get_track_connections(node.name, node.param2) if newdir==conn1 or newdir==conn2 then return end --rail at other end? local adj1, adj2=tp.find_already_connected(pos) if adj1 and adj2 then return false--dont destroy existing track elseif adj1 and not adj2 then if tr.double_conn[adj1.."_"..newdir] then minetest.set_node(pos, tr.double_conn[adj1.."_"..newdir]) return true--if exists, connect new rail and old end end return false else if tr.single_conn[newdir] then--just rotate old rail to right orientation minetest.set_node(pos, tr.single_conn[newdir]) return true end return false end end function tp.placetrack(pos, nnpref, placer, itemstack, pointed_thing) --1. find all rails that are likely to be connected local tr=tp.tracks[nnpref] local p_rails={} for i=0,15 do if tp.rail_and_can_be_bent(pos, i, nnpref) then p_rails[#p_rails+1]=i end end if #p_rails==0 then minetest.set_node(pos, {name=nnpref.."_"..tr.default}) if minetest.registered_nodes[nnpref.."_"..tr.default] and minetest.registered_nodes[nnpref.."_"..tr.default].after_place_node then minetest.registered_nodes[nnpref.."_"..tr.default].after_place_node(pos, placer, itemstack, pointed_thing) end elseif #p_rails==1 then tp.bend_rail(pos, p_rails[1], nnpref) minetest.set_node(pos, tr.single_conn[p_rails[1]]) local nname=tr.single_conn[p_rails[1]].name if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing) end else --iterate subsets for k1, conn1 in ipairs(p_rails) do for k2, conn2 in ipairs(p_rails) do if k1~=k2 then if (tr.double_conn[conn1.."_"..conn2]) then tp.bend_rail(pos, conn1, nnpref) tp.bend_rail(pos, conn2, nnpref) minetest.set_node(pos, tr.double_conn[conn1.."_"..conn2]) local nname=tr.double_conn[conn1.."_"..conn2].name if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing) end return end end end end --not found tp.bend_rail(pos, p_rails[1], nnpref) minetest.set_node(pos, tr.single_conn[p_rails[1]]) local nname=tr.single_conn[p_rails[1]].name if minetest.registered_nodes[nname] and minetest.registered_nodes[nname].after_place_node then minetest.registered_nodes[nname].after_place_node(pos, placer, itemstack, pointed_thing) end end end function tp.register_track_placer(nnprefix, imgprefix, dispname) minetest.register_craftitem(nnprefix.."_placer",{ description = dispname, inventory_image = imgprefix.."_placer.png", 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=pointed_thing.under if minetest.is_protected(pos,name) and minetest.is_protected(upos,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() end end end return itemstack end, }) end minetest.register_craftitem("advtrains:trackworker",{ description = "Track Worker Tool\n\nLeft-click: change rail type (straight/curve/switch)\nRight-click: rotate rail/bumper/signal/etc.", groups = {cracky=1}, -- key=name, value=rating; rating=1..3. inventory_image = "advtrains_trackworker.png", 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 minetest.is_protected(pos, name) then 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.is_train_at_pos(pos) then return end local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") --print(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 = "" if not tp.tracks[nnprefix] or not tp.tracks[nnprefix].twrotate[suffix] then minetest.chat_send_player(placer:get_player_name(), "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 minetest.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(), "This node can't be rotated using the trackworker!") return end minetest.swap_node(pos, {name=nnprefix.."_"..suffix..modext[modpos+1], param2=node.param2}) end advtrains.invalidate_all_paths() 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 minetest.is_protected(pos, 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.is_train_at_pos(pos) then return end local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") --print(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(), "This node can't be changed using the trackworker!") return end end local nextsuffix=tp.tracks[nnprefix].twcycle[suffix] minetest.swap_node(pos, {name=nnprefix.."_"..nextsuffix..rotation, param2=node.param2}) --invalidate trains advtrains.invalidate_all_paths() else print(name, dump(tp.tracks)) end end, }) --putting into right place advtrains.trackplacer=tp