forked from VoxeLibre/VoxeLibre
Change to vector.new from {x=...}, relocate movement code to own function for future changes
This commit is contained in:
parent
744b47088b
commit
4a42157e66
|
@ -10,9 +10,17 @@ end
|
|||
|
||||
function mcl_minecarts:velocity_to_dir(v)
|
||||
if math.abs(v.x) > math.abs(v.z) then
|
||||
return {x=mcl_minecarts:get_sign(v.x), y=mcl_minecarts:get_sign(v.y), z=0}
|
||||
return vector.new(
|
||||
mcl_minecarts:get_sign(v.x),
|
||||
mcl_minecarts:get_sign(v.y),
|
||||
0
|
||||
)
|
||||
else
|
||||
return {x=0, y=mcl_minecarts:get_sign(v.y), z=mcl_minecarts:get_sign(v.z)}
|
||||
return vector.new(
|
||||
0,
|
||||
mcl_minecarts:get_sign(v.y),
|
||||
mcl_minecarts:get_sign(v.z)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -69,8 +77,8 @@ function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
|
|||
local left_check, right_check = true, true
|
||||
|
||||
-- Check left and right
|
||||
local left = {x=0, y=0, z=0}
|
||||
local right = {x=0, y=0, z=0}
|
||||
local left = vector.new(0, 0, 0)
|
||||
local right = vector.new(0, 0, 0)
|
||||
if dir.z ~= 0 and dir.x == 0 then
|
||||
left.x = -dir.z
|
||||
right.x = dir.z
|
||||
|
@ -124,44 +132,14 @@ function mcl_minecarts:get_rail_direction(pos_, dir, ctrl, old_switch, railtype)
|
|||
end
|
||||
-- Backwards
|
||||
if not old_switch then
|
||||
cur = mcl_minecarts:check_front_up_down(pos, {
|
||||
x = -dir.x,
|
||||
y = dir.y,
|
||||
z = -dir.z
|
||||
}, true, railtype)
|
||||
cur = mcl_minecarts:check_front_up_down(pos, vector.new(
|
||||
-dir.x,
|
||||
dir.y,
|
||||
-dir.z
|
||||
), true, railtype)
|
||||
if cur then
|
||||
return cur
|
||||
end
|
||||
end
|
||||
return {x=0, y=0, z=0}
|
||||
end
|
||||
|
||||
local plane_adjacents = {
|
||||
vector.new(-1,0,0),
|
||||
vector.new(1,0,0),
|
||||
vector.new(0,0,-1),
|
||||
vector.new(0,0,1),
|
||||
}
|
||||
|
||||
function mcl_minecarts:get_start_direction(pos)
|
||||
local dir
|
||||
local i = 0
|
||||
while (not dir and i < #plane_adjacents) do
|
||||
i = i+1
|
||||
local node = minetest.get_node_or_nil(vector.add(pos, plane_adjacents[i]))
|
||||
if node ~= nil
|
||||
and minetest.get_item_group(node.name, "rail") == 0
|
||||
and minetest.get_item_group(node.name, "solid") == 1
|
||||
and minetest.get_item_group(node.name, "opaque") == 1
|
||||
then
|
||||
dir = mcl_minecarts:check_front_up_down(pos, vector.multiply(plane_adjacents[i], -1), true)
|
||||
end
|
||||
end
|
||||
return dir
|
||||
end
|
||||
|
||||
function mcl_minecarts:set_velocity(obj, dir, factor)
|
||||
obj._velocity = vector.multiply(dir, factor or 3)
|
||||
obj._old_pos = nil
|
||||
obj._punched = true
|
||||
return vector.new(0,0,0) --{x=0, y=0, z=0}
|
||||
end
|
||||
|
|
|
@ -305,9 +305,193 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
|
||||
local passenger_attach_position = vector.new(0, -1.75, 0)
|
||||
|
||||
local function do_movement_step( self )
|
||||
local vel = self.object:get_velocity()
|
||||
local pos, rou_pos, node = self.object:get_pos()
|
||||
local update = {}
|
||||
|
||||
local dir, last_switch = nil, nil
|
||||
if not pos then
|
||||
pos = self.object:get_pos()
|
||||
end
|
||||
if self._old_pos and not self._punched then
|
||||
local flo_pos = vector.floor(pos)
|
||||
local flo_old = vector.floor(self._old_pos)
|
||||
if vector.equals(flo_pos, flo_old) and (not has_fuel) then
|
||||
return
|
||||
-- Prevent querying the same node over and over again
|
||||
end
|
||||
|
||||
if not rou_pos then
|
||||
rou_pos = vector.round(pos)
|
||||
end
|
||||
local rou_old = vector.round(self._old_pos)
|
||||
if not node then
|
||||
node = minetest.get_node(rou_pos)
|
||||
end
|
||||
local node_old = minetest.get_node(rou_old)
|
||||
|
||||
-- Update detector rails
|
||||
if node.name == "mcl_minecarts:detector_rail" then
|
||||
local newnode = {name="mcl_minecarts:detector_rail_on", param2 = node.param2}
|
||||
minetest.swap_node(rou_pos, newnode)
|
||||
mesecon.receptor_on(rou_pos)
|
||||
end
|
||||
if node_old.name == "mcl_minecarts:detector_rail_on" then
|
||||
local newnode = {name="mcl_minecarts:detector_rail", param2 = node_old.param2}
|
||||
minetest.swap_node(rou_old, newnode)
|
||||
mesecon.receptor_off(rou_old)
|
||||
end
|
||||
-- Activate minecart if on activator rail
|
||||
if node_old.name == "mcl_minecarts:activator_rail_on" and self.on_activate_by_rail then
|
||||
self:on_activate_by_rail()
|
||||
end
|
||||
end
|
||||
|
||||
-- Stop cart if velocity vector flips
|
||||
if self._old_vel and self._old_vel.y == 0 and
|
||||
(self._old_vel.x * vel.x < 0 or self._old_vel.z * vel.z < 0) then
|
||||
self._old_vel = {x = 0, y = 0, z = 0}
|
||||
self._old_pos = pos
|
||||
self.object:set_velocity(vector.new())
|
||||
self.object:set_acceleration(vector.new())
|
||||
return
|
||||
end
|
||||
self._old_vel = vector.new(vel)
|
||||
|
||||
if self._old_pos then
|
||||
local diff = vector.subtract(self._old_pos, pos)
|
||||
for _,v in ipairs({"x","y","z"}) do
|
||||
if math.abs(diff[v]) > 1.1 then
|
||||
local expected_pos = vector.add(self._old_pos, self._old_dir)
|
||||
dir, last_switch = mcl_minecarts:get_rail_direction(pos, self._old_dir, ctrl, self._old_switch, self._railtype)
|
||||
|
||||
if vector.equals(dir, {x=0, y=0, z=0}) then
|
||||
dir = false
|
||||
pos = vector.new(expected_pos)
|
||||
update.pos = true
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if vel.y == 0 then
|
||||
for _,v in ipairs({"x", "z"}) do
|
||||
if vel[v] ~= 0 and math.abs(vel[v]) < 0.9 then
|
||||
vel[v] = 0
|
||||
update.vel = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cart_dir = mcl_minecarts:velocity_to_dir(vel)
|
||||
local max_vel = mcl_minecarts.speed_max
|
||||
if not dir then
|
||||
dir, last_switch = mcl_minecarts:get_rail_direction(pos, cart_dir, ctrl, self._old_switch, self._railtype)
|
||||
end
|
||||
|
||||
local new_acc = {x=0, y=0, z=0}
|
||||
if vector.equals(dir, {x=0, y=0, z=0}) and not has_fuel then
|
||||
vel = {x=0, y=0, z=0}
|
||||
update.vel = true
|
||||
else
|
||||
-- If the direction changed
|
||||
if dir.x ~= 0 and self._old_dir.z ~= 0 then
|
||||
vel.x = dir.x * math.abs(vel.z)
|
||||
vel.z = 0
|
||||
pos.z = math.floor(pos.z + 0.5)
|
||||
update.pos = true
|
||||
end
|
||||
if dir.z ~= 0 and self._old_dir.x ~= 0 then
|
||||
vel.z = dir.z * math.abs(vel.x)
|
||||
vel.x = 0
|
||||
pos.x = math.floor(pos.x + 0.5)
|
||||
update.pos = true
|
||||
end
|
||||
-- Up, down?
|
||||
if dir.y ~= self._old_dir.y then
|
||||
vel.y = dir.y * math.abs(vel.x + vel.z)
|
||||
pos = vector.round(pos)
|
||||
update.pos = true
|
||||
end
|
||||
|
||||
-- Slow down or speed up
|
||||
local acc = dir.y * -1.8
|
||||
local friction = 0.4
|
||||
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||
local speed_mod = ndef and ndef._rail_acceleration
|
||||
|
||||
acc = acc - friction
|
||||
|
||||
if has_fuel then
|
||||
acc = acc + 0.6
|
||||
end
|
||||
|
||||
if speed_mod and speed_mod ~= 0 then
|
||||
acc = acc + speed_mod + friction
|
||||
end
|
||||
|
||||
new_acc = vector.multiply(dir, acc)
|
||||
end
|
||||
|
||||
self.object:set_acceleration(new_acc)
|
||||
self._old_pos = vector.new(pos)
|
||||
self._old_dir = vector.new(dir)
|
||||
self._old_switch = last_switch
|
||||
|
||||
-- Limits
|
||||
for _,v in ipairs({"x","y","z"}) do
|
||||
if math.abs(vel[v]) > max_vel then
|
||||
vel[v] = mcl_minecarts:get_sign(vel[v]) * max_vel
|
||||
new_acc[v] = 0
|
||||
update.vel = true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
if update.pos or self._punched then
|
||||
local yaw = 0
|
||||
if dir.x < 0 then
|
||||
yaw = 0.5
|
||||
elseif dir.x > 0 then
|
||||
yaw = 1.5
|
||||
elseif dir.z < 0 then
|
||||
yaw = 1
|
||||
end
|
||||
self.object:set_yaw(yaw * math.pi)
|
||||
end
|
||||
|
||||
if self._punched then
|
||||
self._punched = false
|
||||
end
|
||||
|
||||
if not (update.vel or update.pos) then
|
||||
return
|
||||
end
|
||||
|
||||
local anim = {x=0, y=0}
|
||||
if dir.y == -1 then
|
||||
anim = {x=1, y=1}
|
||||
elseif dir.y == 1 then
|
||||
anim = {x=2, y=2}
|
||||
end
|
||||
self.object:set_animation(anim, 1, 0)
|
||||
|
||||
self.object:set_velocity(vel)
|
||||
if update.pos then
|
||||
self.object:set_pos(pos)
|
||||
end
|
||||
end
|
||||
|
||||
function cart:on_step(dtime)
|
||||
hopper_take_item(self, dtime)
|
||||
|
||||
local vel = self.object:get_velocity()
|
||||
local pos, rou_pos, node = self.object:get_pos()
|
||||
local update = {}
|
||||
|
||||
-- Controls
|
||||
local ctrl, player = nil, nil
|
||||
if self._driver then
|
||||
player = minetest.get_player_by_name(self._driver)
|
||||
|
@ -319,17 +503,23 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
return
|
||||
end
|
||||
end
|
||||
|
||||
-- Give achievement when player reached a distance of 1000 nodes from the start position
|
||||
if vector.distance(self._start_pos, pos) >= 1000 then
|
||||
awards.unlock(self._driver, "mcl:onARail")
|
||||
end
|
||||
end
|
||||
|
||||
local vel = self.object:get_velocity()
|
||||
local update = {}
|
||||
if self._last_float_check == nil then
|
||||
self._last_float_check = 0
|
||||
else
|
||||
self._last_float_check = self._last_float_check + dtime
|
||||
-- Go faster when punched
|
||||
if self._punched then
|
||||
vel = vector.add(vel, self._velocity)
|
||||
self.object:set_velocity(vel)
|
||||
self._old_dir.y = 0
|
||||
elseif vector.equals(vel, {x=0, y=0, z=0}) and (not has_fuel) then
|
||||
return
|
||||
end
|
||||
|
||||
local pos, rou_pos, node = self.object:get_pos()
|
||||
-- Drop minecart if it collides with a cactus node
|
||||
local r = 0.6
|
||||
for _, node_pos in pairs({{r, 0}, {0, r}, {-r, 0}, {0, -r}}) do
|
||||
if minetest.get_node(vector.offset(pos, node_pos[1], 0, node_pos[2])).name == "mcl_core:cactus" then
|
||||
|
@ -342,6 +532,17 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
end
|
||||
end
|
||||
|
||||
-- Debug
|
||||
local node = minetest.get_node(pos).name
|
||||
local dist = 0
|
||||
if pos and self._old_pos then
|
||||
dist = vector.distance(pos,self._old_pos)
|
||||
end
|
||||
if dist > 1.5 then
|
||||
print("pos="..tostring(pos)..",dist="..tostring(dist)..",node="..tostring(node)..",old_pos="..tostring(self._old_pos)..",vel="..tostring(vel))
|
||||
end
|
||||
-- Rail jumps can occur when dist > 1.5, because the cart can skip over a gap in track
|
||||
|
||||
-- Grab mob
|
||||
if math.random(1,20) > 15 and not self._passenger then
|
||||
if self.name == "mcl_minecarts:minecart" then
|
||||
|
@ -366,6 +567,11 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
end
|
||||
|
||||
-- Drop minecart if it isn't on a rail anymore
|
||||
if self._last_float_check == nil then
|
||||
self._last_float_check = 0
|
||||
else
|
||||
self._last_float_check = self._last_float_check + dtime
|
||||
end
|
||||
if self._last_float_check >= mcl_minecarts.check_float_time then
|
||||
pos = self.object:get_pos()
|
||||
rou_pos = vector.round(pos)
|
||||
|
@ -458,202 +664,7 @@ local function register_entity(entity_id, mesh, textures, drop, on_rightclick, o
|
|||
end
|
||||
end
|
||||
|
||||
if self._punched then
|
||||
vel = vector.add(vel, self._velocity)
|
||||
self.object:set_velocity(vel)
|
||||
self._old_dir.y = 0
|
||||
elseif vector.equals(vel, {x=0, y=0, z=0}) and (not has_fuel) then
|
||||
return
|
||||
end
|
||||
|
||||
local dir, last_switch, restart_pos = nil, nil, nil
|
||||
if not pos then
|
||||
pos = self.object:get_pos()
|
||||
end
|
||||
if self._old_pos and not self._punched then
|
||||
local flo_pos = vector.floor(pos)
|
||||
local flo_old = vector.floor(self._old_pos)
|
||||
if vector.equals(flo_pos, flo_old) and (not has_fuel) then
|
||||
return
|
||||
-- Prevent querying the same node over and over again
|
||||
end
|
||||
|
||||
if not rou_pos then
|
||||
rou_pos = vector.round(pos)
|
||||
end
|
||||
local rou_old = vector.round(self._old_pos)
|
||||
if not node then
|
||||
node = minetest.get_node(rou_pos)
|
||||
end
|
||||
local node_old = minetest.get_node(rou_old)
|
||||
|
||||
-- Update detector rails
|
||||
if node.name == "mcl_minecarts:detector_rail" then
|
||||
local newnode = {name="mcl_minecarts:detector_rail_on", param2 = node.param2}
|
||||
minetest.swap_node(rou_pos, newnode)
|
||||
mesecon.receptor_on(rou_pos)
|
||||
end
|
||||
if node.name == "mcl_minecarts:golden_rail_on" then
|
||||
restart_pos = rou_pos
|
||||
end
|
||||
if node_old.name == "mcl_minecarts:detector_rail_on" then
|
||||
local newnode = {name="mcl_minecarts:detector_rail", param2 = node_old.param2}
|
||||
minetest.swap_node(rou_old, newnode)
|
||||
mesecon.receptor_off(rou_old)
|
||||
end
|
||||
-- Activate minecart if on activator rail
|
||||
if node_old.name == "mcl_minecarts:activator_rail_on" and self.on_activate_by_rail then
|
||||
self:on_activate_by_rail()
|
||||
end
|
||||
end
|
||||
|
||||
-- Stop cart if velocity vector flips
|
||||
if self._old_vel and self._old_vel.y == 0 and
|
||||
(self._old_vel.x * vel.x < 0 or self._old_vel.z * vel.z < 0) then
|
||||
self._old_vel = {x = 0, y = 0, z = 0}
|
||||
self._old_pos = pos
|
||||
self.object:set_velocity(vector.new())
|
||||
self.object:set_acceleration(vector.new())
|
||||
return
|
||||
end
|
||||
self._old_vel = vector.new(vel)
|
||||
|
||||
if self._old_pos then
|
||||
local diff = vector.subtract(self._old_pos, pos)
|
||||
for _,v in ipairs({"x","y","z"}) do
|
||||
if math.abs(diff[v]) > 1.1 then
|
||||
local expected_pos = vector.add(self._old_pos, self._old_dir)
|
||||
dir, last_switch = mcl_minecarts:get_rail_direction(pos, self._old_dir, ctrl, self._old_switch, self._railtype)
|
||||
if vector.equals(dir, {x=0, y=0, z=0}) then
|
||||
dir = false
|
||||
pos = vector.new(expected_pos)
|
||||
update.pos = true
|
||||
end
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if vel.y == 0 then
|
||||
for _,v in ipairs({"x", "z"}) do
|
||||
if vel[v] ~= 0 and math.abs(vel[v]) < 0.9 then
|
||||
vel[v] = 0
|
||||
update.vel = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local cart_dir = mcl_minecarts:velocity_to_dir(vel)
|
||||
local max_vel = mcl_minecarts.speed_max
|
||||
if not dir then
|
||||
dir, last_switch = mcl_minecarts:get_rail_direction(pos, cart_dir, ctrl, self._old_switch, self._railtype)
|
||||
end
|
||||
|
||||
local new_acc = {x=0, y=0, z=0}
|
||||
if vector.equals(dir, {x=0, y=0, z=0}) and not has_fuel then
|
||||
vel = {x=0, y=0, z=0}
|
||||
update.vel = true
|
||||
else
|
||||
-- If the direction changed
|
||||
if dir.x ~= 0 and self._old_dir.z ~= 0 then
|
||||
vel.x = dir.x * math.abs(vel.z)
|
||||
vel.z = 0
|
||||
pos.z = math.floor(pos.z + 0.5)
|
||||
update.pos = true
|
||||
end
|
||||
if dir.z ~= 0 and self._old_dir.x ~= 0 then
|
||||
vel.z = dir.z * math.abs(vel.x)
|
||||
vel.x = 0
|
||||
pos.x = math.floor(pos.x + 0.5)
|
||||
update.pos = true
|
||||
end
|
||||
-- Up, down?
|
||||
if dir.y ~= self._old_dir.y then
|
||||
vel.y = dir.y * math.abs(vel.x + vel.z)
|
||||
pos = vector.round(pos)
|
||||
update.pos = true
|
||||
end
|
||||
|
||||
-- Slow down or speed up
|
||||
local acc = dir.y * -1.8
|
||||
local friction = 0.4
|
||||
local ndef = minetest.registered_nodes[minetest.get_node(pos).name]
|
||||
local speed_mod = ndef and ndef._rail_acceleration
|
||||
|
||||
acc = acc - friction
|
||||
|
||||
if has_fuel then
|
||||
acc = acc + 0.6
|
||||
end
|
||||
|
||||
if speed_mod and speed_mod ~= 0 then
|
||||
acc = acc + speed_mod + friction
|
||||
end
|
||||
|
||||
new_acc = vector.multiply(dir, acc)
|
||||
end
|
||||
|
||||
self.object:set_acceleration(new_acc)
|
||||
self._old_pos = vector.new(pos)
|
||||
self._old_dir = vector.new(dir)
|
||||
self._old_switch = last_switch
|
||||
|
||||
-- Limits
|
||||
for _,v in ipairs({"x","y","z"}) do
|
||||
if math.abs(vel[v]) > max_vel then
|
||||
vel[v] = mcl_minecarts:get_sign(vel[v]) * max_vel
|
||||
new_acc[v] = 0
|
||||
update.vel = true
|
||||
end
|
||||
end
|
||||
|
||||
-- Give achievement when player reached a distance of 1000 nodes from the start position
|
||||
if self._driver and (vector.distance(self._start_pos, pos) >= 1000) then
|
||||
awards.unlock(self._driver, "mcl:onARail")
|
||||
end
|
||||
|
||||
|
||||
if update.pos or self._punched then
|
||||
local yaw = 0
|
||||
if dir.x < 0 then
|
||||
yaw = 0.5
|
||||
elseif dir.x > 0 then
|
||||
yaw = 1.5
|
||||
elseif dir.z < 0 then
|
||||
yaw = 1
|
||||
end
|
||||
self.object:set_yaw(yaw * math.pi)
|
||||
end
|
||||
|
||||
if self._punched then
|
||||
self._punched = false
|
||||
end
|
||||
|
||||
if not (update.vel or update.pos) then
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local anim = {x=0, y=0}
|
||||
if dir.y == -1 then
|
||||
anim = {x=1, y=1}
|
||||
elseif dir.y == 1 then
|
||||
anim = {x=2, y=2}
|
||||
end
|
||||
self.object:set_animation(anim, 1, 0)
|
||||
|
||||
self.object:set_velocity(vel)
|
||||
if update.pos then
|
||||
self.object:set_pos(pos)
|
||||
end
|
||||
|
||||
-- stopped on "mcl_minecarts:golden_rail_on"
|
||||
if vector.equals(vel, {x=0, y=0, z=0}) and restart_pos then
|
||||
local dir = mcl_minecarts:get_start_direction(restart_pos)
|
||||
if dir then
|
||||
mcl_minecarts:set_velocity(self, dir)
|
||||
end
|
||||
end
|
||||
do_movement_step(self)
|
||||
end
|
||||
|
||||
function cart:get_staticdata()
|
||||
|
|
Loading…
Reference in New Issue