2024-01-10 17:29:05 +01:00

252 lines
6.3 KiB
Lua

sf_projectiles = {}
sf_projectiles.add_projectile = function(pos, projectilename, velocity, shooter, punch_tool_properties)
local obj = minetest.add_entity(pos, projectilename)
if obj then
local lua = obj:get_luaentity()
if shooter then
lua._shooter = shooter:get_player_name()
end
obj:set_velocity(velocity)
if punch_tool_properties then
lua._punch_tool_properties = punch_tool_properties
end
return obj
end
end
local PROJECTILE_LIFE_TIME = 30
local LIGHT_GLOW = 12
local light_move_particles = function(ent)
minetest.add_particlespawner({
amount = 8,
time = 0.01,
exptime = {
min = 0.3,
max = 0.6,
},
size = 1.1,
pos = ent.object:get_pos(),
vel = {
min = vector.new(-2, -2, -2),
max = vector.new(2, 2, 2),
},
drag = vector.new(8, 8, 8),
texture = {
name = "sf_particles_light.png",
scale_tween = { 1, 0, start = 0.5 },
alpha_tween = { 1, 0, start = 0.5 },
},
glow = LIGHT_GLOW,
})
end
local light_impact_particles = function(ent)
minetest.add_particlespawner({
amount = 16,
time = 0.05,
exptime = {
min = 1,
max = 2,
},
size = 1.75,
pos = ent.object:get_pos(),
vel = {
min = vector.new(-5, -5, -5),
max = vector.new(5, 5, 5),
},
drag = vector.new(7, 7, 7),
texture = {
name = "sf_particles_light.png",
scale_tween = { 1, 0, start = 0.5 },
alpha_tween = { 1, 0, start = 0.5 },
},
glow = LIGHT_GLOW,
})
end
local shadow_move_particles = function(ent)
local pos = ent.object:get_pos()
pos = vector.add(pos, vector.new(0, 0.1, 0))
minetest.add_particlespawner({
amount = 8,
time = 0.01,
exptime = {
min = 0.3,
max = 0.6,
},
size = 1.1,
pos = pos,
vel = {
min = vector.new(-2, -2, -2),
max = vector.new(2, 2, 2),
},
drag = vector.new(8, 8, 8),
texture = {
name = "sf_particles_shadow.png",
scale_tween = { 1, 0, start = 0.5 },
alpha_tween = { 1, 0, start = 0.5 },
},
glow = LIGHT_GLOW,
})
end
local shadow_impact_particles = function(ent)
minetest.add_particlespawner({
amount = 12,
time = 0.05,
exptime = {
min = 0.7,
max = 1.4,
},
size = 1,
pos = ent.object:get_pos(),
vel = {
min = vector.new(-2, -2, -2),
max = vector.new(2, 2, 2),
},
drag = vector.new(5, 5, 5),
texture = {
name = "sf_particles_shadow_poof_anim.png",
},
animation = {
type = "vertical_frames",
aspect_w = 16,
aspect_h = 16,
length = -1,
},
})
end
local function register_simple_projectile(id, initial_properties, def)
minetest.register_entity("sf_projectiles:"..id, {
initial_properties = initial_properties,
_life_timer = 0,
_shooter = nil,
_punch_tool_properties = nil,
get_staticdata = function(self)
local data = {
punch_tool_properties = self._punch_tool_properties,
shooter = self._shooter,
life_timer = self._life_timer,
}
local sdata = minetest.serialize(data)
return sdata
end,
on_activate = function(self, staticdata)
local ddata = minetest.deserialize(staticdata)
if type(ddata) == "table" then
self._punch_tool_properties = ddata.punch_tool_properties
self._shooter = ddata.shooter
self._life_timer = ddata.life_timer
end
self.object:set_armor_groups(def.armor)
end,
on_step = function(self, dtime, moveresult)
local opos = self.object:get_pos()
if def.move_particles_func then
def.move_particles_func(self)
end
if moveresult.collides then
for c=1, #moveresult.collisions do
local collision = moveresult.collisions[c]
if collision.type == "object" then
local armor = collision.object:get_armor_groups()
local dir = vector.direction(opos, collision.object:get_pos())
if self._punch_tool_properties then
collision.object:punch(self.object, math.huge, self._punch_tool_properties, dir)
else
self.object:remove()
minetest.log("warning", "[sf_projectiles] Projectile collided with object without _punch_tool_properties!")
return
end
if def.impact_particles_func then
def.impact_particles_func(self)
end
if def.impact_sound then
minetest.sound_play(def.impact_sound, {pos=opos, max_hear_distance=12}, true)
end
if self._shooter then
-- Play notify sound to shooter when hitting a shadow mob
if armor and armor.shadow_physical ~= nil and armor.shadow_physical ~= 0 then
local shooter = minetest.get_player_by_name(self._shooter)
-- No sound for self-hit
if shooter and not (collision.object:is_player() and collision.object:get_player_name() == self._shooter) then
minetest.sound_play({name="sf_projectiles_hit_ranged", gain=0.8}, {to_player=self._shooter}, true)
end
end
end
self.object:remove()
return
elseif collision.type == "node" then
if def.impact_particles_func then
def.impact_particles_func(self)
end
if def.impact_sound then
minetest.sound_play(def.impact_sound, {pos=opos}, true)
end
self.object:remove()
return
end
end
end
self._life_timer = self._life_timer + dtime
if self._life_timer > PROJECTILE_LIFE_TIME then
self.object:remove()
return
end
end,
})
end
register_simple_projectile("shadow",
{
hp_max = 1,
textures = {"sf_projectiles_shadow.png"},
pointable = true,
is_visible = true,
visual = "mesh",
mesh = "sf_projectiles_shadow.obj",
automatic_rotate = 9,
physical = true,
collides_with_objects = true,
textures = {
"sf_projectiles_shadow.png",
},
collisionbox = { -0.125, 0, -0.125, 0.125, 0.25, 0.125 },
visual_size = { x = 2.5, y = 2.5, z = 2.5 },
},
{
impact_particles_func=shadow_impact_particles,
move_particles_func=shadow_move_particles,
impact_sound={name="sf_projectiles_shadow_impact", gain=0.1},
-- Special armor group to differenciate the shadow projectile
-- from shadow mobs (which use shadow_physical)
armor={shadow_special=100},
}
)
register_simple_projectile("light",
{
hp_max = 1,
pointable = false,
visual = "sprite",
is_visible = true,
textures = {
"blank.png",
"blank.png",
},
physical = true,
collides_with_objects = true,
collisionbox = { -0.25, 0, -0.25, 0.25, 0.5, 0.25 },
visual_size = { x = 0.5, y = 0.5, z = 0.5 },
},
{
impact_particles_func=light_impact_particles,
move_particles_func=light_move_particles,
impact_sound={name="sf_projectiles_light_impact", gain=0.2},
armor={light=100},
}
)