local pool = {}
+local player_pool = {}
+
+
local dirs = {
{x= 1,y= 0,z= 0},
{x=-1,y= 0,z= 0},
{x= 0,y=-1,z=-1},
}
-local axis_order = {
+local function coupling_particles(pos,truth)
+ local color = "red"
+ if truth then
+ color = "green"
+ end
+
+ minetest.add_particlespawner({
+ amount = 15,
+ time = 0.001,
+ minpos = pos,
+ maxpos = pos,
+ minvel = vector.new(-10,-10,-10),
+ maxvel = vector.new(10,10,10),
+ minacc = {x=0, y=0, z=0},
+ maxacc = {x=0, y=0, z=0},
+ minexptime = 1.1,
+ maxexptime = 1.5,
+ minsize = 1,
+ maxsize = 2,
+ collisiondetection = false,
+ collision_removal = false,
+ vertical = false,
+ texture = "couple_particle.png^[colorize:"..color..":200",
+ glow = 14,
+ })
+end
-}
local function data_injection(pos,data)
if data then
pool[minetest.hash_node_position(pos)] = true
end
end
+local function speed_limiter(self,speed)
+ local test = self.object:get_velocity()--vector.multiply(self.velocity,new_vel)
+
+ if test.x > speed then
+ test.x = speed
+ elseif test.x < -speed then
+ test.x = -speed
+ end
+ if test.z > speed then
+ test.z = speed
+ elseif test.z < -speed then
+ test.z = -speed
+ end
+ self.object:set_velocity(test)
+end
local function create_axis(pos)
local possible_dirs = {}
local function collision_detect(self)
if not self.axis_lock then return end
local pos = self.object:get_pos()
-
for _,object in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
if object:is_player() then
local pos2 = object:get_pos()
if self.axis_lock == "x" then
- local velocity = (1-vector.distance(vector.new(pos.x,0,0),vector.new(pos2.x,0,0)))/10
+
+ local velocity = (1-vector.distance(vector.new(pos.x,0,0),vector.new(pos2.x,0,0)))*5
local dir = vector.direction(vector.new(pos2.x,0,0),vector.new(pos.x,0,0))
- --self.object:add_velocity(vector.multiply(dir,velocity))
- self.velocity = vector.multiply(dir,velocity)
+ local new_vel = vector.multiply(dir,velocity)
+ self.object:add_velocity(new_vel)
self.dir = dir
elseif self.axis_lock == "z" then
- local velocity = (1-vector.distance(vector.new(0,0,pos.z),vector.new(0,0,pos2.z)))/10
+ local velocity = (1-vector.distance(vector.new(0,0,pos.z),vector.new(0,0,pos2.z)))*5
local dir = vector.direction(vector.new(0,0,pos2.z),vector.new(0,0,pos.z))
- --self.object:add_velocity(vector.multiply(dir,velocity))
- self.velocity = vector.multiply(dir,velocity)
+ local new_vel = vector.multiply(dir,velocity)
+ self.object:add_velocity(new_vel)
self.dir = dir
end
return
local function direction_snap(self)
local dir = self.dir
+ local pitch = 0
+ if dir.y == 1 then pitch = math.pi/4 end
+ if dir.y == -1 then pitch = -math.pi/4 end
local yaw = minetest.dir_to_yaw(dir)
- self.object:set_rotation(vector.new(0,yaw,0))
+ self.object:set_rotation(vector.new(pitch,yaw,0))
end
local function turn_snap(pos,self,dir,dir2)
- if dir.x ~= 0 and dir2.z ~= 0 then
- --local inertia = math.abs(self.object:get_velocity().x)
- local inertia = math.abs(self.velocity.x)
- --self.object:set_velocity(vector.multiply(dir2,inertia))
-
- self.velocity = vector.multiply(dir2,inertia)
- self.dir = dir2
- self.axis_lock = "z"
- self.object:set_pos(pos)
- direction_snap(self)
- return(true)
- elseif dir.z ~= 0 and dir2.x ~= 0 then
- --local inertia = math.abs(self.object:get_velocity().z)
- --print(dump(self.velocity))
- local inertia = math.abs(self.velocity.z)
- --self.object:set_velocity(vector.multiply(dir2,inertia))
-
- self.velocity = vector.multiply(dir2,inertia)
+ if self.axis_lock == "x" then
+ if dir.x ~= 0 and dir2.z ~= 0 then
+ local velocity = self.object:get_velocity()
+ local inertia = math.abs(velocity.x)
+ self.object:set_velocity(vector.multiply(dir2,inertia))
+ self.dir = dir2
+ self.axis_lock = "z"
+ self.object:set_pos(pos)
+ direction_snap(self)
+ return(true)
+ end
+ end
+ if self.axis_lock == "z" then
+ if dir.z ~= 0 and dir2.x ~= 0 then
+ local velocity = self.object:get_velocity()
+ local inertia = math.abs(velocity.z)
+ self.object:set_velocity(vector.multiply(dir2,inertia))
+ self.dir = dir2
+ self.axis_lock = "x"
+ self.object:set_pos(pos)
+ direction_snap(self)
+ return(true)
+ end
+ end
+ return(false)
+end
+
+local function climb_snap(pos,self,dir,dir2)
+ if self.axis_lock == "x" then
+ if dir.x == dir2.x and dir2.y ~= 0 then
+ local velocity = self.object:get_velocity()
+ local inertia = math.abs(velocity.x)
+ self.object:set_velocity(vector.multiply(dir2,inertia))
+ self.dir = dir2
+ self.axis_lock = "x"
+ self.object:set_pos(pos)
+ direction_snap(self)
+ return(true)
+ end
+ end
+ if self.axis_lock == "z" then
+ if dir.z == dir2.z and dir2.y ~= 0 then
+ local velocity = self.object:get_velocity()
+ local inertia = math.abs(velocity.z)
+ self.object:set_velocity(vector.multiply(dir2,inertia))
+ self.dir = dir2
+ self.axis_lock = "z"
+ self.object:set_pos(pos)
+ direction_snap(self)
+ return(true)
+ end
+ end
+ return(false)
+end
+
+local function straight_snap(pos,self,dir)
+ if self.axis_lock == "x" then
+ if dir.x ~= 0 and pool[minetest.hash_node_position(vector.add(pos,vector.new(dir.x,0,0)))] then
+ local velocity = self.object:get_velocity()
+ self.object:set_velocity(vector.new(velocity.x,0,0))
+ self.dir = vector.new(dir.x,0,0)
+ self.axis_lock = "x"
+ self.object:set_pos(pos)
+ direction_snap(self)
+ return(true)
+ end
+ end
+ if self.axis_lock == "z" then
+ if dir.z ~= 0 and pool[minetest.hash_node_position(vector.add(pos,vector.new(0,0,dir.z)))] then
+ local velocity = self.object:get_velocity()
+ self.object:set_velocity(vector.new(0,0,velocity.z))
+ self.dir = vector.new(0,0,dir.z)
+ self.axis_lock = "z"
+ self.object:set_pos(pos)
+ direction_snap(self)
+ return(true)
+ end
+ end
+ return(false)
+end
+
+
+local function coupling_logic(self)
+
+ if not self.axis_lock then return end
+
+ if not self.coupler1 then return end
- self.dir = dir2
- self.axis_lock = "x"
- self.object:set_pos(pos)
- direction_snap(self)
- return(true)
+ if self.dir.y ~= 0 then return end
+
+ local pos = self.object:get_pos()
+
+ local pos2 = self.coupler1:get_pos()
+
+ if self.axis_lock == "x" then
+ local velocity_real = self.object:get_velocity()
+ local distance = vector.distance(pos,pos2)
+ local new_vel = vector.new(0,0,0)
+ if distance > 1.5 then
+ local velocity = (distance-1)
+ local dir = vector.direction(vector.new(pos.x,0,0),vector.new(pos2.x,0,0))
+ self.dir = dir
+ new_vel = vector.multiply(dir,velocity)
+ else
+ new_vel = vector.multiply(velocity_real,-1)
+ end
+ self.object:add_velocity(new_vel)
+ elseif self.axis_lock == "z" then
+ local velocity_real = self.object:get_velocity()
+ local distance = vector.distance(pos,pos2)
+ local new_vel = vector.new(0,0,0)
+ if distance > 1.5 then
+ local velocity = (distance-1)
+ local dir = vector.direction(vector.new(0,0,pos.z),vector.new(0,0,pos2.z))
+ self.dir = dir
+ new_vel = vector.multiply(dir,velocity)
+ else
+ new_vel = vector.multiply(velocity_real,-1)
+ end
+ self.object:add_velocity(new_vel)
end
+
+ return
end
+
local function rail_brain(self,pos)
- if not self.dir then return end
- --if self.dir then print(dump(self.dir)) end
+
+ if not self.dir then self.dir = vector.new(0,0,0) end
local pos2 = self.object:get_pos()
local dir = self.dir
- local triggered = false
+ speed_limiter(self,6)
- if dir.x < 0 and pos2.x < pos.x then
- triggered = true
- elseif dir.x > 0 and pos2.x > pos.x then
- triggered = true
- elseif dir.z < 0 and pos2.z < pos.z then
- triggered = true
- elseif dir.z > 0 and pos2.z > pos.z then
- triggered = true
- end
+ if not pool[minetest.hash_node_position(vector.add(pos,dir))] then
+
+ if straight_snap(pos,self,dir) then
+ return
+ end
- --print(dump(dir))
- if triggered and not pool[minetest.hash_node_position(vector.add(pos,dir))] then
local possible_dirs = create_axis(pos)
+
if table.getn(possible_dirs) == 0 then
- --print("train fails")
- --stop slow down become physical, something
+ --stop slow down become physical
else
for _,dir2 in pairs(possible_dirs) do
if turn_snap(pos,self,dir,dir2) then
return
end
+ if climb_snap(pos,self,dir,dir2) then
+ return
+ end
end
end
+ else
+ coupling_logic(self)
end
-end
-
-
+end
local minecart = {}
minecart.on_step = function(self,dtime)
- local float_pos = self.object:get_pos()
- local pos = vector.round(float_pos)
-
- if self.velocity then
- local new_vel = dtime/0.01
- print(new_vel)
- self.object:move_to(vector.add(float_pos,vector.multiply(self.velocity,new_vel)))
- end
-
- --stop minecarts from derailing when going super fast
- if self.old_pos and vector.distance(float_pos,self.old_pos) > 0.5 then
- self.object:move_to(self.old_pos)
- float_pos = self.object:get_pos()
- pos = vector.round(self.old_pos)
+ if dtime > 0.1 then
+ self.object:set_pos(self.old_pos)
end
-
+ local pos = vector.round(self.object:get_pos())
if not self.axis_lock then
local possible_dirs = create_axis(pos)
for _,dir in pairs(possible_dirs) do
if dir.x ~=0 then
self.axis_lock = "x"
+ self.dir = dir
+ direction_snap(self)
break
elseif dir.z ~= 0 then
self.axis_lock = "z"
+ self.dir = dir
+ direction_snap(self)
break
end
end
else
- collision_detect(self)
rail_brain(self,pos)
+ --collision_detect(self)
end
- self.old_pos = float_pos
+ self.old_pos = self.object:get_pos()
end
+
+minecart.on_punch = function(self, puncher)
+ if not puncher:get_wielded_item():get_name() == "minecart:wrench" then
+ return
+ end
+ if self.furnace then
+ self.object:set_velocity(vector.multiply(self.dir,6))
+ minetest.add_particlespawner({
+ amount = 30,
+ time = 0,
+ minpos = vector.new(0,0.5,0),
+ maxpos = vector.new(0,0.5,0),
+ minvel = vector.new(0,0,0),
+ maxvel = vector.new(0,0,0),
+ minacc = {x=0, y=3, z=0},
+ maxacc = {x=0, y=5, z=0},
+ minexptime = 1.1,
+ maxexptime = 1.5,
+ minsize = 1,
+ maxsize = 2,
+ collisiondetection = false,
+ collision_removal = false,
+ vertical = false,
+ texture = "smoke.png",
+ attached = self.object
+ })
+ end
+
+end
+
+
minecart.on_rightclick = function(self,clicker)
+ local pos = self.object:get_pos()
+ if clicker:get_wielded_item():get_name() == "utility:furnace" then
+ local obj = minetest.add_entity(pos, "minecart:furnace")
+ obj:set_attach(self.object,"",vector.new(0,0,0),vector.new(0,0,0))
+ minetest.sound_play("wrench",{
+ object = self.object,
+ gain = 1.0,
+ max_hear_distance = 64,
+ })
+ coupling_particles(pos,true)
+ self.furnace = true
+ return
+ end
+
+ if not clicker:get_wielded_item():get_name() == "minecart:wrench" then
+ return
+ end
+
+ local name = clicker:get_player_name()
+ if not pool[name] then
+ if not self.coupler2 then
+ pool[name] = self.object
+ minetest.sound_play("wrench",{
+ object = self.object,
+ gain = 1.0,
+ max_hear_distance = 64,
+ })
+ coupling_particles(pos,true)
+ else
+ minetest.sound_play("wrench",{
+ object = self.object,
+ gain = 1.0,
+ max_hear_distance = 64,
+ pitch = 0.7,
+ })
+ coupling_particles(pos,false)
+ end
+ else
+ if not (pool[name]:get_luaentity().coupler1 and pool[name]:get_luaentity().coupler1 == self.object or self.coupler2) then
+ self.coupler1 = pool[name]
+ pool[name]:get_luaentity().coupler2 = self.object
+ minetest.sound_play("wrench",{
+ object = self.object,
+ gain = 1.0,
+ max_hear_distance = 64,
+ })
+ coupling_particles(pos,true)
+ else
+ minetest.sound_play("wrench",{
+ object = self.object,
+ gain = 1.0,
+ max_hear_distance = 64,
+ pitch = 0.7,
+ })
+ coupling_particles(pos,false)
+ end
+ pool[name] = nil
+ end
end
--get old data
textures = {"minecart.png"},
}
-
-minecart.on_punch = function(self,puncher, time_from_last_punch, tool_capabilities, dir, damage)
- --local obj = minetest.add_item(self.object:getpos(), "minecart:minecart")
- --self.object:remove()
-end
-
minetest.register_entity("minecart:minecart", minecart)
run_at_every_load = true,
action = function(pos)
data_injection(pos,true)
- print("buildin dat cash")
end,
})
{"main:iron","","main:iron"}
}
})
+
+
+minetest.register_food("minecart:wrench",{
+ description = "Train Wrench",
+ texture = "wrench.png",
+})
+
+minetest.register_craft({
+ output = "minecart:wrench",
+ recipe = {
+ {"main:iron", "", "main:iron"},
+ {"main:iron", "main:lapis", "main:iron"},
+ {"", "main:lapis", ""}
+ }
+})
+
+
+
+minetest.register_entity("minecart:furnace", {
+ initial_properties = {
+ visual = "wielditem",
+ visual_size = {x = 0.6, y = 0.6},
+ textures = {},
+ physical = true,
+ is_visible = false,
+ collide_with_objects = false,
+ pointable=false,
+ collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
+ },
+ set_node = function(self)
+ self.object:set_properties({
+ is_visible = true,
+ textures = {"utility:furnace"},
+ })
+ end,
+
+
+ on_activate = function(self, staticdata)
+ self.object:set_armor_groups({immortal = 1})
+
+ self:set_node()
+ end,
+})