315 lines
10 KiB
Lua
315 lines
10 KiB
Lua
function quake.register_weapon(name, def)
|
|
|
|
local weap_delay = def.weap_delay
|
|
local weap_sound_shooting = def.weap_sound_shooting
|
|
local is_hitscan = def.is_hitscan
|
|
local range = def.range
|
|
local has_knockback = def.has_knockback
|
|
|
|
minetest.register_node(name, {
|
|
|
|
description = def.description,
|
|
drawtype = "mesh",
|
|
mesh = def.mesh,
|
|
tiles = def.tiles,
|
|
wield_scale = def.wield_scale,
|
|
inventory_image = def.inventory_image,
|
|
stack_max = 1,
|
|
groups = {oddly_breakable_by_hand = "2"},
|
|
on_drop = function()
|
|
return nil
|
|
end,
|
|
|
|
on_place = function()
|
|
return nil
|
|
end,
|
|
|
|
on_use = function(itemstack, user, pointed_thing)
|
|
|
|
----- gestione delay dell'arma -----
|
|
if user:get_meta():get_int("quake_weap_delay") == 1 then
|
|
return end
|
|
|
|
user:get_meta():set_int("quake_weap_delay", 1)
|
|
|
|
local inv = user:get_inventory()
|
|
|
|
minetest.after(weap_delay, function()
|
|
if inv:contains_item("main", "quake:match_over") then return end
|
|
user:get_meta():set_int("quake_weap_delay", 0)
|
|
end)
|
|
-----fine gestione delay -----
|
|
|
|
|
|
--se sono immune e sparo, perdo l'immunità
|
|
if inv:contains_item("main", "arena_lib:immunity") then
|
|
inv:remove_item("main", "arena_lib:immunity")
|
|
end
|
|
|
|
-- riproduzione suono
|
|
minetest.sound_play(weap_sound_shooting, {
|
|
to_player = user:get_player_name(),
|
|
max_hear_distance = 5,
|
|
})
|
|
|
|
local dir = user:get_look_dir()
|
|
local pos = user:get_pos()
|
|
local pos_head = {x = pos.x, y = pos.y+1.475, z = pos.z} -- deve sparare all'altezza mirino, ovvero dalla testa
|
|
local username = user:get_player_name()
|
|
|
|
|
|
if def.is_hitscan then
|
|
local target_pointed_thing = get_pointed_players(pos_head, dir, range, username)
|
|
if not target_pointed_thing then return end
|
|
|
|
for i = 2,(target_pointed_thing[1])+1 do
|
|
if target_pointed_thing[i] then
|
|
quake.shoot(target_pointed_thing[1], user:get_player_name(), target_pointed_thing[i].ref, def.weap_damage, has_knockback)
|
|
end
|
|
end
|
|
else
|
|
local has_knockback = def.knockback
|
|
local bullet = def.bullet
|
|
--i parametri potrebbero essere inutili ma non ne sono sicuro. Lasciamo così finchè va.
|
|
quake.shoot_bullet(user, pointed_thing, bullet, pos_head, dir)
|
|
end
|
|
|
|
end,
|
|
})
|
|
|
|
end
|
|
|
|
|
|
-- ritorna un array di player con a index 1 il numero di player trovati. Se non
|
|
-- trova player diversi da se stessi ritorna nil
|
|
function get_pointed_players(head_pos, dir, dist, username)
|
|
local p1 = vector.add(head_pos, vector.divide(dir,4))
|
|
local p2 = vector.add(head_pos, vector.multiply(dir, dist))
|
|
local ray = minetest.raycast(p1, p2, true, true)
|
|
|
|
minetest.add_particlespawner({
|
|
amount = 20,
|
|
time = 0.3,
|
|
minpos = p1,
|
|
maxpos = p1,
|
|
minvel = vector.multiply(dir,120),
|
|
maxvel = vector.multiply(dir,120),
|
|
minexptime = 0.2,
|
|
maxexptime = 0.2,
|
|
size = 2,
|
|
collisiondetection = false,
|
|
vertical = false,
|
|
texture = "quake_railgun_trail.png"
|
|
})
|
|
|
|
local array = {} --inizializzo array con numero di giocatori a 0
|
|
array[1] = 0
|
|
local i = 2
|
|
-- check su ogni cosa attraversata dal raycast (p1 a p2)
|
|
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
|
|
array[i] = hit
|
|
array[1] = i - 1 --incrementa il numero di giocatori
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
else
|
|
-- se è un nodo mi fermo, e ritorno l'array se > 0 (ovvero ha trovato giocatori)
|
|
if hit.type == "node" then
|
|
if array[1] > 0 then
|
|
return array
|
|
else
|
|
return nil
|
|
end
|
|
end
|
|
end
|
|
end
|
|
-- se ho sparato a qualcuno puntando in aria (quindi senza incrociare blocchi)
|
|
if array[1] > 0 then
|
|
return array
|
|
end
|
|
|
|
end
|
|
|
|
|
|
--funzione che usa quando esplode il proiettile. Posso piazzarla dove cazzo mi pare come file ma per ora va bene così.
|
|
--funziona. E fa danno in base alla distanza.
|
|
quake.explode = function(self)
|
|
local explosion_range = self.initial_properties.explosion_range
|
|
local explosion_damage = self.initial_properties.explosion_damage
|
|
local p1 = self.object:getpos()
|
|
local objs = minetest.env:get_objects_inside_radius(p1,explosion_range)
|
|
|
|
if objs then
|
|
local n_players = get_number_players_in_objs(objs)
|
|
for _, obj in ipairs(objs) do
|
|
--check da aggiungere
|
|
if (obj:get_entity_name() ~= self.initial_properties.name and obj:is_player()) then
|
|
local p2 = obj:getpos()
|
|
local lenx = math.abs(p2.x - p1.x)
|
|
local leny = math.abs(p2.y - p1.y)
|
|
local lenz = math.abs(p2.z - p1.z)
|
|
local hypot = math.sqrt((lenx * lenx) + (lenz * lenz))
|
|
local dist = math.sqrt((hypot * hypot) + (leny * leny))
|
|
local damage = explosion_damage - (explosion_damage * dist / explosion_range)
|
|
if (obj:get_player_name() ~= self.p_name) then
|
|
quake.shoot(n_players, self.p_name, obj, damage, false)
|
|
else
|
|
quake.shoot(n_players, self.p_name, obj, (damage/5), false)
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
function get_number_players_in_objs(objs)
|
|
local counter = 0
|
|
for _, obj in ipairs(objs) do
|
|
if obj:is_player() then
|
|
counter = counter + 1
|
|
end
|
|
end
|
|
return counter
|
|
end
|
|
|
|
|
|
local shooted_players = 0
|
|
local number_players = 0
|
|
local counter = 0
|
|
function quake.shoot(number_of_players, p_name, pointed_thing, damage, has_knockback)
|
|
|
|
counter = counter + 1
|
|
local pos = minetest.get_pointed_thing_position(pointed_thing)
|
|
local target = pointed_thing
|
|
local arena = arena_lib.get_arena_by_player(p_name)
|
|
|
|
if not arena then return end -- uno potrebbe sparare nel decimo di secondo di sostituzione arma a fine match e far crashare
|
|
|
|
if target:get_hp() <= 0 or arena.in_celebration then return end
|
|
|
|
-- controllo le immunità
|
|
if target:get_inventory():contains_item("main", "arena_lib:immunity") then
|
|
minetest.chat_send_player(p_name, "Non puoi colpire " .. target:get_player_name() .. ", è immune")
|
|
--TODO: sostituire con un suono
|
|
return end
|
|
|
|
-- eventuale knockback
|
|
if has_knockback then
|
|
local dir = minetest.get_player_by_name(p_name):get_look_dir()
|
|
local knockback = vector.multiply(dir,14)
|
|
target:add_player_velocity(knockback)
|
|
end
|
|
|
|
local t_name = target:get_player_name()
|
|
local remaining_HP = target:get_hp() - damage
|
|
|
|
-- controllo se è shutdown PRIMA di ucciderlo, sennò si resetta killstreak
|
|
if remaining_HP <= 0 and arena.players[t_name].killstreak >= 3 then
|
|
quake.add_achievement(p_name, 4)
|
|
quake.show_achievement(p_name, 4)
|
|
arena_lib.send_message_players_in_arena(arena, "[Quake] " .. minetest.colorize("#eea160", p_name) .. " ha fermato " .. minetest.colorize("#eea160", t_name))
|
|
end
|
|
|
|
-- applico il danno
|
|
target:set_hp(remaining_HP)
|
|
|
|
if target:get_hp() > 0 then return end
|
|
|
|
|
|
----- applico la morte -----
|
|
|
|
-- riproduco suono morte
|
|
minetest.sound_play("quake_kill", {
|
|
to_player = p_name,
|
|
max_hear_distance = 1,
|
|
})
|
|
|
|
-- informo dell'uccisione
|
|
minetest.chat_send_player(p_name, "[Quake] Hai ucciso " .. minetest.colorize("#eea160", t_name))
|
|
minetest.chat_send_player(t_name, "[Quake] Sei stato ucciso da " .. minetest.colorize("#eea160", p_name))
|
|
|
|
--achievement doppia kill
|
|
--viene fatto qua cosicchè appare dopo il messaggio "hai ucciso"
|
|
|
|
if number_players ~= number_of_players or number_of_players == 1 or counter == number_of_players then
|
|
number_players = number_of_players
|
|
shooted_players = 0
|
|
counter = 0
|
|
end
|
|
|
|
shooted_players = shooted_players + 1
|
|
|
|
if shooted_players > 1 then
|
|
|
|
if shooted_players == 2 then
|
|
quake.add_achievement(p_name, 6)
|
|
quake.show_achievement(p_name, 6)
|
|
elseif shooted_players >= 3 then
|
|
quake.add_achievement(p_name, 7)
|
|
quake.show_achievement(p_name, 7)
|
|
end
|
|
arena_lib.send_message_players_in_arena(arena, "[Quake] " .. minetest.colorize("#eea160", p_name) .. " ha ucciso " .. shooted_players.. " giocatori in un colpo!")
|
|
|
|
end
|
|
|
|
-- aggiungo la kill
|
|
local p_stats = arena.players[p_name]
|
|
p_stats.kills = p_stats.kills +1
|
|
p_stats.killstreak = p_stats.killstreak +1
|
|
quake.calc_kill_leader(arena, p_name)
|
|
|
|
--eventuale first blood
|
|
if arena.first_blood == "" then
|
|
arena.first_blood = p_name
|
|
quake.add_achievement(p_name, 5)
|
|
quake.show_achievement(p_name, 5)
|
|
arena_lib.send_message_players_in_arena(arena, "[Quake] " .. minetest.colorize("#eea160", p_name) .. " ha versato il primo sangue")
|
|
end
|
|
|
|
-- visibilità kill leader
|
|
local kill_leader = arena.kill_leader
|
|
for pl_name, stats in pairs(arena.players) do
|
|
quake.update_HUD(arena, pl_name, "KLR_data", arena.players[kill_leader].kills .. " | " .. kill_leader)
|
|
end
|
|
|
|
-- eventuale killstreak
|
|
if p_stats.killstreak == 3 then
|
|
arena_lib.send_message_players_in_arena(arena, "[Quake] " .. minetest.colorize("#eea160", p_name) .. " è in una " .. minetest.colorize("#eea160", "serie d'uccisioni").. "!")
|
|
quake.add_xp(p_name, 10)
|
|
quake.add_achievement(p_name, 1)
|
|
quake.show_achievement(p_name, 1)
|
|
elseif p_stats.killstreak == 5 then
|
|
arena_lib.send_message_players_in_arena(arena, "[Quake] " .. minetest.colorize("#eea160", p_name) .. " è " .. minetest.colorize("#eea160", "inarrestabile").. "!")
|
|
quake.add_xp(p_name, 25)
|
|
quake.add_achievement(p_name, 2)
|
|
quake.show_achievement(p_name, 2)
|
|
elseif p_stats.killstreak == 7 then
|
|
arena_lib.send_message_players_in_arena(arena, "[Quake] " .. minetest.colorize("#eea160", p_name) .. " è una " .. minetest.colorize("#eea160", "FURIA OMICIDA").. "!")
|
|
quake.add_xp(p_name, 50)
|
|
quake.add_achievement(p_name, 3)
|
|
quake.show_achievement(p_name, 3)
|
|
end
|
|
|
|
-- aggiorno HUD
|
|
quake.update_HUD(arena, p_name, "KLS_data", p_stats.kills)
|
|
quake.update_stats(arena)
|
|
|
|
-- aggiungo XP
|
|
quake.add_xp(p_name, 5)
|
|
|
|
-- se kill cap raggiunto finisce match
|
|
if arena.players[p_name].kills == arena.kill_cap then
|
|
|
|
local mod = arena_lib.get_mod_by_player(p_name)
|
|
arena_lib.load_celebration(mod, arena, p_name)
|
|
end
|
|
|
|
end
|