guns4d-cd2025/classes/raycast_defunked.lua
2023-06-11 23:34:28 -07:00

159 lines
7.8 KiB
Lua

function guns3d.ray(player, pos, dir, def, bullet_info)
--"transverse" just means in a node
--"free" means in open air
local playername = player:get_player_name()
local is_first_iter = false
local constant = .7
local normal
----------------------------------------------------------initialize------------------------------------------------------------------
if not bullet_info then
is_first_iter = true
bullet_info = {
history = {},
state = "free",
last_pos = pos,
last_node = "",
last_normal = vector.new(),
end_direction = dir,
range_left = def.bullet.range,
penetrating_force = def.bullet.penetration_RHA
--last_pointed
}
end
table.insert(bullet_info.history, {start_pos=pos, state=bullet_info.state, normal=bullet_info.last_normal, end_direction = bullet_info.end_direction})
--set ray end
local pos2 = pos+(dir*bullet_info.range_left)
local block_ends_early = false
--if was last in a block, check where the "transverse" state should end.
--------------------------------------------------prepare for raycast --------------------------------------------------------------
if bullet_info.state == "transverse" then
local pointed
local ray = minetest.raycast(pos+(dir*(constant+.01)), pos, false, false)
for p in ray do
if p.type == "node" and (table.compare(p.under, bullet_info.last_pointed.under) or not minetest.registered_nodes[minetest.get_node(bullet_info.last_pointed.under).name].node_box) then
pointed = p
break
end
end
--maybe remove check for pointed
if pointed and vector.distance(pointed.intersection_point, pos) < constant then
pos2 = pointed.intersection_point
block_ends_early = true
normal = pointed.intersection_normal
bullet_info.end_direction = vector.direction(dir, vector.new())
else
pos2 = pos+(dir*constant)
end
end
-----------------------------------------------------------raycast--------------------------------------------------------------
local ray = minetest.raycast(pos, pos2, true, true)
local pointed
local next_ray_pos = pos2
for p in ray do
if vector.distance(p.intersection_point, bullet_info.last_pos) > 0.0005 and vector.distance(p.intersection_point, bullet_info.last_pos) < bullet_info.range_left then
local distance = vector.distance(pos, p.intersection_point)
--if it's a node, check that it's note supposed to be ignored according to it's generated properties
if p.type == "node" and guns3d.node_properties[minetest.get_node(p.under).name].behavior ~= "ignore" then
local next_penetration_val = bullet_info.penetrating_force-(distance*guns3d.node_properties[minetest.get_node(p.under).name].rha*1000)
if bullet_info.state ~= "transverse" then
pointed = p
--print(dump(p))
bullet_info.state = "transverse"
next_ray_pos = p.intersection_point
else
pointed = p
if minetest.get_node(p.under).name ~= bullet_info.last_node and next_penetration_val > 0 and guns3d.node_properties[minetest.get_node(p.under).name].behavior ~= "ignore" then
next_ray_pos = p.intersection_point
end
end
break
end
--if it's an object, make sure it's not the player object
--note that while it may seem like this will create a infinite hit loop, it resolves itself as the intersection_point of the next ray will be close enough as to skip the pointed. See first line of iterator.
if p.type == "object" and p.ref ~= player then
--apply force dropoff
local next_penetration_val = bullet_info.penetrating_force-def.bullet.penetration_dropoff_RHA*distance
if bullet_info.state == "transverse" then
next_penetration_val = bullet_info.penetrating_force-(distance*guns3d.node_properties[minetest.get_node(bullet_info.last_pointed.under).name].rha*1000)
end
--insure there's still penetrating force left to actually damage the player
if bullet_info.penetrating_force > 0 then
if (bullet_info.state == "transverse" and next_penetration_val > 0) or (bullet_info.state == "free" and bullet_info.penetrating_force-def.bullet.penetration_dropoff_RHA*distance > 0) then
local penetration_val = next_penetration_val
if bullet_info.state == "free" then
bullet_info.penetrating_force = next_penetration_val
penetration_val = bullet_info.penetrating_force
end
local damage = math.floor((def.bullet.damage*(next_penetration_val/def.bullet.penetration_RHA))+1)
p.ref:punch(player, nil, {damage_groups = {fleshy = damage}}, dir)
if p.ref:is_player() then
--TODO: finish
end
end
end
end
end
end
---------------------prepare for recursion---------------------------------------------------------------------------------
local penetration_loss = def.bullet.penetration_dropoff_RHA
local distance = vector.distance(pos, next_ray_pos)
local new_dir = dir
local node_properties
if pointed then
node_properties = guns3d.node_properties[minetest.get_node(pointed.under).name]
end
if pointed and (not normal) then
normal = pointed.intersection_normal
else
normal = vector.new()
end
if not bullet_info.end_direction then
bullet_info.end_direction = new_dir
end
--we know if the first raycast didn't find it ended early, or if there wasn't a hit, that it isn't in a block
if block_ends_early or not pointed then
bullet_info.state = "free"
end
--calculate penetration loss, and simulate loss of accuracy
if bullet_info.history[#bullet_info.history].state == "transverse" and pointed then
local rotation = vector.apply(vector.new(), function(a)
a=a+(((math.random()-.5)*2)*node_properties.random_deviation*def.bullet.penetration_deviation*distance)
return a
end)
new_dir = vector.rotate(new_dir, rotation*math.pi/180)
penetration_loss = node_properties.rha*1000
end
--set the current bullet info.
bullet_info.penetrating_force=bullet_info.penetrating_force-(penetration_loss*distance)
bullet_info.range_left = bullet_info.range_left-distance
bullet_info.last_pointed = pointed
bullet_info.last_normal = normal
bullet_info.last_pos = pos
--set the last node
if pointed then
bullet_info.last_node = minetest.get_node(pointed.under).name
end
--recurse.
if bullet_info.range_left > 0.001 and bullet_info.penetrating_force > 0 then
guns3d.ray(player, next_ray_pos, new_dir, def, bullet_info)
end
-------------------------- visual -------------------------------------------------------------------------------------
if is_first_iter then
for i, val in pairs(bullet_info.history) do
if not table.compare(val.normal, vector.new()) then
guns3d.handle_node_hit_fx(val.normal, val.end_direction, val.start_pos)
end
end
end
end
local raycast = {
history = {},
state = "free",
last_pos = pos,
last_node = "",
last_normal = vector.new(),
end_direction = dir,
range_left = def.bullet.range,
penetrating_force = def.bullet.penetration_RHA
}