dofile(minetest.get_modpath("carts").."/functions.lua") local cart = { physical = true, -- Set to false to not make carts collide with other entities such as carts or the player. collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5}, visual = "mesh", mesh = "cart.x", visual_size = {x=1, y=1}, textures = {"cart.png"}, -- Set to "invisible.png" to make the cart invisible, which is sometimes useful for videos and custom maps. driver = nil, velocity = {x=0, y=0, z=0}, old_pos = nil, old_velocity = nil, pre_stop_dir = nil, MAX_V = 9.6, -- Limit of the velocity (speed). TARGET_TOUR_V = 6, -- Target touring velocity, currently unused. railcount = 0, ignorekeypos = nil, lockyaw = false, -- Set to true to lock camera by default. If set to false, player has to press the "jump" key to lock camera. yawtarget = nil, YAW_STEP = math.pi/64 -- Larger YAW_STEP makes for slower camera turning. } function cart:on_rightclick(clicker) if not clicker or not clicker:is_player() then return end if self.driver and clicker == self.driver then self.driver = nil clicker:set_detach() elseif not self.driver then self.driver = clicker clicker:set_attach(self.object, "", {x=0,y=5,z=0}, {x=0,y=0,z=0}) end end function cart:on_activate(staticdata, dtime_s) self.object:set_armor_groups({immortal=1}) if staticdata then local tmp = minetest.deserialize(staticdata) if tmp then self.velocity = tmp.velocity end if tmp and tmp.pre_stop_dir then self.pre_stop_dir = tmp.pre_stop_dir end end self.old_pos = self.object:getpos() self.old_velocity = self.velocity end function cart:get_staticdata() return minetest.serialize({ velocity = self.velocity, pre_stop_dir = self.pre_stop_dir, }) end -- Remove the cart if holding a tool or accelerate it function cart:on_punch(puncher, time_from_last_punch, tool_capabilities, direction) if not puncher or not puncher:is_player() then return end if puncher:get_player_control().sneak then minetest.log("action", "carts:cart removed at " .. pos_to_string(vector.round(self.object:getpos())) .. ", " .. self.railcount .. " rails travelled.") self.object:remove() local inv = puncher:get_inventory() if minetest.setting_getbool("creative_mode") then if not inv:contains_item("main", "carts:cart") then inv:add_item("main", "carts:cart") end else inv:add_item("main", "carts:cart") end return end if puncher == self.driver and (math.abs(self.velocity.x)>1 or math.abs(self.velocity.z)>1) then return end local d = cart_func:velocity_to_dir(direction) if d.x==0 and d.z==0 then local fd = minetest.dir_to_facedir(puncher:get_look_dir()) if fd == 0 then d.x = 1 elseif fd == 1 then d.z = -1 elseif fd == 2 then d.x = -1 elseif fd == 3 then d.z = 1 end end local s = self.velocity if time_from_last_punch > tool_capabilities.full_punch_interval then time_from_last_punch = tool_capabilities.full_punch_interval end local f = 4*(time_from_last_punch/tool_capabilities.full_punch_interval) local v = {x=s.x+d.x*f, y=s.y, z=s.z+d.z*f} if math.abs(v.x) < 6 and math.abs(v.z) < 6 then self.velocity = v else if math.abs(self.velocity.x) < 6 and math.abs(v.x) >= 6 then self.velocity.x = 6*cart_func:get_sign(self.velocity.x) end if math.abs(self.velocity.z) < 6 and math.abs(v.z) >= 6 then self.velocity.z = 6*cart_func:get_sign(self.velocity.z) end end end -- Returns the direction as a unit vector function cart:get_rail_direction(pos, dir) --minetest.log("action", "get_rail_direction top pos="..pos_to_string(pos).." dir="..pos_to_string(dir)) local fwd=cart_func.v3:copy(dir) fwd.y=0 local up=cart_func.v3:copy(dir) up.y=1 local down=cart_func.v3:copy(dir) down.y=-1 -- figure out left and right local left={x=0,y=0,z=0} local right={x=0,y=0,z=0} if dir.z ~= 0 and dir.x == 0 then left.x=-dir.z --left is opposite sign from z right.x=dir.z --right is same sign as z elseif dir.x ~= 0 and dir.z == 0 then left.z=dir.x --left is same sign as x right.z=-dir.x --right is opposite sign from x end --left and right local leftdown=cart_func.v3:copy(left) leftdown.y=-1 local rightdown=cart_func.v3:copy(right) rightdown.y=-1 --minetest.log("action", " fwd="..pos_to_string(fwd)) --minetest.log("action", " down="..pos_to_string(down)) --minetest.log("action", " up="..pos_to_string(up)) --minetest.log("action", " left="..pos_to_string(left)) --minetest.log("action", " leftdown="..pos_to_string(leftdown)) --minetest.log("action", " right="..pos_to_string(right)) --minetest.log("action", " rightdown="..pos_to_string(rightdown)) local ignorekeys=false --ignorekeypos stores a position where we changed direction because the --player was pressing left or right keys. once we have changed direction, --we want to ignore those keys until you have changed to a different rail --(otherwise you end up reversing) --I use the ignorekeys boolean to make the key logic more readable if self.ignorekeypos then --ignorekeypos was set if cart_func.v3:equal(self.ignorekeypos,pos) then ignorekeys=true --if still at same position, ignore left and right keys else self.ignorekeypos=nil --if ignorekeypos was set but pos does not match anymore, clear it end end local ctrl=nil if self.driver and not ignorekeys then ctrl = self.driver:get_player_control() end if ctrl and ctrl.left then --left key pressed, check left first if cart_func:check_rail_in_direction(pos,left) then self.ignorekeypos=cart_func.v3:copy(pos) --ignore keys until pos changes return left elseif cart_func:check_rail_in_direction(pos,leftdown) then self.ignorekeypos=cart_func.v3:copy(pos) return leftdown end elseif ctrl and ctrl.right then --right key pressed, check right first if cart_func:check_rail_in_direction(pos,right) then self.ignorekeypos=cart_func.v3:copy(pos) return right elseif cart_func:check_rail_in_direction(pos,rightdown) then self.ignorekeypos=cart_func.v3:copy(pos) return rightdown end end --ctrl.left ctrl.right --now for normal checks if cart_func:check_rail_in_direction(pos,fwd) then return fwd elseif cart_func:check_rail_in_direction(pos,down) then return down elseif cart_func:check_rail_in_direction(pos,up) then return up elseif (not ctrl or not ctrl.left) --only check left if we didnt above and cart_func:check_rail_in_direction(pos,left) then return left elseif (not ctrl or not ctrl.left) and cart_func:check_rail_in_direction(pos,leftdown) then return leftdown elseif (not ctrl or not ctrl.right) --only check right if we didnt above and cart_func:check_rail_in_direction(pos,right) then return right elseif (not ctrl or not ctrl.right) and cart_func:check_rail_in_direction(pos,rightdown) then return rightdown else return {x=0, y=0, z=0} end --normal rail checks end --get_rail_direction function cart:calc_rail_direction(pos, vel) local velocity = cart_func.v3:copy(vel) local p = cart_func.v3:copy(pos) if cart_func:is_int(p.x) and cart_func:is_int(p.z) then local dir = cart_func:velocity_to_dir(velocity) local dir_old = cart_func.v3:copy(dir) dir = self:get_rail_direction(cart_func.v3:round(p), dir) local v = math.max(math.abs(velocity.x), math.abs(velocity.z)) velocity = { x = v * dir.x, y = v * dir.y, z = v * dir.z, } if cart_func.v3:equal(velocity, {x=0, y=0, z=0}) and not cart_func:is_rail(p) then -- First try this HACK -- Move the cart on the rail if above or under it if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=1, z=0})) and vel.y >= 0 then p = cart_func.v3:add(p, {x=0, y=1, z=0}) return self:calc_rail_direction(p, vel) end if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=-1, z=0})) and vel.y <= 0 then p = cart_func.v3:add(p, {x=0, y=-1, z=0}) return self:calc_rail_direction(p, vel) end -- Now the HACK gets really dirty if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=2, z=0})) and vel.y >= 0 then p = cart_func.v3:add(p, {x=0, y=1, z=0}) return self:calc_rail_direction(p, vel) end if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=-2, z=0})) and vel.y <= 0 then p = cart_func.v3:add(p, {x=0, y=-1, z=0}) return self:calc_rail_direction(p, vel) end return {x=0, y=0, z=0}, p end if not cart_func.v3:equal(dir, dir_old) then return velocity, cart_func.v3:round(p) end end return velocity, p end -- built in pos_to_string doesn't handle nil. function pos_to_string(pos) if pos==nil then return "(nil)" else return minetest.pos_to_string(pos) end --poss==nil end --pos_to_string function cart:on_step(dtime) local pos = self.object:getpos() local dir = cart_func:velocity_to_dir(self.velocity) -- *!* Debug. if self.old_pos then local cmp_old=vector.round(self.old_pos) local cmp_new=vector.round(pos) if cmp_old.x~=cmp_new.x or cmp_old.y~=cmp_new.y or cmp_old.z~=cmp_new.z then self.railcount=self.railcount+1 -- local a = tonumber(minetest.get_meta(pos):get_string("cart_acceleration")) -- local railtype="" -- if a and a>0 then railtype="power" end -- minetest.chat_send_all("-- cart pos="..pos_to_string(vector.round(pos)).." railcount="..self.railcount.." vel="..pos_to_string(self.velocity).." "..railtype) --*!*debug end end -- *!* Debug. local ctrl=nil if self.driver then ctrl = self.driver:get_player_control() if ctrl and ctrl.jump and not self.lockyaw then self.lockyaw=true self.yawtarget=self.object:getyaw() -- minetest.chat_send_player(self.driver:get_player_name(),"Player view locked to cart, sneak to unlock.") elseif ctrl and ctrl.sneak and self.lockyaw then self.lockyaw=false -- minetest.chat_send_player(self.driver:get_player_name(),"Player view unlocked from cart, jump to lock.") end end -- Check lockyaw if self.driver. if not cart_func.v3:equal(self.velocity, {x=0,y=0,z=0}) then self.pre_stop_dir = cart_func:velocity_to_dir(self.velocity) end -- Stop the cart if the velocity is nearly 0, only if on a flat railway. if dir.y == 0 then if math.abs(self.velocity.x) < 0.1 and math.abs(self.velocity.z) < 0.1 then -- Start the cart if powered from mesecons. local a = tonumber(minetest.get_meta(pos):get_string("cart_acceleration")) if a and a ~= 0 then if self.pre_stop_dir and cart_func.v3:equal(self:get_rail_direction(self.object:getpos(), self.pre_stop_dir), self.pre_stop_dir) then self.velocity = { x = self.pre_stop_dir.x * 0.2, y = self.pre_stop_dir.y * 0.2, z = self.pre_stop_dir.z * 0.2, } self.old_velocity = self.velocity return end for _,y in ipairs({0,-1,1}) do for _,z in ipairs({1,-1}) do if cart_func.v3:equal(self:get_rail_direction(self.object:getpos(), {x=0, y=y, z=z}), {x=0, y=y, z=z}) then self.velocity = { x = 0, y = 0.2*y, z = 0.2*z, } self.old_velocity = self.velocity return end end for _,x in ipairs({1,-1}) do if cart_func.v3:equal(self:get_rail_direction(self.object:getpos(), {x=x, y=y, z=0}), {x=x, y=y, z=0}) then self.velocity = { x = 0.2*x, y = 0.2*y, z = 0, } self.old_velocity = self.velocity return end end end end self.velocity = {x=0, y=0, z=0} self.object:setvelocity(self.velocity) self.old_velocity = self.velocity self.old_pos = self.object:getpos() return end end -- -- Set the new moving direction -- -- Recalcualte the rails that are passed since the last server step local old_dir = cart_func:velocity_to_dir(self.old_velocity) if old_dir.x ~= 0 then local sign = cart_func:get_sign(pos.x-self.old_pos.x) while true do if sign ~= cart_func:get_sign(pos.x-self.old_pos.x) or pos.x == self.old_pos.x then break end self.old_pos.x = self.old_pos.x + cart_func:get_sign(pos.x-self.old_pos.x)*0.1 self.old_pos.y = self.old_pos.y + cart_func:get_sign(pos.x-self.old_pos.x)*0.1*old_dir.y self.old_velocity, self.old_pos = self:calc_rail_direction(self.old_pos, self.old_velocity) old_dir = cart_func:velocity_to_dir(self.old_velocity) if not cart_func.v3:equal(cart_func:velocity_to_dir(self.old_velocity), dir) then self.velocity = self.old_velocity pos = self.old_pos self.object:setpos(self.old_pos) break end end elseif old_dir.z ~= 0 then local sign = cart_func:get_sign(pos.z-self.old_pos.z) while true do if sign ~= cart_func:get_sign(pos.z-self.old_pos.z) or pos.z == self.old_pos.z then break end self.old_pos.z = self.old_pos.z + cart_func:get_sign(pos.z-self.old_pos.z)*0.1 self.old_pos.y = self.old_pos.y + cart_func:get_sign(pos.z-self.old_pos.z)*0.1*old_dir.y self.old_velocity, self.old_pos = self:calc_rail_direction(self.old_pos, self.old_velocity) old_dir = cart_func:velocity_to_dir(self.old_velocity) if not cart_func.v3:equal(cart_func:velocity_to_dir(self.old_velocity), dir) then self.velocity = self.old_velocity pos = self.old_pos self.object:setpos(self.old_pos) break end end end -- Calculate the new step self.velocity, pos = self:calc_rail_direction(pos, self.velocity) self.object:setpos(pos) dir = cart_func:velocity_to_dir(self.velocity) -- Accelerate or decelerate the cart according to the pitch and acceleration of the rail node local a = tonumber(minetest.get_meta(pos):get_string("cart_acceleration")) if not a then a = 0 end local t = tonumber(minetest.get_meta(pos):get_string("cart_touring_velocity")) if not t then t=0 end if t>0 then local vx=math.abs(self.velocity.x) local vy=math.abs(self.velocity.y) local vz=math.abs(self.velocity.z) -- make v the largest of the 3 velocities local v=vx if vy>v then v=vy end if vz>v then v=vz end -- local diff=0 local acelordecl=0 if v>t then diff=v-t acelordecl=-1 elseif vt --minetest.log("action", " on_step t1 v="..v.." t="..t.." diff="..diff.." a="..a.." acelordecl="..acelordecl) --adjust for grav if self.velocity.y<0 then --going downhill so grav will acel by extra 0.13 --if we are decel then add an extra 0.13 to how much we need to decel --if we are accel then subtract an extra 0.13 from how much we need to acel diff=diff-(0.13*acelordecl) elseif self.velocity.y>0 then --going uphill grav will decl by extra 0.10 --if we are decel then subtract 0.1 from how much we need to decel --if we are acel then add 0.1 to how much we need to acel diff=diff+(0.1*acelordecl) end -- self.velocity.y<0 --so now diff is the difference between cart velocity (after this turns grav) --and our target touring velocity --minetest.log("action", "*!* on_step t2 grav v="..v.." diff="..diff.." a="..a) if diffa*4 then a=a*2 --if big difference, play catchup fast! elseif diff>a*3 then a=a*1.5 --if big difference, play catchup fast! end --diff0 -- Check if down arrow is being pressed (handbrake). if self.driver then local ctrl = self.driver:get_player_control() if ctrl and ctrl.down then a=a-0.1 -- Same as uphill. end -- If handbrake. end -- If self.driver. if self.velocity.y < 0 then self.velocity = { x = self.velocity.x + (a+0.13)*cart_func:get_sign(self.velocity.x), y = self.velocity.y + (a+0.13)*cart_func:get_sign(self.velocity.y), z = self.velocity.z + (a+0.13)*cart_func:get_sign(self.velocity.z), } elseif self.velocity.y > 0 then self.velocity = { x = self.velocity.x + (a-0.1)*cart_func:get_sign(self.velocity.x), y = self.velocity.y + (a-0.1)*cart_func:get_sign(self.velocity.y), z = self.velocity.z + (a-0.1)*cart_func:get_sign(self.velocity.z), } else self.velocity = { x = self.velocity.x + (a-0.03)*cart_func:get_sign(self.velocity.x), y = self.velocity.y + (a-0.03)*cart_func:get_sign(self.velocity.y), z = self.velocity.z + (a-0.03)*cart_func:get_sign(self.velocity.z), } -- Place the cart exactly on top of the rail if cart_func:is_rail(cart_func.v3:round(pos)) then self.object:setpos({x=pos.x, y=math.floor(pos.y+0.5), z=pos.z}) pos = self.object:getpos() end end -- Dont switch moving direction -- Only if on flat railway if dir.y == 0 then if cart_func:get_sign(dir.x) ~= cart_func:get_sign(self.velocity.x) then self.velocity.x = 0 end if cart_func:get_sign(dir.y) ~= cart_func:get_sign(self.velocity.y) then self.velocity.y = 0 end if cart_func:get_sign(dir.z) ~= cart_func:get_sign(self.velocity.z) then self.velocity.z = 0 end end -- Allow only one moving direction (multiply the other one with 0) dir = cart_func:velocity_to_dir(self.velocity) self.velocity = { x = math.abs(self.velocity.x) * dir.x, y = self.velocity.y, z = math.abs(self.velocity.z) * dir.z, } -- Move cart exactly on the rail if dir.x ~= 0 and not cart_func:is_int(pos.z) then pos.z = math.floor(0.5+pos.z) self.object:setpos(pos) elseif dir.z ~= 0 and not cart_func:is_int(pos.x) then pos.x = math.floor(0.5+pos.x) self.object:setpos(pos) end -- Limit the velocity. if math.abs(self.velocity.x) > self.MAX_V then self.velocity.x = self.MAX_V*cart_func:get_sign(self.velocity.x) end if math.abs(self.velocity.y) > self.MAX_V then self.velocity.y = self.MAX_V*cart_func:get_sign(self.velocity.y) end if math.abs(self.velocity.z) > self.MAX_V then self.velocity.z = self.MAX_V*cart_func:get_sign(self.velocity.z) end self.object:setvelocity(self.velocity) self.old_pos = self.object:getpos() self.old_velocity = cart_func.v3:copy(self.velocity) local oldyaw=self.object:getyaw() if dir.x < 0 then self.object:setyaw(math.pi/2) elseif dir.x > 0 then self.object:setyaw(3*math.pi/2) elseif dir.z < 0 then self.object:setyaw(math.pi) elseif dir.z > 0 then self.object:setyaw(0) end local newyaw=self.object:getyaw() -- Now if driver and lockyaw, change drivers direction. if self.driver and self.lockyaw then if oldyaw~=newyaw then self.yawtarget=newyaw -- Set new target. -- minetest.log("action", "--Cart yawtarget set "..self.yawtarget) end if self.driver:get_look_yaw() == nil then return end local playeryaw=self.driver:get_look_yaw()-1.57 if playeryaw<0 then playeryaw=playeryaw+(math.pi*2) end if self.yawtarget and playeryaw ~= self.yawtarget then local diff = self.yawtarget - playeryaw if diff>math.pi then diff=diff-(2*math.pi) elseif diff<(-math.pi) then diff=diff+(2*math.pi) end local yawdir=cart_func:get_sign(diff) local step=self.YAW_STEP if math.abs(diff)<=self.YAW_STEP then step=diff self.yawtarget=nil end local setyaw=playeryaw+(step*yawdir) self.driver:set_look_yaw(setyaw) end -- Move yaw. end -- lockyaw set. if dir.y == -1 then self.object:set_animation({x=1, y=1}, 1, 0) elseif dir.y == 1 then self.object:set_animation({x=2, y=2}, 1, 0) else self.object:set_animation({x=0, y=0}, 1, 0) end end minetest.register_entity("carts:cart", cart) minetest.register_craftitem("carts:cart", { description = "Cart", inventory_image = minetest.inventorycube("cart_top.png", "cart_side.png", "cart_side.png"), wield_image = "cart_side.png", on_place = function(itemstack, placer, pointed_thing) if not pointed_thing.type == "node" then return end if cart_func:is_rail(pointed_thing.under) then local obj=minetest.add_entity(pointed_thing.under, "carts:cart") minetest.log("action", "carts:cart placed at " .. pos_to_string(vector.round(obj:getpos())) .. ".") -- minetest.chat_send_player(placer:get_player_name(),"Right click to ride, left click to push, sneak + left click to put back in inventory, jump to lock view to cart, sneak to unlock view from cart, move left and right to switch tracks, move backwards to apply handbrake.") if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end return itemstack elseif cart_func:is_rail(pointed_thing.above) then minetest.add_entity(pointed_thing.above, "carts:cart") if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end return itemstack end end, }) minetest.register_craft({ output = "carts:cart", recipe = { {"default:steel_ingot", "", "default:steel_ingot"}, {"default:steel_ingot", "default:steel_ingot", "default:steel_ingot"}, }, }) -- -- Mesecon support -- minetest.register_node(":default:rail", { description = "Rail", drawtype = "raillike", tiles = {"default_rail.png", "default_rail_curved.png", "default_rail_t_junction.png", "default_rail_crossing.png"}, inventory_image = "default_rail.png", wield_image = "default_rail.png", paramtype = "light", sunlight_propagates = true, is_ground_content = true, walkable = false, selection_box = { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, groups = {bendy = 2, snappy = 1, dig_immediate = 2, rail = 1, connect_to_raillike = 1}, mesecons = { effector = { action_off = function(pos, node) minetest.get_meta(pos):set_string("cart_acceleration", "0.5") minetest.get_meta(pos):set_string("cart_touring_velocity", cart:get_staticdata().velocity) end, action_on = function(pos, node) minetest.get_meta(pos):set_string("cart_acceleration", "0") end, }, }, }) minetest.register_node("carts:rail_copper", { description = "Copper Rail", drawtype = "raillike", tiles = {"carts_rail_copper.png", "carts_rail_copper_curved.png", "carts_rail_copper_t_junction.png", "carts_rail_copper_crossing.png"}, inventory_image = "carts_rail_copper.png", wield_image = "carts_rail_copper.png", paramtype = "light", sunlight_propagates = true, is_ground_content = true, walkable = false, selection_box = { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, groups = {bendy = 2, snappy = 1, dig_immediate = 2, rail = 1, connect_to_raillike = 1}, }) minetest.register_node("carts:rail_invisible", { description = "Invisible Rail", stack_max = 10000, range = 12, drawtype = "raillike", tiles = {"invisible.png", "invisible.png", "invisible.png", "invisible.png"}, inventory_image = "default_rail.png^default_steel_ingot.png", wield_image = "default_rail.png^default_steel_ingot.png", paramtype = "light", sunlight_propagates = true, is_ground_content = true, walkable = false, selection_box = { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, drop = "", groups = {unbreakable = 1, rail = 1, connect_to_raillike = 1, not_in_creative_inventory = 1}, }) minetest.register_node("carts:rail_power", { description = "Powered Rail", drawtype = "raillike", tiles = {"carts_rail_pwr.png", "carts_rail_curved_pwr.png", "carts_rail_t_junction_pwr.png", "carts_rail_crossing_pwr.png"}, inventory_image = "carts_rail_pwr.png", wield_image = "carts_rail_pwr.png", paramtype = "light", sunlight_propagates = true, is_ground_content = true, walkable = false, selection_box = { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, groups = {bendy = 2, snappy = 1, dig_immediate = 2, rail = 1, connect_to_raillike = 1}, after_place_node = function(pos, placer, itemstack) minetest.get_meta(pos):set_string("cart_acceleration", "0.5") minetest.get_meta(pos):set_string("cart_touring_velocity", cart:get_staticdata().velocity) end, mesecons = { effector = { action_off = function(pos, node) minetest.get_meta(pos):set_string("cart_acceleration", "0.5") end, action_on = function(pos, node) minetest.get_meta(pos):set_string("cart_acceleration", "0") end, }, }, }) minetest.register_node("carts:rail_power_invisible", { description = "Invisible Powered Rail", stack_max = 10000, range = 12, drawtype = "raillike", tiles = {"invisible.png", "invisible.png", "invisible.png", "invisible.png"}, inventory_image = "default_rail.png^default_mese_crystal_fragment.png", wield_image = "default_rail.png^default_mese_crystal_fragment.png", paramtype = "light", sunlight_propagates = true, is_ground_content = true, walkable = false, selection_box = { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, drop = "", groups = {unbreakable = 1, rail = 1, connect_to_raillike = 1, not_in_creative_inventory = 1}, after_place_node = function(pos, placer, itemstack) minetest.get_meta(pos):set_string("cart_acceleration", "10") minetest.get_meta(pos):set_string("cart_touring_velocity", cart:get_staticdata().velocity) end, }) minetest.register_node("carts:rail_brake", { description = "Brake Rail", drawtype = "raillike", tiles = {"carts_rail_brk.png", "carts_rail_curved_brk.png", "carts_rail_t_junction_brk.png", "carts_rail_crossing_brk.png"}, inventory_image = "carts_rail_brk.png", wield_image = "carts_rail_brk.png", paramtype = "light", sunlight_propagates = true, is_ground_content = true, walkable = false, selection_box = { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, groups = {bendy = 2, snappy = 1, dig_immediate = 2, rail = 1, connect_to_raillike = 1}, after_place_node = function(pos, placer, itemstack) minetest.get_meta(pos):set_string("cart_acceleration", "-0.2") minetest.get_meta(pos):set_string("cart_touring_velocity", cart.TARGET_TOUR_V) end, mesecons = { effector = { action_off = function(pos, node) minetest.get_meta(pos):set_string("cart_acceleration", "-0.2") end, action_on = function(pos, node) minetest.get_meta(pos):set_string("cart_acceleration", "0") end, }, }, }) minetest.register_node("carts:rail_brake_invisible", { description = "Invisible Brake Rail", stack_max = 10000, range = 12, drawtype = "raillike", tiles = {"invisible.png", "invisible.png", "invisible.png", "invisible.png"}, inventory_image = "default_rail.png^default_coal_lump.png", wield_image = "default_rail.png^default_coal_lump.png", paramtype = "light", sunlight_propagates = true, is_ground_content = true, walkable = false, selection_box = { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, drop = "", groups = {bendy = 2, snappy = 1, dig_immediate = 2, rail = 1, connect_to_raillike = 1, not_in_creative_inventory = 1}, after_place_node = function(pos, placer, itemstack) minetest.get_meta(pos):set_string("cart_acceleration", "-10") minetest.get_meta(pos):set_string("cart_touring_velocity", cart:get_staticdata().velocity) end, }) --[[ minetest.register_node("carts:rail_tour", { description = "Touring Rail", drawtype = "raillike", tiles = {"carts_rail_tour.png", "carts_rail_curved_tour.png", "carts_rail_t_junction_tour.png", "carts_rail_crossing_tour.png"}, inventory_image = "carts_rail_tour.png", wield_image = "carts_rail_tour.png", paramtype = "light", sunlight_propagates = true, is_ground_content = true, walkable = false, selection_box = { type = "fixed", fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, groups = {bendy = 2, snappy = 1, dig_immediate = 2, rail = 1, connect_to_raillike = 1}, after_place_node = function(pos, placer, itemstack) if not mesecon then minetest.get_meta(pos):set_string("cart_acceleration", "0.5") minetest.get_meta(pos):set_string("cart_touring_velocity", cart.TARGET_TOUR_V) end end, mesecons = { effector = { action_on = function(pos, node) minetest.get_meta(pos):set_string("cart_acceleration", "0.5") end, action_off = function(pos, node) minetest.get_meta(pos):set_string("cart_acceleration", "0") end, }, }, }) --]] minetest.register_craft({ output = "carts:rail_copper 16", recipe = { {"default:copper_ingot", "group:stick", "default:copper_ingot"}, {"default:copper_ingot", "group:stick", "default:copper_ingot"}, {"default:copper_ingot", "group:stick", "default:copper_ingot"}, } }) minetest.register_craft({ type = "shapeless", output = "carts:rail_power", recipe = {"group:rail", "default:mese_crystal_fragment"}, }) minetest.register_craft({ type = "shapeless", output = "carts:rail_brake", recipe = {"group:rail", "default:coal_lump"}, }) minetest.register_craft({ type = "shapeless", output = "carts:rail_tour", recipe = {"group:rail", "default:clay_lump"}, }) minetest.register_alias("carts:powerrail", "carts:rail_power") minetest.register_alias("carts:power_rail", "carts:rail_power") minetest.register_alias("carts:brakerail", "carts:rail_brake") minetest.register_alias("carts:brake_rail", "carts:rail_power") minetest.register_alias("carts:tourrail", "carts:rail_tour") if minetest.setting_getbool("log_mods") then minetest.log("action", "Carbone: [carts] loaded.") end -- temporary minetest.register_abm({ nodes = {"group:rail"}, func = function(pos) local name = minetest.get_node(pos).name minetest.remove_node(pos) minetest.place_node(pos,{name = name}) end })