diff --git a/mods/carts/cart_entity.lua b/mods/carts/cart_entity.lua index 434ea943..38337dbc 100644 --- a/mods/carts/cart_entity.lua +++ b/mods/carts/cart_entity.lua @@ -27,6 +27,10 @@ function cart_entity:on_rightclick(clicker) elseif not self.driver then self.driver = player_name carts:manage_attachment(clicker, self.object) + + -- player_api does not update the animation + -- when the player is attached, reset to default animation + player_api.set_animation(clicker, "stand") end end @@ -36,7 +40,7 @@ function cart_entity:on_activate(staticdata, dtime_s) return end local data = minetest.deserialize(staticdata) - if not data or type(data) ~= "table" then + if type(data) ~= "table" then return end self.railtype = data.railtype @@ -52,6 +56,13 @@ function cart_entity:get_staticdata() }) end +-- 0.5.x and later: When the driver leaves +function cart_entity:on_detach_child(child) + if child and child:get_player_name() == self.driver then + self.driver = nil + end +end + function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities, direction) local pos = self.object:get_pos() local vel = self.object:get_velocity() @@ -82,7 +93,7 @@ function cart_entity:on_punch(puncher, time_from_last_punch, tool_capabilities, local player = minetest.get_player_by_name(self.driver) carts:manage_attachment(player, nil) end - for _,obj_ in ipairs(self.attached_items) do + for _, obj_ in ipairs(self.attached_items) do if obj_ then obj_:set_detach() end @@ -165,6 +176,7 @@ local function get_railparams(pos) return carts.railparams[node.name] or {} end +local v3_len = vector.length local function rail_on_step(self, dtime) local vel = self.object:get_velocity() if self.punched then @@ -201,17 +213,23 @@ local function rail_on_step(self, dtime) local stop_wiggle = false if self.old_pos and same_dir then - -- Detection for "skipping" nodes - local found_path = carts:pathfinder( - pos, self.old_pos, self.old_dir, ctrl, self.old_switch, self.railtype + -- Detection for "skipping" nodes (perhaps use average dtime?) + -- It's sophisticated enough to take the acceleration in account + local acc = self.object:get_acceleration() + local distance = dtime * (v3_len(vel) + 0.5 * dtime * v3_len(acc)) + + local new_pos, new_dir = carts:pathfinder( + pos, self.old_pos, self.old_dir, distance, ctrl, + self.old_switch, self.railtype ) - if not found_path then - -- No rail found: reset back to the expected position - pos = vector.new(self.old_pos) + if new_pos then + -- No rail found: set to the expected position + pos = new_pos update.pos = true + cart_dir = new_dir end - elseif self.old_pos and cart_dir.y ~= -1 and not self.punched then + elseif self.old_pos and self.old_dir.y ~= 1 and not self.punched then -- Stop wiggle stop_wiggle = true end @@ -223,12 +241,14 @@ local function rail_on_step(self, dtime) local dir, switch_keys = carts:get_rail_direction( pos, cart_dir, ctrl, self.old_switch, self.railtype ) + local dir_changed = not vector.equals(dir, self.old_dir) local new_acc = {x=0, y=0, z=0} if stop_wiggle or vector.equals(dir, {x=0, y=0, z=0}) then vel = {x = 0, y = 0, z = 0} local pos_r = vector.round(pos) - if not carts:is_rail(pos_r, self.railtype) then + if not carts:is_rail(pos_r, self.railtype) + and self.old_pos then pos = self.old_pos elseif not stop_wiggle then pos = pos_r @@ -239,7 +259,7 @@ local function rail_on_step(self, dtime) update.vel = true else -- Direction change detected - if not vector.equals(dir, self.old_dir) then + if dir_changed then vel = vector.multiply(dir, math.abs(vel.x + vel.z)) update.vel = true if dir.y ~= self.old_dir.y then @@ -291,7 +311,7 @@ local function rail_on_step(self, dtime) end self.object:set_acceleration(new_acc) - self.old_pos = vector.new(pos) + self.old_pos = vector.round(pos) if not vector.equals(dir, {x=0, y=0, z=0}) and not stop_wiggle then self.old_dir = vector.new(dir) end @@ -338,9 +358,15 @@ local function rail_on_step(self, dtime) end self.object:set_animation(anim, 1, 0) - self.object:set_velocity(vel) + if update.vel then + self.object:set_velocity(vel) + end if update.pos then - self.object:set_pos(pos) + if dir_changed then + self.object:set_pos(pos) + else + self.object:move_to(pos) + end end -- call event handler diff --git a/mods/carts/functions.lua b/mods/carts/functions.lua index 8408cc1a..a54b5948 100644 --- a/mods/carts/functions.lua +++ b/mods/carts/functions.lua @@ -99,6 +99,16 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype) right.z = -dir.x end + local straight_priority = ctrl and dir.y ~= 0 + + -- Normal, to disallow rail switching up- & downhill + if straight_priority then + cur = self:check_front_up_down(pos, dir, true, railtype) + if cur then + return cur + end + end + if ctrl then if old_switch == 1 then left_check = false @@ -106,14 +116,14 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype) right_check = false end if ctrl.left and left_check then - cur = carts:check_front_up_down(pos, left, false, railtype) + cur = self:check_front_up_down(pos, left, false, railtype) if cur then return cur, 1 end left_check = false end if ctrl.right and right_check then - cur = carts:check_front_up_down(pos, right, false, railtype) + cur = self:check_front_up_down(pos, right, false, railtype) if cur then return cur, 2 end @@ -122,9 +132,11 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype) end -- Normal - cur = carts:check_front_up_down(pos, dir, true, railtype) - if cur then - return cur + if not straight_priority then + cur = self:check_front_up_down(pos, dir, true, railtype) + if cur then + return cur + end end -- Left, if not already checked @@ -158,33 +170,37 @@ function carts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype) return {x=0, y=0, z=0} end -function carts:pathfinder(pos_, old_pos, old_dir, ctrl, pf_switch, railtype) - if vector.equals(old_pos, pos_) then - return true - end +function carts:pathfinder(pos_, old_pos, old_dir, distance, ctrl, + pf_switch, railtype) local pos = vector.round(pos_) + if vector.equals(old_pos, pos) then + return + end + local pf_pos = vector.round(old_pos) local pf_dir = vector.new(old_dir) + distance = math.min(carts.path_distance_max, + math.floor(distance + 1)) - for i = 1, 3 do - pf_dir, pf_switch = carts:get_rail_direction( - pf_pos, pf_dir, ctrl, pf_switch, railtype) + for i = 1, distance do + pf_dir, pf_switch = self:get_rail_direction( + pf_pos, pf_dir, ctrl, pf_switch or 0, railtype) if vector.equals(pf_dir, {x=0, y=0, z=0}) then -- No way forwards - return false + return pf_pos, pf_dir end pf_pos = vector.add(pf_pos, pf_dir) if vector.equals(pf_pos, pos) then -- Success! Cart moved on correctly - return true + return end end - -- Cart not found - return false + -- Not found. Put cart to predicted position + return pf_pos, pf_dir end function carts:register_rail(name, def_overwrite, railparams) diff --git a/mods/carts/init.lua b/mods/carts/init.lua index b2ba5f37..fe45303a 100644 --- a/mods/carts/init.lua +++ b/mods/carts/init.lua @@ -7,6 +7,8 @@ carts.railparams = {} carts.speed_max = 7 -- Set to -1 to disable punching the cart from inside (min = -1) carts.punch_speed_max = 5 +-- Maximal distance for the path correction (for dtime peaks) +carts.path_distance_max = 3 dofile(carts.modpath.."/functions.lua")