Add intllib support and German translation
[advtrains.git] / advtrains / advtrains / tracks.lua
1 --advtrains by orwell96, see readme.txt
2
3 --dev-time settings:
4 --EDIT HERE
5 --If the old non-model rails on straight tracks should be replaced by the new...
6 --false: no
7 --true: yes
8 advtrains.register_replacement_lbms=false
9
10 --[[TracksDefinition
11 nodename_prefix
12 texture_prefix
13 description
14 common={}
15 straight={}
16 straight45={}
17 curve={}
18 curve45={}
19 lswitchst={}
20 lswitchst45={}
21 rswitchst={}
22 rswitchst45={}
23 lswitchcr={}
24 lswitchcr45={}
25 rswitchcr={}
26 rswitchcr45={}
27 vert1={
28 --you'll probably want to override mesh here
29 }
30 vert2={
31 --you'll probably want to override mesh here
32 }
33 ]]--
34 advtrains.all_tracktypes={}
35
36 --definition preparation
37 local function conns(c1, c2, r1, r2, rh, rots) return {conn1=c1, conn2=c2, rely1=r1, rely2=r2, railheight=rh} end
38
39 local ap={}
40 ap.t_30deg={
41 regstep=1,
42 variant={
43 st=conns(0,8),
44 cr=conns(0,7),
45 swlst=conns(0,8),
46 swlcr=conns(0,7),
47 swrst=conns(0,8),
48 swrcr=conns(0,9),
49 vst1=conns(8,0,0,0.5,0.25),
50 vst2=conns(8,0,0.5,1,0.75),
51 vst31=conns(8,0,0,0.33,0.16),
52 vst32=conns(8,0,0.33,0.66,0.5),
53 vst33=conns(8,0,0.66,1,0.83),
54 },
55 description={
56 st="straight",
57 cr="curve",
58 swlst="left switch (straight)",
59 swlcr="left switch (curve)",
60 swrst="right switch (straight)",
61 swrcr="right switch (curve)",
62 vst1="steep uphill 1/2",
63 vst2="steep uphill 2/2",
64 vst31="uphill 1/3",
65 vst32="uphill 2/3",
66 vst33="uphill 3/3",
67 },
68 switch={
69 swlst="swlcr",
70 swlcr="swlst",
71 swrst="swrcr",
72 swrcr="swrst",
73 },
74 switchmc={
75 swlst="on",
76 swlcr="off",
77 swrst="on",
78 swrcr="off",
79 },
80 regtp=true,
81 trackplacer={
82 st=true,
83 cr=true,
84 },
85 tpsingle={
86 st=true,
87 },
88 tpdefault="st",
89 trackworker={
90 ["swrcr"]="st",
91 ["swrst"]="st",
92 ["st"]="cr",
93 ["cr"]="swlst",
94 ["swlcr"]="swrcr",
95 ["swlst"]="swrst",
96 },
97 regsp=true,
98 slopenodes={
99 vst1=true, vst2=true,
100 vst31=true, vst32=true, vst33=true,
101 },
102 slopeplacer={
103 [2]={"vst1", "vst2"},
104 [3]={"vst31", "vst32", "vst33"},
105 max=3,--highest entry
106 },
107 slopeplacer_45={
108 [2]={"vst1_45", "vst2_45"},
109 max=2,
110 },
111 rotation={"", "_30", "_45", "_60"},
112 increativeinv={},
113 }
114 ap.t_30deg_straightonly={
115 regstep=1,
116 variant={
117 st=conns(0,8),
118 },
119 description={
120 st="straight",
121 },
122 switch={
123 },
124 switchmc={
125 },
126 regtp=true,
127 trackplacer={
128 },
129 tpsingle={
130 },
131 tpdefault="st",
132 trackworker={
133 ["st"]="st",
134 },
135 slopenodes={},
136 rotation={"", "_30", "_45", "_60"},
137 increativeinv={st},
138 }
139 ap.t_30deg_straightonly_noplacer={
140 regstep=1,
141 variant={
142 st=conns(0,8),
143 },
144 description={
145 st="straight",
146 },
147 switch={
148 },
149 switchmc={
150 },
151 regtp=false,
152 trackplacer={
153 },
154 tpsingle={
155 },
156 tpdefault="st",
157 trackworker={
158 ["st"]="st",
159 },
160 slopenodes={},
161 rotation={"", "_30", "_45", "_60"},
162 increativeinv={st},
163 }
164 ap.t_45deg={
165 regstep=2,
166 variant={
167 st=conns(0,8),
168 cr=conns(0,6),
169 swlst=conns(0,8),
170 swlcr=conns(0,6),
171 swrst=conns(0,8),
172 swrcr=conns(0,10),
173 vst1=conns(8,0,0,0.5,0.25),
174 vst2=conns(8,0,0.5,1,0.75),
175 },
176 description={
177 st="straight",
178 cr="curve",
179 swlst="left switch (straight)",
180 swlcr="left switch (curve)",
181 swrst="right switch (straight)",
182 swrcr="right switch (curve)",
183 vst1="vertical lower node",
184 vst2="vertical upper node",
185 },
186 switch={
187 swlst="swlcr",
188 swlcr="swlst",
189 swrst="swrcr",
190 swrcr="swrst",
191 },
192 switchmc={
193 swlst="on",
194 swlcr="off",
195 swrst="on",
196 swrcr="off",
197 },
198 regtp=true,
199 trackplacer={
200 st=true,
201 cr=true,
202 },
203 tpsingle={
204 st=true,
205 },
206 tpdefault="st",
207 trackworker={
208 ["swrcr"]="st",
209 ["swrst"]="st",
210 ["st"]="cr",
211 ["cr"]="swlst",
212 ["swlcr"]="swrcr",
213 ["swlst"]="swrst",
214 },
215 slopenodes={},
216 rotation={"", "_45"},
217 increativeinv={vst1=true, vst2=true}
218 }
219 advtrains.trackpresets = ap
220
221 --definition format: ([] optional)
222 --[[{
223 nodename_prefix
224 texture_prefix
225 [shared_texture]
226 models_prefix
227 models_suffix (with dot)
228 [shared_model]
229 formats={
230 st,cr,swlst,swlcr,swrst,swrcr,vst1,vst2
231 (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)
232 }
233 common={} change something on common rail appearance
234 }]]
235 function advtrains.register_tracks(tracktype, def, preset)
236 local function make_switchfunc(suffix_target, mesecon_state)
237 local switchfunc=function(pos, node)
238 advtrains.ndb.swap_node(pos, {name=def.nodename_prefix.."_"..suffix_target, param2=node.param2})
239 end
240 return switchfunc, {effector = {
241 ["action_"..mesecon_state] = switchfunc,
242 rules=advtrains.meseconrules
243 }}
244 end
245 local function make_overdef(suffix, rotation, conns, switchfunc, mesecontbl, in_creative_inv, drop_slope)
246 local img_suffix=suffix..rotation
247 return {
248 mesh = def.shared_model or (def.models_prefix.."_"..img_suffix..def.models_suffix),
249 tiles = {def.shared_texture or (def.texture_prefix.."_"..img_suffix..".png")},
250 --inventory_image = def.texture_prefix.."_"..img_suffix..".png",
251 --wield_image = def.texture_prefix.."_"..img_suffix..".png",
252 description=def.description.."("..preset.description[suffix]..rotation..")",
253 connect1=conns.conn1,
254 connect2=conns.conn2,
255 rely1=conns.rely1 or 0,
256 rely2=conns.rely2 or 0,
257 railheight=conns.railheight or 0,
258
259 on_rightclick=switchfunc,
260 groups = {
261 attached_node=1,
262 ["advtrains_track_"..tracktype]=1,
263 save_in_nodedb=1,
264 dig_immediate=2,
265 not_in_creative_inventory=(not in_creative_inv and 1 or nil),
266 not_blocking_trains=1,
267 },
268 mesecons=mesecontbl,
269 drop = increativeinv and def.nodename_prefix.."_"..suffix..rotation or (drop_slope and def.nodename_prefix.."_slopeplacer" or def.nodename_prefix.."_placer"),
270 }
271 end
272 local function cycle_conns(conns, rotid)
273 local add=(rotid-1)*preset.regstep
274 return {
275 conn1=(conns.conn1+add)%16,
276 conn2=(conns.conn2+add)%16,
277 rely1=conns.rely1 or 0,
278 rely2=conns.rely2 or 0,
279 railheight=conns.railheight or 0,
280 }
281 end
282 local common_def=advtrains.merge_tables({
283 description = def.description,
284 drawtype = "mesh",
285 paramtype="light",
286 paramtype2="facedir",
287 walkable = false,
288 selection_box = {
289 type = "fixed",
290 fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2},
291 },
292 rely1=0,
293 rely2=0,
294 railheight=0,
295 drop=def.nodename_prefix.."_placer",
296 can_dig=function(pos)
297 return not advtrains.is_train_at_pos(pos)
298 end,
299 after_dig_node=function(pos)
300 advtrains.invalidate_all_paths()
301 advtrains.ndb.update(pos)
302 end,
303 after_place_node=function(pos)
304 advtrains.ndb.update(pos)
305 end,
306 }, def.common or {})
307 --make trackplacer base def
308 advtrains.trackplacer.register_tracktype(def.nodename_prefix, preset.tpdefault)
309 if preset.regtp then
310 advtrains.trackplacer.register_track_placer(def.nodename_prefix, def.texture_prefix, def.description)
311 end
312 if preset.regsp then
313 advtrains.slope.register_placer(def, preset)
314 end
315 for suffix, conns in pairs(preset.variant) do
316 for rotid, rotation in ipairs(preset.rotation) do
317 if not def.formats[suffix] or def.formats[suffix][rotid] then
318 local switchfunc, mesecontbl
319 if preset.switch[suffix] then
320 switchfunc, mesecontbl=make_switchfunc(preset.switch[suffix]..rotation, preset.switchmc[suffix])
321 end
322 local adef={}
323 if def.get_additional_definiton then
324 adef=def.get_additional_definiton(def, preset, suffix, rotation)
325 end
326
327 minetest.register_node(def.nodename_prefix.."_"..suffix..rotation, advtrains.merge_tables(
328 common_def,
329 make_overdef(
330 suffix, rotation,
331 cycle_conns(conns, rotid),
332 switchfunc, mesecontbl, preset.increativeinv[suffix], preset.slopenodes[suffix]
333 ),
334 adef
335 )
336 )
337 --trackplacer
338 if preset.regtp then
339 if preset.trackplacer[suffix] then
340 advtrains.trackplacer.add_double_conn(def.nodename_prefix, suffix, rotation, cycle_conns(conns, rotid))
341 end
342 if preset.tpsingle[suffix] then
343 advtrains.trackplacer.add_single_conn(def.nodename_prefix, suffix, rotation, cycle_conns(conns, rotid))
344 end
345 end
346 advtrains.trackplacer.add_worked(def.nodename_prefix, suffix, rotation, preset.trackworker[suffix])
347 end
348 end
349 end
350 advtrains.all_tracktypes[tracktype]=true
351 end
352
353
354 function advtrains.is_track_and_drives_on(nodename, drives_on_p)
355 if not minetest.registered_nodes[nodename] then
356 return false
357 end
358 local nodedef=minetest.registered_nodes[nodename]
359 for k,v in pairs(drives_on_p) do
360 if nodedef.groups["advtrains_track_"..k] then
361 return true
362 end
363 end
364 return false
365 end
366
367 function advtrains.get_track_connections(name, param2)
368 local nodedef=minetest.registered_nodes[name]
369 if not nodedef then atprint(" get_track_connections couldn't find nodedef for nodename "..(name or "nil")) return 0, 8, 0, 0, 0 end
370 local noderot=param2
371 if not param2 then noderot=0 end
372 if noderot > 3 then atprint(" get_track_connections: rail has invaild param2 of "..noderot) noderot=0 end
373
374 local tracktype
375 for k,_ in pairs(nodedef.groups) do
376 local tt=string.match(k, "^advtrains_track_(.+)$")
377 if tt then
378 tracktype=tt
379 end
380 end
381 return (nodedef.connect1 + 4 * noderot)%16, (nodedef.connect2 + 4 * noderot)%16, nodedef.rely1 or 0, nodedef.rely2 or 0, nodedef.railheight or 0, tracktype
382 end
383
384 --detector code
385 --holds a table with nodes on which trains are on.
386
387 advtrains.detector = {}
388 advtrains.detector.on_node = {}
389 advtrains.detector.on_node_restore = {}
390 --set if paths were invalidated before. tells trainlogic.lua to call advtrains.detector.finalize_restore()
391 advtrains.detector.clean_step_before = false
392
393 --when train enters a node, call this
394 --The entry already being contained in advtrains.detector.on_node_restore will not trigger an on_train_enter event on the node. (when path is reset, this is saved).
395 function advtrains.detector.enter_node(pos, train_id)
396 local pts = minetest.pos_to_string(advtrains.round_vector_floor_y(pos))
397 --atprint("enterNode "..pts.." "..sid(train_id))
398 if advtrains.detector.on_node[pts] then
399 if advtrains.trains[advtrains.detector.on_node[pts]] then
400 --atprint(""..pts.." already occupied")
401 return false
402 else
403 advtrains.detector.leave_node(pos, advtrains.detector.on_node[pts])
404 end
405 end
406 advtrains.detector.on_node[pts]=train_id
407 if advtrains.detector.on_node_restore[pts]==train_id then
408 advtrains.detector.on_node_restore[pts]=nil
409 else
410 advtrains.detector.call_enter_callback(advtrains.round_vector_floor_y(pos), train_id)
411 end
412 return true
413 end
414 function advtrains.detector.leave_node(pos, train_id)
415 local pts = minetest.pos_to_string(advtrains.round_vector_floor_y(pos))
416 --atprint("leaveNode "..pts.." "..sid(train_id))
417 if not advtrains.detector.on_node[pts] then
418 --atprint(""..pts.." leave: nothing here")
419 return false
420 end
421 if advtrains.detector.on_node[pts]==train_id then
422 advtrains.detector.call_leave_callback(advtrains.round_vector_floor_y(pos), train_id)
423 advtrains.detector.on_node[pts]=nil
424 else
425 if advtrains.trains[advtrains.detector.on_node[pts]] then
426 --atprint(""..pts.." occupied by another train")
427 return false
428 else
429 advtrains.detector.leave_node(pos, advtrains.detector.on_node[pts])
430 return false
431 end
432 end
433 return true
434 end
435 --called immediately before invalidating paths
436 function advtrains.detector.setup_restore()
437 --atprint("setup_restore")
438 -- don't execute if it already has been called. For some reason it gets called twice...
439 if advtrains.detector.clean_step_before then
440 return
441 end
442 advtrains.detector.on_node_restore={}
443 for k, v in pairs(advtrains.detector.on_node) do
444 advtrains.detector.on_node_restore[k]=v
445 end
446 advtrains.detector.on_node = {}
447 advtrains.detector.clean_step_before = true
448 end
449 --called one step after invalidating paths, when all trains have restored their path and called enter_node for their contents.
450 function advtrains.detector.finalize_restore()
451 --atprint("finalize_restore")
452 for pts, train_id in pairs(advtrains.detector.on_node_restore) do
453 --atprint("called leave callback "..pts.." "..train_id)
454 advtrains.detector.call_leave_callback(minetest.string_to_pos(pts), train_id)
455 end
456 advtrains.detector.on_node_restore = {}
457 advtrains.detector.clean_step_before = false
458 end
459 function advtrains.detector.call_enter_callback(pos, train_id)
460 --atprint("instructed to call enter calback")
461
462 local node = minetest.get_node(pos) --this spares the check if node is nil, it has a name in any case
463 local mregnode=minetest.registered_nodes[node.name]
464 if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_enter then
465 mregnode.advtrains.on_train_enter(pos, train_id)
466 end
467
468 --atc code wants to be notified too
469 advtrains.atc.trigger_controller_train_enter(pos, train_id)
470 end
471 function advtrains.detector.call_leave_callback(pos, train_id)
472 --atprint("instructed to call leave calback")
473
474 local node = minetest.get_node(pos) --this spares the check if node is nil, it has a name in any case
475 local mregnode=minetest.registered_nodes[node.name]
476 if mregnode and mregnode.advtrains and mregnode.advtrains.on_train_leave then
477 mregnode.advtrains.on_train_leave(pos, train_id)
478 end
479 end
480
481 -- slope placer. Defined in register_tracks.
482 --crafted with rail and gravel
483 local sl={}
484 function sl.register_placer(def, preset)
485 minetest.register_craftitem(def.nodename_prefix.."_slopeplacer",{
486 description = attrans("@1 Slope", def.description),
487 inventory_image = def.texture_prefix.."_slopeplacer.png",
488 wield_image = def.texture_prefix.."_slopeplacer.png",
489 groups={},
490 on_place = sl.create_slopeplacer_on_place(def, preset)
491 })
492 end
493 --(itemstack, placer, pointed_thing)
494 function sl.create_slopeplacer_on_place(def, preset)
495 return function(istack, player, pt)
496 if not pt.type=="node" then
497 minetest.chat_send_player(player:get_player_name(), attrans("Can't place: not pointing at node"))
498 return istack
499 end
500 local pos=pt.above
501 if not pos then
502 minetest.chat_send_player(player:get_player_name(), attrans("Can't place: not pointing at node"))
503 return istack
504 end
505 local node=minetest.get_node(pos)
506 if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to then
507 minetest.chat_send_player(player:get_player_name(), attrans("Can't place: space occupied!"))
508 return istack
509 end
510 if minetest.is_protected(pos, player:get_player_name()) then
511 minetest.chat_send_player(player:get_player_name(), attrans("Can't place: protected position!"))
512 return istack
513 end
514 --determine player orientation (only horizontal component)
515 --get_look_horizontal may not be available
516 local yaw=player.get_look_horizontal and player:get_look_horizontal() or (player:get_look_yaw() - math.pi/2)
517
518 --rounding unit vectors is a nice way for selecting 1 of 8 directions since sin(30°) is 0.5.
519 dirvec={x=math.floor(math.sin(-yaw)+0.5), y=0, z=math.floor(math.cos(-yaw)+0.5)}
520 --translate to direction to look up inside the preset table
521 local param2, rot45=({
522 [-1]={
523 [-1]=2,
524 [0]=3,
525 [1]=3,
526 },
527 [0]={
528 [-1]=2,
529 [1]=0,
530 },
531 [1]={
532 [-1]=1,
533 [0]=1,
534 [1]=0,
535 },
536 })[dirvec.x][dirvec.z], dirvec.x~=0 and dirvec.z~=0
537 local lookup=preset.slopeplacer
538 if rot45 then lookup=preset.slopeplacer_45 end
539
540 --go unitvector forward and look how far the next node is
541 local step=1
542 while step<=lookup.max do
543 local node=minetest.get_node(vector.add(pos, dirvec))
544 --next node solid?
545 if not minetest.registered_nodes[node.name] or not minetest.registered_nodes[node.name].buildable_to or minetest.is_protected(pos, player:get_player_name()) then
546 --do slopes of this distance exist?
547 if lookup[step] then
548 if minetest.setting_getbool("creative_mode") or istack:get_count()>=step then
549 --start placing
550 local placenodes=lookup[step]
551 while step>0 do
552 minetest.set_node(pos, {name=def.nodename_prefix.."_"..placenodes[step], param2=param2})
553 if not minetest.setting_getbool("creative_mode") then
554 istack:take_item()
555 end
556 step=step-1
557 pos=vector.subtract(pos, dirvec)
558 end
559 else
560 minetest.chat_send_player(player:get_player_name(), attrans("Can't place: Not enough slope items left (@1 required)", step))
561 end
562 else
563 minetest.chat_send_player(player:get_player_name(), attrans("Can't place: There's no slope of length @1",step))
564 end
565 return istack
566 end
567 step=step+1
568 pos=vector.add(pos, dirvec)
569 end
570 minetest.chat_send_player(player:get_player_name(), attrans("Can't place: no supporting node at upper end."))
571 return itemstack
572 end
573 end
574
575 advtrains.slope=sl
576
577 --END code, BEGIN definition
578 --definition format: ([] optional)
579 --[[{
580 nodename_prefix
581 texture_prefix
582 [shared_texture]
583 models_prefix
584 models_suffix (with dot)
585 [shared_model]
586 formats={
587 st,cr,swlst,swlcr,swrst,swrcr,vst1,vst2
588 (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)
589 }
590 common={} change something on common rail appearance
591 }]]
592
593 advtrains.register_tracks("regular", {
594 nodename_prefix="advtrains:track",
595 texture_prefix="advtrains_track",
596 shared_model="trackplane.b3d",
597 description=attrans("Deprecated Track"),
598 formats={vst1={}, vst2={}},
599 }, ap.t_45deg)
600
601
602 advtrains.register_tracks("default", {
603 nodename_prefix="advtrains:dtrack",
604 texture_prefix="advtrains_dtrack",
605 models_prefix="advtrains_dtrack",
606 models_suffix=".b3d",
607 shared_texture="advtrains_dtrack_rail.png",
608 description=attrans("Track"),
609 formats={vst1={true, false, true}, vst2={true, false, true}, vst31={true}, vst32={true}, vst33={true}},
610 }, ap.t_30deg)
611
612 --bumpers
613 advtrains.register_tracks("default", {
614 nodename_prefix="advtrains:dtrack_bumper",
615 texture_prefix="advtrains_dtrack_bumper",
616 models_prefix="advtrains_dtrack_bumper",
617 models_suffix=".b3d",
618 shared_texture="advtrains_dtrack_rail.png",
619 description=attrans("Bumper"),
620 formats={},
621 }, ap.t_30deg_straightonly)
622 --legacy bumpers
623 for _,rot in ipairs({"", "_30", "_45", "_60"}) do
624 minetest.register_alias("advtrains:dtrack_bumper"..rot, "advtrains:dtrack_bumper_st"..rot)
625 end
626
627 if mesecon then
628 advtrains.register_tracks("default", {
629 nodename_prefix="advtrains:dtrack_detector_off",
630 texture_prefix="advtrains_dtrack_detector",
631 models_prefix="advtrains_dtrack_detector",
632 models_suffix=".b3d",
633 shared_texture="advtrains_dtrack_rail.png",
634 description=attrans("Detector Rail"),
635 formats={},
636 get_additional_definiton = function(def, preset, suffix, rotation)
637 return {
638 mesecons = {
639 receptor = {
640 state = mesecon.state.off,
641 rules = advtrains.meseconrules
642 }
643 },
644 advtrains = {
645 on_train_enter=function(pos, train_id)
646 minetest.swap_node(pos, {name="advtrains:dtrack_detector_on".."_"..suffix..rotation, param2=minetest.get_node(pos).param2})
647 mesecon.receptor_on(pos, advtrains.meseconrules)
648 end
649 }
650 }
651 end
652 }, ap.t_30deg_straightonly)
653 advtrains.register_tracks("default", {
654 nodename_prefix="advtrains:dtrack_detector_on",
655 texture_prefix="advtrains_dtrack_detector",
656 models_prefix="advtrains_dtrack_detector",
657 models_suffix=".b3d",
658 shared_texture="advtrains_dtrack_rail_detector_on.png",
659 description="Detector(on)(you hacker you)",
660 formats={},
661 get_additional_definiton = function(def, preset, suffix, rotation)
662 return {
663 mesecons = {
664 receptor = {
665 state = mesecon.state.on,
666 rules = advtrains.meseconrules
667 }
668 },
669 advtrains = {
670 on_train_leave=function(pos, train_id)
671 minetest.swap_node(pos, {name="advtrains:dtrack_detector_off".."_"..suffix..rotation, param2=minetest.get_node(pos).param2})
672 mesecon.receptor_off(pos, advtrains.meseconrules)
673 end
674 }
675 }
676 end
677 }, ap.t_30deg_straightonly_noplacer)
678 end
679 --TODO legacy
680 --I know lbms are better for this purpose
681 for name,rep in pairs({swl_st="swlst", swr_st="swrst", swl_cr="swlcr", swr_cr="swrcr", }) do
682 minetest.register_abm({
683 -- In the following two fields, also group:groupname will work.
684 nodenames = {"advtrains:track_"..name},
685 interval = 1.0, -- Operation interval in seconds
686 chance = 1, -- Chance of trigger per-node per-interval is 1.0 / this
687 action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:track_"..rep, param2=node.param2}) end,
688 })
689 minetest.register_abm({
690 -- In the following two fields, also group:groupname will work.
691 nodenames = {"advtrains:track_"..name.."_45"},
692 interval = 1.0, -- Operation interval in seconds
693 chance = 1, -- Chance of trigger per-node per-interval is 1.0 / this
694 action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:track_"..rep.."_45", param2=node.param2}) end,
695 })
696 end
697
698 if advtrains.register_replacement_lbms then
699 minetest.register_lbm({
700 name = "advtrains:ramp_replacement_1",
701 -- In the following two fields, also group:groupname will work.
702 nodenames = {"advtrains:track_vert1"},
703 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,
704 })
705 minetest.register_lbm({
706 name = "advtrains:ramp_replacement_1",
707 -- -- In the following two fields, also group:groupname will work.
708 nodenames = {"advtrains:track_vert2"},
709 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,
710 })
711 minetest.register_abm({
712 name = "advtrains:st_rep_1",
713 -- In the following two fields, also group:groupname will work.
714 nodenames = {"advtrains:track_st"},
715 interval=1,
716 chance=1,
717 action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_st", param2=node.param2}) end,
718 })
719 minetest.register_lbm({
720 name = "advtrains:st_rep_1",
721 -- -- In the following two fields, also group:groupname will work.
722 nodenames = {"advtrains:track_st_45"},
723 action = function(pos, node, active_object_count, active_object_count_wider) minetest.set_node(pos, {name="advtrains:dtrack_st_45", param2=node.param2}) end,
724 })
725 end
726
727
728
729
730
731
732
733