mirror of
https://git.code.sf.net/p/quake/game-source
synced 2024-11-28 22:52:26 +00:00
265 lines
6.1 KiB
C++
265 lines
6.1 KiB
C++
#include "common.qh"
|
|
#include "misc.qh"
|
|
|
|
#include "weapon.qh"
|
|
#include "equip.qh"
|
|
#include "damage.qh"
|
|
#include "effect.qh"
|
|
|
|
#define STR_EQUIPID_SHOTGUN "Shotgun"
|
|
|
|
#define PUFF_RADIUS 60 /* FIXME: Base on spread too! */
|
|
|
|
void() _deathmsg_shotgun = {
|
|
local string def_nname, att_nname;
|
|
local float r;
|
|
|
|
def_nname = name(self);
|
|
att_nname = name(self.dmg_attacker);
|
|
|
|
if (self.dmg_attacker == self) {
|
|
r = random()*2;
|
|
if (r < 1) bprint(PRINT_DEATH, def_nname, " eats lead.\n");
|
|
else bprint(PRINT_DEATH, def_nname, " can't aim a shotgun.\n");
|
|
} else {
|
|
r = random()*2;
|
|
if (r < 1) bprint(PRINT_DEATH, def_nname, " eats a load of ", att_nname, "'s buckshot.\n");
|
|
else bprint(PRINT_DEATH, att_nname, " fills ", def_nname, " full of lead.\n");
|
|
}
|
|
};
|
|
|
|
void() _deathmsg_super_shotgun = {
|
|
local float r;
|
|
local string def_nname, att_nname;
|
|
|
|
def_nname = name(self);
|
|
att_nname = name(self.dmg_attacker);
|
|
|
|
if (self.dmg_attacker == self) {
|
|
r = random()*2;
|
|
if (r < 1) bprint(PRINT_DEATH, def_nname, " gets 2 shells.\n");
|
|
else bprint(PRINT_DEATH, def_nname, " practices hunting with a teleporter.\n");
|
|
} else {
|
|
r = random()*2;
|
|
if (r < 1) bprint(PRINT_DEATH, def_nname, " eats two loads of ", att_nname, "'s buckshot.\n");
|
|
else bprint(PRINT_DEATH, att_nname, " makes ", def_nname, " radiation resistant.\n");
|
|
}
|
|
};
|
|
|
|
entity(vector org, vector dir, entity ent) spawn_puff_damage = {
|
|
local entity inflictor;
|
|
|
|
inflictor = world;
|
|
while ((inflictor = find(inflictor, classname, "PUFF"))) {
|
|
if (vlen(inflictor.origin - org) > PUFF_RADIUS)
|
|
continue;
|
|
|
|
if (inflictor.enemy == ent)
|
|
break;
|
|
}
|
|
|
|
if (!inflictor) {
|
|
inflictor = spawn("PUFF");
|
|
inflictor.solid = SOLID_BBOX;
|
|
inflictor.movetype = MOVETYPE_FLY;
|
|
inflictor.deadflag = DEAD_NONLIVING;
|
|
|
|
inflictor.velocity = dir;
|
|
inflictor.angles = vectoangles(dir);
|
|
|
|
inflictor.owner = ent;
|
|
inflictor.enemy = ent;
|
|
|
|
inflictor.origin = org; // Don't bother linking.
|
|
}
|
|
|
|
inflictor.count++;
|
|
|
|
return inflictor;
|
|
};
|
|
|
|
void(float shotcount, vector spread, void() deathmessage) _fire_bullets =
|
|
{
|
|
local vector dir, direction;
|
|
local vector src;
|
|
|
|
local entity ignore, puff;
|
|
local float t_dmg, t_mass;
|
|
|
|
local float dist_left;
|
|
|
|
makevectors(self.v_angle);
|
|
dir = aim(self, 10000);
|
|
src = shootorigin(self);
|
|
|
|
|
|
/* See what a single missile would take.. */
|
|
ghost_inflictor.classname = "BULLET";
|
|
ghost_inflictor.velocity = dir*10000;
|
|
ghost_inflictor.dmg = 4;
|
|
ghost_inflictor.mass = ghost_inflictor.dmg;
|
|
damage_attack(ghost_inflictor);
|
|
t_dmg = ghost_inflictor.dmg;
|
|
t_mass = ghost_inflictor.mass;
|
|
|
|
|
|
/* Create the puff damage entities */
|
|
tl_proj_begin();
|
|
|
|
ignore = self;
|
|
dist_left = 8192;
|
|
|
|
do {
|
|
for (; shotcount > 0; shotcount--) {
|
|
direction = dir + crandom()*spread_x*v_right + crandom()*spread_y*v_up;
|
|
traceline(src, src + direction*dist_left, FALSE, ignore);
|
|
|
|
puff = spawn_puff_damage(trace_endpos, dir, trace_ent);
|
|
puff.health = dist_left;
|
|
}
|
|
|
|
puff = world;
|
|
while ((puff = find(puff, classname, "PUFF"))) {
|
|
tl_touch(puff.enemy, puff);
|
|
|
|
if (!tl_issolid(puff.enemy)) {
|
|
dist_left = puff.health - (dist_left*trace_fraction);
|
|
if (dist_left > 100)
|
|
break;
|
|
} else {
|
|
puff.dmg = t_dmg * puff.count;
|
|
puff.mass = t_mass * puff.mass;
|
|
if (!damage(puff.enemy, self, puff, puff.dmg, deathmessage))
|
|
effect_gun_spark(puff.origin, puff.velocity, puff.count);
|
|
}
|
|
|
|
puff.classname = "REMOVED_PUFF";
|
|
safe_remove(puff);
|
|
}
|
|
|
|
if (!puff)
|
|
break;
|
|
|
|
src = puff.origin;
|
|
ignore = puff.enemy;
|
|
shotcount = puff.count;
|
|
|
|
makevectors(puff.angles);
|
|
dir = v_forward;
|
|
|
|
remove(puff);
|
|
} while (1);
|
|
|
|
tl_proj_end();
|
|
};
|
|
|
|
void() _w_shotgun_think = {
|
|
self.weaponframe++;
|
|
if (self.weaponframe < 1 || self.weaponframe > 6) {
|
|
self.w_think = NOTHING_function;
|
|
self.weaponframe = 0;
|
|
}
|
|
};
|
|
|
|
void() _w_shotgun_fire =
|
|
{
|
|
if (!util_weapon_use_ammo(ammo_shells, 1))
|
|
return;
|
|
|
|
sound(self, CHAN_WEAPON, "weapons/guncock.wav", 1, ATTN_NORM);
|
|
|
|
_fire_bullets(6, '0.04 0.04 0', _deathmsg_shotgun);
|
|
|
|
self.weaponframe = 1;
|
|
self.w_think = _w_shotgun_think;
|
|
self.mdl_func(MDL_FUNC_FIRE, 0);
|
|
effect_smallkick(self);
|
|
|
|
self.attack_finished = time + 0.5;
|
|
};
|
|
|
|
/* WEAPON 2 shotgun */
|
|
float(float action)
|
|
w_shotgun = {
|
|
if (action == WEAPON_AMMO) {
|
|
self.items |= IT_SHELLS;
|
|
return self.ammo_shells;
|
|
} else if (action == WEAPON_WEIGHT) {
|
|
return 20;
|
|
} else if (action == WEAPON_SELECTABLE) {
|
|
if (!equip_query(self, EQUIPID_SHOTGUN))
|
|
return 0;
|
|
if (self.ammo_shells >= 1)
|
|
return 1;
|
|
return -1;
|
|
} else if (action == WEAPON_SELECT) {
|
|
self.weaponmodel = "progs/v_shot.mdl";
|
|
self.weaponframe = 0;
|
|
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_SHOTGUN;
|
|
|
|
weaponprint(STR_EQUIPID_SHOTGUN);
|
|
} else if (action == WEAPON_FIRE) {
|
|
_w_shotgun_fire();
|
|
} else if (action == WEAPON_INIT) {
|
|
precache_model("progs/v_shot.mdl");
|
|
precache_sound("weapons/guncock.wav");
|
|
}
|
|
|
|
return 0;
|
|
};
|
|
|
|
// ================================================================
|
|
|
|
#define STR_EQUIPID_SUPER_SHOTGUN "Super Shotgun"
|
|
|
|
void() _w_super_shotgun_fire =
|
|
{
|
|
if (self.ammo_shells == 1) {
|
|
_w_shotgun_fire();
|
|
return;
|
|
}
|
|
|
|
if (!util_weapon_use_ammo(ammo_shells, 2))
|
|
return;
|
|
|
|
sound(self, CHAN_WEAPON, "weapons/shotgn2.wav", 1, ATTN_NORM);
|
|
|
|
_fire_bullets(14, '0.14 0.08 0', _deathmsg_super_shotgun);
|
|
|
|
self.weaponframe = 1;
|
|
self.w_think = _w_shotgun_think;
|
|
self.mdl_func(MDL_FUNC_FIRE, 0);
|
|
effect_smallkick(self);
|
|
|
|
self.attack_finished = time + 0.7;
|
|
};
|
|
|
|
/* WEAPON 3 super_shotgun */
|
|
float(float action)
|
|
w_super_shotgun = {
|
|
if (action == WEAPON_AMMO) {
|
|
self.items |= IT_SHELLS;
|
|
return self.ammo_shells;
|
|
} else if (action == WEAPON_WEIGHT) {
|
|
return 40;
|
|
} else if (action == WEAPON_SELECTABLE) {
|
|
if (!equip_query(self, EQUIPID_SUPER_SHOTGUN))
|
|
return 0;
|
|
if (self.ammo_shells >= 2)
|
|
return 1;
|
|
return -1;
|
|
} else if (action == WEAPON_SELECT) {
|
|
self.weaponmodel = "progs/v_shot2.mdl";
|
|
self.weaponframe = 0;
|
|
self.mdl_mod = (self.mdl_mod & ~MDL_MOD_WEP_MASK) | MDL_MOD_WEP_SUPER_SHOTGUN;
|
|
|
|
weaponprint(STR_EQUIPID_SUPER_SHOTGUN);
|
|
} else if (action == WEAPON_FIRE) {
|
|
_w_super_shotgun_fire();
|
|
} else if (action == WEAPON_INIT) {
|
|
precache_model("progs/v_shot2.mdl");
|
|
precache_sound("weapons/shotgn2.wav");
|
|
}
|
|
|
|
return 0;
|
|
};
|