199 lines
5.5 KiB
Lua
199 lines
5.5 KiB
Lua
local shared = ...
|
|
local S = shared.S
|
|
local bloodyness = tonumber(core.settings:get("rifles.bloodyness")) or 10
|
|
|
|
local glass_panes_doors = {
|
|
["doors:door_glass_a"]=true,
|
|
["xpanes:pane"]=true,
|
|
["xpanes:pane_flat"]=true,
|
|
["default:glass"]=true,
|
|
}
|
|
|
|
local function is_node_glass_or_leaves(name, nodedef)
|
|
if nodedef.groups and nodedef.groups.leaves then
|
|
return true
|
|
end
|
|
|
|
if glass_panes_doors[name] then
|
|
return true
|
|
end
|
|
end
|
|
|
|
core.register_craftitem(
|
|
"powerguns:shot_bullet_visual",
|
|
{
|
|
wield_scale = {x = 1.0, y = 1.0, z = 1.0},
|
|
inventory_image = "powerguns_bulletshot.png"
|
|
}
|
|
)
|
|
|
|
local use_particles = core.settings:get_bool("rifles.impact_particles", true)
|
|
local max_lifetime = tonumber(core.settings:get("rifles.bullet_lifetime")) or 10.0
|
|
|
|
local function play_dig_sound(node, hit_pos)
|
|
local nodedef = minetest.registered_nodes[node.name]
|
|
if nodedef and nodedef.sounds and (nodedef.sounds.dig or nodedef.sounds.dug) then
|
|
core.sound_play((nodedef.sounds.dig or nodedef.sounds.dug).name, {pos = hit_pos}, true)
|
|
end
|
|
end
|
|
|
|
local powerguns_shot_bullet = {
|
|
timer = 0,
|
|
initial_properties = {
|
|
static_save = false,
|
|
pointable = false,
|
|
physical = false,
|
|
glow = 100,
|
|
visual = "wielditem",
|
|
visual_size = {x = 0.75, y = 0.75},
|
|
textures = {"powerguns:shot_bullet_visual"},
|
|
},
|
|
_ricochet = 0,
|
|
on_activate = function (self, staticdata, dtime_s)
|
|
self._old_pos = self.object:get_pos()
|
|
end,
|
|
on_step = function(self, dtime, moveresult)
|
|
if self.owner == nil then
|
|
self.object:remove()
|
|
return
|
|
end
|
|
|
|
local ignite = self.ignite or 0
|
|
local size = self.size or 0.0025
|
|
|
|
self.timer = self.timer + dtime
|
|
|
|
if self.timer >= 0 then
|
|
self.object:set_properties({collide_with_objects = true})
|
|
self.object:set_properties({collisionbox = {-size, -size, -size, size, size, size}})
|
|
end
|
|
|
|
if self.timer > max_lifetime then
|
|
self.object:remove()
|
|
return
|
|
end
|
|
for pointed_thing in core.raycast(self._old_pos, self.object:get_pos(), true, true) do
|
|
local hit_pos = pointed_thing.intersection_point
|
|
local mobPen = self.mobPen or 0
|
|
local door_break = self.door_break or 0
|
|
|
|
if pointed_thing.type == "node" then
|
|
local node_pos = pointed_thing.under
|
|
local node = core.get_node(node_pos)
|
|
local node_def = core.registered_nodes[node.name]
|
|
if node_def and node_def.walkable and not is_node_glass_or_leaves(node.name, node_def) then
|
|
if use_particles and node_def and node_def.tiles and node_def.tiles[1] then
|
|
local hit_texture = node_def.tiles[1]
|
|
|
|
if hit_texture.name ~= nil then
|
|
hit_texture = hit_texture.name
|
|
end
|
|
|
|
-- does not face the right direction because of a limitation in the current particle system
|
|
-- https://github.com/minetest/minetest/issues/15574
|
|
core.add_particle(
|
|
{
|
|
pos = hit_pos,
|
|
expirationtime = 30,
|
|
size = math.random(10, 20) / 10,
|
|
texture = "powerguns_bullethole.png",
|
|
}
|
|
)
|
|
|
|
for i = 1, math.random(4, 8) do
|
|
core.add_particle(
|
|
{
|
|
pos = hit_pos,
|
|
velocity = {
|
|
x = math.random(-3.0, 3.0),
|
|
y = math.random(2.0, 5.0),
|
|
z = math.random(-3.0, 3.0)
|
|
},
|
|
acceleration = {
|
|
x = math.random(-3.0, 3.0),
|
|
y = math.random(-10.0, -15.0),
|
|
z = math.random(-3.0, 3.0)
|
|
},
|
|
expirationtime = 0.5,
|
|
size = math.random(10, 20) / 10,
|
|
collisiondetection = true,
|
|
vertical = false,
|
|
texture = "" .. hit_texture .. "^[resize:4x4" .. "",
|
|
glow = 0
|
|
}
|
|
)
|
|
end
|
|
end
|
|
|
|
play_dig_sound(node, hit_pos)
|
|
|
|
if node.name == "tnt:tnt" then
|
|
core.get_node_timer(node_pos):start(0)
|
|
end
|
|
|
|
if core.get_item_group(node.name, "level") > 1 then
|
|
self.hit_leaves = false
|
|
|
|
local node_pos = node_pos
|
|
local node = core.get_node(node_pos)
|
|
|
|
local normal = vector.new(0, 0, 0)
|
|
if pointed_thing.intersection_normal then normal = pointed_thing.intersection_normal end
|
|
|
|
-- Reflect the bullet
|
|
local incoming_vec = self.object:get_velocity()
|
|
local reflected_vec = vector.subtract(incoming_vec, vector.multiply(normal, 2 * vector.dot(incoming_vec, normal)))
|
|
|
|
-- Set new velocity
|
|
self.object:set_velocity(reflected_vec)
|
|
|
|
-- Update rotation to match new velocity
|
|
local yaw = math.atan2(reflected_vec.z, reflected_vec.x)
|
|
local pitch = math.asin(-reflected_vec.y / vector.length(reflected_vec))
|
|
self.object:set_rotation({x = pitch, y = yaw, z = 0})
|
|
|
|
-- Move the bullet slightly above the hit position
|
|
local new_pos = vector.add(hit_pos, vector.multiply(normal, 0.001))
|
|
self.object:set_pos(new_pos)
|
|
self._ricochet = self._ricochet + 1
|
|
if self._ricochet > 2 then
|
|
self.object:remove()
|
|
return
|
|
end
|
|
break
|
|
else
|
|
self.object:remove()
|
|
return
|
|
end
|
|
end
|
|
elseif pointed_thing.type == "object" and (
|
|
(pointed_thing.ref:is_player() and (pointed_thing.ref:get_player_name() ~= self.owner or self._ricochet > 0))
|
|
or
|
|
(pointed_thing.ref:get_luaentity() and pointed_thing.ref:get_properties().physical and pointed_thing.ref:get_luaentity().name ~= '__builtin:item')
|
|
) then
|
|
|
|
local owner = core.get_player_by_name(self.owner)
|
|
-- put bullet in front of object before punching in order to get correct engine knockback
|
|
self.object:set_pos(self._old_pos)
|
|
pointed_thing.ref:punch(
|
|
self.object,
|
|
1.0,
|
|
{
|
|
full_punch_interval = 1.0,
|
|
damage_groups = self.damage
|
|
},
|
|
nil
|
|
)
|
|
accuracy.hit(owner)
|
|
|
|
self.object:remove()
|
|
return
|
|
end
|
|
end
|
|
|
|
|
|
self._old_pos = self.object:get_pos()
|
|
end
|
|
}
|
|
core.register_entity("powerguns:shot_bullet", powerguns_shot_bullet)
|