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
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
})
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()
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
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
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
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
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
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
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
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
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
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
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)