]> git.lizzy.rs Git - Crafter.git/blobdiff - mods/minecart/init.lua
Add in lag exception for minecarts
[Crafter.git] / mods / minecart / init.lua
index c42862ab3d178996ae44169925a02358617c35f2..a989390bd26ca021ac58923519246932105a50b5 100644 (file)
@@ -1,5 +1,8 @@
 local pool = {}
 
+local player_pool = {}
+
+
 local dirs = {
        {x= 1,y= 0,z= 0},
        {x=-1,y= 0,z= 0},
@@ -20,9 +23,33 @@ local dirs = {
        {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
@@ -31,6 +58,21 @@ local function data_injection(pos,data)
        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 = {}
@@ -46,21 +88,21 @@ end
 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
@@ -70,116 +112,296 @@ end
 
 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
@@ -212,12 +434,6 @@ minecart.initial_properties = {
        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)
@@ -307,7 +523,6 @@ minetest.register_lbm({
        run_at_every_load = true,
        action = function(pos)
                data_injection(pos,true)
-               print("buildin dat cash")
        end,
 })
 
@@ -319,3 +534,46 @@ minetest.register_craft({
                {"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,
+})