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