minetest-quake/_weapons/bullets.lua

234 lines
6.1 KiB
Lua

local function calc_dir_from_pos() end
local function jump() end
local function spawn_particles_sphere() end
local function get_dist() end
local function get_pointed_thing() end
-- definisco le proprietà e i costruttori delle entità 'proiettili' e le registro alla fine
function quake.register_bullet(name, def)
if not def.speed then return end
-- definizione proprietà iniziali: uguali per tutte le istanze dello stesso tipo
local bulletentity = {
initial_properties = {
name = name,
physical = def.physical,
visual = def.visual,
visual_size = def.visual_size,
mesh = def.mesh,
explosion_texture = def.explosion_texture,
textures = def.textures,
collisionbox = def.collisionbox,
speed = def.speed,
damage = def.damage,
explosion_range = def.explosion_range,
duration = def.duration,
jump = def.jump,
explosion_damage = def.explosion_damage,
no_collision_time = 1/(2*def.speed), -- il tempo necessario per non far impattare il proiettile contro il giocatore
def = def,
},
}
-- variabili assegnate alla SINGOLA entity quando istanziata. Non rimangono in memoria al riavvio
local shooter = nil
local p_name = nil
local lifetime = 0
-- cosa succede alla distruzione del proiettile. In pratica prende il metodo impostato
-- nella creazione del proiettile e lo usa alla distruzione. Comodo perchè così è astratta anche quella
function bulletentity:_destroy()
if self.initial_properties.def.on_destroy then
self.initial_properties.def.on_destroy(self)
end
-- spawna le particelle
spawn_particles_sphere(self.object:get_pos(), self.initial_properties.explosion_texture)
self.object:remove()
end
-- quando si istanzia un'entità
function bulletentity:on_activate(staticdata)
if staticdata ~= "" and staticdata ~= nil then
self.p_name = staticdata -- nome utente come staticdata
self.shooter = minetest.get_player_by_name(staticdata)
else
self.object:remove()
return
end
self.lifetime = 0
local pos = self.object:get_pos()
end
function bulletentity:on_step(dtime)
-- incremento tempo di vita
self.lifetime = self.lifetime + dtime
local pos = self.object:get_pos()
local node = minetest.env:get_node(pos)
local dir = vector.normalize(self.object:get_velocity())
-- se ha raggiunto la durata di vita massima
if self.lifetime >= self.initial_properties.duration then
self:_destroy()
return
end
local hit = get_pointed_thing(pos, dir, self.p_name)
-- se il proiettile ha qualcosa sulla sua linea d'aria
if hit then
local hit_pos
local dist
-- se è un'entità
if hit.type == "object" and hit.ref then
-- se è un giocatore
if hit.ref:is_player() then
quake.shoot(self.p_name, hit.ref, self.initial_properties.damage, false)
self:_destroy()
return
end
-- se è un nodo
elseif hit.type == "node" then
hit_pos = hit["under"] -- NON SO IL PERCHé MA IN IRC MI HANNO DETTO COSì
local player_pos = self.shooter:get_pos()
local player_dist = get_dist(hit_pos, player_pos)
if player_dist <= self.initial_properties.explosion_range then
local dir_jump = calc_dir_from_pos(hit_pos, player_pos)
jump(self.shooter, self.initial_properties.jump, dir_jump)
end
self:_destroy()
return
end
end
end
--registra l'entità
minetest.register_entity(name, bulletentity)
end
function quake.shoot_bullet(shooter, bullet, pos_head, dir)
local username = shooter:get_player_name()
local bullet = minetest.add_entity(pos_head, bullet, username) -- spawna il proiettile dalla testa e passo il nick come staticdata
local yaw = shooter:get_look_horizontal()
local pitch = shooter:get_look_vertical()
bullet:set_rotation({x = -pitch, y = yaw, z = 0})
local speed = bullet:get_luaentity().initial_properties.speed
bullet:set_velocity({
x=(dir.x * speed),
y=(dir.y * speed),
z=(dir.z * speed),
})
bullet:set_acceleration({ x=dir.x, y=dir.y, z=dir.z })
end
----------------------------------------------
---------------FUNZIONI LOCALI----------------
----------------------------------------------
function calc_dir_from_pos(p1,p2)
local dir = vector.subtract(p1,p2)
return dir
end
function jump(shooter, amount, dir)
local knockback = vector.multiply(dir,-(amount))
shooter:add_player_velocity(knockback)
end
--aggiunge le particelle dell'esplosione
function spawn_particles_sphere(pos, particle_texture)
minetest.add_particlespawner({
amount = 80,
time = .1,
minpos = {x=pos.x,y=pos.y,z=pos.z},
maxpos = {x=pos.x,y=pos.y,z=pos.z},
minvel = {x=-4, y=-4, z=-4},
maxvel = {x=4, y=4, z=4},
minacc = {x=0, y=-0.4, z=0},
maxacc = {x=0, y=-0.8, z=0},
minexptime = .5,
maxexptime = .5,
minsize = 1,
maxsize = 5,
collisiondetection = false,
vertical = false,
texture = particle_texture,
})
end
-- ottiene la distanza tra proiettile e che cosa sta puntando
function get_dist(hit_pos, pos_ent)
local lenx = math.abs(hit_pos.x - pos_ent.x)
local leny = math.abs(hit_pos.y + 0.975 - pos_ent.y)
local lenz = math.abs(hit_pos.z - pos_ent.z)
local hypot = math.sqrt((lenx * lenx) + (lenz * lenz))
local dist = math.sqrt((hypot * hypot) + (leny * leny))
return dist
end
-- ottiene la cosa puntata dall'entità. Inizia da dietro l'entità perchè serve a verificare che non abbia attraversato un player senza colpirlo
function get_pointed_thing(pos_bullet, dir, username)
local p1 = vector.add(pos_bullet, vector.multiply(dir, -1))
local p2 = vector.add(pos_bullet, vector.multiply(dir, 0.1))
local ray = minetest.raycast(p1, p2, true, true)
for hit in ray do
-- se è un oggetto
if hit.type == "object" and hit.ref then
-- se è un giocatore
if hit.ref:is_player() then
-- e non è colui che spara
if hit.ref:get_player_name() ~= username then
return hit
end
end
else
if hit.type == "node" then
return hit
end
end
end
end