diff --git a/README.txt b/README.txt index 58673ce..94b6fdd 100644 --- a/README.txt +++ b/README.txt @@ -1,6 +1,19 @@ Minetest 0.4 mod: carts ======================= by PilzAdam +This version is modified by Kilarin (Donald Hines), all changes CC-0 +modifications include: + New Controls:LEFT or RIGHT to switch track at junction + DOWN for hand break + JUMP lock the users view to the view of the cart + SNEAK unlock the users view from the cart + Touring Rails: Try to maintain a speed of 4.5 + Chat notification of controls when cart is placed + Track rail count in debug.txt + punch by driver patch from spillz + get_voxel when hit ignore patch by minermoder27 + searches further up and down for rail when cart falls off rails in order to + avoid cart getting stuck above or below rails. License of source code: ----------------------- diff --git a/functions.lua b/functions.lua index 8a7da47..685257b 100644 --- a/functions.lua +++ b/functions.lua @@ -25,24 +25,44 @@ end function cart_func:is_rail(p) local nn = minetest.env:get_node(p).name + if nn == "ignore" then + nn=cart_func:get_content_voxel(p) + print("carts: is_rail hit ignore, trying again with get_content: now nn=",nn," group rail=", minetest.get_item_group(nn, "rail")," p="..cart_func:pos_to_string(p)) + end return minetest.get_item_group(nn, "rail") ~= 0 end +--dir is a vector that indicates the direction to the rail to be checked. +--so, for example, pos={10,20,30} dir={-1,0,0} will check for rail pos {9,20,30} +function cart_func:check_rail_in_direction(pos, dir) + local p = cart_func.v3:add(pos, dir) + if cart_func:is_rail(p) then + return true + else + return false + end +end -- cart:check_rail_in_direction + + function cart_func:is_int(z) z = math.abs(z) return math.abs(math.floor(z+0.5)-z) <= 0.1 end + cart_func.v3 = {} + function cart_func.v3:add(v1, v2) return {x=v1.x+v2.x, y=v1.y+v2.y, z=v1.z+v2.z} end + function cart_func.v3:copy(v) return {x=v.x, y=v.y, z=v.z} end + function cart_func.v3:round(v) return { x = math.floor(v.x+0.5), @@ -51,6 +71,41 @@ function cart_func.v3:round(v) } end + function cart_func.v3:equal(v1, v2) return v1.x == v2.x and v1.y == v2.y and v1.z == v2.z end + + +--by minermoder27, used by is_rail ONLY when it gets "ignore" +function cart_func:get_content_voxel(pos) + local t1 = os.clock() + local vm = minetest.get_voxel_manip() + local pos1, pos2 = vm:read_from_map(vector.add(pos, {x=-1,y=-1,z=-1}),vector.add(pos, {x=1,y=1,z=1})) + local a = VoxelArea:new{ + MinEdge=pos1, + MaxEdge=pos2, + } + + local data = vm:get_data() + local vi = a:indexp(pos) + local railid = data[vi] + local real_name = minetest.get_name_from_content_id(railid) + print(string.format("voxel-ing rail: elapsed time: %.2fms", (os.clock() - t1) * 1000)) + return real_name +end --get_content_voxel + + +function cart_func:round_digits(num,digits) + return math.floor(num*(10^digits)+0.5)/(10^digits) +end --round_digits + + +--because built in pos_to_string doesn't handle nil +--this also rounds to 2 digits +function cart_func:pos_to_string(pos) + if pos==nil then return "(nil)" + else return "(" .. cart_func:round_digits(pos.x,2) .. "," .. cart_func:round_digits(pos.y,2) .. "," .. cart_func:round_digits(pos.z,2) .. ")" + end --pos==nill +end --pos_to_string + diff --git a/init.lua b/init.lua index 03bc1a3..661aa44 100644 --- a/init.lua +++ b/init.lua @@ -12,15 +12,27 @@ local cart = { mesh = "cart.x", visual_size = {x=1, y=1}, textures = {"cart.png"}, - + driver = nil, velocity = {x=0, y=0, z=0}, old_pos = nil, old_velocity = nil, pre_stop_dir = nil, - MAX_V = 8, -- Limit of the velocity + MAX_V = 8, -- Limit of the velocity -- + TARGET_TOUR_V = 4.5, -- target touring velocity + railcount=0, --stores how many rails a cart has passed over + --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) + ignorekeypos=nil, -- so will not keep turning when pressing an arrow on track fork + lockyaw=false, -- is player view locked to cart. + yawtarget=nil, -- target yaw for player view when locked to cart + YAW_STEP=math.pi/12 -- step to turn player view when view locked to cart + --smaller YAW_STEP makes for smoother camera turning. BUT, takes much longer and can fall behind } + function cart:on_rightclick(clicker) if not clicker or not clicker:is_player() then return @@ -34,6 +46,7 @@ function cart:on_rightclick(clicker) end end + function cart:on_activate(staticdata, dtime_s) self.object:set_armor_groups({immortal=1}) if staticdata then @@ -49,6 +62,7 @@ function cart:on_activate(staticdata, dtime_s) self.old_velocity = self.velocity end + function cart:get_staticdata() return minetest.serialize({ velocity = self.velocity, @@ -56,13 +70,15 @@ function cart:get_staticdata() }) 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 + print("cart: end pos="..cart_func:pos_to_string(vector.round(self.object:getpos())).." railcount="..self.railcount) self.object:remove() local inv = puncher:get_inventory() if minetest.setting_getbool("creative_mode") then @@ -73,13 +89,28 @@ function cart:on_punch(puncher, time_from_last_punch, tool_capabilities, directi inv:add_item("main", "carts:cart") end return - end - - if puncher == self.driver then + end + + --patch by spillz to allow punching a cart you are riding. + --if puncher == self.driver then + 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 @@ -98,143 +129,189 @@ function cart:on_punch(puncher, time_from_last_punch, tool_capabilities, directi end end + -- Returns the direction as a unit vector function cart:get_rail_direction(pos, dir) - local d = cart_func.v3:copy(dir) - - -- Check front - d.y = 0 - local p = cart_func.v3:add(cart_func.v3:copy(pos), d) - if cart_func:is_rail(p) then - return d - end - - -- Check downhill - d.y = -1 - p = cart_func.v3:add(cart_func.v3:copy(pos), d) - if cart_func:is_rail(p) then - return d + --print("get_rail_direction top pos="..cart_func:pos_to_string(pos).." dir="..cart_func: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 + + 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 - - -- Check uphill - d.y = 1 - p = cart_func.v3:add(cart_func.v3:copy(pos), d) - if cart_func:is_rail(p) then - return d + + local ctrl=nil + if self.driver and not ignorekeys then + ctrl = self.driver:get_player_control() end - d.y = 0 - - -- Check left and right - local view_dir - local other_dir - local a - - if d.x == 0 and d.z ~= 0 then - view_dir = "z" - other_dir = "x" - if d.z < 0 then - a = {1, -1} - else - a = {-1, 1} + + --if player is pressing left or right arrows, check left or right first + 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 d.z == 0 and d.x ~= 0 then - view_dir = "x" - other_dir = "z" - if d.x > 0 then - a = {1, -1} - else - a = {-1, 1} + 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 + + --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 - - d[view_dir] = 0 - d[other_dir] = a[1] - p = cart_func.v3:add(cart_func.v3:copy(pos), d) - if cart_func:is_rail(p) then - return d - end - d.y = -1 - p = cart_func.v3:add(cart_func.v3:copy(pos), d) - if cart_func:is_rail(p) then - return d - end - d.y = 0 - d[other_dir] = a[2] - p = cart_func.v3:add(cart_func.v3:copy(pos), d) - if cart_func:is_rail(p) then - return d - end - d.y = -1 - p = cart_func.v3:add(cart_func.v3:copy(pos), d) - if cart_func:is_rail(p) then - return d - end - d.y = 0 - - return {x=0, y=0, z=0} -end + 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}) 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 - + + --if cart_func.v3:equal(velocity, {x=0, y=0, z=0}) then + if cart_func.v3:equal(velocity, {x=0, y=0, z=0}) and not cart_func:is_rail(p) then + + --this loop tries to find the rail if we lost it moving up or down. + --it is almost always within 2 nodes, but SOMETIMES 3 or more away, and if you + --dont check those, then the cart gets stuck above or below the rail. + local upordown=1 + if vel.y<0 then upordown=-1 end + for i=1,2 do + local deltay=0 + while deltay<6 do + deltay=deltay+1 + if cart_func:is_rail(cart_func.v3:add(p, {x=0, y=deltay*upordown, z=0})) then + p = cart_func.v3:add(p, {x=0, y=deltay*upordown, z=0}) + --print("cart: off rails"..i.." old_pos="..cart_func:pos_to_string(self.old_pos).." old_vel="..cart_func:pos_to_string(old_velocity).." pos in="..cart_func:pos_to_string(pos).." vel in="..cart_func:pos_to_string(vel).." dir="..cart_func:pos_to_string(dir)) + --print(" v="..v.." velocity="..cart_func:pos_to_string(velocity).." rail found at p="..cart_func:pos_to_string(p).." deltay="..deltay*upordown) + return self:calc_rail_direction(p,vel) + end --if + end --while + upordown=-upordown --if that direction failed, try the other direction. + end --for + + --if we got through all of that + --print("cart: off rails old_pos="..cart_func:pos_to_string(self.old_pos).." old_vel="..cart_func:pos_to_string(old_velocity).." pos in="..cart_func:pos_to_string(pos).." vel in="..cart_func:pos_to_string(vel).." dir="..cart_func:pos_to_string(dir)) + --print(" v="..v.." velocity="..cart_func:pos_to_string(velocity)) return {x=0, y=0, z=0}, p - end - + end --hack + if not cart_func.v3:equal(dir, dir_old) then return velocity, cart_func.v3:round(p) end - + end return velocity, p -end +end --calc_rail_direction + function cart:on_step(dtime) - + local pos = self.object:getpos() local dir = cart_func:velocity_to_dir(self.velocity) - + --minetest.chat_send_all("cart: on_step top pos="..cart_func:pos_to_string(pos).." dir="..cart_func:pos_to_string(dir).." vel="..cart_func:pos_to_string(self.velocity)) + --print("cart: on_step top pos="..cart_func:pos_to_string(pos).." dir="..cart_func:pos_to_string(dir).." vel="..cart_func:pos_to_string(self.velocity)) + + --count rails to put in debug.txt + 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.env:get_meta(pos):get_string("cart_acceleration")) + --local railtype="" + --if a and a>0 then railtype="power" end + --minetest.chat_send_all("-- cart pos="..cart_func:pos_to_string(vector.round(pos)).." railcount="..self.railcount.." vel="..cart_func:pos_to_string(self.velocity).." "..railtype) + end + end + + --check to see if we should lock or unlock player view to cart + local ctrl=nil + if self.driver then + ctrl = self.driver:get_player_control() + --if user pressed jump while driving cart, and lockyaw not set, then lock view to cart + 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(),"cart: player view locked to cart, hit SNEAK to unlock") + --if user pressed sneak while driving cart, and lockyaw is set, then unlock view from cart + elseif ctrl and ctrl.sneak and self.lockyaw then + self.lockyaw=false + minetest.chat_send_player(self.driver:get_player_name(),"cart: player view NOT locked to cart, hit 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 @@ -276,7 +353,7 @@ function cart:on_step(dtime) end end end - + self.velocity = {x=0, y=0, z=0} self.object:setvelocity(self.velocity) self.old_velocity = self.velocity @@ -284,11 +361,11 @@ function cart:on_step(dtime) 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 @@ -326,17 +403,71 @@ function cart:on_step(dtime) 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.env:get_meta(pos):get_string("cart_acceleration")) if not a then - a = 0 + a = 0 end + + --touring rail adjustments + --this needs to be redone, if I moved this to AFTER the gravity section, + --then there would be no need for the messy logic to adjust for gravity here. + local t = tonumber(minetest.env: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 + --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 + 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 (hand break) + 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 hand break + 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), @@ -355,14 +486,14 @@ function cart:on_step(dtime) 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 + 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 @@ -376,7 +507,7 @@ function cart:on_step(dtime) 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 = { @@ -384,7 +515,7 @@ function cart:on_step(dtime) 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) @@ -393,7 +524,7 @@ function cart:on_step(dtime) 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) @@ -404,12 +535,13 @@ function cart:on_step(dtime) 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 @@ -419,7 +551,33 @@ function cart:on_step(dtime) elseif dir.z > 0 then self.object:setyaw(0) end - + + local newyaw=self.object:getyaw() + --now if driver and lockyaw, change drivers viewing direction. + if self.driver and self.lockyaw then + if oldyaw~=newyaw then + self.yawtarget=newyaw --set new target + 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 + 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 @@ -427,8 +585,9 @@ function cart:on_step(dtime) else self.object:set_animation({x=0, y=0}, 1, 0) end - -end + +end --on_step + minetest.register_entity("carts:cart", cart) @@ -437,19 +596,22 @@ minetest.register_craftitem("carts:cart", { description = "Minecart", 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 - minetest.env:add_entity(pointed_thing.under, "carts:cart") + local obj=minetest.env:add_entity(pointed_thing.under, "carts:cart") + print("cart: begin pos="..cart_func:pos_to_string(vector.round(obj:getpos()))) + minetest.chat_send_player(placer:get_player_name(),"cart: 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, LEFT and RIGHT ARROWS to switch tracks, DOWN ARROW to apply hand break") if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end return itemstack elseif cart_func:is_rail(pointed_thing.above) then minetest.env:add_entity(pointed_thing.above, "carts:cart") + print("cart: begin pos="..cart_func:pos_to_string(self.object:getpos())) if not minetest.setting_getbool("creative_mode") then itemstack:take_item() end @@ -503,19 +665,19 @@ minetest.register_node("carts:powerrail", { fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, groups = {bendy=2,snappy=1,dig_immediate=2,attached_node=1,rail=1,connect_to_raillike=1}, - + after_place_node = function(pos, placer, itemstack) if not mesecon then minetest.env:get_meta(pos):set_string("cart_acceleration", "0.5") end end, - + mesecons = { effector = { action_on = function(pos, node) minetest.env:get_meta(pos):set_string("cart_acceleration", "0.5") end, - + action_off = function(pos, node) minetest.env:get_meta(pos):set_string("cart_acceleration", "0") end, @@ -523,6 +685,7 @@ minetest.register_node("carts:powerrail", { }, }) + minetest.register_node("carts:brakerail", { description = "Brake Rail", drawtype = "raillike", @@ -538,19 +701,19 @@ minetest.register_node("carts:brakerail", { fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, }, groups = {bendy=2,snappy=1,dig_immediate=2,attached_node=1,rail=1,connect_to_raillike=1}, - + after_place_node = function(pos, placer, itemstack) if not mesecon then minetest.env:get_meta(pos):set_string("cart_acceleration", "-0.2") end end, - + mesecons = { effector = { action_on = function(pos, node) minetest.env:get_meta(pos):set_string("cart_acceleration", "-0.2") end, - + action_off = function(pos, node) minetest.env:get_meta(pos):set_string("cart_acceleration", "0") end, @@ -558,6 +721,44 @@ minetest.register_node("carts:brakerail", { }, }) + +minetest.register_node("carts:touringrail", { + 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", + is_ground_content = true, + walkable = false, + selection_box = { + type = "fixed", + -- but how to specify the dimensions for curved and sideways rails? + fixed = {-1/2, -1/2, -1/2, 1/2, -1/2+1/16, 1/2}, + }, + groups = {bendy=2,snappy=1,dig_immediate=2,attached_node=1,rail=1,connect_to_raillike=1}, + + after_place_node = function(pos, placer, itemstack) + if not mesecon then + minetest.env:get_meta(pos):set_string("cart_acceleration", "0.5") + minetest.env:get_meta(pos):set_string("cart_touring_velocity", cart.TARGET_TOUR_V) + end + end, + + mesecons = { + effector = { + action_on = function(pos, node) + minetest.env:get_meta(pos):set_string("cart_acceleration", "0.5") + end, + + action_off = function(pos, node) + minetest.env:get_meta(pos):set_string("cart_acceleration", "0") + end, + }, + }, +}) + + minetest.register_craft({ output = "carts:powerrail 2", recipe = { @@ -567,6 +768,7 @@ minetest.register_craft({ } }) + minetest.register_craft({ output = "carts:powerrail 2", recipe = { @@ -576,6 +778,7 @@ minetest.register_craft({ } }) + minetest.register_craft({ output = "carts:brakerail 2", recipe = { @@ -593,3 +796,23 @@ minetest.register_craft({ {"default:steel_ingot", "default:coal_lump", "default:steel_ingot"}, } }) + + +minetest.register_craft({ + output = "carts:touringrail 7", + recipe = { + {"default:steel_ingot", "default:coal_lump", "default:steel_ingot"}, + {"default:steel_ingot", "default:stick", "default:steel_ingot"}, + {"default:steel_ingot", "default:mese_crystal_fragment", "default:steel_ingot"}, + } +}) + + +minetest.register_craft({ + output = "carts:touringrail 7", + recipe = { + {"default:coal_lump"}, + {"carts:powerrail"}, + {"carts:powerrail"}, + } +}) diff --git a/textures/carts_rail_crossing_tour.png b/textures/carts_rail_crossing_tour.png new file mode 100644 index 0000000..3572256 Binary files /dev/null and b/textures/carts_rail_crossing_tour.png differ diff --git a/textures/carts_rail_curved_tour.png b/textures/carts_rail_curved_tour.png new file mode 100644 index 0000000..fbe1dc2 Binary files /dev/null and b/textures/carts_rail_curved_tour.png differ diff --git a/textures/carts_rail_t_junction_tour.png b/textures/carts_rail_t_junction_tour.png new file mode 100644 index 0000000..67f1cca Binary files /dev/null and b/textures/carts_rail_t_junction_tour.png differ diff --git a/textures/carts_rail_tour.png b/textures/carts_rail_tour.png new file mode 100644 index 0000000..49dd1f9 Binary files /dev/null and b/textures/carts_rail_tour.png differ