From 950d6f640cae76d28253fadb7974a064017b104c Mon Sep 17 00:00:00 2001 From: orwell96 Date: Mon, 4 Sep 2023 19:34:47 +0200 Subject: Begin major rework of track registration system --- advtrains/api_doc.txt | 2 - advtrains/copytool.lua | 2 +- advtrains/helpers.lua | 6 +- advtrains/nodedb.lua | 6 +- advtrains/oldtracks.lua | 751 ++++++++++++++++++++++++ advtrains/passive.lua | 90 ++- advtrains/path.lua | 7 +- advtrains/signals.lua | 7 +- advtrains/trackplacer.lua | 592 ++++++++----------- advtrains/tracks.lua | 1038 ++++++++++----------------------- advtrains/trainlogic.lua | 12 +- advtrains/wagons.lua | 5 +- advtrains_interlocking/init.lua | 4 +- advtrains_line_automation/init.lua | 4 +- advtrains_signals_ks/init.lua | 21 +- advtrains_train_track/init.lua | 1109 ++++++------------------------------ advtrains_train_track/oldinit.lua | 937 ++++++++++++++++++++++++++++++ 17 files changed, 2443 insertions(+), 2150 deletions(-) create mode 100644 advtrains/oldtracks.lua create mode 100644 advtrains_train_track/oldinit.lua diff --git a/advtrains/api_doc.txt b/advtrains/api_doc.txt index 5668ba3..6b338a7 100644 --- a/advtrains/api_doc.txt +++ b/advtrains/api_doc.txt @@ -18,8 +18,6 @@ advtrains.register_wagon(name, prototype, description, inventory_image) # Wagon prototype properties { ... all regular luaentity properties (mesh, textures, collisionbox a.s.o)... - drives_on = {default=true}, - ^- used to define the tracktypes (see below) that wagon can drive on. The tracktype identifiers are given as keys, similar to privileges) max_speed = 10, ^- optional, default 10: defines the maximum speed this wagon can drive. The maximum speed of a train is determined by the wagon with the lowest max_speed value. seats = { diff --git a/advtrains/copytool.lua b/advtrains/copytool.lua index 0c1cdfe..8a6d2f7 100644 --- a/advtrains/copytool.lua +++ b/advtrains/copytool.lua @@ -21,7 +21,7 @@ minetest.register_tool("advtrains:copytool", { 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, {default=true})) then + if(not advtrains.is_track(nodename)) then atprint("no track here, not placing.") return itemstack end diff --git a/advtrains/helpers.lua b/advtrains/helpers.lua index 7e078fb..7a774d9 100644 --- a/advtrains/helpers.lua +++ b/advtrains/helpers.lua @@ -294,7 +294,7 @@ end -- Going from the rail at pos (does not need to be rounded) along connection with id conn_idx, if there is a matching rail, return it and the matching connid -- returns: , , , -- parameter this_conns_p is connection table of this rail and is optional, is determined by get_rail_info_at if not provided. -function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx, drives_on) +function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx) local this_pos = advtrains.round_vector_floor_y(this_posnr) local this_conns = this_conns_p local _ @@ -318,11 +318,11 @@ function advtrains.get_adjacent_rail(this_posnr, this_conns_p, conn_idx, drives_ adj_pos.y = adj_pos.y + 1 end - local nextnode_ok, nextconns, nextrail_y=advtrains.get_rail_info_at(adj_pos, drives_on) + local nextnode_ok, nextconns, nextrail_y=advtrains.get_rail_info_at(adj_pos) if not nextnode_ok then adj_pos.y = adj_pos.y - 1 conn_y = conn_y + 1 - nextnode_ok, nextconns, nextrail_y=advtrains.get_rail_info_at(adj_pos, drives_on) + nextnode_ok, nextconns, nextrail_y=advtrains.get_rail_info_at(adj_pos) if not nextnode_ok then return nil end diff --git a/advtrains/nodedb.lua b/advtrains/nodedb.lua index 41ac089..39106b2 100644 --- a/advtrains/nodedb.lua +++ b/advtrains/nodedb.lua @@ -268,17 +268,17 @@ end --false if it's not a rail or the train does not drive on this rail, but it is loaded or --nil if the node is neither loaded nor in trackdb --the distraction between false and nil will be needed only in special cases.(train initpos) -function advtrains.get_rail_info_at(pos, drives_on) +function advtrains.get_rail_info_at(pos) local rdp=advtrains.round_vector_floor_y(pos) local node=ndb.get_node_or_nil(rdp) if not node then return end local nodename=node.name - if(not advtrains.is_track_and_drives_on(nodename, drives_on)) then + if(not advtrains.is_track(nodename)) then return false end - local conns, railheight, tracktype=advtrains.get_track_connections(node.name, node.param2) + local conns, railheight = advtrains.get_track_connections(node.name, node.param2) return true, conns, railheight end diff --git a/advtrains/oldtracks.lua b/advtrains/oldtracks.lua new file mode 100644 index 0000000..c415143 --- /dev/null +++ b/advtrains/oldtracks.lua @@ -0,0 +1,751 @@ +--advtrains by orwell96, see readme.txt + +--dev-time settings: +--EDIT HERE +--If the old non-model rails on straight tracks should be replaced by the new... +--false: no +--true: yes +advtrains.register_replacement_lbms=false + +--[[TracksDefinition +nodename_prefix +texture_prefix +description +common={} +straight={} +straight45={} +curve={} +curve45={} +lswitchst={} +lswitchst45={} +rswitchst={} +rswitchst45={} +lswitchcr={} +lswitchcr45={} +rswitchcr={} +rswitchcr45={} +vert1={ + --you'll probably want to override mesh here +} +vert2={ + --you'll probably want to override mesh here +} +]]-- +advtrains.all_tracktypes={} + +--definition preparation +local function conns(c1, c2, r1, r2) return {{c=c1, y=r1}, {c=c2, y=r2}} end +local function conns3(c1, c2, c3, r1, r2, r3) return {{c=c1, y=r1}, {c=c2, y=r2}, {c=c3, y=r3}} end + +advtrains.ap={} +advtrains.ap.t_30deg_flat={ + regstep=1, + variant={ + st={ + conns = conns(0,8), + desc = "straight", + tpdouble = true, + tpsingle = true, + trackworker = "cr", + }, + cr={ + conns = conns(0,7), + desc = "curve", + tpdouble = true, + trackworker = "swlst", + }, + swlst={ + conns = conns3(0,8,7), + desc = "left switch (straight)", + trackworker = "swrst", + switchalt = "cr", + switchmc = "on", + switchst = "st", + switchprefix = "swl", + }, + swlcr={ + conns = conns3(0,7,8), + desc = "left switch (curve)", + trackworker = "swrcr", + switchalt = "st", + switchmc = "off", + switchst = "cr", + switchprefix = "swl", + }, + swrst={ + conns = conns3(0,8,9), + desc = "right switch (straight)", + trackworker = "st", + switchalt = "cr", + switchmc = "on", + switchst = "st", + switchprefix = "swr", + }, + swrcr={ + conns = conns3(0,9,8), + desc = "right switch (curve)", + trackworker = "st", + switchalt = "st", + switchmc = "off", + switchst = "cr", + switchprefix = "swr", + }, + }, + regtp=true, + tpdefault="st", + trackworker={ + ["swrcr"]="st", + ["swrst"]="st", + ["cr"]="swlst", + ["swlcr"]="swrcr", + ["swlst"]="swrst", + }, + rotation={"", "_30", "_45", "_60"}, +} +advtrains.ap.t_yturnout={ + regstep=1, + variant={ + l={ + conns = conns3(0,7,9), + desc = "Y-turnout (left)", + switchalt = "r", + switchmc = "off", + switchst = "l", + switchprefix = "", + }, + r={ + conns = conns3(0,9,7), + desc = "Y-turnout (right)", + switchalt = "l", + switchmc = "on", + switchst = "r", + switchprefix = "", + } + }, + regtp=true, + tpdefault="l", + rotation={"", "_30", "_45", "_60"}, +} +advtrains.ap.t_s3way={ + regstep=1, + variant={ + l={ + conns = { {c=0}, {c=7}, {c=8}, {c=9}, {c=0} }, + desc = "3-way turnout (left)", + switchalt = "s", + switchst="l", + switchprefix = "", + }, + s={ + conns = { {c=0}, {c=8}, {c=7}, {c=9}, {c=0} }, + desc = "3-way turnout (straight)", + switchalt ="r", + switchst = "s", + switchprefix = "", + }, + r={ + conns = { {c=0}, {c=9}, {c=8}, {c=7}, {c=0} }, + desc = "3-way turnout (right)", + switchalt = "l", + switchst="r", + switchprefix = "", + } + }, + regtp=true, + tpdefault="l", + rotation={"", "_30", "_45", "_60"}, +} +advtrains.ap.t_30deg_slope={ + regstep=1, + variant={ + vst1={conns = conns(8,0,0,0.5), rail_y = 0.25, desc = "steep uphill 1/2", slope=true}, + vst2={conns = conns(8,0,0.5,1), rail_y = 0.75, desc = "steep uphill 2/2", slope=true}, + vst31={conns = conns(8,0,0,0.33), rail_y = 0.16, desc = "uphill 1/3", slope=true}, + vst32={conns = conns(8,0,0.33,0.66), rail_y = 0.5, desc = "uphill 2/3", slope=true}, + vst33={conns = conns(8,0,0.66,1), rail_y = 0.83, desc = "uphill 3/3", slope=true}, + }, + regsp=true, + slopeplacer={ + [2]={"vst1", "vst2"}, + [3]={"vst31", "vst32", "vst33"}, + max=3,--highest entry + }, + slopeplacer_45={ + [2]={"vst1_45", "vst2_45"}, + max=2, + }, + rotation={"", "_30", "_45", "_60"}, + trackworker={}, + increativeinv={}, +} +advtrains.ap.t_30deg_straightonly={ + regstep=1, + variant={ + st={ + conns = conns(0,8), + desc = "straight", + tpdouble = true, + tpsingle = true, + trackworker = "st", + }, + }, + regtp=true, + tpdefault="st", + rotation={"", "_30", "_45", "_60"}, +} +advtrains.ap.t_30deg_straightonly_noplacer={ + regstep=1, + variant={ + st={ + conns = conns(0,8), + desc = "straight", + tpdouble = true, + tpsingle = true, + trackworker = "st", + }, + }, + tpdefault="st", + rotation={"", "_30", "_45", "_60"}, +} +advtrains.ap.t_45deg={ + regstep=2, + variant={ + st={ + conns = conns(0,8), + desc = "straight", + tpdouble = true, + tpsingle = true, + trackworker = "cr", + }, + cr={ + conns = conns(0,6), + desc = "curve", + tpdouble = true, + trackworker = "swlst", + }, + swlst={ + conns = conns3(0,8,6), + desc = "left switch (straight)", + trackworker = "swrst", + switchalt = "cr", + switchmc = "on", + switchst = "st", + }, + swlcr={ + conns = conns3(0,6,8), + desc = "left switch (curve)", + trackworker = "swrcr", + switchalt = "st", + switchmc = "off", + switchst = "cr", + }, + swrst={ + conns = conns3(0,8,10), + desc = "right switch (straight)", + trackworker = "st", + switchalt = "cr", + switchmc = "on", + switchst = "st", + }, + swrcr={ + conns = conns3(0,10,8), + desc = "right switch (curve)", + trackworker = "st", + switchalt = "st", + switchmc = "off", + switchst = "cr", + }, + }, + regtp=true, + tpdefault="st", + trackworker={ + ["swrcr"]="st", + ["swrst"]="st", + ["cr"]="swlst", + ["swlcr"]="swrcr", + ["swlst"]="swrst", + }, + rotation={"", "_30", "_45", "_60"}, +} +advtrains.ap.t_perpcrossing={ + regstep = 1, + variant={ + st={ + conns = { {c=0}, {c=8}, {c=4}, {c=12} }, + desc = "perpendicular crossing", + tpdouble = true, + tpsingle = true, + trackworker = "st", + }, + }, + regtp=true, + tpdefault="st", + rotation={"", "_30", "_45", "_60"}, +} +advtrains.ap.t_90plusx_crossing={ + regstep = 1, + variant={ + ["30l"]={ + conns = { {c=0}, {c=8}, {c=1}, {c=9} }, + desc = "30/90 degree crossing (left)", + tpdouble = true, + tpsingle = true, + trackworker = "45l" + }, + ["45l"]={ + conns = { {c=0}, {c=8}, {c=2}, {c=10} }, + desc = "45/90 degree crossing (left)", + tpdouble = true, + tpsingle = true, + trackworker = "60l", + }, + ["60l"]={ + conns = { {c=0}, {c=8}, {c=3}, {c=11}}, + desc = "60/90 degree crossing (left)", + tpdouble = true, + tpsingle = true, + trackworker = "60r", + }, + ["60r"]={ + conns = { {c=0}, {c=8}, {c=5}, {c=13} }, + desc = "60/90 degree crossing (right)", + tpdouble = true, + tpsingle = true, + trackworker = "45r" + }, + ["45r"]={ + conns = { {c=0}, {c=8}, {c=6}, {c=14} }, + desc = "45/90 degree crossing (right)", + tpdouble = true, + tpsingle = true, + trackworker = "30r", + }, + ["30r"]={ + conns = { {c=0}, {c=8}, {c=7}, {c=15}}, + desc = "30/90 degree crossing (right)", + tpdouble = true, + tpsingle = true, + trackworker = "30l", + }, + }, + regtp=true, + tpdefault="30l", + rotation={""}, + trackworker = { + ["30l"] = "45l", + ["45l"] = "60l", + ["60l"] = "60r", + ["60r"] = "45r", + ["45r"] = "30r", + ["30r"] = "30l", + } +} + +advtrains.ap.t_diagonalcrossing = { + regstep=1, + variant={ + ["30l45r"]={ + conns = {{c=1}, {c=9}, {c=6}, {c=14}}, + desc = "30left-45right diagonal crossing", + tpdouble=true, + tpsingle=true, + trackworker="60l30l", + }, + ["60l30l"]={ + conns = {{c=3}, {c=11}, {c=1}, {c=9}}, + desc = "30left-60right diagonal crossing", + tpdouble=true, + tpsingle=true, + trackworker="60l45r" + }, + ["60l45r"]={ + conns = {{c=3}, {c=11}, {c=6}, {c=14}}, + desc = "60left-45right diagonal crossing", + tpdouble=true, + tpsingle=true, + trackworker="60l60r" + }, + ["60l60r"]={ + conns = {{c=3}, {c=11}, {c=5}, {c=13}}, + desc = "60left-60right diagonal crossing", + tpdouble=true, + tpsingle=true, + trackworker="60r45l", + }, + --If 60l60r had a mirror image, it would be here, but it's symmetric. + -- 60l60r is also equivalent to 30l30r but rotated 90 degrees. + ["60r45l"]={ + conns = {{c=5}, {c=13}, {c=2}, {c=10}}, + desc = "60right-45left diagonal crossing", + tpdouble=true, + tpsingle=true, + trackworker="60r30r", + }, + ["60r30r"]={ + conns = {{c=5}, {c=13}, {c=7}, {c=15}}, + desc = "60right-30right diagonal crossing", + tpdouble=true, + tpsingle=true, + trackworker="30r45l", + }, + ["30r45l"]={ + conns = {{c=7}, {c=15}, {c=2}, {c=10}}, + desc = "30right-45left diagonal crossing", + tpdouble=true, + tpsingle=true, + trackworker="30l45r", + }, + + }, + regtp=true, + tpdefault="30l45r", + rotation={""}, + trackworker = { + ["30l45r"] = "60l30l", + ["60l30l"] = "60l45r", + ["60l45r"] = "60l60r", + ["60l60r"] = "60r45l", + ["60r45l"] = "60r30r", + ["60r30r"] = "30r45l", + ["30r45l"] = "30l45r", + } +} + +advtrains.trackpresets = advtrains.ap + +--definition format: ([] optional) +--[[{ + nodename_prefix + texture_prefix + [shared_texture] + models_prefix + models_suffix (with dot) + [shared_model] + formats={ + st,cr,swlst,swlcr,swrst,swrcr,vst1,vst2 + (each a table with indices 0-3, for if to register a rail with this 'rotation' table entry. nil is assumed as 'all', set {} to not register at all) + } + common={} change something on common rail appearance +} +[18.12.17] Note on new connection system: +In order to support real rail crossing nodes and finally make the trackplacer respect switches, I changed the connection system. +There can be a variable number of connections available. These are specified as tuples {c=, y=} +The table "at_conns" consists of {, ...} +the "at_rail_y" property holds the value that was previously called "railheight" +Depending on the number of connections: +2 conns: regular rail +3 conns: switch: + - when train passes in at conn1, will move out of conn2 + - when train passes in at conn2 or conn3, will move out of conn1 +4 conns: cross (or cross switch, depending on arrangement of conns): + - conn1 <> conn2 + - conn3 <> conn4 +]] + +-- Notify the user if digging the rail is not allowed +local function can_dig_callback(pos, player) + local ok, reason = advtrains.can_dig_or_modify_track(pos) + if not ok and player then + minetest.chat_send_player(player:get_player_name(), attrans("This track can not be removed!") .. " " .. reason) + end + return ok +end + +function advtrains.register_tracks(tracktype, def, preset) + advtrains.trackplacer.register_tracktype(def.nodename_prefix, preset.tpdefault) + if preset.regtp then + advtrains.trackplacer.register_track_placer(def.nodename_prefix, def.texture_prefix, def.description, def) + end + if preset.regsp then + advtrains.slope.register_placer(def, preset) + end + for suffix, var in pairs(preset.variant) do + for rotid, rotation in ipairs(preset.rotation) do + if not def.formats[suffix] or def.formats[suffix][rotid] then + local img_suffix = suffix..rotation + local ndef = advtrains.merge_tables({ + description=def.description.."("..(var.desc or "any")..rotation..")", + drawtype = "mesh", + paramtype="light", + paramtype2="facedir", + walkable = false, + selection_box = { + type = "fixed", + fixed = {-1/2-1/16, -1/2, -1/2, 1/2+1/16, -1/2+2/16, 1/2}, + }, + + mesh = def.shared_model or (def.models_prefix.."_"..img_suffix..def.models_suffix), + tiles = {def.shared_texture or (def.texture_prefix.."_"..img_suffix..".png"), def.second_texture}, + + groups = { + attached_node = advtrains.IGNORE_WORLD and 0 or 1, + advtrains_track=1, + ["advtrains_track_"..tracktype]=1, + save_in_at_nodedb=1, + dig_immediate=2, + not_in_creative_inventory=1, + not_blocking_trains=1, + }, + + can_dig = can_dig_callback, + after_dig_node=function(pos) + advtrains.ndb.update(pos) + end, + after_place_node=function(pos) + advtrains.ndb.update(pos) + end, + at_nnpref = def.nodename_prefix, + at_suffix = suffix, + at_rotation = rotation, + at_rail_y = var.rail_y + }, def.common or {}) + + if preset.regtp then + ndef.drop = def.nodename_prefix.."_placer" + end + if preset.regsp and var.slope then + ndef.drop = def.nodename_prefix.."_slopeplacer" + end + + --connections + ndef.at_conns = advtrains.rotate_conn_by(var.conns, (rotid-1)*preset.regstep) + + local ndef_avt_table + + if var.switchalt and var.switchst then + local switchfunc=function(pos, node, newstate) + newstate = newstate or var.switchalt -- support for 3 (or more) state switches + -- this code is only called from the internal setstate function, which + -- ensures that it is safe to switch the turnout + if newstate~=var.switchst then + advtrains.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..(var.switchprefix or "")..newstate..rotation, param2=node.param2}) + advtrains.invalidate_all_paths(pos) + end + end + ndef.on_rightclick = function(pos, node, player) + if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then + advtrains.setstate(pos, nil, node) + advtrains.log("Switch", player:get_player_name(), pos) + end + end + if var.switchmc then + ndef.mesecons = {effector = { + ["action_"..var.switchmc] = function(pos, node) + advtrains.setstate(pos, nil, node) + end, + rules=advtrains.meseconrules + }} + end + ndef_avt_table = { + getstate = var.switchst, + setstate = switchfunc, + } + end + + local adef={} + if def.get_additional_definiton then + adef=def.get_additional_definiton(def, preset, suffix, rotation) + end + ndef = advtrains.merge_tables(ndef, adef) + + -- insert getstate/setstate functions after merging the additional definitions + if ndef_avt_table then + ndef.advtrains = advtrains.merge_tables(ndef.advtrains or {}, ndef_avt_table) + end + + minetest.register_node(":"..def.nodename_prefix.."_"..suffix..rotation, ndef) + --trackplacer + if preset.regtp then + local tpconns = {conn1=ndef.at_conns[1].c, conn2=ndef.at_conns[2].c} + if var.tpdouble then + advtrains.trackplacer.add_double_conn(def.nodename_prefix, suffix, rotation, tpconns) + end + if var.tpsingle then + advtrains.trackplacer.add_single_conn(def.nodename_prefix, suffix, rotation, tpconns) + end + end + advtrains.trackplacer.add_worked(def.nodename_prefix, suffix, rotation, var.trackworker) + end + end + end + advtrains.all_tracktypes[tracktype]=true +end + +function advtrains.is_track_and_drives_on(nodename, drives_on_p) + local drives_on = drives_on_p + if not drives_on then drives_on = advtrains.all_tracktypes end + local hasentry = false + for _,_ in pairs(drives_on) do + hasentry=true + end + if not hasentry then drives_on = advtrains.all_tracktypes end + + if not minetest.registered_nodes[nodename] then + return false + end + local nodedef=minetest.registered_nodes[nodename] + for k,v in pairs(drives_on) do + if nodedef.groups["advtrains_track_"..k] then + return true + end + end + return false +end + +function advtrains.get_track_connections(name, param2) + local nodedef=minetest.registered_nodes[name] + if not nodedef then atprint(" get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return nil end + local noderot=param2 + if not param2 then noderot=0 end + if noderot > 3 then atprint(" get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end + + local tracktype + for k,_ in pairs(nodedef.groups) do + local tt=string.match(k, "^advtrains_track_(.+)$") + if tt then + tracktype=tt + end + end + return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), tracktype +end + +-- Function called when a track is about to be dug or modified by the trackworker +-- Returns either true (ok) or false,"translated string describing reason why it isn't allowed" +function advtrains.can_dig_or_modify_track(pos) + if advtrains.get_train_at_pos(pos) then + return false, attrans("Position is occupied by a train.") + end + -- interlocking: tcb, signal IP a.s.o. + if advtrains.interlocking then + -- TCB? + if advtrains.interlocking.db.get_tcb(pos) then + return false, attrans("There's a Track Circuit Break here.") + end + -- signal ip? + if advtrains.interlocking.db.is_ip_at(pos, true) then -- is_ip_at with purge parameter + return false, attrans("There's a Signal Influence Point here.") + end + end + return true +end + +-- slope placer. Defined in register_tracks. +--crafted with rail and gravel +local sl={} +function sl.register_placer(def, preset) + minetest.register_craftitem(":"..def.nodename_prefix.."_slopeplacer",{ + description = attrans("@1 Slope", def.description), + inventory_image = def.texture_prefix.."_slopeplacer.png", + wield_image = def.texture_prefix.."_slopeplacer.png", + groups={}, + on_place = sl.create_slopeplacer_on_place(def, preset) + }) +end +--(itemstack, placer, pointed_thing) +function sl.create_slopeplacer_on_place(def, preset) + return function(istack, player, pt) + if not pt.type=="node" then + minetest.chat_send_player(player:get_player_name(), attrans("Can't place: not pointing at node")) + return istack + end + local pos=pt.above + if not pos then + minetest.chat_send_player(player:get_player_name(), attrans("Can't place: not pointing at node")) + return istack + end + local node=minetest.get_node(pos) + if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to then + minetest.chat_send_player(player:get_player_name(), attrans("Can't place: space occupied!")) + return istack + end + if not advtrains.check_track_protection(pos, player:get_player_name()) then + minetest.record_protection_violation(pos, player:get_player_name()) + return istack + end + --determine player orientation (only horizontal component) + --get_look_horizontal may not be available + local yaw=player.get_look_horizontal and player:get_look_horizontal() or (player:get_look_yaw() - math.pi/2) + + --rounding unit vectors is a nice way for selecting 1 of 8 directions since sin(30°) is 0.5. + local dirvec={x=math.floor(math.sin(-yaw)+0.5), y=0, z=math.floor(math.cos(-yaw)+0.5)} + --translate to direction to look up inside the preset table + local param2, rot45=({ + [-1]={ + [-1]=2, + [0]=3, + [1]=3, + }, + [0]={ + [-1]=2, + [1]=0, + }, + [1]={ + [-1]=1, + [0]=1, + [1]=0, + }, + })[dirvec.x][dirvec.z], dirvec.x~=0 and dirvec.z~=0 + local lookup=preset.slopeplacer + if rot45 then lookup=preset.slopeplacer_45 end + + --go unitvector forward and look how far the next node is + local step=1 + while step<=lookup.max do + local node=minetest.get_node(vector.add(pos, dirvec)) + --next node solid? + if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to or advtrains.is_protected(pos, player:get_player_name()) then + --do slopes of this distance exist? + if lookup[step] then + if minetest.settings:get_bool("creative_mode") or istack:get_count()>=step then + --start placing + local placenodes=lookup[step] + while step>0 do + minetest.set_node(pos, {name=def.nodename_prefix.."_"..placenodes[step], param2=param2}) + if not minetest.settings:get_bool("creative_mode") then + istack:take_item() + end + step=step-1 + pos=vector.subtract(pos, dirvec) + end + else + minetest.chat_send_player(player:get_player_name(), attrans("Can't place: Not enough slope items left (@1 required)", step)) + end + else + minetest.chat_send_player(player:get_player_name(), attrans("Can't place: There's no slope of length @1",step)) + end + return istack + end + step=step+1 + pos=vector.add(pos, dirvec) + end + minetest.chat_send_player(player:get_player_name(), attrans("Can't place: no supporting node at upper end.")) + return itemstack + end +end + +advtrains.slope=sl + +--END code, BEGIN definition +--definition format: ([] optional) +--[[{ + nodename_prefix + texture_prefix + [shared_texture] + models_prefix + models_suffix (with dot) + [shared_model] + formats={ + st,cr,swlst,swlcr,swrst,swrcr,vst1,vst2 + (each a table with indices 0-3, for if to register a rail with this 'rotation' table entry. nil is assumed as 'all', set {} to not register at all) + } + common={} change something on common rail appearance +}]] + + + + + + + + + diff --git a/advtrains/passive.lua b/advtrains/passive.lua index fe4790c..76da720 100644 --- a/advtrains/passive.lua +++ b/advtrains/passive.lua @@ -1,9 +1,5 @@ -- passive.lua --- API to passive components, as described in passive_api.txt of advtrains_luaautomation --- This has been moved to the advtrains core in turn with the interlocking system, --- to prevent a dependency on luaautomation. - -local deprecation_warned = {} +-- Rework for advtrains 2.5: The passive API now uses the reworked node_state system. Please see the comment in tracks.lua function advtrains.getstate(parpos, pnode) local pos @@ -19,20 +15,8 @@ function advtrains.getstate(parpos, pnode) local node=pnode or advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] local st - if ndef and ndef.advtrains and ndef.advtrains.getstate then - st=ndef.advtrains.getstate - elseif ndef and ndef.luaautomation and ndef.luaautomation.getstate then - if not deprecation_warned[node.name] then - minetest.log("warning", node.name.." uses deprecated definition of ATLATC functions in the 'luaautomation' field. Please move them to the 'advtrains' field!") - end - st=ndef.luaautomation.getstate - else - return nil - end - if type(st)=="function" then - return st(pos, node) - else - return st + if ndef and ndef.advtrains then + return ndef.advtrains.node_state end end @@ -45,31 +29,46 @@ function advtrains.setstate(parpos, newstate, pnode) end if type(pos)~="table" or (not pos.x or not pos.y or not pos.z) then debug.sethook() - error("Invalid position supplied to getstate") + error("Invalid position supplied to setstate") end local node=pnode or advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] - local st - if ndef and ndef.advtrains and ndef.advtrains.setstate then - st=ndef.advtrains.setstate - elseif ndef and ndef.luaautomation and ndef.luaautomation.setstate then - if not deprecation_warned[node.name] then - minetest.log("warning", node.name.." uses deprecated definition of ATLATC functions in the 'luaautomation' field. Please move them to the 'advtrains' field!") - end - st=ndef.luaautomation.setstate - else - return nil + + if not ndef or not ndef.advtrains then + return false, "missing_node_def" + end + local old_state = ndef.advtrains.node_state + + if old_state == newstate then + -- nothing needs to be done + return true end + if not ndef.advtrains.node_state_map then + return false, "missing_node_state_map" + end + local new_node_name = ndef.advtrains.node_state_map[newstate] + if not new_node_name then + return false, "no_such_state" + end + + -- prevent state switching when route lock or train is present if advtrains.get_train_at_pos(pos) then - return false + return false, "train_here" end if advtrains.interlocking and advtrains.interlocking.route.has_route_lock(minetest.pos_to_string(pos)) then - return false + return false, "route_lock_here" end - st(pos, node, newstate) + -- perform the switch + local new_node = {name = new_node_name, param2 = node.param2} + advtrains.ndb.swap_node(pos, new_node) + -- if callback is present, call it + if ndef.advtrains.node_on_switch_state then + ndef.advtrains.node_on_switch_state(pos, new_node, old_state, newstate) + end + return true end @@ -86,12 +85,7 @@ function advtrains.is_passive(parpos, pnode) end local node=pnode or advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] - if ndef and ndef.advtrains and ndef.advtrains.getstate then - return true - elseif ndef and ndef.luaautomation and ndef.luaautomation.getstate then - if not deprecation_warned[node.name] then - minetest.log("warning", node.name.." uses deprecated definition of ATLATC functions in the 'luaautomation' field. Please move them to the 'advtrains' field!") - end + if ndef and ndef.advtrains and ndef.advtrains.node_state_map then return true else return false @@ -102,20 +96,10 @@ end function advtrains.set_fallback_state(pos, pnode) local node=pnode or advtrains.ndb.get_node(pos) local ndef=minetest.registered_nodes[node.name] - local st - if ndef and ndef.advtrains and ndef.advtrains.setstate - and ndef.advtrains.fallback_state then - if advtrains.get_train_at_pos(pos) then - return false - end - - if advtrains.interlocking and advtrains.interlocking.route.has_route_lock(minetest.pos_to_string(pos)) then - return false - end - - ndef.advtrains.setstate(pos, node, ndef.advtrains.fallback_state) - return true - end + if not ndef or not ndef.advtrains or not ndef.advtrains.node_fallback_state then + return false, "no_fallback_state" + end + return advtrains.setstate(pos, ndef.advtrains.node_fallback_state, node) end diff --git a/advtrains/path.lua b/advtrains/path.lua index 19387b1..72ee05d 100644 --- a/advtrains/path.lua +++ b/advtrains/path.lua @@ -33,13 +33,12 @@ -- If you need to proceed along the path by a specific actual distance, it does NOT work to simply add it to the index. You should use the path_get_index_by_offset() function. -- creates the path data structure, reconstructing the train from a position and a connid --- Important! train.drives_on must exist while calling this method -- returns: true - successful -- nil - node not yet available/unloaded, please wait -- false - node definitely gone, remove train function advtrains.path_create(train, pos, connid, rel_index) local posr = advtrains.round_vector_floor_y(pos) - local node_ok, conns, rhe = advtrains.get_rail_info_at(pos, train.drives_on) + local node_ok, conns, rhe = advtrains.get_rail_info_at(pos) if not node_ok then return node_ok end @@ -211,7 +210,7 @@ function advtrains.path_get(train, index) if pef == train.path_trk_f then node_ok, this_conns = advtrains.get_rail_info_at(pos) if not node_ok then error("For train "..train.id..": Path item "..pef.." on-track but not a valid node!") end - adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on) + adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid) end pef = pef + 1 if adj_pos then @@ -250,7 +249,7 @@ function advtrains.path_get(train, index) if peb == train.path_trk_b then node_ok, this_conns = advtrains.get_rail_info_at(pos) if not node_ok then error("For train "..train.id..": Path item "..peb.." on-track but not a valid node!") end - adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid, train.drives_on) + adj_pos, adj_connid, conn_idx, nextrail_y, next_conns = advtrains.get_adjacent_rail(pos, this_conns, connid) end peb = peb - 1 if adj_pos then diff --git a/advtrains/signals.lua b/advtrains/signals.lua index b26c950..58d28a5 100644 --- a/advtrains/signals.lua +++ b/advtrains/signals.lua @@ -40,9 +40,6 @@ local suppasp = { for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", als="green"}}) do - advtrains.trackplacer.register_tracktype("advtrains:retrosignal", "") - advtrains.trackplacer.register_tracktype("advtrains:signal", "") - for rotid, rotation in ipairs({"", "_30", "_45", "_60"}) do local crea=1 if rotid==1 and r=="off" then crea=0 end @@ -108,8 +105,8 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", }, can_dig = can_dig_func, after_dig_node = after_dig_func, + --TODO add rotation using trackworker }) - advtrains.trackplacer.add_worked("advtrains:retrosignal", r, rotation, nil) minetest.register_node("advtrains:signal_"..r..rotation, { drawtype = "mesh", @@ -179,8 +176,8 @@ for r,f in pairs({on={as="off", ls="green", als="red"}, off={as="on", ls="red", }, can_dig = can_dig_func, after_dig_node = after_dig_func, + --TODO add rotation using trackworker }) - advtrains.trackplacer.add_worked("advtrains:signal", r, rotation, nil) end local crea=1 diff --git a/advtrains/trackplacer.lua b/advtrains/trackplacer.lua index fe76290..9d63199 100644 --- a/advtrains/trackplacer.lua +++ b/advtrains/trackplacer.lua @@ -3,311 +3,204 @@ --all new trackplacer code local tp={ - tracks={} + groups={} } -function tp.register_tracktype(nnprefix, n_suffix) - if tp.tracks[nnprefix] then return end--due to the separate registration of slopes and flats for the same nnpref, definition would be overridden here. just don't. - tp.tracks[nnprefix]={ - default=n_suffix, - single_conn={}, - single_conn_1={}, - single_conn_2={}, - double_conn={}, - double_conn_1={}, - double_conn_2={}, - --keys:conn1_conn2 (example:1_4) - --values:{name=x, param2=x} - twcycle={}, - twrotate={},--indexed by suffix, list, tells order of rotations - modify={}, - } -end -function tp.add_double_conn(nnprefix, suffix, rotation, conns) - local nodename=nnprefix.."_"..suffix..rotation - for i=0,3 do - tp.tracks[nnprefix].double_conn[((conns.conn1+4*i)%16).."_"..((conns.conn2+4*i)%16)]={name=nodename, param2=i} - tp.tracks[nnprefix].double_conn[((conns.conn2+4*i)%16).."_"..((conns.conn1+4*i)%16)]={name=nodename, param2=i} - tp.tracks[nnprefix].double_conn_1[((conns.conn1+4*i)%16).."_"..((conns.conn2+4*i)%16)]={name=nodename, param2=i} - tp.tracks[nnprefix].double_conn_2[((conns.conn2+4*i)%16).."_"..((conns.conn1+4*i)%16)]={name=nodename, param2=i} - end - tp.tracks[nnprefix].modify[nodename]=true -end -function tp.add_single_conn(nnprefix, suffix, rotation, conns) - local nodename=nnprefix.."_"..suffix..rotation - for i=0,3 do - tp.tracks[nnprefix].single_conn[((conns.conn1+4*i)%16)]={name=nodename, param2=i} - tp.tracks[nnprefix].single_conn[((conns.conn2+4*i)%16)]={name=nodename, param2=i} - tp.tracks[nnprefix].single_conn_1[((conns.conn1+4*i)%16)]={name=nodename, param2=i} - tp.tracks[nnprefix].single_conn_2[((conns.conn2+4*i)%16)]={name=nodename, param2=i} - end - tp.tracks[nnprefix].modify[nodename]=true -end +--[[ New in version 2.5: +The track placer no longer uses hacky nodename pattern matching. +The base criterion for rotating or matching tracks is the common "ndef.advtrains.track_place_group" property. +Only rails where this field is set are considered for replacement. Other rails can still be considered for connection. +Replacement ("bending") of rails can only happen within their respective track place group. Only two-conn rails are allowed in the trackplacer. -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 +The track registration functions register the candidates for any given track_place_group in two separate collections: +- double: tracks that can be used to connect both ends of the rail +- single: tracks that will be used to connect conn1 when only a single end is to be connected +When track placing is requested, the calling code just supplies the track_place_group to be placed. ---[[ - 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 -]] +]]-- -local function istrackandbc(pos_p, conn) - local tpos = pos_p - local cnode=minetest.get_node(advtrains.dirCoordSet(tpos, conn.c)) - if advtrains.is_track_and_drives_on(cnode.name, advtrains.all_tracktypes) then - local cconns=advtrains.get_track_connections(cnode.name, cnode.param2) - return advtrains.conn_matches_to(conn, cconns) - end - --try the same 1 node below - tpos = {x=tpos.x, y=tpos.y-1, z=tpos.z} - cnode=minetest.get_node(advtrains.dirCoordSet(tpos, conn.c)) - if advtrains.is_track_and_drives_on(cnode.name, advtrains.all_tracktypes) then - local cconns=advtrains.get_track_connections(cnode.name, cnode.param2) - return advtrains.conn_matches_to(conn, cconns) - end - return false +local function rotate(conn, rot) + return (conn + rot) % 16 end -function tp.find_already_connected(pos) - local dnode=minetest.get_node(pos) - local dconns=advtrains.get_track_connections(dnode.name, dnode.param2) - local found_conn - for connid, conn in ipairs(dconns) do - if istrackandbc(pos, conn) then - if found_conn then --we found one in previous iteration - return true, true --signal that it's connected - else - found_conn = conn.c +-- Register a track node as candidate +-- tpg: the track place group to register the candidates for +-- name, ndef: the node name and node definition table to register +-- as_single: whether the rail should be considered as candidate for one-endpoint connection +-- Typically only set for the straight rail variants +-- as_double: whether the rail should be considered as candidate for two-endpoint connection +-- Typically set for straights and curves +function tp.register_candidate(tpg, name, ndef, as_single, as_double) + --get or create TP group + if not tp.groups[tpg] then + tp.groups[tpg] = {double = {}, single1 = {}, single2 = {}, default = {name = name, param2 = 0} } + -- note: this causes the first candidate to ever be registered to be the default (which is typically what you want) + end + local g = tp.groups[tpg] + + -- get conns + assert(#ndef.at_conns == 2) + local c1, c2 = ndef.at_conns[1].c, ndef.at_conns[2].c + local is_symmetrical = (rotate(c1, 8) == c2) + + -- store all possible rotations (param2 values) + for i=0,3 do + if as_double then + g.double[rotate(c1,i*4).."_"..rotate(c2,i*4)] = {name=name, param2=i} + if not is_symmmetrical then + g.double[rotate(c2,i*4).."_"..rotate(c1,i*4)] = {name=name, param2=i} + -- if the track is unsymmetric (e.g. a curve), we may require the "wrong" orientation to fill a gap. end end + if as_single then + g.single1[rotate(c1,i*4)] = {name=name, param2=i} + g.single2[rotate(c2,i*4)] = {name=name, param2=i} + end end - return found_conn end -function tp.rail_and_can_be_bent(originpos, conn) - local pos=advtrains.dirCoordSet(originpos, conn) - local newdir=(conn+8)%16 - local node=minetest.get_node(pos) - if not advtrains.is_track_and_drives_on(node.name, advtrains.all_tracktypes) then + +local function check_or_bend_rail(origin, dir, pname, commit) + local pos = advtrains.pos_add_dir(origin, dir) + local back_dir = advtrains.oppd(dir); + + local node_ok, conns = advtrains.get_rail_info_at(pos) + if not node_ok then + -- try the node one level below + pos.y = pos.y - 1 + node_ok, conns = advtrains.get_rail_info_at(pos) + end + if not node_ok then return false end - local ndef=minetest.registered_nodes[node.name] - local nnpref = ndef and ndef.at_nnpref - if not nnpref then return false end - local tr=tp.tracks[nnpref] - if not tr then return false end - if not tr.modify[node.name] then - --we actually can use this rail, but only if it already points to the desired direction. - if advtrains.is_track_and_drives_on(node.name, advtrains.all_tracktypes) then - local cconns=advtrains.get_track_connections(node.name, node.param2) - return advtrains.conn_matches_to(conn, cconns) + -- if one conn of the node here already points towards us, nothing to do + for connid, conn in ipairs(conns) do + if back_dir == conn.c then + return true end end - -- If the rail is not allowed to be modified, also only use if already in desired direction + -- can we bend the node here? + local node = advtrains.ndb.get_node(pos) + local ndef = minetest.registered_nodes[node.name] + if not ndef or not ndef.advtrains or not ndef.advtrains.track_place_group then + return false + end + -- now the track must be two-conn, else it wouldn't be allowed to have track_place_group set. + assert(#conns == 2) + -- Is player and game allowed to do this? if not advtrains.can_dig_or_modify_track(pos) then - local cconns=advtrains.get_track_connections(node.name, node.param2) - return advtrains.conn_matches_to(conn, cconns) + 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 + if not advtrains.check_track_protection(pos, pname) then return false - else - if tr.single_conn[newdir] then--just rotate old rail to right orientation - return true + end + -- we confirmed that track can be modified. Does there exist a suitable connection candidate? + -- check if there are any unbound ends + local bound_connids = {} + for connid, conn in ipairs(conns) do + local adj_pos, adj_connid = advtrains.get_adjacent_rail(pos, conns, connid) + if adj_pos then + bound_connids[#bound_connids+1] = connid end - return false end -end -function tp.bend_rail(originpos, conn) - local pos=advtrains.dirCoordSet(originpos, conn) - local newdir=advtrains.oppd(conn) - local node=minetest.get_node(pos) - local ndef=minetest.registered_nodes[node.name] - local nnpref = ndef and ndef.at_nnpref - if not nnpref then return false end - local tr=tp.tracks[nnpref] - if not tr then return false end - --is rail already connected? no need to bend. - local conns=advtrains.get_track_connections(node.name, node.param2) - if advtrains.conn_matches_to(conn, conns) then - return + -- depending on the nummber of ends, decide + if #bound_connids == 2 then + -- rail is within a fixed track, do not break up + 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 - advtrains.ndb.swap_node(pos, tr.double_conn[adj1.."_"..newdir]) - return true--if exists, connect new rail and old end + -- obtain the group table + local g = tp.groups[ndef.advtrains.track_place_group] + if #bound_connids == 1 then + -- we can attempt double + local bound_dir = conns[bound_connids[1]].c + if g.double[back_dir.."_"..bound_dir] then + if commit then + advtrains.ndb.swap_node(pos, g.double[back_dir.."_"..bound_dir]) + end + return true end - return false else - if tr.single_conn[newdir] then--just rotate old rail to right orientation - advtrains.ndb.swap_node(pos, tr.single_conn[newdir]) + -- rail is entirely unbound, we can attempt single1 + if g.single1[back_dir] then + if commit then + advtrains.ndb.swap_node(pos, g.single1[back_dir]) + end return true end - return false end end -function tp.placetrack(pos, nnpref, placer, itemstack, pointed_thing, yaw) - --1. find all rails that are likely to be connected - local tr=tp.tracks[nnpref] - local p_rails={} - local p_railpos={} + +local function track_place_node(pos, node, ndef) + advtrains.ndb.swap_node(pos, node) + local ndef = minetest.registered_nodes[node.name] + if ndef and ndef.after_place_node then + ndef.after_place_node(pos) + end +end + + +-- Main API function to place a track. Replaces the older "placetrack" +-- This function will attempt to place a track of the specified track placing group at the specified position, connecting it +-- with neighboring rails. Neighboring rails can themselves be replaced ("bent") within their own track place group, +-- if the player is permitted to do this. +-- Order of preference is: +-- Connect two track ends if possible +-- Connect one track end if any rail is near +-- Place the default track if no tracks are near +-- The function returns true on success. +function tp.place_track(pos, tpg, pname, yaw) + -- 1. collect neighboring tracks and whether they can be connected + local cand = {} for i=0,15 do - if tp.rail_and_can_be_bent(pos, i, nnpref) then - p_rails[#p_rails+1]=i - p_railpos[i] = pos - else - local upos = {x=pos.x, y=pos.y-1, z=pos.z} - if tp.rail_and_can_be_bent(upos, i, nnpref) then - p_rails[#p_rails+1]=i - p_railpos[i] = upos - end + if check_or_bend_rail(pos, i, pname) then + cand[#cand+1] = i end end - - -- try double_conn - if #p_rails > 1 then - --iterate subsets - for k1, conn1 in ipairs(p_rails) do - for k2, conn2 in ipairs(p_rails) do - if k1~=k2 then - local dconn1 = tr.double_conn_1 - local dconn2 = tr.double_conn_2 - if not (advtrains.yawToDirection(yaw, conn1, conn2) == conn1) then - dconn1 = tr.double_conn_2 - dconn2 = tr.double_conn_1 - end - -- Checks are made this way round so that dconn1 has priority (this will make arrows of atc rails - -- point in the right direction) - local using - if (dconn2[conn1.."_"..conn2]) then - using = dconn2[conn1.."_"..conn2] - end - if (dconn1[conn1.."_"..conn2]) then - using = dconn1[conn1.."_"..conn2] - end - if using then - -- has found a fitting rail in either direction - -- if not, continue loop - tp.bend_rail(p_railpos[conn1], conn1, nnpref) - tp.bend_rail(p_railpos[conn2], conn2, nnpref) - advtrains.ndb.swap_node(pos, using) - local nname=using.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 + -- obtain the group table + local g = tp.groups[tpg] + -- 2. try all possible two-endpoint connections + for k1, conn1 in ipairs(cand) do + for k2, conn2 in ipairs(cand) do + if k1~=k2 then + -- order of conn1/conn2: prefer conn2 being in the direction of the player facing. + -- the combination the other way round will be run through in a later loop iteration + if advtrains.yawToDirection(yaw, conn1, conn2) == conn2 then + -- does there exist a suitable double-connection rail? + local node = g.double[conn1.."_"..conn2] + if node then + check_or_bend_rail(pos, conn1, pname, true) + check_or_bend_rail(pos, conn2, pname, true) + track_place_node(pos, node) -- calls after_place_node implicitly + return true end end end end end - -- try single_conn - if #p_rails > 0 then - for ix, p_rail in ipairs(p_rails) do - local sconn1 = tr.single_conn_1 - local sconn2 = tr.single_conn_2 - if not (advtrains.yawToDirection(yaw, p_rail, (p_rail+8)%16) == p_rail) then - sconn1 = tr.single_conn_2 - sconn2 = tr.single_conn_1 - end - if sconn1[p_rail] then - local using = sconn1[p_rail] - tp.bend_rail(p_railpos[p_rail], p_rail, nnpref) - advtrains.ndb.swap_node(pos, using) - local nname=using.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 - if sconn2[p_rail] then - local using = sconn2[p_rail] - tp.bend_rail(p_railpos[p_rail], p_rail, nnpref) - advtrains.ndb.swap_node(pos, using) - local nname=using.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 + -- 3. try all possible one_endpoint connections + for k1, conn1 in ipairs(cand) do + -- select single1 or single2? depending on yaw + local single + if advtrains.yawToDirection(yaw, conn1, advtrains.oppd(conn1)) == conn1 then + single = g.single1 + else + single = g.single2 + end + local node = single[conn1] + if node then + check_or_bend_rail(pos, conn1, pname, true) + track_place_node(pos, node) -- calls after_place_node implicitly + return true end end - --use default - 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 + -- 4. if nothing worked, set the default + local node = g.default + track_place_node(pos, node) -- calls after_place_node implicitly + return true end - -function tp.register_track_placer(nnprefix, imgprefix, dispname, def) - minetest.register_craftitem(":"..nnprefix.."_placer",{ - description = dispname, - inventory_image = imgprefix.."_placer.png", - wield_image = imgprefix.."_placer.png", - groups={advtrains_trackplacer=1, digtron_on_place=1}, - liquids_pointable = def.liquids_pointable, - on_place = function(itemstack, placer, pointed_thing) - local name = placer:get_player_name() - if not name then - return itemstack, false - 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 not advtrains.check_track_protection(pos, name) then - return itemstack, false - end - if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to then - local s - if def.suitable_substrate then - s = def.suitable_substrate(upos) - else - s = minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable - end - if s then --- minetest.chat_send_all(nnprefix) - local yaw = placer:get_look_horizontal() - tp.placetrack(pos, nnprefix, placer, itemstack, pointed_thing, yaw) - if not advtrains.is_creative(name) then - itemstack:take_item() - end - end - end - end - return itemstack, true - end, - }) -end - - +-- TRACK WORKER -- minetest.register_craftitem("advtrains:trackworker",{ description = attrans("Track Worker Tool\n\nLeft-click: change rail type (straight/curve/switch)\nRight-click: rotate rail/bumper/signal/etc."), @@ -316,116 +209,93 @@ 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 + local name = placer:get_player_name() + if not name then + return + end + local has_aux1_down = placer:get_player_control().aux1 + if pointed_thing.type=="node" then + local pos=pointed_thing.under + if not advtrains.check_track_protection(pos, name) then return end - local has_aux1_down = placer:get_player_control().aux1 - if pointed_thing.type=="node" then - local pos=pointed_thing.under - if not advtrains.check_track_protection(pos, name) then - return - end - local node=minetest.get_node(pos) + 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 - - local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") - --atdebug(node.name.."\npattern recognizes:"..nnprefix.." / "..suffix.." / "..rotation) - --atdebug("nntab: ",tp.tracks[nnprefix]) - 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(), attrans("This node can't be rotated using the trackworker!")) - return - end - end - - -- check if the node is modify-protected - if advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then - -- is a track, we can query - local can_modify, reason = advtrains.can_dig_or_modify_track(pos) - if not can_modify then - local str = attrans("This track can not be rotated!") - if reason then - str = str .. " " .. reason - end - minetest.chat_send_player(placer:get_player_name(), str) - return + -- New since 2.5: only the fields in the node definition are considered, no more hacky pattern matching on the nodename + + local ndef = minetest.registered_nodes[node.name] + + if not ndef.advtrains or not ndef.advtrains.trackworker_next_rot then + minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be rotated using the trackworker!")) + return + end + + -- check if the node is modify-protected + if advtrains.is_track(node.name) then + -- is a track, we can query + local can_modify, reason = advtrains.can_dig_or_modify_track(pos) + if not can_modify then + local str = attrans("This track can not be rotated!") + if reason then + str = str .. " " .. reason end - end - - if has_aux1_down then - --feature: flip the node by 180° - --i've always wanted this! - advtrains.ndb.swap_node(pos, {name=node.name, param2=(node.param2+2)%4}) + minetest.chat_send_player(placer:get_player_name(), str) return 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 end + + if has_aux1_down then + --feature: flip the node by 180° + --i've always wanted this! + advtrains.ndb.swap_node(pos, {name=node.name, param2=(node.param2+2)%4}) + return + end + + local new_node = {name = ndef.advtrains.trackworker_next_rot, param2 = node.param2} + if ndef.advtrains.trackworker_rot_incr_param2 then + new_node.param2 = ((node.param2 + 1) % 4) + end + advtrains.ndb.swap_node(pos, new_node) + end end, on_use=function(itemstack, user, pointed_thing) - local name = user:get_player_name() - if not name then - return + 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 not advtrains.check_track_protection(pos, name) then + return end - if pointed_thing.type=="node" then - local pos=pointed_thing.under - local node=minetest.get_node(pos) - if not advtrains.check_track_protection(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.get_train_at_pos(pos) then return end - local nnprefix, suffix, rotation=string.match(node.name, "^(.+)_([^_]+)(_[^_]+)$") - --atdebug(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 - - -- check if the node is modify-protected - if advtrains.is_track_and_drives_on(minetest.get_node(pos).name, advtrains.all_tracktypes) then - -- is a track, we can query - local can_modify, reason = advtrains.can_dig_or_modify_track(pos) - if not can_modify then - local str = attrans("This track can not be changed!") - if reason then - str = str .. " " .. reason - end - minetest.chat_send_player(user:get_player_name(), str) - return + + -- New since 2.5: only the fields in the node definition are considered, no more hacky pattern matching on the nodename + + local ndef = minetest.registered_nodes[node.name] + + if not ndef.advtrains or not ndef.advtrains.trackworker_next_var then + minetest.chat_send_player(placer:get_player_name(), attrans("This node can't be changed using the trackworker!")) + return + end + + -- check if the node is modify-protected + if advtrains.is_track(node.name) then + -- is a track, we can query + local can_modify, reason = advtrains.can_dig_or_modify_track(pos) + if not can_modify then + local str = attrans("This track can not be rotated!") + if reason then + str = str .. " " .. reason end + minetest.chat_send_player(placer:get_player_name(), str) + return 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 + + local new_node = {name = ndef.advtrains.trackworker_next_var, param2 = node.param2} + advtrains.ndb.swap_node(pos, new_node) + end end, }) diff --git a/advtrains/tracks.lua b/advtrains/tracks.lua index c415143..dc2d909 100644 --- a/advtrains/tracks.lua +++ b/advtrains/tracks.lua @@ -1,751 +1,287 @@ ---advtrains by orwell96, see readme.txt - ---dev-time settings: ---EDIT HERE ---If the old non-model rails on straight tracks should be replaced by the new... ---false: no ---true: yes -advtrains.register_replacement_lbms=false - ---[[TracksDefinition -nodename_prefix -texture_prefix -description -common={} -straight={} -straight45={} -curve={} -curve45={} -lswitchst={} -lswitchst45={} -rswitchst={} -rswitchst45={} -lswitchcr={} -lswitchcr45={} -rswitchcr={} -rswitchcr45={} -vert1={ - --you'll probably want to override mesh here -} -vert2={ - --you'll probably want to override mesh here -} -]]-- -advtrains.all_tracktypes={} - ---definition preparation -local function conns(c1, c2, r1, r2) return {{c=c1, y=r1}, {c=c2, y=r2}} end -local function conns3(c1, c2, c3, r1, r2, r3) return {{c=c1, y=r1}, {c=c2, y=r2}, {c=c3, y=r3}} end - -advtrains.ap={} -advtrains.ap.t_30deg_flat={ - regstep=1, - variant={ - st={ - conns = conns(0,8), - desc = "straight", - tpdouble = true, - tpsingle = true, - trackworker = "cr", - }, - cr={ - conns = conns(0,7), - desc = "curve", - tpdouble = true, - trackworker = "swlst", - }, - swlst={ - conns = conns3(0,8,7), - desc = "left switch (straight)", - trackworker = "swrst", - switchalt = "cr", - switchmc = "on", - switchst = "st", - switchprefix = "swl", - }, - swlcr={ - conns = conns3(0,7,8), - desc = "left switch (curve)", - trackworker = "swrcr", - switchalt = "st", - switchmc = "off", - switchst = "cr", - switchprefix = "swl", - }, - swrst={ - conns = conns3(0,8,9), - desc = "right switch (straight)", - trackworker = "st", - switchalt = "cr", - switchmc = "on", - switchst = "st", - switchprefix = "swr", - }, - swrcr={ - conns = conns3(0,9,8), - desc = "right switch (curve)", - trackworker = "st", - switchalt = "st", - switchmc = "off", - switchst = "cr", - switchprefix = "swr", - }, - }, - regtp=true, - tpdefault="st", - trackworker={ - ["swrcr"]="st", - ["swrst"]="st", - ["cr"]="swlst", - ["swlcr"]="swrcr", - ["swlst"]="swrst", - }, - rotation={"", "_30", "_45", "_60"}, -} -advtrains.ap.t_yturnout={ - regstep=1, - variant={ - l={ - conns = conns3(0,7,9), - desc = "Y-turnout (left)", - switchalt = "r", - switchmc = "off", - switchst = "l", - switchprefix = "", - }, - r={ - conns = conns3(0,9,7), - desc = "Y-turnout (right)", - switchalt = "l", - switchmc = "on", - switchst = "r", - switchprefix = "", - } - }, - regtp=true, - tpdefault="l", - rotation={"", "_30", "_45", "_60"}, -} -advtrains.ap.t_s3way={ - regstep=1, - variant={ - l={ - conns = { {c=0}, {c=7}, {c=8}, {c=9}, {c=0} }, - desc = "3-way turnout (left)", - switchalt = "s", - switchst="l", - switchprefix = "", - }, - s={ - conns = { {c=0}, {c=8}, {c=7}, {c=9}, {c=0} }, - desc = "3-way turnout (straight)", - switchalt ="r", - switchst = "s", - switchprefix = "", - }, - r={ - conns = { {c=0}, {c=9}, {c=8}, {c=7}, {c=0} }, - desc = "3-way turnout (right)", - switchalt = "l", - switchst="r", - switchprefix = "", - } - }, - regtp=true, - tpdefault="l", - rotation={"", "_30", "_45", "_60"}, -} -advtrains.ap.t_30deg_slope={ - regstep=1, - variant={ - vst1={conns = conns(8,0,0,0.5), rail_y = 0.25, desc = "steep uphill 1/2", slope=true}, - vst2={conns = conns(8,0,0.5,1), rail_y = 0.75, desc = "steep uphill 2/2", slope=true}, - vst31={conns = conns(8,0,0,0.33), rail_y = 0.16, desc = "uphill 1/3", slope=true}, - vst32={conns = conns(8,0,0.33,0.66), rail_y = 0.5, desc = "uphill 2/3", slope=true}, - vst33={conns = conns(8,0,0.66,1), rail_y = 0.83, desc = "uphill 3/3", slope=true}, - }, - regsp=true, - slopeplacer={ - [2]={"vst1", "vst2"}, - [3]={"vst31", "vst32", "vst33"}, - max=3,--highest entry - }, - slopeplacer_45={ - [2]={"vst1_45", "vst2_45"}, - max=2, - }, - rotation={"", "_30", "_45", "_60"}, - trackworker={}, - increativeinv={}, -} -advtrains.ap.t_30deg_straightonly={ - regstep=1, - variant={ - st={ - conns = conns(0,8), - desc = "straight", - tpdouble = true, - tpsingle = true, - trackworker = "st", - }, - }, - regtp=true, - tpdefault="st", - rotation={"", "_30", "_45", "_60"}, -} -advtrains.ap.t_30deg_straightonly_noplacer={ - regstep=1, - variant={ - st={ - conns = conns(0,8), - desc = "straight", - tpdouble = true, - tpsingle = true, - trackworker = "st", - }, - }, - tpdefault="st", - rotation={"", "_30", "_45", "_60"}, -} -advtrains.ap.t_45deg={ - regstep=2, - variant={ - st={ - conns = conns(0,8), - desc = "straight", - tpdouble = true, - tpsingle = true, - trackworker = "cr", - }, - cr={ - conns = conns(0,6), - desc = "curve", - tpdouble = true, - trackworker = "swlst", - }, - swlst={ - conns = conns3(0,8,6), - desc = "left switch (straight)", - trackworker = "swrst", - switchalt = "cr", - switchmc = "on", - switchst = "st", - }, - swlcr={ - conns = conns3(0,6,8), - desc = "left switch (curve)", - trackworker = "swrcr", - switchalt = "st", - switchmc = "off", - switchst = "cr", - }, - swrst={ - conns = conns3(0,8,10), - desc = "right switch (straight)", - trackworker = "st", - switchalt = "cr", - switchmc = "on", - switchst = "st", - }, - swrcr={ - conns = conns3(0,10,8), - desc = "right switch (curve)", - trackworker = "st", - switchalt = "st", - switchmc = "off", - switchst = "cr", - }, - }, - regtp=true, - tpdefault="st", - trackworker={ - ["swrcr"]="st", - ["swrst"]="st", - ["cr"]="swlst", - ["swlcr"]="swrcr", - ["swlst"]="swrst", - }, - rotation={"", "_30", "_45", "_60"}, -} -advtrains.ap.t_perpcrossing={ - regstep = 1, - variant={ - st={ - conns = { {c=0}, {c=8}, {c=4}, {c=12} }, - desc = "perpendicular crossing", - tpdouble = true, - tpsingle = true, - trackworker = "st", - }, - }, - regtp=true, - tpdefault="st", - rotation={"", "_30", "_45", "_60"}, -} -advtrains.ap.t_90plusx_crossing={ - regstep = 1, - variant={ - ["30l"]={ - conns = { {c=0}, {c=8}, {c=1}, {c=9} }, - desc = "30/90 degree crossing (left)", - tpdouble = true, - tpsingle = true, - trackworker = "45l" - }, - ["45l"]={ - conns = { {c=0}, {c=8}, {c=2}, {c=10} }, - desc = "45/90 degree crossing (left)", - tpdouble = true, - tpsingle = true, - trackworker = "60l", - }, - ["60l"]={ - conns = { {c=0}, {c=8}, {c=3}, {c=11}}, - desc = "60/90 degree crossing (left)", - tpdouble = true, - tpsingle = true, - trackworker = "60r", - }, - ["60r"]={ - conns = { {c=0}, {c=8}, {c=5}, {c=13} }, - desc = "60/90 degree crossing (right)", - tpdouble = true, - tpsingle = true, - trackworker = "45r" - }, - ["45r"]={ - conns = { {c=0}, {c=8}, {c=6}, {c=14} }, - desc = "45/90 degree crossing (right)", - tpdouble = true, - tpsingle = true, - trackworker = "30r", - }, - ["30r"]={ - conns = { {c=0}, {c=8}, {c=7}, {c=15}}, - desc = "30/90 degree crossing (right)", - tpdouble = true, - tpsingle = true, - trackworker = "30l", - }, - }, - regtp=true, - tpdefault="30l", - rotation={""}, - trackworker = { - ["30l"] = "45l", - ["45l"] = "60l", - ["60l"] = "60r", - ["60r"] = "45r", - ["45r"] = "30r", - ["30r"] = "30l", - } -} - -advtrains.ap.t_diagonalcrossing = { - regstep=1, - variant={ - ["30l45r"]={ - conns = {{c=1}, {c=9}, {c=6}, {c=14}}, - desc = "30left-45right diagonal crossing", - tpdouble=true, - tpsingle=true, - trackworker="60l30l", - }, - ["60l30l"]={ - conns = {{c=3}, {c=11}, {c=1}, {c=9}}, - desc = "30left-60right diagonal crossing", - tpdouble=true, - tpsingle=true, - trackworker="60l45r" - }, - ["60l45r"]={ - conns = {{c=3}, {c=11}, {c=6}, {c=14}}, - desc = "60left-45right diagonal crossing", - tpdouble=true, - tpsingle=true, - trackworker="60l60r" - }, - ["60l60r"]={ - conns = {{c=3}, {c=11}, {c=5}, {c=13}}, - desc = "60left-60right diagonal crossing", - tpdouble=true, - tpsingle=true, - trackworker="60r45l", - }, - --If 60l60r had a mirror image, it would be here, but it's symmetric. - -- 60l60r is also equivalent to 30l30r but rotated 90 degrees. - ["60r45l"]={ - conns = {{c=5}, {c=13}, {c=2}, {c=10}}, - desc = "60right-45left diagonal crossing", - tpdouble=true, - tpsingle=true, - trackworker="60r30r", - }, - ["60r30r"]={ - conns = {{c=5}, {c=13}, {c=7}, {c=15}}, - desc = "60right-30right diagonal crossing", - tpdouble=true, - tpsingle=true, - trackworker="30r45l", - }, - ["30r45l"]={ - conns = {{c=7}, {c=15}, {c=2}, {c=10}}, - desc = "30right-45left diagonal crossing", - tpdouble=true, - tpsingle=true, - trackworker="30l45r", - }, - - }, - regtp=true, - tpdefault="30l45r", - rotation={""}, - trackworker = { - ["30l45r"] = "60l30l", - ["60l30l"] = "60l45r", - ["60l45r"] = "60l60r", - ["60l60r"] = "60r45l", - ["60r45l"] = "60r30r", - ["60r30r"] = "30r45l", - ["30r45l"] = "30l45r", - } -} - -advtrains.trackpresets = advtrains.ap - ---definition format: ([] optional) ---[[{ - nodename_prefix - texture_prefix - [shared_texture] - models_prefix - models_suffix (with dot) - [shared_model] - formats={ - st,cr,swlst,swlcr,swrst,swrcr,vst1,vst2 - (each a table with indices 0-3, for if to register a rail with this 'rotation' table entry. nil is assumed as 'all', set {} to not register at all) - } - common={} change something on common rail appearance -} -[18.12.17] Note on new connection system: -In order to support real rail crossing nodes and finally make the trackplacer respect switches, I changed the connection system. -There can be a variable number of connections available. These are specified as tuples {c=, y=} -The table "at_conns" consists of {, ...} -the "at_rail_y" property holds the value that was previously called "railheight" -Depending on the number of connections: -2 conns: regular rail -3 conns: switch: - - when train passes in at conn1, will move out of conn2 - - when train passes in at conn2 or conn3, will move out of conn1 -4 conns: cross (or cross switch, depending on arrangement of conns): - - conn1 <> conn2 - - conn3 <> conn4 -]] - --- Notify the user if digging the rail is not allowed -local function can_dig_callback(pos, player) - local ok, reason = advtrains.can_dig_or_modify_track(pos) - if not ok and player then - minetest.chat_send_player(player:get_player_name(), attrans("This track can not be removed!") .. " " .. reason) - end - return ok -end - -function advtrains.register_tracks(tracktype, def, preset) - advtrains.trackplacer.register_tracktype(def.nodename_prefix, preset.tpdefault) - if preset.regtp then - advtrains.trackplacer.register_track_placer(def.nodename_prefix, def.texture_prefix, def.description, def) - end - if preset.regsp then - advtrains.slope.register_placer(def, preset) - end - for suffix, var in pairs(preset.variant) do - for rotid, rotation in ipairs(preset.rotation) do - if not def.formats[suffix] or def.formats[suffix][rotid] then - local img_suffix = suffix..rotation - local ndef = advtrains.merge_tables({ - description=def.description.."("..(var.desc or "any")..rotation..")", - drawtype = "mesh", - paramtype="light", - paramtype2="facedir", - walkable = false, - selection_box = { - type = "fixed", - fixed = {-1/2-1/16, -1/2, -1/2, 1/2+1/16, -1/2+2/16, 1/2}, - }, - - mesh = def.shared_model or (def.models_prefix.."_"..img_suffix..def.models_suffix), - tiles = {def.shared_texture or (def.texture_prefix.."_"..img_suffix..".png"), def.second_texture}, - - groups = { - attached_node = advtrains.IGNORE_WORLD and 0 or 1, - advtrains_track=1, - ["advtrains_track_"..tracktype]=1, - save_in_at_nodedb=1, - dig_immediate=2, - not_in_creative_inventory=1, - not_blocking_trains=1, - }, - - can_dig = can_dig_callback, - after_dig_node=function(pos) - advtrains.ndb.update(pos) - end, - after_place_node=function(pos) - advtrains.ndb.update(pos) - end, - at_nnpref = def.nodename_prefix, - at_suffix = suffix, - at_rotation = rotation, - at_rail_y = var.rail_y - }, def.common or {}) - - if preset.regtp then - ndef.drop = def.nodename_prefix.."_placer" - end - if preset.regsp and var.slope then - ndef.drop = def.nodename_prefix.."_slopeplacer" - end - - --connections - ndef.at_conns = advtrains.rotate_conn_by(var.conns, (rotid-1)*preset.regstep) - - local ndef_avt_table - - if var.switchalt and var.switchst then - local switchfunc=function(pos, node, newstate) - newstate = newstate or var.switchalt -- support for 3 (or more) state switches - -- this code is only called from the internal setstate function, which - -- ensures that it is safe to switch the turnout - if newstate~=var.switchst then - advtrains.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..(var.switchprefix or "")..newstate..rotation, param2=node.param2}) - advtrains.invalidate_all_paths(pos) - end - end - ndef.on_rightclick = function(pos, node, player) - if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then - advtrains.setstate(pos, nil, node) - advtrains.log("Switch", player:get_player_name(), pos) - end - end - if var.switchmc then - ndef.mesecons = {effector = { - ["action_"..var.switchmc] = function(pos, node) - advtrains.setstate(pos, nil, node) - end, - rules=advtrains.meseconrules - }} - end - ndef_avt_table = { - getstate = var.switchst, - setstate = switchfunc, - } - end - - local adef={} - if def.get_additional_definiton then - adef=def.get_additional_definiton(def, preset, suffix, rotation) - end - ndef = advtrains.merge_tables(ndef, adef) - - -- insert getstate/setstate functions after merging the additional definitions - if ndef_avt_table then - ndef.advtrains = advtrains.merge_tables(ndef.advtrains or {}, ndef_avt_table) - end - - minetest.register_node(":"..def.nodename_prefix.."_"..suffix..rotation, ndef) - --trackplacer - if preset.regtp then - local tpconns = {conn1=ndef.at_conns[1].c, conn2=ndef.at_conns[2].c} - if var.tpdouble then - advtrains.trackplacer.add_double_conn(def.nodename_prefix, suffix, rotation, tpconns) - end - if var.tpsingle then - advtrains.trackplacer.add_single_conn(def.nodename_prefix, suffix, rotation, tpconns) - end - end - advtrains.trackplacer.add_worked(def.nodename_prefix, suffix, rotation, var.trackworker) - end - end - end - advtrains.all_tracktypes[tracktype]=true -end - -function advtrains.is_track_and_drives_on(nodename, drives_on_p) - local drives_on = drives_on_p - if not drives_on then drives_on = advtrains.all_tracktypes end - local hasentry = false - for _,_ in pairs(drives_on) do - hasentry=true - end - if not hasentry then drives_on = advtrains.all_tracktypes end - - if not minetest.registered_nodes[nodename] then - return false - end - local nodedef=minetest.registered_nodes[nodename] - for k,v in pairs(drives_on) do - if nodedef.groups["advtrains_track_"..k] then - return true - end - end - return false -end - -function advtrains.get_track_connections(name, param2) - local nodedef=minetest.registered_nodes[name] - if not nodedef then atprint(" get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return nil end - local noderot=param2 - if not param2 then noderot=0 end - if noderot > 3 then atprint(" get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end - - local tracktype - for k,_ in pairs(nodedef.groups) do - local tt=string.match(k, "^advtrains_track_(.+)$") - if tt then - tracktype=tt - end - end - return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), tracktype -end - --- Function called when a track is about to be dug or modified by the trackworker --- Returns either true (ok) or false,"translated string describing reason why it isn't allowed" -function advtrains.can_dig_or_modify_track(pos) - if advtrains.get_train_at_pos(pos) then - return false, attrans("Position is occupied by a train.") - end - -- interlocking: tcb, signal IP a.s.o. - if advtrains.interlocking then - -- TCB? - if advtrains.interlocking.db.get_tcb(pos) then - return false, attrans("There's a Track Circuit Break here.") - end - -- signal ip? - if advtrains.interlocking.db.is_ip_at(pos, true) then -- is_ip_at with purge parameter - return false, attrans("There's a Signal Influence Point here.") - end - end - return true -end - --- slope placer. Defined in register_tracks. ---crafted with rail and gravel -local sl={} -function sl.register_placer(def, preset) - minetest.register_craftitem(":"..def.nodename_prefix.."_slopeplacer",{ - description = attrans("@1 Slope", def.description), - inventory_image = def.texture_prefix.."_slopeplacer.png", - wield_image = def.texture_prefix.."_slopeplacer.png", - groups={}, - on_place = sl.create_slopeplacer_on_place(def, preset) - }) -end ---(itemstack, placer, pointed_thing) -function sl.create_slopeplacer_on_place(def, preset) - return function(istack, player, pt) - if not pt.type=="node" then - minetest.chat_send_player(player:get_player_name(), attrans("Can't place: not pointing at node")) - return istack - end - local pos=pt.above - if not pos then - minetest.chat_send_player(player:get_player_name(), attrans("Can't place: not pointing at node")) - return istack - end - local node=minetest.get_node(pos) - if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to then - minetest.chat_send_player(player:get_player_name(), attrans("Can't place: space occupied!")) - return istack - end - if not advtrains.check_track_protection(pos, player:get_player_name()) then - minetest.record_protection_violation(pos, player:get_player_name()) - return istack - end - --determine player orientation (only horizontal component) - --get_look_horizontal may not be available - local yaw=player.get_look_horizontal and player:get_look_horizontal() or (player:get_look_yaw() - math.pi/2) - - --rounding unit vectors is a nice way for selecting 1 of 8 directions since sin(30°) is 0.5. - local dirvec={x=math.floor(math.sin(-yaw)+0.5), y=0, z=math.floor(math.cos(-yaw)+0.5)} - --translate to direction to look up inside the preset table - local param2, rot45=({ - [-1]={ - [-1]=2, - [0]=3, - [1]=3, - }, - [0]={ - [-1]=2, - [1]=0, - }, - [1]={ - [-1]=1, - [0]=1, - [1]=0, - }, - })[dirvec.x][dirvec.z], dirvec.x~=0 and dirvec.z~=0 - local lookup=preset.slopeplacer - if rot45 then lookup=preset.slopeplacer_45 end - - --go unitvector forward and look how far the next node is - local step=1 - while step<=lookup.max do - local node=minetest.get_node(vector.add(pos, dirvec)) - --next node solid? - if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to or advtrains.is_protected(pos, player:get_player_name()) then - --do slopes of this distance exist? - if lookup[step] then - if minetest.settings:get_bool("creative_mode") or istack:get_count()>=step then - --start placing - local placenodes=lookup[step] - while step>0 do - minetest.set_node(pos, {name=def.nodename_prefix.."_"..placenodes[step], param2=param2}) - if not minetest.settings:get_bool("creative_mode") then - istack:take_item() - end - step=step-1 - pos=vector.subtract(pos, dirvec) - end - else - minetest.chat_send_player(player:get_player_name(), attrans("Can't place: Not enough slope items left (@1 required)", step)) - end - else - minetest.chat_send_player(player:get_player_name(), attrans("Can't place: There's no slope of length @1",step)) - end - return istack - end - step=step+1 - pos=vector.add(pos, dirvec) - end - minetest.chat_send_player(player:get_player_name(), attrans("Can't place: no supporting node at upper end.")) - return itemstack - end -end - -advtrains.slope=sl - ---END code, BEGIN definition ---definition format: ([] optional) ---[[{ - nodename_prefix - texture_prefix - [shared_texture] - models_prefix - models_suffix (with dot) - [shared_model] - formats={ - st,cr,swlst,swlcr,swrst,swrcr,vst1,vst2 - (each a table with indices 0-3, for if to register a rail with this 'rotation' table entry. nil is assumed as 'all', set {} to not register at all) - } - common={} change something on common rail appearance -}]] - - - - - - - - - +-- tracks.lua +-- rewritten with advtrains 2.5 according to new track registration system + + +--[[ + +Tracks in advtrains are defined by the node definition. They must have at least 2 connections, but can have any number. +Switchable nodes (turnouts, single/double-slip switches) are implemented by having a separate node (node name) for each of the possible states. + + minetest.register_node(nodename, { + ... usual node definition ... + groups = { + advtrains_track = 1, + advtrains_track_=1 + ^- these groups tell that the node is a track + not_blocking_trains=1, + ^- this group tells that the node should not block trains although it's walkable. + }, + + at_rail_y = 0, + ^- Height of this rail node (the y position of a wagon that stands centered on this rail) + at_conns = { + [1] = { c=0..15, y=0..1 }, + [2] = { c=0..15, y=0..1 }, + ( [3] = { c=0..15, y=0..1 }, ) + ( [4] = { c=0..15, y=0..1 }, ) + ( ... ) + } + ^- Connections of this rail. There are two general cases: + a) SIMPLE TRACK - the track has exactly 2 connections, and does not feature a turnout, crossing or other contraption + For simple tracks, except for the at_conns table no further setup needs to be specified. A train entering on conn 1 will go out at conn 2 and vice versa. + A track with only one connection defined is not permitted. + b) COMPOUND TRACK - the track has more than 2 connections + This will be used for turnouts and crossings. Tracks with more than 2 conns MUST define 'at_conn_map'. + Switchable nodes, whose state can be changed (e.g. turnouts) MUST define a 'state_map' within the advtrains table as well. + This differs from the behavior up until 2.4.2, where the conn mapping was fixed. + ^- Connection definition: + - c is the direction of the connection (0-16). For the mapping to world directions see helpers.lua. + - Connections will be auto-rotated with param2 of the node (horizontal, param2 values 0-3 only) + - y is the height of the connection (rail will only connect when this matches) + ^- The index of a connection inside the conns table (1, 2, 3, ...) is referred throughout advtrains code as 'connid' + ^- IMPORTANT: For switchable nodes (any kind of turnout), it is crucial that for all of the node's variants the at_conns table stays the same. See below. + + at_conn_map = { + [1] = 2, + [2] = 1, + [3] = 1, + } + ^- Connection map of this rail. It specifies when a train enters the track on connid X, on which connid it will leave + This field MUST be specified when the number of connections in at_conns is greater than 2 + This field may, and obviously will, vary between nodes for switchable nodes. + + can_dig = advtrains.track_can_dig_callback + after_dig_node = advtrains.track_update_callback + after_place_node = advtrains.track_update_callback + ^- the code in these 3 default minetest API functions is required for advtrains to work, however you can add your own code + + on_rightclick = advtrains.state_node_on_rightclick_callback + ^- Must be added if the node is a turnout and if it should be switched by right-click. It will cause the turnout to be switched to next_state. + + advtrains = { + on_train_enter=function(pos, train_id, train, index) end + ^- called when a train enters the rail + on_train_leave=function(pos, train_id, train, index) end + ^- called when a train leaves the rail + + -- The following function is only in effect when interlocking is enabled: + on_train_approach = function(pos, train_id, train, index, has_entered, lzbdata) + ^- called when a train is approaching this position, called exactly once for every path recalculation (which can happen at any time) + ^- This is called so that if the train would start braking now, it would come to halt about(wide approx) 5 nodes before the rail. + ^- has_entered: when true, the train is already standing on this node with its front tip, and the enter callback has already been called. + Possibly, some actions need not to be taken in this case. Only set if it's the very first node the train is standing on. + ^- lzbdata should be ignored and nothing should be assigned to it + + -- The following information is required if the node is a turnout (e.g. can be switched into different positions) + node_state = "st" + ^- The name of the state this node represents + ^- Conventions for this field are as follows: + - Two-way straight/turn switches: 'st'=straight branch, 'cr'=diverting/turn branch + - 3-way turnouts, Y-turnouts: 'l'=left branch, 's'=straight branch, 'r'=right branch + + node_next_state = "cr" + ^- The name of the state that the turnout should be switched to when it is right-clicked + + node_fallback_state = "st" + ^- The name of the state that the turnout should "fall back" to when it is released + Only used by the interlocking system, when a route on the node is released it is switched back to this state. + + node_state_map = { + ["st"] = "", + ["cr"] = "", + ... etc ... + } + ^- Map of state name to the appropriate node name that should be set by advtrains when a switch is requested + Note that for all of those nodes, the at_conns table must be identical (however the conn_map will vary) + + node_on_switch_state = function(pos, node, oldstate, newstate) + ^- Called when the node state is switched by advtrains, after the node replacement has commenced. + + Turnout switching can happen programmatically via advtrains.setstate(pos, state), via user right_click or via the interlocking system. + In no other situation is it permissible to exchange track nodes in-place, unless both at_conns and at_conn_map stay identical. + + Note that the fields node_state, node_next_state and node_state_map completely replace the getstate/setstate functions. + There must be a one-to-one mapping between states and node names and no function can be defined for state switching. + This principle enables the seamless working of the interlocking autorouter and reduces failure points. + The node_state_* system can also be used as drop-in replacement for the passive-API-enabled nodes (andrews-cross, mesecon_switch etc.) + The advtrains API functions advtrains.getstate() and advtrains.setstate() remain the programmatic access points, but will now utilize the new state system. + + + trackworker_next_rot = , + ^- if set, right-click with trackworker will set this node + trackworker_rot_incr_param2 = true + ^- if set, trackworker will increase node param2 on rightclick + + trackworker_next_var = + ^- if set, left-click with trackworker will set this node + } + }) + +]]-- + +-- This file provides some utilities to register tracks, but tries to not get into the way too much + + +function advtrains.track_can_dig_callback(pos, player) + local ok, reason = advtrains.can_dig_or_modify_track(pos) + if not ok and player then + minetest.chat_send_player(player:get_player_name(), attrans("This track can not be removed!") .. " " .. reason) + end + return ok +end + +function advtrains.track_update_callback(pos) + advtrains.ndb.update(pos) +end + +function advtrains.state_node_on_rightclick_callback(pos, node, player) + if advtrains.check_turnout_signal_protection(pos, player:get_player_name()) then + local ndef = minetest.registered_nodes[node.name] + if ndef and ndef.advtrains and ndef.advtrains.node_next_state then + advtrains.setstate(pos, ndef.advtrains.node_next_state, node) + advtrains.log("Switch", player:get_player_name(), pos) + end + end +end + +-- advtrains.register_node_4rot(name, nodedef) +-- Registers four rotations for the node defined by nodedef (0°, 30°, 45° and 60°; the 4 90°-steps are already handled by the param2, resulting in 16 directions total). +-- You must provide the definition for the base node, and certain fields are altered automatically for the 3 additional rotations: +-- name: appends the suffix "_30", "_45" or "_60" +-- description: appends the rotation (human-readable) in parenthesis +-- tiles_prefix: if defined, "tiles" field will be set as prefix..rotationExtension..".png" +-- mesh_prefix, mesh_suffix: if defined, "mesh" field will be set as prefix..rotationExtension..suffix +-- at_conns: are rotated according to the node rotation +-- node_state_map, trackworker_next_var: appends the suffix appropriately. +-- groups: applies save_in_at_nodedb and not_blocking_trains groups if not already present +-- The nodes are registered in the trackworker to be rotated with right-click. +-- definition_mangling_function is an optional parameter. For each of the 4 rotations, it gets passed the modified node definition and may perform final modifications to it. +-- signature: function definition_mangling_function(name, nodedef, rotationIndex, rotationSuffix) +-- Example usage: define the setstate function of turnouts (if that is not done via the "automatic" way of state_node_map) +local rotations = { + {i = 0, s = "", h = " (0)", n = "_30"}, + {i = 1, s = "_30", h = " (30)", n = "_45"}, + {i = 2, s = "_45", h = " (45)", n = "_60"}, + {i = 3, s = "_60", h = " (60)", n = ""}, +} +function advtrains.register_node_4rot(ori_name, ori_ndef, definition_mangling_function) + for _, rot in ipairs(rotations) do + local ndef = table.copy(ori_ndef) + if ori_ndef.advtrains then + -- make sure advtrains table is deep-copied because we may need to replace node_state_map + ndef.advtrains = table.copy(ori_ndef.advtrains) + else + ndef.advtrains = {} -- we need the table later for trackworker + end + -- Perform the name mangling + local suffix = rot.s + local name = ori_name..suffix + ndef.description = ori_ndef.description .. rot.h + if ori_ndef.tiles_prefix then + ndef.tiles = { ori_ndef.tiles_prefix .. suffix .. ".png" } + end + if ori_ndef.mesh_prefix then + ndef.mesh = ori_ndef.mesh_prefix .. suffix .. ori_ndef.mesh_suffix + end + -- rotate connections + if ori_ndef.at_conns then + ndef.at_conns = advtrains.rotate_conn_by(ori_ndef.at_conns, rot.i) + end + -- update node state map if present + if ori_ndef.advtrains then + if ori_ndef.advtrains.node_state_map then + local new_nsm = {} + for state, nname in pairs(ori_ndef.advtrains.node_state_map) do + new_nsm[state] = nname .. suffix + end + ndef.advtrains.node_state_map = new_nsm + end + if ori_ndef.advtrains.trackworker_next_var then + ndef.advtrains.trackworker_next_var = ori_ndef.advtrains.trackworker_next_var .. suffix + end + -- apply trackworker rot field + ndef.advtrains.trackworker_next_rot = ori_name .. rot.n + ndef.advtrains.trackworker_rot_incr_param2 = (rot.n=="") + end + -- apply groups + ndef.groups.save_in_at_nodedb = 1 + ndef.groups.not_blocking_trains = 1 + + -- give the definition mangling function an option to do some adjustments + if definition_mangling_function then + definition_mangling_function(name, ndef, rot.i, suffix) + end + + -- register node + atdebug("Registering: ",name, ndef) + minetest.register_node(":"..name, ndef) + + -- if this has the track_place_group set, register as a candidate for the track_place_group + if ndef.advtrains.track_place_group then + advtrains.trackplacer.register_candidate(ndef.advtrains.track_place_group, name, ndef, ndef.advtrains.track_place_single, true) + end + end +end + + +-- Registers an item to place and automatically connect nearby tracks +function advtrains.register_track_placer(...) + +end + +-- Registers an item to place and adjust slope tracks +function advtrains.register_slope_placer(...) + +end + + + +-- track-related helper functions + +function advtrains.is_track(nodename) + if not minetest.registered_nodes[nodename] then + return false + end + local nodedef=minetest.registered_nodes[nodename] + if nodedef and nodedef.groups.advtrains_track then + return true + end + return false +end + +function advtrains.get_track_connections(name, param2) + local nodedef=minetest.registered_nodes[name] + if not nodedef then atprint(" get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return nil end + local noderot=param2 + if not param2 then noderot=0 end + if noderot > 3 then atprint(" get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end + + local tracktype + for k,_ in pairs(nodedef.groups) do + local tt=string.match(k, "^advtrains_track_(.+)$") + if tt then + tracktype=tt + end + end + return advtrains.rotate_conn_by(nodedef.at_conns, noderot*AT_CMAX/4), (nodedef.at_rail_y or 0), tracktype +end + +-- Function called when a track is about to be dug or modified by the trackworker +-- Returns either true (ok) or false,"translated string describing reason why it isn't allowed" +function advtrains.can_dig_or_modify_track(pos) + if advtrains.get_train_at_pos(pos) then + return false, attrans("Position is occupied by a train.") + end + -- interlocking: tcb, signal IP a.s.o. + if advtrains.interlocking then + -- TCB? + if advtrains.interlocking.db.get_tcb(pos) then + return false, attrans("There's a Track Circuit Break here.") + end + -- signal ip? + if advtrains.interlocking.db.is_ip_at(pos, true) then -- is_ip_at with purge parameter + return false, attrans("There's a Signal Influence Point here.") + end + end + return true +end \ No newline at end of file diff --git a/advtrains/trainlogic.lua b/advtrains/trainlogic.lua index 288e224..c6762c9 100644 --- a/advtrains/trainlogic.lua +++ b/advtrains/trainlogic.lua @@ -283,7 +283,7 @@ function advtrains.train_ensure_init(id, train) assertdef(train, "id", id) - if not train.drives_on or not train.max_speed then + if not train.max_speed then --atprint("in ensure_init: missing properties, updating!") advtrains.update_trainpart_properties(id) end @@ -1034,10 +1034,9 @@ end -- Note: safe_decouple_wagon() has been moved to wagons.lua --- this function sets wagon's pos_in_train(parts) properties and train's max_speed and drives_on (and more) +-- this function sets wagon's pos_in_train(parts) properties and train's max_speed (and more) function advtrains.update_trainpart_properties(train_id, invert_flipstate) local train=advtrains.trains[train_id] - train.drives_on=advtrains.merge_tables(advtrains.all_tracktypes) --FIX: deep-copy the table!!! train.max_speed=20 train.extent_h = 0; @@ -1079,13 +1078,6 @@ function advtrains.update_trainpart_properties(train_id, invert_flipstate) end rel_pos=rel_pos+wagon.wagon_span - if wagon.drives_on then - for k,_ in pairs(train.drives_on) do - if not wagon.drives_on[k] then - train.drives_on[k]=nil - end - end - end train.max_speed=math.min(train.max_speed, wagon.max_speed) train.extent_h = math.max(train.extent_h, wagon.extent_h or 1); end diff --git a/advtrains/wagons.lua b/advtrains/wagons.lua index b0fb575..f231546 100644 --- a/advtrains/wagons.lua +++ b/advtrains/wagons.lua @@ -1367,7 +1367,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati 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 + if(not advtrains.is_track(nodename)) then atprint("no track here, not placing.") return itemstack end @@ -1382,7 +1382,7 @@ function advtrains.register_wagon(sysname_p, prototype, desc, inv_img, nincreati local yaw = placer:get_look_horizontal() local plconnid = advtrains.yawToClosestConn(yaw, tconns) - local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid, prototype.drives_on) + local prevpos = advtrains.get_adjacent_rail(pointed_thing.under, tconns, plconnid) if not prevpos then minetest.chat_send_player(pname, "The track you are trying to place the wagon on is not long enough!") return @@ -1407,7 +1407,6 @@ advtrains.register_wagon("advtrains:wagon_placeholder", { collisionbox = {-0.3,-0.3,-0.3, 0.3,0.3,0.3}, visual_size = {x=0.7, y=0.7}, initial_sprite_basepos = {x=0, y=0}, - drives_on = advtrains.all_tracktypes, max_speed = 5, seats = { }, diff --git a/advtrains_interlocking/init.lua b/advtrains_interlocking/init.lua index a2f5882..cc46b83 100644 --- a/advtrains_interlocking/init.lua +++ b/advtrains_interlocking/init.lua @@ -24,7 +24,9 @@ dofile(modpath.."tool.lua") dofile(modpath.."approach.lua") dofile(modpath.."ars.lua") -dofile(modpath.."tsr_rail.lua") + +--TODO reenable tsr rail +--dofile(modpath.."tsr_rail.lua") minetest.register_privilege("interlocking", {description = "Can set up track sections, routes and signals.", give_to_singleplayer = true}) diff --git a/advtrains_line_automation/init.lua b/advtrains_line_automation/init.lua index 7b758bc..cc8df3c 100644 --- a/advtrains_line_automation/init.lua +++ b/advtrains_line_automation/init.lua @@ -20,7 +20,9 @@ local modpath = minetest.get_modpath(minetest.get_current_modname()) .. DIR_DELI dofile(modpath.."railwaytime.lua") dofile(modpath.."scheduler.lua") -dofile(modpath.."stoprail.lua") + +--TODO reenable stop rail +--dofile(modpath.."stoprail.lua") function advtrains.lines.load(data) diff --git a/advtrains_signals_ks/init.lua b/advtrains_signals_ks/init.lua index bdbd50d..99d059a 100755 --- a/advtrains_signals_ks/init.lua +++ b/advtrains_signals_ks/init.lua @@ -113,15 +113,6 @@ local suppasp_ra = { } } -advtrains.trackplacer.register_tracktype("advtrains_signals_ks:hs") -advtrains.trackplacer.register_tracktype("advtrains_signals_ks:ra") -advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign") -advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign_lf") -advtrains.trackplacer.register_tracktype("advtrains_signals_ks:sign_lf7") -advtrains.trackplacer.register_tracktype("advtrains_signals_ks:zs3") -advtrains.trackplacer.register_tracktype("advtrains_signals_ks:zs3v") -advtrains.trackplacer.register_tracktype("advtrains_signals_ks:mast") - for _, rtab in ipairs({ {rot = "0", sbox = {-1/8, -1/2, -1/2, 1/8, 1/2, -1/4}, ici=true}, {rot = "30", sbox = {-3/8, -1/2, -1/2, -1/8, 1/2, -1/4},}, @@ -201,7 +192,7 @@ for _, rtab in ipairs({ after_dig_node = advtrains.interlocking.signal_after_dig, }) -- rotatable by trackworker - advtrains.trackplacer.add_worked("advtrains_signals_ks:hs", typ, "_"..rot) + --TODO add rotation using trackworker end @@ -246,7 +237,7 @@ for _, rtab in ipairs({ after_dig_node = advtrains.interlocking.signal_after_dig, }) -- rotatable by trackworker - advtrains.trackplacer.add_worked("advtrains_signals_ks:ra", typ, "_"..rot) + --TODO add rotation using trackworker end -- Schilder: @@ -283,7 +274,7 @@ for _, rtab in ipairs({ after_dig_node = advtrains.interlocking.signal_after_dig, }) -- rotatable by trackworker - advtrains.trackplacer.add_worked("advtrains_signals_ks:"..prefix, typ, "_"..rot, nxt) + --TODO add rotation using trackworker end for typ, prts in pairs { @@ -378,7 +369,7 @@ for _, rtab in ipairs({ t.drop = "advtrains_signals_ks:zs3_off_0" t.selection_box.fixed[1][5] = 0 minetest.register_node("advtrains_signals_ks:zs3_"..typ.."_"..rot, t) - advtrains.trackplacer.add_worked("advtrains_signals_ks:zs3", typ, "_"..rot) + --TODO add rotation using trackworker -- Zs 3v local t = table.copy(def) @@ -387,7 +378,7 @@ for _, rtab in ipairs({ t.drop = "advtrains_signals_ks:zs3v_off_0" t.tiles[3] = t.tiles[3] .. "^[multiply:yellow" minetest.register_node("advtrains_signals_ks:zs3v_"..typ.."_"..rot, t) - advtrains.trackplacer.add_worked("advtrains_signals_ks:zs3v", typ, "_"..rot) + --TODO add rotation using trackworker end minetest.register_node("advtrains_signals_ks:mast_mast_"..rot, { @@ -412,7 +403,7 @@ for _, rtab in ipairs({ }, drop = "advtrains_signals_ks:mast_mast_0", }) - advtrains.trackplacer.add_worked("advtrains_signals_ks:mast","mast", "_"..rot) + --TODO add rotation using trackworker end -- Crafting diff --git a/advtrains_train_track/init.lua b/advtrains_train_track/init.lua index 5065155..55b1367 100755 --- a/advtrains_train_track/init.lua +++ b/advtrains_train_track/init.lua @@ -1,937 +1,172 @@ --- Default tracks for advtrains --- (c) orwell96 and contributors - -local default_boxen = { - ["st"] = { - [""] = { - selection_box = { - type = "fixed", - fixed = {-1/2-1/16, -1/2, -1/2, 1/2+1/16, -1/2+2/16, 1/2}, - } - }, - ["_30"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, - {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, - {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, - {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} - } - } - }, - ["_45"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750}, - {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, - {-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000} - } - } - }, - ["_60"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, - {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, - {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, - {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} - } - } - }, - }, - - ["cr"] = { - [""] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -0.5000, 0.6875, -0.3750, 0.5000}, - {-0.3750, -0.5000, -1.000, 1.000, -0.3750, 0.000} - } - } - }, - ["_30"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -0.5000, 0.7500, -0.3750, 0.8750}, - {-0.3750, -0.5000, 0.8750, 0.2500, -0.3750, 1.188}, - {0.7500, -0.5000, 0.2500, 1.063, -0.3750, 0.8750} - } - } - }, - ["_45"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -1.125, 0.5000, -0.3750, 0.6875}, - {-0.8750, -0.5000, -0.9375, -0.5000, -0.3750, 0.06250}, - {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000} - } - } - }, - ["_60"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.8125, -0.5000, -0.5000, 1.188, -0.3750, 0.5000}, - {-0.1875, -0.5000, 0.5000, 0.8750, -0.3125, 0.8750}, - {-0.2500, -0.5000, -0.9375, 0.3125, -0.3125, -0.5000} - } - } - }, - }, - - ["swlst"] = { - [""] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -0.5000, 0.6250, -0.3750, 0.5000}, - {-0.3125, -0.5000, -1.000, 0.9375, -0.3125, -0.06250} - } - } - }, - ["_30"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, - {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, - {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, - {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} - } - } - }, - ["_45"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -1.1875, 0.5000, -0.3750, 0.8750}, - {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, - {-0.8750, -0.5000, -0.8125, -0.5000, -0.3750, 0.5000} - } - } - }, - ["_60"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, - {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, - {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, - {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} - } - } - }, - }, - - ["swrst"] = { - [""] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -0.5000, 0.6250, -0.3750, 0.5000}, - {-0.8125, -0.5000, -1.000, 0.4375, -0.3125, -0.06250} - } - } - }, - ["_30"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, - {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, - {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, - {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} - } - } - }, - ["_45"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.1875, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, - {-0.5000, -0.5000, 0.5000, 0.5000, -0.3750, 0.8750}, - {-0.8125, -0.5000, -0.8750, 0.5000, -0.3750, -0.5000} - } - } - }, - ["_60"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, - {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, - {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, - {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} - } - } - }, - }, -} - -default_boxen["swlcr"] = default_boxen["swlst"] -default_boxen["swrcr"] = default_boxen["swrst"] - ---flat -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack", - texture_prefix="advtrains_dtrack", - models_prefix="advtrains_dtrack", - models_suffix=".b3d", - shared_texture="advtrains_dtrack_shared.png", - description=attrans("Track"), - formats={}, - - get_additional_definiton = function(def, preset, suffix, rotation) - if default_boxen[suffix] ~= nil and default_boxen[suffix][rotation] ~= nil then - return default_boxen[suffix][rotation] - else - return {} - end - end, -}, advtrains.ap.t_30deg_flat) - -minetest.register_craft({ - output = 'advtrains:dtrack_placer 50', - recipe = { - {'default:steel_ingot', 'group:stick', 'default:steel_ingot'}, - {'default:steel_ingot', 'group:stick', 'default:steel_ingot'}, - {'default:steel_ingot', 'group:stick', 'default:steel_ingot'}, - }, -}) - -local y3_boxen = { - [""] = { - selection_box = { - type = "fixed", - fixed = { - {-0.8750, -0.5000, -1.125, 0.8750, -0.3750, 0.4375} - } - } - }, - - ["_30"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -0.875, 0.5000, -0.3750, 1.000}, - {-0.8750, -0.5000, -0.4375, -0.5000, -0.3750, 0.5625}, - {0.5000, -0.5000, -0.2500, 0.8125, -0.3750, 1.000}, - } - } - }, - - --UX FIXME: - 3way - have to place straight route before l and r or the - --nodebox overlaps too much and can't place the straight track node. - ["_45"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -1.1250, 0.5000, -0.3750, 0.8750}, - {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, - {-1.1250, -0.5000, -0.9375, -0.5000, -0.3750, 0.5000} - } - } - }, - - ["_60"] = { - selection_box = { - type = "fixed", - fixed = { - --{-0.5000, -0.5000, -0.875, 0.5000, -0.3750, 1.000}, - {-0.875, -0.5000, -0.5, 1.0, -0.3750, 0.5}, - --{-0.8750, -0.5000, -0.4375, -0.5000, -0.3750, 0.5625}, - {-0.4375, -0.5000, -0.8750, 0.5625, -0.3750, -0.5000}, - --{0.5000, -0.5000, -0.2500, 0.8125, -0.3750, 1.000}, - {-0.2500, -0.5000, -0.2500, 1.0000, -0.3750, 0.8125}, - } - } - }, -} - - -local function y3_turnouts_addef(def, preset, suffix, rotation) - return y3_boxen[rotation] or {} -end --- y-turnout -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_sy", - texture_prefix="advtrains_dtrack_sy", - models_prefix="advtrains_dtrack_sy", - models_suffix=".obj", - shared_texture="advtrains_dtrack_shared.png", - description=attrans("Y-turnout"), - formats = {}, - get_additional_definiton = y3_turnouts_addef, -}, advtrains.ap.t_yturnout) -minetest.register_craft({ - output = 'advtrains:dtrack_sy_placer 2', - recipe = { - {'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'}, - {'', 'advtrains:dtrack_placer', ''}, - {'', 'advtrains:dtrack_placer', ''}, - }, -}) ---3-way turnout -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_s3", - texture_prefix="advtrains_dtrack_s3", - models_prefix="advtrains_dtrack_s3", - models_suffix=".obj", - shared_texture="advtrains_dtrack_shared.png", - description=attrans("3-way turnout"), - formats = {}, - get_additional_definiton = y3_turnouts_addef, -}, advtrains.ap.t_s3way) -minetest.register_craft({ - output = 'advtrains:dtrack_s3_placer 1', - recipe = { - {'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'}, - {'', 'advtrains:dtrack_placer', ''}, - {'', '', ''}, - }, -}) - --- Diamond Crossings - -local perp_boxen = { - [""] = {}, --default size - ["_30"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000} - } - } - }, - ["_45"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.8125, -0.5000, -0.8125, 0.8125, -0.3750, 0.8125} - } - } - }, - ["_60"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000} - } - } - }, -} - --- perpendicular -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_xing", - texture_prefix="advtrains_dtrack_xing", - models_prefix="advtrains_dtrack_xing", - models_suffix=".obj", - shared_texture="advtrains_dtrack_shared.png", - description=attrans("Perpendicular Diamond Crossing Track"), - formats = {}, - get_additional_definiton = function(def, preset, suffix, rotation) - return perp_boxen[rotation] or {} - end -}, advtrains.ap.t_perpcrossing) - -minetest.register_craft({ - output = 'advtrains:dtrack_xing_placer 3', - recipe = { - {'', 'advtrains:dtrack_placer', ''}, - {'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'}, - {'', 'advtrains:dtrack_placer', ''} - } -}) - -local ninety_plus_boxen = { - ["30l"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, - {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, - {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, - {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} - } - } - }, - ["30r"] = { - selection_box = { - type = "fixed", - fixed = { - {0.5000, -0.5000, -1.000, -0.5000, -0.3750, 1.000}, - {0.8750, -0.5000, -1.000, 0.5000, -0.3750, 0.2500}, - {-0.5000, -0.5000, -0.2500, -0.8750, -0.3750, 1.000}, - {0.1250, -0.5000, -1.375, -0.1875, -0.3750, -1.000} - } - } - }, - ["45l"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750}, - {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, - {-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000} - } - } - }, - ["45r"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750}, - {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, - {-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000} - } - } - }, - ["60l"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, - {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, - {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, - {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} - } - } - }, - ["60r"] = { - selection_box = { - type = "fixed", - fixed = { - {1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000}, - {1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000}, - {0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750}, - {1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875} - } - } - }, -} - --- 90plusx --- When you face east and param2=0, then this set of rails has a rail at 90 --- degrees to the viewer, plus another rail crossing at 30, 45 or 60 degrees. -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_xing90plusx", - texture_prefix="advtrains_dtrack_xing4590", - models_prefix="advtrains_dtrack_xing90plusx", - models_suffix=".obj", - shared_texture="advtrains_dtrack_shared.png", - description=attrans("90+Angle Diamond Crossing Track"), - formats = {}, - get_additional_definiton = function(def, preset, suffix, rotation) - return ninety_plus_boxen[suffix] or {} - end, -}, advtrains.ap.t_90plusx_crossing) -minetest.register_craft({ - output = 'advtrains:dtrack_xing90plusx_placer 2', - recipe = { - {'advtrains:dtrack_placer', '', ''}, - {'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'}, - {'', '', 'advtrains:dtrack_placer'} - } -}) - --- Deprecate any rails using the old name scheme -minetest.register_lbm({ - label = "Upgrade legacy 4590 rails", - name = "advtrains_train_track:replace_legacy_4590", - nodenames = {"advtrains:dtrack_xing4590_st"}, - run_at_every_load = true, - action = function(pos, node) - minetest.log("actionPos!: " .. pos.x .. "," .. pos.y .. "," .. pos.z) - minetest.log("node!: " .. node.name .. "," .. node.param1 .. "," .. node.param2) - advtrains.ndb.swap_node(pos, - { - name="advtrains:dtrack_xing90plusx_45l", - param1=node.param1, - param2=node.param2, - }) - end -}) --- This will replace any items left in the inventory -minetest.register_alias("advtrains:dtrack_xing4590_placer", "advtrains:dtrack_xing90plusx_placer") - -local diagonal_boxen = { - ["30r45l"] = { - selection_box = { - type = "fixed", - fixed = { - {0.5000, -0.5000, -1.000, -0.5000, -0.3750, 1.000}, - {0.8750, -0.5000, -1.000, 0.5000, -0.3750, 0.2500}, - {-0.5000, -0.5000, -0.2500, -0.8750, -0.3750, 1.000}, - {0.1250, -0.5000, -1.375, -0.1875, -0.3750, -1.000} - } - } - }, - ["60l30l"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, - {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, - {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, - {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} - } - } - }, - ["60l60r"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000} - } - } - }, - ["60r30r"] = { - selection_box = { - type = "fixed", - fixed = { - {1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000}, - {1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000}, - {0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750}, - {1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875} - } - } - }, - ["30l45r"] = { - selection_box = { - type = "fixed", - fixed = { - {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, - {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, - {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, - {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} - } - } - }, - ["60l45r"] = { - selection_box = { - type = "fixed", - fixed = { - {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, - {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, - {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, - {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} - } - } - }, - ["60r45l"] = { - selection_box = { - type = "fixed", - fixed = { - {1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000}, - {1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000}, - {0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750}, - {1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875} - } - } - }, -} - --- Diagonal --- This set of rail crossings is named based on the angle of each intersecting --- direction when facing east and param2=0. Rails with l/r swapped are mirror --- images. For example, 30r45l is the mirror image of 30l45r. -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_xingdiag", - texture_prefix="advtrains_dtrack_xingdiag", - models_prefix="advtrains_dtrack_xingdiag", - models_suffix=".obj", - shared_texture="advtrains_dtrack_shared.png", - description=attrans("Diagonal Diamond Crossing Track"), - formats = {}, - get_additional_definiton = function(def, preset, suffix, rotation) - return diagonal_boxen[suffix] or {} - end, -}, advtrains.ap.t_diagonalcrossing) -minetest.register_craft({ - output = 'advtrains:dtrack_xingdiag_placer 2', - recipe = { - {'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'}, - {'', 'advtrains:dtrack_placer', ''}, - {'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'} - } -}) ----- Not included: very shallow crossings like (30/60)+45. ----- At an angle of only 18.4 degrees, the models would not ----- translate well to a block game. --- END crossings - ---slopes -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack", - texture_prefix="advtrains_dtrack", - models_prefix="advtrains_dtrack", - models_suffix=".obj", - shared_texture="advtrains_dtrack_shared.png", - second_texture="default_gravel.png", - description=attrans("Track"), - formats={vst1={true, false, true}, vst2={true, false, true}, vst31={true}, vst32={true}, vst33={true}}, -}, advtrains.ap.t_30deg_slope) - -minetest.register_craft({ - type = "shapeless", - output = 'advtrains:dtrack_slopeplacer 2', - recipe = { - "advtrains:dtrack_placer", - "advtrains:dtrack_placer", - "default:gravel", - }, -}) - - ---bumpers -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_bumper", - texture_prefix="advtrains_dtrack_bumper", - models_prefix="advtrains_dtrack_bumper", - models_suffix=".b3d", - shared_texture="advtrains_dtrack_rail.png", - --bumpers still use the old texture until the models are redone. - description=attrans("Bumper"), - formats={}, -}, advtrains.ap.t_30deg_straightonly) -minetest.register_craft({ - output = 'advtrains:dtrack_bumper_placer 2', - recipe = { - {'group:wood', 'dye:red'}, - {'default:steel_ingot', 'default:steel_ingot'}, - {'advtrains:dtrack_placer', 'advtrains:dtrack_placer'}, - }, -}) ---legacy bumpers -for _,rot in ipairs({"", "_30", "_45", "_60"}) do - minetest.register_alias("advtrains:dtrack_bumper"..rot, "advtrains:dtrack_bumper_st"..rot) -end --- atc track -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_atc", - texture_prefix="advtrains_dtrack_atc", - models_prefix="advtrains_dtrack", - models_suffix=".b3d", - shared_texture="advtrains_dtrack_shared_atc.png", - description=attrans("ATC controller"), - formats={}, - get_additional_definiton = advtrains.atc_function -}, advtrains.trackpresets.t_30deg_straightonly) - - --- Tracks for loading and unloading trains --- Copyright (C) 2017 Gabriel Pérez-Cerezo - -local function get_far_node(pos) - local node = minetest.get_node(pos) - if node.name == "ignore" then - minetest.get_voxel_manip():read_from_map(pos, pos) - node = minetest.get_node(pos) - end - return node -end - - -local function show_fc_formspec(pos,player) - local pname = player:get_player_name() - if minetest.is_protected(pos,pname) then - minetest.chat_send_player(pname, "Position is protected!") - return - end - - local meta = minetest.get_meta(pos) - local fc = meta:get_string("fc") or "" - - local form = 'formspec_version[4]'.. - 'size[10,5]'.. - 'label[0.5,0.4;Advtrains Loading/Unloading Track]'.. - 'label[0.5,1.1;Set the code to match against the wagon\'s freight code]'.. - 'label[0.5,1.6;A blank field matches all wagons (default)]'.. - 'label[0.5,2.1;Use code # to disable the track section]'.. - 'field[0.5,3;5.5,1;fc;FC;'..minetest.formspec_escape(fc)..']'.. - 'button[6.5,3;3,1;save;Submit]' - minetest.show_formspec(pname, "at_load_unload_"..advtrains.encode_pos(pos), form) -end - -minetest.register_on_player_receive_fields(function(player, formname, fields) - local pname = player:get_player_name() - local pe = string.match(formname, "^at_load_unload_(............)$") - local pos = advtrains.decode_pos(pe) - if pos then - if minetest.is_protected(pos, pname) then - minetest.chat_send_player(pname, "Position is protected!") - return - end - - if fields.save then - minetest.get_meta(pos):set_string("fc",tostring(fields.fc)) - minetest.chat_send_player(pname,"Freight code set: "..tostring(fields.fc)) - show_fc_formspec(pos,player) - end - end -end) - - -local function train_load(pos, train_id, unload) - local train=advtrains.trains[train_id] - local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z}) - if not string.match(below.name, "chest") then - atprint("this is not a chest! at "..minetest.pos_to_string(pos)) - return - end - - local node_fc = minetest.get_meta(pos):get_string("fc") or "" - if node_fc == "#" then - --track section is disabled - return - end - - local inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}}) - if inv and train.velocity < 2 then - for k, v in ipairs(train.trainparts) do - local i=minetest.get_inventory({type="detached", name="advtrains_wgn_"..v}) - if i and i:get_list("box") then - - local wagon_data = advtrains.wagons[v] - local wagon_fc - if wagon_data.fc then - if not wagon_data.fcind then wagon_data.fcind = 1 end - wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or "" - end - - if node_fc == "" or wagon_fc == node_fc then - if not unload then - for _, item in ipairs(inv:get_list("main")) do - if i:get_list("box") and i:room_for_item("box", item) then - i:add_item("box", item) - inv:remove_item("main", item) - end - end - else - for _, item in ipairs(i:get_list("box")) do - if inv:get_list("main") and inv:room_for_item("main", item) then - i:remove_item("box", item) - inv:add_item("main", item) - end - end - end - end - end - end - end -end - - - -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_unload", - texture_prefix="advtrains_dtrack_unload", - models_prefix="advtrains_dtrack", - models_suffix=".b3d", - shared_texture="advtrains_dtrack_shared_unload.png", - description=attrans("Unloading Track"), - formats={}, - get_additional_definiton = function(def, preset, suffix, rotation) - return { - after_dig_node=function(pos) - advtrains.invalidate_all_paths() - advtrains.ndb.clear(pos) - end, - on_rightclick = function(pos, node, player) - show_fc_formspec(pos, player) - end, - advtrains = { - on_train_enter = function(pos, train_id) - train_load(pos, train_id, true) - end, - }, - } - end - }, advtrains.trackpresets.t_30deg_straightonly) -advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_load", - texture_prefix="advtrains_dtrack_load", - models_prefix="advtrains_dtrack", - models_suffix=".b3d", - shared_texture="advtrains_dtrack_shared_load.png", - description=attrans("Loading Track"), - formats={}, - get_additional_definiton = function(def, preset, suffix, rotation) - return { - after_dig_node=function(pos) - advtrains.invalidate_all_paths() - advtrains.ndb.clear(pos) - end, - on_rightclick = function(pos, node, player) - show_fc_formspec(pos, player) - end, - advtrains = { - on_train_enter = function(pos, train_id) - train_load(pos, train_id, false) - end, - }, - } - end - }, advtrains.trackpresets.t_30deg_straightonly) - --- mod-dependent crafts -local loader_core = "default:mese_crystal" --fallback -if minetest.get_modpath("basic_materials") then - loader_core = "basic_materials:ic" -elseif minetest.get_modpath("technic") then - loader_core = "technic:control_logic_unit" -end ---print("Loader Core: "..loader_core) - -minetest.register_craft({ - type="shapeless", - output = 'advtrains:dtrack_load_placer', - recipe = { - "advtrains:dtrack_placer", - loader_core, - "default:chest" - }, -}) -loader_core = nil --nil the crafting variable - ---craft between load/unload tracks -minetest.register_craft({ - type="shapeless", - output = 'advtrains:dtrack_unload_placer', - recipe = { - "advtrains:dtrack_load_placer", - }, -}) -minetest.register_craft({ - type="shapeless", - output = 'advtrains:dtrack_load_placer', - recipe = { - "advtrains:dtrack_unload_placer", - }, -}) - - -if mesecon then - advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_detector_off", - texture_prefix="advtrains_dtrack_detector", - models_prefix="advtrains_dtrack", - models_suffix=".b3d", - shared_texture="advtrains_dtrack_shared_detector_off.png", - description=attrans("Detector Rail"), - formats={}, - get_additional_definiton = function(def, preset, suffix, rotation) - return { - mesecons = { - receptor = { - state = mesecon.state.off, - rules = advtrains.meseconrules - } - }, - advtrains = { - on_updated_from_nodedb = function(pos, node) - mesecon.receptor_off(pos, advtrains.meseconrules) - end, - on_train_enter=function(pos, train_id) - advtrains.ndb.swap_node(pos, {name="advtrains:dtrack_detector_on".."_"..suffix..rotation, param2=advtrains.ndb.get_node(pos).param2}) - if advtrains.is_node_loaded(pos) then - mesecon.receptor_on(pos, advtrains.meseconrules) - end - end - } - } - end - }, advtrains.ap.t_30deg_straightonly) - advtrains.register_tracks("default", { - nodename_prefix="advtrains:dtrack_detector_on", - texture_prefix="advtrains_dtrack", - models_prefix="advtrains_dtrack", - models_suffix=".b3d", - shared_texture="advtrains_dtrack_shared_detector_on.png", - description="Detector(on)(you hacker you)", - formats={}, - get_additional_definiton = function(def, preset, suffix, rotation) - return { - mesecons = { - receptor = { - state = mesecon.state.on, - rules = advtrains.meseconrules - } - }, - advtrains = { - on_updated_from_nodedb = function(pos, node) - mesecon.receptor_on(pos, advtrains.meseconrules) - end, - on_train_leave=function(pos, train_id) - advtrains.ndb.swap_node(pos, {name="advtrains:dtrack_detector_off".."_"..suffix..rotation, param2=advtrains.ndb.get_node(pos).param2}) - if advtrains.is_node_loaded(pos) then - mesecon.receptor_off(pos, advtrains.meseconrules) - end - end - } - } - end - }, advtrains.ap.t_30deg_straightonly_noplacer) -minetest.register_craft({ - type="shapeless", - output = 'advtrains:dtrack_detector_off_placer', - recipe = { - "advtrains:dtrack_placer", - "mesecons:wire_00000000_off" - }, -}) -end ---TODO legacy ---I know lbms are better for this purpose -for name,rep in pairs({swl_st="swlst", swr_st="swrst", swl_cr="swlcr", swr_cr="swrcr", }) do - minetest.register_abm({ - -- In the following two fields, also group:groupname will work. - nodenames = {"advtrains:track_"..name}, - interval = 1.0, -- Operation interval in seconds - chance = 1, -- Chance of trigger per-node per-interval is 1.0 / this - action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:track_"..rep, param2=node.param2}) end, - }) - minetest.register_abm({ - -- In the following two fields, also group:groupname will work. - nodenames = {"advtrains:track_"..name.."_45"}, - interval = 1.0, -- Operation interval in seconds - chance = 1, -- Chance of trigger per-node per-interval is 1.0 / this - action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:track_"..rep.."_45", param2=node.param2}) end, - }) -end - -if advtrains.register_replacement_lbms then -minetest.register_lbm({ - name = "advtrains:ramp_replacement_1", --- In the following two fields, also group:groupname will work. - nodenames = {"advtrains:track_vert1"}, - action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_vst1", param2=(node.param2+2)%4}) end, -}) -minetest.register_lbm({ - name = "advtrains:ramp_replacement_1", --- -- In the following two fields, also group:groupname will work. - nodenames = {"advtrains:track_vert2"}, - action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_vst2", param2=(node.param2+2)%4}) end, -}) - minetest.register_abm({ - name = "advtrains:st_rep_1", - -- In the following two fields, also group:groupname will work. - nodenames = {"advtrains:track_st"}, - interval=1, - chance=1, - action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_st", param2=node.param2}) end, - }) - minetest.register_lbm({ - name = "advtrains:st_rep_1", - -- -- In the following two fields, also group:groupname will work. - nodenames = {"advtrains:track_st_45"}, - action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_st_45", param2=node.param2}) end, - }) -end +-- advtrains_train_track +-- rewritten to work with advtrains 2.5 track system + +local function conns(c1, c2, r1, r2) return {{c=c1, y=r1}, {c=c2, y=r2}} end +local function conns3(c1, c2, c3, r1, r2, r3) return {{c=c1, y=r1}, {c=c2, y=r2}, {c=c3, y=r3}} end + + +local common_def = { + drawtype = "mesh", + paramtype = "light", + paramtype2 = "facedir", + walkable = false, + selection_box = { + type = "fixed", + fixed = {-1/2-1/16, -1/2, -1/2, 1/2+1/16, -1/2+2/16, 1/2}, + }, + + mesh_suffix = ".b3d", + tiles = { "advtrains_dtrack_shared.png" }, + + groups = { + advtrains_track=1, + advtrains_track_default=1, + dig_immediate=2, + --not_in_creative_inventory=1, + }, + + can_dig = advtrains.track_can_dig_callback, + after_dig_node = advtrains.track_update_callback, + after_place_node = advtrains.track_update_callback, + + drop = "advtrains:dtrack_placer" +} + +-- Normal tracks, straight and curved +advtrains.register_node_4rot("advtrains:dtrack_st", + advtrains.merge_tables(common_def, { + description=attrans("Track Straight"), + mesh_prefix="advtrains_dtrack_st", + at_conns = conns(0,8), + advtrains = { + trackworker_next_var = "advtrains:dtrack_cr", + track_place_group = "advtrains:dtrack", + track_place_single = true, + }, + }) +) + +advtrains.register_node_4rot("advtrains:dtrack_cr", + advtrains.merge_tables(common_def, { + description=attrans("Track Curve"), + mesh_prefix="advtrains_dtrack_cr", + at_conns = conns(0,7), + advtrains = { + trackworker_next_var = "advtrains:dtrack_swlst", + track_place_group = "advtrains:dtrack", + }, + }) +) + +-- simple turnouts left and right + +local stm_left = { + st = "advtrains:dtrack_swlst", + cr = "advtrains:dtrack_swlcr", +} + +advtrains.register_node_4rot("advtrains:dtrack_swlst", + advtrains.merge_tables(common_def, { + description=attrans("Track Turnout Left Straight"), + mesh_prefix="advtrains_dtrack_swlst", + at_conns = conns3(0,8,7), + at_conn_map = {2,1,1}, + on_rightclick = advtrains.state_node_on_rightclick_callback, + advtrains = { + node_state = "st", + node_next_state = "cr", + node_state_map = stm_left, + trackworker_next_var = "advtrains:dtrack_swrst" + }, + }) +) + +advtrains.register_node_4rot("advtrains:dtrack_swlcr", + advtrains.merge_tables(common_def, { + description=attrans("Track Turnout Left Curve"), + mesh_prefix="advtrains_dtrack_swlcr", + at_conns = conns3(0,8,7), -- note: conns must stay identical + at_conn_map = {3,1,1}, -- now points to curve branch + on_rightclick = advtrains.state_node_on_rightclick_callback, + advtrains = { + node_state = "cr", + node_next_state = "st", + node_state_map = stm_left, + trackworker_next_var = "advtrains:dtrack_swrcr" + }, + }) +) + +local stm_right = { + st = "advtrains:dtrack_swrst", + cr = "advtrains:dtrack_swrcr", +} + +advtrains.register_node_4rot("advtrains:dtrack_swrst", + advtrains.merge_tables(common_def, { + description=attrans("Track Turnout Right Straight"), + mesh_prefix="advtrains_dtrack_swrst", + at_conns = conns3(0,8,9), + at_conn_map = {2,1,1}, + on_rightclick = advtrains.state_node_on_rightclick_callback, + advtrains = { + node_state = "st", + node_next_state = "cr", + node_state_map = stm_right, + trackworker_next_var = "advtrains:dtrack_st" + }, + }) +) + +advtrains.register_node_4rot("advtrains:dtrack_swrcr", + advtrains.merge_tables(common_def, { + description=attrans("Track Turnout Right Curve"), + mesh_prefix="advtrains_dtrack_swrcr", + at_conns = conns3(0,8,9), -- note: conns must stay identical + at_conn_map = {3,1,1}, -- now points to curve branch + on_rightclick = advtrains.state_node_on_rightclick_callback, + advtrains = { + node_state = "cr", + node_next_state = "st", + node_state_map = stm_right, + trackworker_next_var = "advtrains:dtrack_st" + }, + }) +) + +-- register placer item +minetest.register_craftitem(":advtrains:dtrack_placer", { + description = attrans("Track"), + inventory_image = "advtrains_dtrack_placer.png", + wield_image = "advtrains_dtrack_placer.png", + groups={advtrains_trackplacer=1, digtron_on_place=1}, + liquids_pointable = false, + on_place = function(itemstack, placer, pointed_thing) + local name = placer:get_player_name() + if not name then + return itemstack, false + 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 not advtrains.check_track_protection(pos, name) then + return itemstack, false + end + if minetest.registered_nodes[minetest.get_node(pos).name] and minetest.registered_nodes[minetest.get_node(pos).name].buildable_to then + local s = minetest.registered_nodes[minetest.get_node(upos).name] and minetest.registered_nodes[minetest.get_node(upos).name].walkable + if s then +-- minetest.chat_send_all(nnprefix) + local yaw = placer:get_look_horizontal() + advtrains.trackplacer.place_track(pos, "advtrains:dtrack", name, yaw) + if not advtrains.is_creative(name) then + itemstack:take_item() + end + end + end + end + return itemstack, true + end, +}) + + +--TODO restore mesecons! \ No newline at end of file diff --git a/advtrains_train_track/oldinit.lua b/advtrains_train_track/oldinit.lua new file mode 100644 index 0000000..5065155 --- /dev/null +++ b/advtrains_train_track/oldinit.lua @@ -0,0 +1,937 @@ +-- Default tracks for advtrains +-- (c) orwell96 and contributors + +local default_boxen = { + ["st"] = { + [""] = { + selection_box = { + type = "fixed", + fixed = {-1/2-1/16, -1/2, -1/2, 1/2+1/16, -1/2+2/16, 1/2}, + } + }, + ["_30"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, + {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, + {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, + {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} + } + } + }, + ["_45"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750}, + {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, + {-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000} + } + } + }, + ["_60"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, + {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, + {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, + {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} + } + } + }, + }, + + ["cr"] = { + [""] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -0.5000, 0.6875, -0.3750, 0.5000}, + {-0.3750, -0.5000, -1.000, 1.000, -0.3750, 0.000} + } + } + }, + ["_30"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -0.5000, 0.7500, -0.3750, 0.8750}, + {-0.3750, -0.5000, 0.8750, 0.2500, -0.3750, 1.188}, + {0.7500, -0.5000, 0.2500, 1.063, -0.3750, 0.8750} + } + } + }, + ["_45"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -1.125, 0.5000, -0.3750, 0.6875}, + {-0.8750, -0.5000, -0.9375, -0.5000, -0.3750, 0.06250}, + {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000} + } + } + }, + ["_60"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.8125, -0.5000, -0.5000, 1.188, -0.3750, 0.5000}, + {-0.1875, -0.5000, 0.5000, 0.8750, -0.3125, 0.8750}, + {-0.2500, -0.5000, -0.9375, 0.3125, -0.3125, -0.5000} + } + } + }, + }, + + ["swlst"] = { + [""] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -0.5000, 0.6250, -0.3750, 0.5000}, + {-0.3125, -0.5000, -1.000, 0.9375, -0.3125, -0.06250} + } + } + }, + ["_30"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, + {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, + {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, + {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} + } + } + }, + ["_45"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -1.1875, 0.5000, -0.3750, 0.8750}, + {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, + {-0.8750, -0.5000, -0.8125, -0.5000, -0.3750, 0.5000} + } + } + }, + ["_60"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, + {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, + {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, + {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} + } + } + }, + }, + + ["swrst"] = { + [""] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -0.5000, 0.6250, -0.3750, 0.5000}, + {-0.8125, -0.5000, -1.000, 0.4375, -0.3125, -0.06250} + } + } + }, + ["_30"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, + {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, + {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, + {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} + } + } + }, + ["_45"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.1875, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, + {-0.5000, -0.5000, 0.5000, 0.5000, -0.3750, 0.8750}, + {-0.8125, -0.5000, -0.8750, 0.5000, -0.3750, -0.5000} + } + } + }, + ["_60"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, + {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, + {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, + {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} + } + } + }, + }, +} + +default_boxen["swlcr"] = default_boxen["swlst"] +default_boxen["swrcr"] = default_boxen["swrst"] + +--flat +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack", + texture_prefix="advtrains_dtrack", + models_prefix="advtrains_dtrack", + models_suffix=".b3d", + shared_texture="advtrains_dtrack_shared.png", + description=attrans("Track"), + formats={}, + + get_additional_definiton = function(def, preset, suffix, rotation) + if default_boxen[suffix] ~= nil and default_boxen[suffix][rotation] ~= nil then + return default_boxen[suffix][rotation] + else + return {} + end + end, +}, advtrains.ap.t_30deg_flat) + +minetest.register_craft({ + output = 'advtrains:dtrack_placer 50', + recipe = { + {'default:steel_ingot', 'group:stick', 'default:steel_ingot'}, + {'default:steel_ingot', 'group:stick', 'default:steel_ingot'}, + {'default:steel_ingot', 'group:stick', 'default:steel_ingot'}, + }, +}) + +local y3_boxen = { + [""] = { + selection_box = { + type = "fixed", + fixed = { + {-0.8750, -0.5000, -1.125, 0.8750, -0.3750, 0.4375} + } + } + }, + + ["_30"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -0.875, 0.5000, -0.3750, 1.000}, + {-0.8750, -0.5000, -0.4375, -0.5000, -0.3750, 0.5625}, + {0.5000, -0.5000, -0.2500, 0.8125, -0.3750, 1.000}, + } + } + }, + + --UX FIXME: - 3way - have to place straight route before l and r or the + --nodebox overlaps too much and can't place the straight track node. + ["_45"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -1.1250, 0.5000, -0.3750, 0.8750}, + {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, + {-1.1250, -0.5000, -0.9375, -0.5000, -0.3750, 0.5000} + } + } + }, + + ["_60"] = { + selection_box = { + type = "fixed", + fixed = { + --{-0.5000, -0.5000, -0.875, 0.5000, -0.3750, 1.000}, + {-0.875, -0.5000, -0.5, 1.0, -0.3750, 0.5}, + --{-0.8750, -0.5000, -0.4375, -0.5000, -0.3750, 0.5625}, + {-0.4375, -0.5000, -0.8750, 0.5625, -0.3750, -0.5000}, + --{0.5000, -0.5000, -0.2500, 0.8125, -0.3750, 1.000}, + {-0.2500, -0.5000, -0.2500, 1.0000, -0.3750, 0.8125}, + } + } + }, +} + + +local function y3_turnouts_addef(def, preset, suffix, rotation) + return y3_boxen[rotation] or {} +end +-- y-turnout +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_sy", + texture_prefix="advtrains_dtrack_sy", + models_prefix="advtrains_dtrack_sy", + models_suffix=".obj", + shared_texture="advtrains_dtrack_shared.png", + description=attrans("Y-turnout"), + formats = {}, + get_additional_definiton = y3_turnouts_addef, +}, advtrains.ap.t_yturnout) +minetest.register_craft({ + output = 'advtrains:dtrack_sy_placer 2', + recipe = { + {'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'}, + {'', 'advtrains:dtrack_placer', ''}, + {'', 'advtrains:dtrack_placer', ''}, + }, +}) +--3-way turnout +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_s3", + texture_prefix="advtrains_dtrack_s3", + models_prefix="advtrains_dtrack_s3", + models_suffix=".obj", + shared_texture="advtrains_dtrack_shared.png", + description=attrans("3-way turnout"), + formats = {}, + get_additional_definiton = y3_turnouts_addef, +}, advtrains.ap.t_s3way) +minetest.register_craft({ + output = 'advtrains:dtrack_s3_placer 1', + recipe = { + {'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'}, + {'', 'advtrains:dtrack_placer', ''}, + {'', '', ''}, + }, +}) + +-- Diamond Crossings + +local perp_boxen = { + [""] = {}, --default size + ["_30"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000} + } + } + }, + ["_45"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.8125, -0.5000, -0.8125, 0.8125, -0.3750, 0.8125} + } + } + }, + ["_60"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000} + } + } + }, +} + +-- perpendicular +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_xing", + texture_prefix="advtrains_dtrack_xing", + models_prefix="advtrains_dtrack_xing", + models_suffix=".obj", + shared_texture="advtrains_dtrack_shared.png", + description=attrans("Perpendicular Diamond Crossing Track"), + formats = {}, + get_additional_definiton = function(def, preset, suffix, rotation) + return perp_boxen[rotation] or {} + end +}, advtrains.ap.t_perpcrossing) + +minetest.register_craft({ + output = 'advtrains:dtrack_xing_placer 3', + recipe = { + {'', 'advtrains:dtrack_placer', ''}, + {'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'}, + {'', 'advtrains:dtrack_placer', ''} + } +}) + +local ninety_plus_boxen = { + ["30l"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, + {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, + {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, + {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} + } + } + }, + ["30r"] = { + selection_box = { + type = "fixed", + fixed = { + {0.5000, -0.5000, -1.000, -0.5000, -0.3750, 1.000}, + {0.8750, -0.5000, -1.000, 0.5000, -0.3750, 0.2500}, + {-0.5000, -0.5000, -0.2500, -0.8750, -0.3750, 1.000}, + {0.1250, -0.5000, -1.375, -0.1875, -0.3750, -1.000} + } + } + }, + ["45l"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750}, + {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, + {-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000} + } + } + }, + ["45r"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -0.8750, 0.5000, -0.3750, 0.8750}, + {0.5000, -0.5000, -0.5000, 0.8750, -0.3750, 0.5000}, + {-0.8750, -0.5000, -0.5000, -0.5000, -0.3750, 0.5000} + } + } + }, + ["60l"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, + {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, + {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, + {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} + } + } + }, + ["60r"] = { + selection_box = { + type = "fixed", + fixed = { + {1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000}, + {1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000}, + {0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750}, + {1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875} + } + } + }, +} + +-- 90plusx +-- When you face east and param2=0, then this set of rails has a rail at 90 +-- degrees to the viewer, plus another rail crossing at 30, 45 or 60 degrees. +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_xing90plusx", + texture_prefix="advtrains_dtrack_xing4590", + models_prefix="advtrains_dtrack_xing90plusx", + models_suffix=".obj", + shared_texture="advtrains_dtrack_shared.png", + description=attrans("90+Angle Diamond Crossing Track"), + formats = {}, + get_additional_definiton = function(def, preset, suffix, rotation) + return ninety_plus_boxen[suffix] or {} + end, +}, advtrains.ap.t_90plusx_crossing) +minetest.register_craft({ + output = 'advtrains:dtrack_xing90plusx_placer 2', + recipe = { + {'advtrains:dtrack_placer', '', ''}, + {'advtrains:dtrack_placer', 'advtrains:dtrack_placer', 'advtrains:dtrack_placer'}, + {'', '', 'advtrains:dtrack_placer'} + } +}) + +-- Deprecate any rails using the old name scheme +minetest.register_lbm({ + label = "Upgrade legacy 4590 rails", + name = "advtrains_train_track:replace_legacy_4590", + nodenames = {"advtrains:dtrack_xing4590_st"}, + run_at_every_load = true, + action = function(pos, node) + minetest.log("actionPos!: " .. pos.x .. "," .. pos.y .. "," .. pos.z) + minetest.log("node!: " .. node.name .. "," .. node.param1 .. "," .. node.param2) + advtrains.ndb.swap_node(pos, + { + name="advtrains:dtrack_xing90plusx_45l", + param1=node.param1, + param2=node.param2, + }) + end +}) +-- This will replace any items left in the inventory +minetest.register_alias("advtrains:dtrack_xing4590_placer", "advtrains:dtrack_xing90plusx_placer") + +local diagonal_boxen = { + ["30r45l"] = { + selection_box = { + type = "fixed", + fixed = { + {0.5000, -0.5000, -1.000, -0.5000, -0.3750, 1.000}, + {0.8750, -0.5000, -1.000, 0.5000, -0.3750, 0.2500}, + {-0.5000, -0.5000, -0.2500, -0.8750, -0.3750, 1.000}, + {0.1250, -0.5000, -1.375, -0.1875, -0.3750, -1.000} + } + } + }, + ["60l30l"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, + {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, + {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, + {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} + } + } + }, + ["60l60r"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -1.000, 1.000, -0.3750, 1.000} + } + } + }, + ["60r30r"] = { + selection_box = { + type = "fixed", + fixed = { + {1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000}, + {1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000}, + {0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750}, + {1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875} + } + } + }, + ["30l45r"] = { + selection_box = { + type = "fixed", + fixed = { + {-0.5000, -0.5000, -1.000, 0.5000, -0.3750, 1.000}, + {-0.8750, -0.5000, -1.000, -0.5000, -0.3750, 0.2500}, + {0.5000, -0.5000, -0.2500, 0.8750, -0.3750, 1.000}, + {-0.1250, -0.5000, -1.375, 0.1875, -0.3750, -1.000} + } + } + }, + ["60l45r"] = { + selection_box = { + type = "fixed", + fixed = { + {-1.000, -0.5000, -0.5000, 1.000, -0.3750, 0.5000}, + {-1.000, -0.5000, -0.8750, 0.2500, -0.3750, -0.5000}, + {-0.2500, -0.5000, 0.5000, 1.000, -0.3750, 0.8750}, + {-1.375, -0.5000, -0.1250, -1.000, -0.3750, 0.1875} + } + } + }, + ["60r45l"] = { + selection_box = { + type = "fixed", + fixed = { + {1.000, -0.5000, -0.5000, -1.000, -0.3750, 0.5000}, + {1.000, -0.5000, -0.8750, -0.2500, -0.3750, -0.5000}, + {0.2500, -0.5000, 0.5000, -1.000, -0.3750, 0.8750}, + {1.375, -0.5000, -0.1250, 1.000, -0.3750, 0.1875} + } + } + }, +} + +-- Diagonal +-- This set of rail crossings is named based on the angle of each intersecting +-- direction when facing east and param2=0. Rails with l/r swapped are mirror +-- images. For example, 30r45l is the mirror image of 30l45r. +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_xingdiag", + texture_prefix="advtrains_dtrack_xingdiag", + models_prefix="advtrains_dtrack_xingdiag", + models_suffix=".obj", + shared_texture="advtrains_dtrack_shared.png", + description=attrans("Diagonal Diamond Crossing Track"), + formats = {}, + get_additional_definiton = function(def, preset, suffix, rotation) + return diagonal_boxen[suffix] or {} + end, +}, advtrains.ap.t_diagonalcrossing) +minetest.register_craft({ + output = 'advtrains:dtrack_xingdiag_placer 2', + recipe = { + {'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'}, + {'', 'advtrains:dtrack_placer', ''}, + {'advtrains:dtrack_placer', '', 'advtrains:dtrack_placer'} + } +}) +---- Not included: very shallow crossings like (30/60)+45. +---- At an angle of only 18.4 degrees, the models would not +---- translate well to a block game. +-- END crossings + +--slopes +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack", + texture_prefix="advtrains_dtrack", + models_prefix="advtrains_dtrack", + models_suffix=".obj", + shared_texture="advtrains_dtrack_shared.png", + second_texture="default_gravel.png", + description=attrans("Track"), + formats={vst1={true, false, true}, vst2={true, false, true}, vst31={true}, vst32={true}, vst33={true}}, +}, advtrains.ap.t_30deg_slope) + +minetest.register_craft({ + type = "shapeless", + output = 'advtrains:dtrack_slopeplacer 2', + recipe = { + "advtrains:dtrack_placer", + "advtrains:dtrack_placer", + "default:gravel", + }, +}) + + +--bumpers +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_bumper", + texture_prefix="advtrains_dtrack_bumper", + models_prefix="advtrains_dtrack_bumper", + models_suffix=".b3d", + shared_texture="advtrains_dtrack_rail.png", + --bumpers still use the old texture until the models are redone. + description=attrans("Bumper"), + formats={}, +}, advtrains.ap.t_30deg_straightonly) +minetest.register_craft({ + output = 'advtrains:dtrack_bumper_placer 2', + recipe = { + {'group:wood', 'dye:red'}, + {'default:steel_ingot', 'default:steel_ingot'}, + {'advtrains:dtrack_placer', 'advtrains:dtrack_placer'}, + }, +}) +--legacy bumpers +for _,rot in ipairs({"", "_30", "_45", "_60"}) do + minetest.register_alias("advtrains:dtrack_bumper"..rot, "advtrains:dtrack_bumper_st"..rot) +end +-- atc track +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_atc", + texture_prefix="advtrains_dtrack_atc", + models_prefix="advtrains_dtrack", + models_suffix=".b3d", + shared_texture="advtrains_dtrack_shared_atc.png", + description=attrans("ATC controller"), + formats={}, + get_additional_definiton = advtrains.atc_function +}, advtrains.trackpresets.t_30deg_straightonly) + + +-- Tracks for loading and unloading trains +-- Copyright (C) 2017 Gabriel Pérez-Cerezo + +local function get_far_node(pos) + local node = minetest.get_node(pos) + if node.name == "ignore" then + minetest.get_voxel_manip():read_from_map(pos, pos) + node = minetest.get_node(pos) + end + return node +end + + +local function show_fc_formspec(pos,player) + local pname = player:get_player_name() + if minetest.is_protected(pos,pname) then + minetest.chat_send_player(pname, "Position is protected!") + return + end + + local meta = minetest.get_meta(pos) + local fc = meta:get_string("fc") or "" + + local form = 'formspec_version[4]'.. + 'size[10,5]'.. + 'label[0.5,0.4;Advtrains Loading/Unloading Track]'.. + 'label[0.5,1.1;Set the code to match against the wagon\'s freight code]'.. + 'label[0.5,1.6;A blank field matches all wagons (default)]'.. + 'label[0.5,2.1;Use code # to disable the track section]'.. + 'field[0.5,3;5.5,1;fc;FC;'..minetest.formspec_escape(fc)..']'.. + 'button[6.5,3;3,1;save;Submit]' + minetest.show_formspec(pname, "at_load_unload_"..advtrains.encode_pos(pos), form) +end + +minetest.register_on_player_receive_fields(function(player, formname, fields) + local pname = player:get_player_name() + local pe = string.match(formname, "^at_load_unload_(............)$") + local pos = advtrains.decode_pos(pe) + if pos then + if minetest.is_protected(pos, pname) then + minetest.chat_send_player(pname, "Position is protected!") + return + end + + if fields.save then + minetest.get_meta(pos):set_string("fc",tostring(fields.fc)) + minetest.chat_send_player(pname,"Freight code set: "..tostring(fields.fc)) + show_fc_formspec(pos,player) + end + end +end) + + +local function train_load(pos, train_id, unload) + local train=advtrains.trains[train_id] + local below = get_far_node({x=pos.x, y=pos.y-1, z=pos.z}) + if not string.match(below.name, "chest") then + atprint("this is not a chest! at "..minetest.pos_to_string(pos)) + return + end + + local node_fc = minetest.get_meta(pos):get_string("fc") or "" + if node_fc == "#" then + --track section is disabled + return + end + + local inv = minetest.get_inventory({type="node", pos={x=pos.x, y=pos.y-1, z=pos.z}}) + if inv and train.velocity < 2 then + for k, v in ipairs(train.trainparts) do + local i=minetest.get_inventory({type="detached", name="advtrains_wgn_"..v}) + if i and i:get_list("box") then + + local wagon_data = advtrains.wagons[v] + local wagon_fc + if wagon_data.fc then + if not wagon_data.fcind then wagon_data.fcind = 1 end + wagon_fc = tostring(wagon_data.fc[wagon_data.fcind]) or "" + end + + if node_fc == "" or wagon_fc == node_fc then + if not unload then + for _, item in ipairs(inv:get_list("main")) do + if i:get_list("box") and i:room_for_item("box", item) then + i:add_item("box", item) + inv:remove_item("main", item) + end + end + else + for _, item in ipairs(i:get_list("box")) do + if inv:get_list("main") and inv:room_for_item("main", item) then + i:remove_item("box", item) + inv:add_item("main", item) + end + end + end + end + end + end + end +end + + + +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_unload", + texture_prefix="advtrains_dtrack_unload", + models_prefix="advtrains_dtrack", + models_suffix=".b3d", + shared_texture="advtrains_dtrack_shared_unload.png", + description=attrans("Unloading Track"), + formats={}, + get_additional_definiton = function(def, preset, suffix, rotation) + return { + after_dig_node=function(pos) + advtrains.invalidate_all_paths() + advtrains.ndb.clear(pos) + end, + on_rightclick = function(pos, node, player) + show_fc_formspec(pos, player) + end, + advtrains = { + on_train_enter = function(pos, train_id) + train_load(pos, train_id, true) + end, + }, + } + end + }, advtrains.trackpresets.t_30deg_straightonly) +advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_load", + texture_prefix="advtrains_dtrack_load", + models_prefix="advtrains_dtrack", + models_suffix=".b3d", + shared_texture="advtrains_dtrack_shared_load.png", + description=attrans("Loading Track"), + formats={}, + get_additional_definiton = function(def, preset, suffix, rotation) + return { + after_dig_node=function(pos) + advtrains.invalidate_all_paths() + advtrains.ndb.clear(pos) + end, + on_rightclick = function(pos, node, player) + show_fc_formspec(pos, player) + end, + advtrains = { + on_train_enter = function(pos, train_id) + train_load(pos, train_id, false) + end, + }, + } + end + }, advtrains.trackpresets.t_30deg_straightonly) + +-- mod-dependent crafts +local loader_core = "default:mese_crystal" --fallback +if minetest.get_modpath("basic_materials") then + loader_core = "basic_materials:ic" +elseif minetest.get_modpath("technic") then + loader_core = "technic:control_logic_unit" +end +--print("Loader Core: "..loader_core) + +minetest.register_craft({ + type="shapeless", + output = 'advtrains:dtrack_load_placer', + recipe = { + "advtrains:dtrack_placer", + loader_core, + "default:chest" + }, +}) +loader_core = nil --nil the crafting variable + +--craft between load/unload tracks +minetest.register_craft({ + type="shapeless", + output = 'advtrains:dtrack_unload_placer', + recipe = { + "advtrains:dtrack_load_placer", + }, +}) +minetest.register_craft({ + type="shapeless", + output = 'advtrains:dtrack_load_placer', + recipe = { + "advtrains:dtrack_unload_placer", + }, +}) + + +if mesecon then + advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_detector_off", + texture_prefix="advtrains_dtrack_detector", + models_prefix="advtrains_dtrack", + models_suffix=".b3d", + shared_texture="advtrains_dtrack_shared_detector_off.png", + description=attrans("Detector Rail"), + formats={}, + get_additional_definiton = function(def, preset, suffix, rotation) + return { + mesecons = { + receptor = { + state = mesecon.state.off, + rules = advtrains.meseconrules + } + }, + advtrains = { + on_updated_from_nodedb = function(pos, node) + mesecon.receptor_off(pos, advtrains.meseconrules) + end, + on_train_enter=function(pos, train_id) + advtrains.ndb.swap_node(pos, {name="advtrains:dtrack_detector_on".."_"..suffix..rotation, param2=advtrains.ndb.get_node(pos).param2}) + if advtrains.is_node_loaded(pos) then + mesecon.receptor_on(pos, advtrains.meseconrules) + end + end + } + } + end + }, advtrains.ap.t_30deg_straightonly) + advtrains.register_tracks("default", { + nodename_prefix="advtrains:dtrack_detector_on", + texture_prefix="advtrains_dtrack", + models_prefix="advtrains_dtrack", + models_suffix=".b3d", + shared_texture="advtrains_dtrack_shared_detector_on.png", + description="Detector(on)(you hacker you)", + formats={}, + get_additional_definiton = function(def, preset, suffix, rotation) + return { + mesecons = { + receptor = { + state = mesecon.state.on, + rules = advtrains.meseconrules + } + }, + advtrains = { + on_updated_from_nodedb = function(pos, node) + mesecon.receptor_on(pos, advtrains.meseconrules) + end, + on_train_leave=function(pos, train_id) + advtrains.ndb.swap_node(pos, {name="advtrains:dtrack_detector_off".."_"..suffix..rotation, param2=advtrains.ndb.get_node(pos).param2}) + if advtrains.is_node_loaded(pos) then + mesecon.receptor_off(pos, advtrains.meseconrules) + end + end + } + } + end + }, advtrains.ap.t_30deg_straightonly_noplacer) +minetest.register_craft({ + type="shapeless", + output = 'advtrains:dtrack_detector_off_placer', + recipe = { + "advtrains:dtrack_placer", + "mesecons:wire_00000000_off" + }, +}) +end +--TODO legacy +--I know lbms are better for this purpose +for name,rep in pairs({swl_st="swlst", swr_st="swrst", swl_cr="swlcr", swr_cr="swrcr", }) do + minetest.register_abm({ + -- In the following two fields, also group:groupname will work. + nodenames = {"advtrains:track_"..name}, + interval = 1.0, -- Operation interval in seconds + chance = 1, -- Chance of trigger per-node per-interval is 1.0 / this + action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:track_"..rep, param2=node.param2}) end, + }) + minetest.register_abm({ + -- In the following two fields, also group:groupname will work. + nodenames = {"advtrains:track_"..name.."_45"}, + interval = 1.0, -- Operation interval in seconds + chance = 1, -- Chance of trigger per-node per-interval is 1.0 / this + action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:track_"..rep.."_45", param2=node.param2}) end, + }) +end + +if advtrains.register_replacement_lbms then +minetest.register_lbm({ + name = "advtrains:ramp_replacement_1", +-- In the following two fields, also group:groupname will work. + nodenames = {"advtrains:track_vert1"}, + action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_vst1", param2=(node.param2+2)%4}) end, +}) +minetest.register_lbm({ + name = "advtrains:ramp_replacement_1", +-- -- In the following two fields, also group:groupname will work. + nodenames = {"advtrains:track_vert2"}, + action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_vst2", param2=(node.param2+2)%4}) end, +}) + minetest.register_abm({ + name = "advtrains:st_rep_1", + -- In the following two fields, also group:groupname will work. + nodenames = {"advtrains:track_st"}, + interval=1, + chance=1, + action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_st", param2=node.param2}) end, + }) + minetest.register_lbm({ + name = "advtrains:st_rep_1", + -- -- In the following two fields, also group:groupname will work. + nodenames = {"advtrains:track_st_45"}, + action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_st_45", param2=node.param2}) end, + }) +end -- cgit v1.2.3