Merge branch 'mcl_explosions'
[MineClone/MineClone2.git] / mods / ENTITIES / mcl_minecarts / init.lua
blob0d71aa78a6545026029b24685bb3e0ed748275e9
1 local S = minetest.get_translator("mcl_minecarts")
3 mcl_minecarts = {}
4 mcl_minecarts.modpath = minetest.get_modpath("mcl_minecarts")
5 mcl_minecarts.speed_max = 10
6 mcl_minecarts.check_float_time = 15
8 dofile(mcl_minecarts.modpath.."/functions.lua")
9 dofile(mcl_minecarts.modpath.."/rails.lua")
11 local function detach_driver(self)
12 if not self._driver then
13 return
14 end
15 mcl_player.player_attached[self._driver] = nil
16 local player = minetest.get_player_by_name(self._driver)
17 self._driver = nil
18 self._start_pos = nil
19 if player then
20 player:set_detach()
21 player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
22 mcl_player.player_set_animation(player, "stand" , 30)
23 end
24 end
26 local function activate_tnt_minecart(self, timer)
27 if self._boomtimer then
28 return
29 end
30 self.object:set_armor_groups({immortal=1})
31 if timer then
32 self._boomtimer = timer
33 else
34 self._boomtimer = tnt.BOOMTIMER
35 end
36 self.object:set_properties({textures = {
37 "mcl_tnt_blink.png",
38 "mcl_tnt_blink.png",
39 "mcl_tnt_blink.png",
40 "mcl_tnt_blink.png",
41 "mcl_tnt_blink.png",
42 "mcl_tnt_blink.png",
43 "mcl_minecarts_minecart.png",
44 }})
45 self._blinktimer = tnt.BLINKTIMER
46 minetest.sound_play("tnt_ignite", {pos = self.object:get_pos(), gain = 1.0, max_hear_distance = 15}, true)
47 end
49 local activate_normal_minecart = detach_driver
51 -- Table for item-to-entity mapping. Keys: itemstring, Values: Corresponding entity ID
52 local entity_mapping = {}
54 local function register_entity(entity_id, mesh, textures, drop, on_rightclick, on_activate_by_rail)
55 local cart = {
56 physical = false,
57 collisionbox = {-10/16., -0.5, -10/16, 10/16, 0.25, 10/16},
58 visual = "mesh",
59 mesh = mesh,
60 visual_size = {x=1, y=1},
61 textures = textures,
63 on_rightclick = on_rightclick,
65 _driver = nil, -- player who sits in and controls the minecart (only for minecart!)
66 _punched = false, -- used to re-send _velocity and position
67 _velocity = {x=0, y=0, z=0}, -- only used on punch
68 _start_pos = nil, -- Used to calculate distance for “On A Rail” achievement
69 _last_float_check = nil, -- timestamp of last time the cart was checked to be still on a rail
70 _fueltime = nil, -- how many seconds worth of fuel is left. Only used by minecart with furnace
71 _boomtimer = nil, -- how many seconds are left before exploding
72 _blinktimer = nil, -- how many seconds are left before TNT blinking
73 _blink = false, -- is TNT blink texture active?
74 _old_dir = {x=0, y=0, z=0},
75 _old_pos = nil,
76 _old_vel = {x=0, y=0, z=0},
77 _old_switch = 0,
78 _railtype = nil,
81 function cart:on_activate(staticdata, dtime_s)
82 -- Initialize
83 local data = minetest.deserialize(staticdata)
84 if type(data) == "table" then
85 self._railtype = data._railtype
86 end
87 self.object:set_armor_groups({immortal=1})
89 -- Activate cart if on activator rail
90 if self.on_activate_by_rail then
91 local pos = self.object:get_pos()
92 local node = minetest.get_node(vector.floor(pos))
93 if node.name == "mcl_minecarts:activator_rail_on" then
94 self:on_activate_by_rail()
95 end
96 end
97 end
99 function cart:on_punch(puncher, time_from_last_punch, tool_capabilities, direction)
100 local pos = self.object:get_pos()
101 if not self._railtype then
102 local node = minetest.get_node(vector.floor(pos)).name
103 self._railtype = minetest.get_item_group(node, "connect_to_raillike")
106 if not puncher or not puncher:is_player() then
107 local cart_dir = mcl_minecarts:get_rail_direction(pos, {x=1, y=0, z=0}, nil, nil, self._railtype)
108 if vector.equals(cart_dir, {x=0, y=0, z=0}) then
109 return
111 self._velocity = vector.multiply(cart_dir, 3)
112 self._old_pos = nil
113 self._punched = true
114 return
117 -- Punch+sneak: Pick up minecart (unless TNT was ignited)
118 if puncher:get_player_control().sneak and not self._boomtimer then
119 if self._driver then
120 if self._old_pos then
121 self.object:set_pos(self._old_pos)
123 detach_driver(self)
126 -- Disable detector rail
127 local rou_pos = vector.round(pos)
128 local node = minetest.get_node(rou_pos)
129 if node.name == "mcl_minecarts:detector_rail_on" then
130 local newnode = {name="mcl_minecarts:detector_rail", param2 = node.param2}
131 minetest.swap_node(rou_pos, newnode)
132 mesecon.receptor_off(rou_pos)
135 -- Drop items and remove cart entity
136 if not minetest.settings:get_bool("creative_mode") then
137 for d=1, #drop do
138 minetest.add_item(self.object:get_pos(), drop[d])
140 elseif puncher and puncher:is_player() then
141 local inv = puncher:get_inventory()
142 for d=1, #drop do
143 if not inv:contains_item("main", drop[d]) then
144 inv:add_item("main", drop[d])
149 self.object:remove()
150 return
153 local vel = self.object:get_velocity()
154 if puncher:get_player_name() == self._driver then
155 if math.abs(vel.x + vel.z) > 7 then
156 return
160 local punch_dir = mcl_minecarts:velocity_to_dir(puncher:get_look_dir())
161 punch_dir.y = 0
162 local cart_dir = mcl_minecarts:get_rail_direction(pos, punch_dir, nil, nil, self._railtype)
163 if vector.equals(cart_dir, {x=0, y=0, z=0}) then
164 return
167 time_from_last_punch = math.min(time_from_last_punch, tool_capabilities.full_punch_interval)
168 local f = 3 * (time_from_last_punch / tool_capabilities.full_punch_interval)
170 self._velocity = vector.multiply(cart_dir, f)
171 self._old_pos = nil
172 self._punched = true
175 cart.on_activate_by_rail = on_activate_by_rail
177 function cart:on_step(dtime)
178 local vel = self.object:get_velocity()
179 local update = {}
180 if self._last_float_check == nil then
181 self._last_float_check = 0
182 else
183 self._last_float_check = self._last_float_check + dtime
185 local pos, rou_pos, node
186 -- Drop minecart if it isn't on a rail anymore
187 if self._last_float_check >= mcl_minecarts.check_float_time then
188 pos = self.object:get_pos()
189 rou_pos = vector.round(pos)
190 node = minetest.get_node(rou_pos)
191 local g = minetest.get_item_group(node.name, "connect_to_raillike")
192 if g ~= self._railtype and self._railtype ~= nil then
193 -- Detach driver
194 if self._driver then
195 if self._old_pos then
196 self.object:set_pos(self._old_pos)
198 mcl_player.player_attached[self._driver] = nil
199 local player = minetest.get_player_by_name(self._driver)
200 if player then
201 player:set_detach()
202 player:set_eye_offset({x=0, y=0, z=0},{x=0, y=0, z=0})
206 -- Explode if already ignited
207 if self._boomtimer then
208 self.object:remove()
209 mcl_explosions.explode(pos, 4, { drop_chance = 1.0 })
210 return
213 -- Drop items and remove cart entity
214 if not minetest.settings:get_bool("creative_mode") then
215 for d=1, #drop do
216 minetest.add_item(self.object:get_pos(), drop[d])
220 self.object:remove()
221 return
223 self._last_float_check = 0
226 -- Update furnace stuff
227 if self._fueltime and self._fueltime > 0 then
228 self._fueltime = self._fueltime - dtime
229 if self._fueltime <= 0 then
230 self.object:set_properties({textures =
232 "default_furnace_top.png",
233 "default_furnace_top.png",
234 "default_furnace_front.png",
235 "default_furnace_side.png",
236 "default_furnace_side.png",
237 "default_furnace_side.png",
238 "mcl_minecarts_minecart.png",
240 self._fueltime = 0
243 local has_fuel = self._fueltime and self._fueltime > 0
245 -- Update TNT stuff
246 if self._boomtimer then
247 -- Explode
248 self._boomtimer = self._boomtimer - dtime
249 local pos = self.object:get_pos()
250 if self._boomtimer <= 0 then
251 self.object:remove()
252 mcl_explosions.explode(pos, 4, { drop_chance = 1.0 })
253 return
254 else
255 tnt.smoke_step(pos)
258 if self._blinktimer then
259 self._blinktimer = self._blinktimer - dtime
260 if self._blinktimer <= 0 then
261 self._blink = not self._blink
262 if self._blink then
263 self.object:set_properties({textures =
265 "default_tnt_top.png",
266 "default_tnt_bottom.png",
267 "default_tnt_side.png",
268 "default_tnt_side.png",
269 "default_tnt_side.png",
270 "default_tnt_side.png",
271 "mcl_minecarts_minecart.png",
273 else
274 self.object:set_properties({textures =
276 "mcl_tnt_blink.png",
277 "mcl_tnt_blink.png",
278 "mcl_tnt_blink.png",
279 "mcl_tnt_blink.png",
280 "mcl_tnt_blink.png",
281 "mcl_tnt_blink.png",
282 "mcl_minecarts_minecart.png",
285 self._blinktimer = tnt.BLINKTIMER
289 if self._punched then
290 vel = vector.add(vel, self._velocity)
291 self.object:set_velocity(vel)
292 self._old_dir.y = 0
293 elseif vector.equals(vel, {x=0, y=0, z=0}) and (not has_fuel) then
294 return
297 local dir, last_switch = nil, nil
298 if not pos then
299 pos = self.object:get_pos()
301 if self._old_pos and not self._punched then
302 local flo_pos = vector.floor(pos)
303 local flo_old = vector.floor(self._old_pos)
304 if vector.equals(flo_pos, flo_old) and (not has_fuel) then
305 return
306 -- Prevent querying the same node over and over again
309 if not rou_pos then
310 rou_pos = vector.round(pos)
312 rou_old = vector.round(self._old_pos)
313 if not node then
314 node = minetest.get_node(rou_pos)
316 local node_old = minetest.get_node(rou_old)
318 -- Update detector rails
319 if node.name == "mcl_minecarts:detector_rail" then
320 local newnode = {name="mcl_minecarts:detector_rail_on", param2 = node.param2}
321 minetest.swap_node(rou_pos, newnode)
322 mesecon.receptor_on(rou_pos)
324 if node_old.name == "mcl_minecarts:detector_rail_on" then
325 local newnode = {name="mcl_minecarts:detector_rail", param2 = node_old.param2}
326 minetest.swap_node(rou_old, newnode)
327 mesecon.receptor_off(rou_old)
329 -- Activate minecart if on activator rail
330 if node_old.name == "mcl_minecarts:activator_rail_on" and self.on_activate_by_rail then
331 self:on_activate_by_rail()
335 local ctrl, player = nil, nil
336 if self._driver then
337 player = minetest.get_player_by_name(self._driver)
338 if player then
339 ctrl = player:get_player_control()
343 -- Stop cart if velocity vector flips
344 if self._old_vel and self._old_vel.y == 0 and
345 (self._old_vel.x * vel.x < 0 or self._old_vel.z * vel.z < 0) then
346 self._old_vel = {x = 0, y = 0, z = 0}
347 self._old_pos = pos
348 self.object:set_velocity(vector.new())
349 self.object:set_acceleration(vector.new())
350 return
352 self._old_vel = vector.new(vel)
354 if self._old_pos then
355 local diff = vector.subtract(self._old_pos, pos)
356 for _,v in ipairs({"x","y","z"}) do
357 if math.abs(diff[v]) > 1.1 then
358 local expected_pos = vector.add(self._old_pos, self._old_dir)
359 dir, last_switch = mcl_minecarts:get_rail_direction(pos, self._old_dir, ctrl, self._old_switch, self._railtype)
360 if vector.equals(dir, {x=0, y=0, z=0}) then
361 dir = false
362 pos = vector.new(expected_pos)
363 update.pos = true
365 break
370 if vel.y == 0 then
371 for _,v in ipairs({"x", "z"}) do
372 if vel[v] ~= 0 and math.abs(vel[v]) < 0.9 then
373 vel[v] = 0
374 update.vel = true
379 local cart_dir = mcl_minecarts:velocity_to_dir(vel)
380 local max_vel = mcl_minecarts.speed_max
381 if not dir then
382 dir, last_switch = mcl_minecarts:get_rail_direction(pos, cart_dir, ctrl, self._old_switch, self._railtype)
385 local new_acc = {x=0, y=0, z=0}
386 if vector.equals(dir, {x=0, y=0, z=0}) and not has_fuel then
387 vel = {x=0, y=0, z=0}
388 update.vel = true
389 else
390 -- If the direction changed
391 if dir.x ~= 0 and self._old_dir.z ~= 0 then
392 vel.x = dir.x * math.abs(vel.z)
393 vel.z = 0
394 pos.z = math.floor(pos.z + 0.5)
395 update.pos = true
397 if dir.z ~= 0 and self._old_dir.x ~= 0 then
398 vel.z = dir.z * math.abs(vel.x)
399 vel.x = 0
400 pos.x = math.floor(pos.x + 0.5)
401 update.pos = true
403 -- Up, down?
404 if dir.y ~= self._old_dir.y then
405 vel.y = dir.y * math.abs(vel.x + vel.z)
406 pos = vector.round(pos)
407 update.pos = true
410 -- Slow down or speed up
411 local acc = dir.y * -1.8
413 local speed_mod = minetest.registered_nodes[minetest.get_node(pos).name]._rail_acceleration
414 if has_fuel then
415 acc = acc + 0.2
416 elseif speed_mod and speed_mod ~= 0 then
417 acc = acc + speed_mod
418 else
419 acc = acc - 0.4
422 new_acc = vector.multiply(dir, acc)
425 self.object:set_acceleration(new_acc)
426 self._old_pos = vector.new(pos)
427 self._old_dir = vector.new(dir)
428 self._old_switch = last_switch
430 -- Limits
431 for _,v in ipairs({"x","y","z"}) do
432 if math.abs(vel[v]) > max_vel then
433 vel[v] = mcl_minecarts:get_sign(vel[v]) * max_vel
434 new_acc[v] = 0
435 update.vel = true
439 -- Give achievement when player reached a distance of 1000 nodes from the start position
440 if self._driver and (vector.distance(self._start_pos, pos) >= 1000) then
441 awards.unlock(self._driver, "mcl:onARail")
445 if update.pos or self._punched then
446 local yaw = 0
447 if dir.x < 0 then
448 yaw = 0.5
449 elseif dir.x > 0 then
450 yaw = 1.5
451 elseif dir.z < 0 then
452 yaw = 1
454 self.object:set_yaw(yaw * math.pi)
457 if self._punched then
458 self._punched = false
461 if not (update.vel or update.pos) then
462 return
466 local anim = {x=0, y=0}
467 if dir.y == -1 then
468 anim = {x=1, y=1}
469 elseif dir.y == 1 then
470 anim = {x=2, y=2}
472 self.object:set_animation(anim, 1, 0)
474 self.object:set_velocity(vel)
475 if update.pos then
476 self.object:set_pos(pos)
478 update = nil
481 function cart:get_staticdata()
482 return minetest.serialize({_railtype = self._railtype})
485 minetest.register_entity(entity_id, cart)
488 -- Place a minecart at pointed_thing
489 mcl_minecarts.place_minecart = function(itemstack, pointed_thing)
490 if not pointed_thing.type == "node" then
491 return
494 local railpos, node
495 if mcl_minecarts:is_rail(pointed_thing.under) then
496 railpos = pointed_thing.under
497 node = minetest.get_node(pointed_thing.under)
498 elseif mcl_minecarts:is_rail(pointed_thing.above) then
499 railpos = pointed_thing.above
500 node = minetest.get_node(pointed_thing.above)
501 else
502 return
505 -- Activate detector rail
506 if node.name == "mcl_minecarts:detector_rail" then
507 local newnode = {name="mcl_minecarts:detector_rail_on", param2 = node.param2}
508 minetest.swap_node(railpos, newnode)
509 mesecon.receptor_on(railpos)
512 local entity_id = entity_mapping[itemstack:get_name()]
513 local cart = minetest.add_entity(railpos, entity_id)
514 local railtype = minetest.get_item_group(node.name, "connect_to_raillike")
515 local le = cart:get_luaentity()
516 if le ~= nil then
517 le._railtype = railtype
519 local cart_dir = mcl_minecarts:get_rail_direction(railpos, {x=1, y=0, z=0}, nil, nil, railtype)
520 cart:set_yaw(minetest.dir_to_yaw(cart_dir))
522 if not minetest.settings:get_bool("creative_mode") then
523 itemstack:take_item()
525 return itemstack
529 local register_craftitem = function(itemstring, entity_id, description, tt_help, longdesc, usagehelp, icon, creative)
530 entity_mapping[itemstring] = entity_id
532 local groups = { minecart = 1, transport = 1 }
533 if creative == false then
534 groups.not_in_creative_inventory = 1
536 local def = {
537 stack_max = 1,
538 on_place = function(itemstack, placer, pointed_thing)
539 if not pointed_thing.type == "node" then
540 return
543 -- Call on_rightclick if the pointed node defines it
544 local node = minetest.get_node(pointed_thing.under)
545 if placer and not placer:get_player_control().sneak then
546 if minetest.registered_nodes[node.name] and minetest.registered_nodes[node.name].on_rightclick then
547 return minetest.registered_nodes[node.name].on_rightclick(pointed_thing.under, node, placer, itemstack) or itemstack
551 return mcl_minecarts.place_minecart(itemstack, pointed_thing)
552 end,
553 _on_dispense = function(stack, pos, droppos, dropnode, dropdir)
554 -- Place minecart as entity on rail. If there's no rail, just drop it.
555 local placed
556 if minetest.get_item_group(dropnode.name, "rail") ~= 0 then
557 -- FIXME: This places minecarts even if the spot is already occupied
558 local pointed_thing = { under = droppos, above = { x=droppos.x, y=droppos.y+1, z=droppos.z } }
559 placed = mcl_minecarts.place_minecart(stack, pointed_thing)
561 if placed == nil then
562 -- Drop item
563 minetest.add_item(droppos, stack)
565 end,
566 groups = groups,
568 def.description = description
569 def._tt_help = tt_help
570 def._doc_items_longdesc = longdesc
571 def._doc_items_usagehelp = usagehelp
572 def.inventory_image = icon
573 def.wield_image = icon
574 minetest.register_craftitem(itemstring, def)
577 --[[
578 Register a minecart
579 * itemstring: Itemstring of minecart item
580 * entity_id: ID of minecart entity
581 * description: Item name / description
582 * longdesc: Long help text
583 * usagehelp: Usage help text
584 * mesh: Minecart mesh
585 * textures: Minecart textures table
586 * icon: Item icon
587 * drop: Dropped items after destroying minecart
588 * on_rightclick: Called after rightclick
589 * on_activate_by_rail: Called when above activator rail
590 * creative: If false, don't show in Creative Inventory
592 local function register_minecart(itemstring, entity_id, description, tt_help, longdesc, usagehelp, mesh, textures, icon, drop, on_rightclick, on_activate_by_rail, creative)
593 register_entity(entity_id, mesh, textures, drop, on_rightclick, on_activate_by_rail)
594 register_craftitem(itemstring, entity_id, description, tt_help, longdesc, usagehelp, icon, creative)
595 if minetest.get_modpath("doc_identifier") ~= nil then
596 doc.sub.identifier.register_object(entity_id, "craftitems", itemstring)
600 -- Minecart
601 register_minecart(
602 "mcl_minecarts:minecart",
603 "mcl_minecarts:minecart",
604 S("Minecart"),
605 S("Vehicle for fast travel on rails"),
606 S("Minecarts can be used for a quick transportion on rails.") .. "\n" ..
607 S("Minecarts only ride on rails and always follow the tracks. At a T-junction with no straight way ahead, they turn left. The speed is affected by the rail type."),
608 S("You can place the minecart on rails. Right-click it to enter it. Punch it to get it moving.") .. "\n" ..
609 S("To obtain the minecart, punch it while holding down the sneak key.") .. "\n" ..
610 S("If it moves over a powered activator rail, you'll get ejected."),
611 "mcl_minecarts_minecart.b3d",
612 {"mcl_minecarts_minecart.png"},
613 "mcl_minecarts_minecart_normal.png",
614 {"mcl_minecarts:minecart"},
615 function(self, clicker)
616 local name = clicker:get_player_name()
617 if not clicker or not clicker:is_player() then
618 return
620 local player_name = clicker:get_player_name()
621 if self._driver and player_name == self._driver then
622 detach_driver(self)
623 elseif not self._driver then
624 self._driver = player_name
625 self._start_pos = self.object:get_pos()
626 mcl_player.player_attached[player_name] = true
627 clicker:set_attach(self.object, "", {x=0, y=-1.75, z=-2}, {x=0, y=0, z=0})
628 mcl_player.player_attached[name] = true
629 minetest.after(0.2, function(name)
630 local player = minetest.get_player_by_name(name)
631 if player then
632 mcl_player.player_set_animation(player, "sit" , 30)
633 player:set_eye_offset({x=0, y=-5.5, z=0},{x=0, y=-4, z=0})
635 end, name)
637 end, activate_normal_minecart
640 -- Minecart with Chest
641 register_minecart(
642 "mcl_minecarts:chest_minecart",
643 "mcl_minecarts:chest_minecart",
644 S("Minecart with Chest"),
645 nil, nil, nil,
646 "mcl_minecarts_minecart_chest.b3d",
647 { "mcl_chests_normal.png", "mcl_minecarts_minecart.png" },
648 "mcl_minecarts_minecart_chest.png",
649 {"mcl_minecarts:minecart", "mcl_chests:chest"},
650 nil, nil, false)
652 -- Minecart with Furnace
653 register_minecart(
654 "mcl_minecarts:furnace_minecart",
655 "mcl_minecarts:furnace_minecart",
656 S("Minecart with Furnace"),
657 nil,
658 S("A minecart with furnace is a vehicle that travels on rails. It can propel itself with fuel."),
659 S("Place it on rails. If you give it some coal, the furnace will start burning for a long time and the minecart will be able to move itself. Punch it to get it moving.") .. "\n" ..
660 S("To obtain the minecart and furnace, punch them while holding down the sneak key."),
662 "mcl_minecarts_minecart_block.b3d",
664 "default_furnace_top.png",
665 "default_furnace_top.png",
666 "default_furnace_front.png",
667 "default_furnace_side.png",
668 "default_furnace_side.png",
669 "default_furnace_side.png",
670 "mcl_minecarts_minecart.png",
672 "mcl_minecarts_minecart_furnace.png",
673 {"mcl_minecarts:minecart", "mcl_furnaces:furnace"},
674 -- Feed furnace with coal
675 function(self, clicker)
676 if not clicker or not clicker:is_player() then
677 return
679 if not self._fueltime then
680 self._fueltime = 0
682 local held = clicker:get_wielded_item()
683 if minetest.get_item_group(held:get_name(), "coal") == 1 then
684 self._fueltime = self._fueltime + 180
686 if not minetest.settings:get_bool("creative_mode") then
687 held:take_item()
688 local index = clicker:get_wield_index()
689 local inv = clicker:get_inventory()
690 inv:set_stack("main", index, held)
692 self.object:set_properties({textures =
694 "default_furnace_top.png",
695 "default_furnace_top.png",
696 "default_furnace_front_active.png",
697 "default_furnace_side.png",
698 "default_furnace_side.png",
699 "default_furnace_side.png",
700 "mcl_minecarts_minecart.png",
703 end, nil, false
706 -- Minecart with Command Block
707 register_minecart(
708 "mcl_minecarts:command_block_minecart",
709 "mcl_minecarts:command_block_minecart",
710 S("Minecart with Command Block"),
711 nil, nil, nil,
712 "mcl_minecarts_minecart_block.b3d",
714 "jeija_commandblock_off.png^[verticalframe:2:0",
715 "jeija_commandblock_off.png^[verticalframe:2:0",
716 "jeija_commandblock_off.png^[verticalframe:2:0",
717 "jeija_commandblock_off.png^[verticalframe:2:0",
718 "jeija_commandblock_off.png^[verticalframe:2:0",
719 "jeija_commandblock_off.png^[verticalframe:2:0",
720 "mcl_minecarts_minecart.png",
722 "mcl_minecarts_minecart_command_block.png",
723 {"mcl_minecarts:minecart"},
724 nil, nil, false
727 -- Minecart with Hopper
728 register_minecart(
729 "mcl_minecarts:hopper_minecart",
730 "mcl_minecarts:hopper_minecart",
731 S("Minecart with Hopper"),
732 nil, nil, nil,
733 "mcl_minecarts_minecart_hopper.b3d",
735 "mcl_hoppers_hopper_inside.png",
736 "mcl_minecarts_minecart.png",
737 "mcl_hoppers_hopper_outside.png",
738 "mcl_hoppers_hopper_top.png",
740 "mcl_minecarts_minecart_hopper.png",
741 {"mcl_minecarts:minecart", "mcl_hoppers:hopper"},
742 nil, nil, false
745 -- Minecart with TNT
746 register_minecart(
747 "mcl_minecarts:tnt_minecart",
748 "mcl_minecarts:tnt_minecart",
749 S("Minecart with TNT"),
750 S("Vehicle for fast travel on rails").."\n"..S("Can be ignited by tools or powered activator rail"),
751 S("A minecart with TNT is an explosive vehicle that travels on rail."),
752 S("Place it on rails. Punch it to move it. The TNT is ignited with a flint and steel or when the minecart is on an powered activator rail.") .. "\n" ..
753 S("To obtain the minecart and TNT, punch them while holding down the sneak key. You can't do this if the TNT was ignited."),
754 "mcl_minecarts_minecart_block.b3d",
756 "default_tnt_top.png",
757 "default_tnt_bottom.png",
758 "default_tnt_side.png",
759 "default_tnt_side.png",
760 "default_tnt_side.png",
761 "default_tnt_side.png",
762 "mcl_minecarts_minecart.png",
764 "mcl_minecarts_minecart_tnt.png",
765 {"mcl_minecarts:minecart", "mcl_tnt:tnt"},
766 -- Ingite
767 function(self, clicker)
768 if not clicker or not clicker:is_player() then
769 return
771 if self._boomtimer then
772 return
774 local held = clicker:get_wielded_item()
775 if held:get_name() == "mcl_fire:flint_and_steel" then
776 if not minetest.settings:get_bool("creative_mode") then
777 held:add_wear(65535/65) -- 65 uses
778 local index = clicker:get_wield_index()
779 local inv = clicker:get_inventory()
780 inv:set_stack("main", index, held)
782 activate_tnt_minecart(self)
784 end, activate_tnt_minecart)
787 minetest.register_craft({
788 output = "mcl_minecarts:minecart",
789 recipe = {
790 {"mcl_core:iron_ingot", "", "mcl_core:iron_ingot"},
791 {"mcl_core:iron_ingot", "mcl_core:iron_ingot", "mcl_core:iron_ingot"},
795 minetest.register_craft({
796 output = "mcl_minecarts:tnt_minecart",
797 recipe = {
798 {"mcl_tnt:tnt"},
799 {"mcl_minecarts:minecart"},
803 -- TODO: Re-enable crafting of special minecarts when they have been implemented
804 if false then
806 minetest.register_craft({
807 output = "mcl_minecarts:furnace_minecart",
808 recipe = {
809 {"mcl_furnaces:furnace"},
810 {"mcl_minecarts:minecart"},
814 minetest.register_craft({
815 output = "mcl_minecarts:hopper_minecart",
816 recipe = {
817 {"mcl_hoppers:hopper"},
818 {"mcl_minecarts:minecart"},
822 minetest.register_craft({
823 output = "mcl_minecarts:chest_minecart",
824 recipe = {
825 {"mcl_chests:chest"},
826 {"mcl_minecarts:minecart"},