mirror of
https://github.com/blendogames/thirtyflightsofloving.git
synced 2024-11-15 00:41:21 +00:00
7b6f4281ad
Added Zaero flare gun to no-autoswitch in p_weapon.c->Pickup_Weapon() in missionpack DLL. Added LM plasma rifle to p_weapon.c->NoAmmoWeaponChange() in missionpack DLL. Added output of modelindex5&6, alpha, and attenuation to properties command in missionpack DLL. Added nogib and environment spawnflags to trigger_hurt and trigger_hurt_boox in missionpack DLL. Added MONSTER_KNOWS_MIRRORS flag to berserker, barracuda shark, and mutant in missionpack DLL. Added entity class IDs to misc_actor and target_actor in missionpack DLL. Added syntax whitespacing to some files in missionpack DLL. Added backpack drop to certain monsters in missionpack DLL. Changed some sound paths for new monsters and weapons in missionpack DLL.
1024 lines
26 KiB
C
1024 lines
26 KiB
C
// g_weapon_q1.c
|
|
|
|
#include "g_local.h"
|
|
|
|
|
|
void check_dodge (edict_t *self, vec3_t start, vec3_t dir, int speed);
|
|
|
|
|
|
/*
|
|
=================
|
|
q1_fire_nail
|
|
|
|
Fires a Nail, Used by Q1 NG and SNG
|
|
=================
|
|
*/
|
|
void q1_nail_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
int mod;
|
|
|
|
if (other == self->owner)
|
|
return;
|
|
|
|
if (surf && (surf->flags & SURF_SKY))
|
|
{
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
|
|
if (self->owner->client)
|
|
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
|
|
|
|
if (other->takedamage)
|
|
{
|
|
if (self->spawnflags & 1)
|
|
mod = MOD_Q1_SNG;
|
|
else
|
|
mod = MOD_Q1_NG;
|
|
T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 0, DAMAGE_BULLET, mod);
|
|
}
|
|
else
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_SHOTGUN);
|
|
gi.WritePosition (self->s.origin);
|
|
if (!plane)
|
|
gi.WriteDir (vec3_origin);
|
|
else
|
|
gi.WriteDir (plane->normal);
|
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
|
|
|
//not if online, too laggy
|
|
if(!deathmatch->value)
|
|
{
|
|
float sound= random();
|
|
if (sound < 0.3)
|
|
{
|
|
if (sound < 0.1)
|
|
gi.sound (self, CHAN_WEAPON, gi.soundindex ("q1weapons/ric3.wav"), 1, ATTN_STATIC, 0);
|
|
else if (sound < 0.2)
|
|
gi.sound (self, CHAN_WEAPON, gi.soundindex ("q1weapons/ric2.wav"), 1, ATTN_STATIC, 0);
|
|
else
|
|
gi.sound (self, CHAN_WEAPON, gi.soundindex ("q1weapons/ric1.wav"), 1, ATTN_STATIC, 0);
|
|
}
|
|
else if (sound < 0.5)
|
|
gi.sound (self, CHAN_WEAPON, gi.soundindex ("q1weapons/tink1.wav"), 1, ATTN_STATIC, 0);
|
|
}
|
|
|
|
}
|
|
G_FreeEdict (self);
|
|
}
|
|
|
|
|
|
void q1_fire_nail (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, qboolean sng)
|
|
{
|
|
edict_t *nail;
|
|
trace_t tr;
|
|
|
|
VectorNormalize (dir);
|
|
|
|
nail = G_Spawn();
|
|
VectorCopy (start, nail->s.origin);
|
|
VectorCopy (start, nail->s.old_origin);
|
|
vectoangles (dir, nail->s.angles);
|
|
VectorScale (dir, speed, nail->velocity);
|
|
nail->movetype = MOVETYPE_FLYMISSILE;
|
|
nail->clipmask = MASK_SHOT;
|
|
nail->solid = SOLID_BBOX;
|
|
nail->svflags = SVF_DEADMONSTER;
|
|
nail->s.renderfx = RF_FULLBRIGHT;
|
|
VectorClear (nail->mins);
|
|
VectorClear (nail->maxs);
|
|
nail->s.modelindex = gi.modelindex ("models/objects/q1nail/tris.md2");
|
|
nail->owner = self;
|
|
nail->touch = q1_nail_touch;
|
|
nail->nextthink = level.time + 8000/speed;
|
|
nail->think = G_FreeEdict;
|
|
nail->dmg = damage;
|
|
nail->classname = "nail";
|
|
if (sng)
|
|
nail->spawnflags = 1;
|
|
|
|
nail->common_name = "Nail";
|
|
nail->class_id = ENTITY_Q1_NAIL;
|
|
|
|
gi.linkentity (nail);
|
|
|
|
if (self->client)
|
|
check_dodge (self, nail->s.origin, dir, speed);
|
|
|
|
tr = gi.trace (self->s.origin, NULL, NULL, nail->s.origin, nail, MASK_SHOT);
|
|
if (tr.fraction < 1.0)
|
|
{
|
|
VectorMA (nail->s.origin, -10, dir, nail->s.origin);
|
|
nail->touch (nail, tr.ent, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
q1_fire_laser
|
|
|
|
Fires a laser bolt, used by Q1 enforcer and laser trap.
|
|
=================
|
|
*/
|
|
void q1_laser_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
if (other == self->owner)
|
|
return;
|
|
|
|
if (surf && (surf->flags & SURF_SKY))
|
|
{
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
|
|
if (self->owner->client)
|
|
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
|
|
|
|
if (other->takedamage) {
|
|
T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 0, DAMAGE_ENERGY, MOD_Q1_LASER);
|
|
}
|
|
else
|
|
{
|
|
#if 1 // From Decino's Q2Infighter mod
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_WELDING_SPARKS);
|
|
gi.WriteByte (15);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.WriteDir ((!plane) ? vec3_origin : plane->normal);
|
|
gi.WriteByte (226);
|
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
|
#else
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_SHOTGUN);
|
|
gi.WritePosition (self->s.origin);
|
|
if (!plane)
|
|
gi.WriteDir (vec3_origin);
|
|
else
|
|
gi.WriteDir (plane->normal);
|
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
|
#endif
|
|
|
|
// not if online, too laggy
|
|
if (!deathmatch->value)
|
|
{
|
|
gi.sound (self, CHAN_WEAPON, gi.soundindex ("q1enforcer/enfstop.wav"), 1, ATTN_STATIC, 0);
|
|
}
|
|
}
|
|
G_FreeEdict (self);
|
|
}
|
|
|
|
void q1_fire_laser (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed)
|
|
{
|
|
edict_t *laser;
|
|
trace_t tr;
|
|
|
|
VectorNormalize (dir);
|
|
|
|
laser = G_Spawn();
|
|
VectorCopy (start, laser->s.origin);
|
|
VectorCopy (start, laser->s.old_origin);
|
|
vectoangles (dir, laser->s.angles);
|
|
VectorScale (dir, speed, laser->velocity);
|
|
laser->movetype = MOVETYPE_FLYMISSILE;
|
|
laser->clipmask = MASK_SHOT;
|
|
laser->solid = SOLID_BBOX;
|
|
laser->svflags = SVF_DEADMONSTER;
|
|
laser->s.renderfx = RF_FULLBRIGHT;
|
|
VectorClear (laser->mins);
|
|
VectorClear (laser->maxs);
|
|
laser->s.modelindex = gi.modelindex ("models/monsters/q1enforcer/laser/tris.md2");
|
|
laser->owner = self;
|
|
laser->touch = q1_laser_touch;
|
|
laser->nextthink = level.time + 8000/speed;
|
|
laser->think = G_FreeEdict;
|
|
laser->dmg = damage;
|
|
laser->classname = "laser";
|
|
|
|
laser->common_name = "Laser";
|
|
laser->class_id = ENTITY_Q1_LASER;
|
|
|
|
gi.linkentity (laser);
|
|
|
|
if (self->client)
|
|
check_dodge (self, laser->s.origin, dir, speed);
|
|
|
|
tr = gi.trace (self->s.origin, NULL, NULL, laser->s.origin, laser, MASK_SHOT);
|
|
if (tr.fraction < 1.0)
|
|
{
|
|
VectorMA (laser->s.origin, -10, dir, laser->s.origin);
|
|
laser->touch (laser, tr.ent, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
q1_fire_flame
|
|
|
|
Fires a flame bolt. Used by the Hell Knight.
|
|
=================
|
|
*/
|
|
|
|
void q1_flame_splash (int type, int count, int color, vec3_t start, vec3_t movdir, vec3_t origin)
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (type);
|
|
gi.WriteByte (count);
|
|
gi.WritePosition (start);
|
|
gi.WriteDir (movdir);
|
|
gi.WriteByte (color);
|
|
gi.multicast (origin, MULTICAST_PVS);
|
|
}
|
|
|
|
void q1_flame_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
if (other == self->owner)
|
|
return;
|
|
|
|
if (surf && (surf->flags & SURF_SKY))
|
|
{
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
|
|
if (self->owner->client)
|
|
PlayerNoise(self->owner, self->s.origin, PNOISE_IMPACT);
|
|
|
|
if (other->takedamage)
|
|
{
|
|
T_Damage (other, self, self->owner, self->velocity, self->s.origin, plane->normal, self->dmg, 1, DAMAGE_ENERGY, MOD_Q1_FLAMEBOLT);
|
|
}
|
|
else
|
|
{
|
|
#if 1 // From Decino's Q2Infighter mod
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_WELDING_SPARKS);
|
|
gi.WriteByte (15);
|
|
gi.WritePosition (self->s.origin);
|
|
gi.WriteDir ((!plane) ? vec3_origin : plane->normal);
|
|
// gi.WriteByte (66);
|
|
gi.WriteByte (228);
|
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
|
#else
|
|
q1_flame_splash (TE_TUNNEL_SPARKS, 16, 71, self->s.origin, plane->normal, self->s.origin);
|
|
#endif
|
|
}
|
|
|
|
gi.sound (self, CHAN_WEAPON, gi.soundindex("q1hknight/hit.wav"), 1, ATTN_NORM, 0);
|
|
|
|
G_FreeEdict (self);
|
|
}
|
|
|
|
void q1_fire_flame (edict_t *self, vec3_t start, vec3_t dir, float leftrightoff)
|
|
{
|
|
edict_t *bolt;
|
|
trace_t tr;
|
|
int damage, speed;
|
|
// vec3_t up;
|
|
|
|
damage = 9;
|
|
speed = 300;
|
|
|
|
VectorNormalize (dir);
|
|
|
|
bolt = G_Spawn();
|
|
bolt->svflags |= SVF_DEADMONSTER;
|
|
// yes, I know it looks weird that projectiles are deadmonsters
|
|
// what this means is that when prediction is used against the object
|
|
// (blaster/hyperblaster shots), the player won't be solid clipped against
|
|
// the object. Right now trying to run into a firing hyperblaster
|
|
// is very jerky since you are predicted 'against' the shots.
|
|
|
|
VectorCopy (start, bolt->s.origin);
|
|
VectorCopy (start, bolt->s.old_origin);
|
|
vectoangles (dir, bolt->s.angles);
|
|
VectorScale (dir, speed, bolt->velocity);
|
|
bolt->movetype = MOVETYPE_FLYMISSILE;
|
|
bolt->clipmask = MASK_SHOT;
|
|
bolt->solid = SOLID_BBOX;
|
|
bolt->s.effects |= EF_IONRIPPER;
|
|
VectorClear (bolt->mins);
|
|
VectorClear (bolt->maxs);
|
|
bolt->s.modelindex = gi.modelindex ("models/monsters/q1hknight/k_spike/tris.md2");
|
|
bolt->owner = self;
|
|
bolt->touch = q1_flame_touch;
|
|
bolt->nextthink = level.time + 2;
|
|
bolt->think = G_FreeEdict;
|
|
bolt->dmg = damage;
|
|
bolt->classname = "bolt";
|
|
|
|
bolt->common_name = "Hell Knight Flame";
|
|
bolt->class_id = ENTITY_Q1_HKNIGHT_FLAME;
|
|
|
|
gi.linkentity (bolt);
|
|
|
|
tr = gi.trace (self->s.origin, NULL, NULL, bolt->s.origin, bolt, MASK_SHOT);
|
|
if (tr.fraction < 1.0)
|
|
{
|
|
VectorMA (bolt->s.origin, -10, dir, bolt->s.origin);
|
|
bolt->touch (bolt, tr.ent, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
q1_fire_grenade
|
|
|
|
Fires a grenade. Used by the Ogre.
|
|
=================
|
|
*/
|
|
void q1_explode (edict_t *self)
|
|
{
|
|
if (self->s.frame == 5)
|
|
{
|
|
G_FreeEdict (self);
|
|
return;
|
|
}
|
|
self->nextthink = level.time + FRAMETIME;
|
|
self->s.frame++;
|
|
}
|
|
|
|
void q1_grenade_explode (edict_t *ent)
|
|
{
|
|
vec3_t origin;
|
|
|
|
if (ent->owner->client)
|
|
PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
|
|
|
|
// FIXME: if we are onground then raise our Z just a bit since we are a point?
|
|
if (ent->enemy)
|
|
{
|
|
float points;
|
|
vec3_t v;
|
|
vec3_t dir;
|
|
|
|
VectorAdd (ent->enemy->mins, ent->enemy->maxs, v);
|
|
VectorMA (ent->enemy->s.origin, 0.5, v, v);
|
|
VectorSubtract (ent->s.origin, v, v);
|
|
points = ent->dmg - 0.5 * VectorLength (v);
|
|
VectorSubtract (ent->enemy->s.origin, ent->s.origin, dir);
|
|
T_Damage (ent->enemy, ent, ent->owner, dir, ent->s.origin, vec3_origin, (int)points, (int)points, DAMAGE_RADIUS, MOD_Q1_GL);
|
|
}
|
|
|
|
T_RadiusDamage(ent, ent->owner, ent->dmg, ent->enemy, ent->dmg_radius, MOD_Q1_GL_SPLASH);
|
|
|
|
VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
|
|
gi.sound (ent, CHAN_AUTO, gi.soundindex ("q1weapons/r_exp3.wav"), 1.0, ATTN_NORM, 0);
|
|
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_ROCKET_EXPLOSION);
|
|
gi.WritePosition (origin);
|
|
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
|
|
|
// explosion sprite
|
|
gi.unlinkentity (ent);
|
|
ent->solid = SOLID_NOT;
|
|
ent->touch = NULL;
|
|
VectorCopy( origin, ent->s.origin);
|
|
VectorCopy( origin, ent->s.old_origin);
|
|
VectorClear (ent->velocity);
|
|
ent->s.modelindex = gi.modelindex ("sprites/s_explod.sp2");
|
|
ent->s.frame = 0;
|
|
ent->s.sound = 0;
|
|
ent->s.effects &= ~EF_ANIM_ALLFAST;
|
|
ent->think = q1_explode;
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
gi.linkentity (ent);
|
|
}
|
|
|
|
|
|
void q1_grenade_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
if (other == ent->owner)
|
|
return;
|
|
|
|
if (surf && (surf->flags & SURF_SKY))
|
|
{
|
|
G_FreeEdict (ent);
|
|
return;
|
|
}
|
|
|
|
if (!other->takedamage ||
|
|
(other->solid == SOLID_BSP))
|
|
{
|
|
gi.sound (ent, CHAN_RELIABLE|CHAN_WEAPON, gi.soundindex ("q1weapons/bounce.wav"), 1, ATTN_NORM, 0);
|
|
return;
|
|
}
|
|
|
|
ent->enemy = other;
|
|
q1_grenade_explode (ent);
|
|
}
|
|
|
|
|
|
void q1_fire_grenade (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed, float timer, float damage_radius)
|
|
{
|
|
edict_t *grenade;
|
|
vec3_t dir;
|
|
vec3_t forward, right, up;
|
|
|
|
vectoangles (aimdir, dir);
|
|
AngleVectors (dir, forward, right, up);
|
|
grenade = G_Spawn();
|
|
VectorCopy (start, grenade->s.origin);
|
|
VectorScale (aimdir, speed, grenade->velocity);
|
|
VectorMA (grenade->velocity, 200 + (random() - 0.5) * 20.0, up, grenade->velocity);
|
|
VectorMA (grenade->velocity, (random() - 0.5) * 20.0, right, grenade->velocity);
|
|
VectorSet (grenade->avelocity, 300, 300, 300);
|
|
grenade->movetype = MOVETYPE_BOUNCE;
|
|
grenade->clipmask = MASK_SHOT;
|
|
grenade->solid = SOLID_BBOX;
|
|
grenade->s.effects |= EF_GRENADE;
|
|
VectorClear (grenade->mins);
|
|
VectorClear (grenade->maxs);
|
|
grenade->s.modelindex = gi.modelindex ("models/objects/grenade/tris.md2");
|
|
grenade->owner = self;
|
|
grenade->touch = q1_grenade_touch;
|
|
grenade->nextthink = level.time + timer;
|
|
grenade->think = q1_grenade_explode;
|
|
grenade->dmg = damage;
|
|
grenade->dmg_radius = damage_radius;
|
|
grenade->classname = "grenade";
|
|
|
|
grenade->common_name = "Quake Grenade";
|
|
grenade->class_id = ENTITY_Q1_GRENADE;
|
|
|
|
gi.linkentity (grenade);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
q1_fire_rocket
|
|
|
|
Fires a q1 rocket. Used by ?
|
|
=================
|
|
*/
|
|
void q1_rocket_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
vec3_t origin;
|
|
|
|
if (other == ent->owner)
|
|
return;
|
|
|
|
if (surf && (surf->flags & SURF_SKY))
|
|
{
|
|
G_FreeEdict (ent);
|
|
return;
|
|
}
|
|
|
|
if (ent->owner->client)
|
|
PlayerNoise(ent->owner, ent->s.origin, PNOISE_IMPACT);
|
|
|
|
// calculate position for the explosion entity
|
|
VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
|
|
|
|
if (other->takedamage)
|
|
{
|
|
T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_Q1_RL);
|
|
}
|
|
T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_Q1_RL_SPLASH);
|
|
gi.sound (ent,CHAN_AUTO , gi.soundindex ("q1weapons/r_exp3.wav"), 1.0, ATTN_NORM, 0);
|
|
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_ROCKET_EXPLOSION);
|
|
gi.WritePosition (origin);
|
|
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
|
|
|
// if (ent->target_ent)
|
|
// G_FreeEdict(ent->target_ent);
|
|
|
|
// explosion sprite
|
|
gi.unlinkentity (ent);
|
|
ent->solid = SOLID_NOT;
|
|
ent->touch = NULL;
|
|
VectorCopy( origin, ent->s.origin);
|
|
VectorCopy( origin, ent->s.old_origin);
|
|
VectorClear (ent->velocity);
|
|
ent->s.modelindex = gi.modelindex ("sprites/s_explod.sp2");
|
|
ent->s.frame = 0;
|
|
ent->s.sound = 0;
|
|
ent->s.effects &= ~EF_ANIM_ALLFAST;
|
|
ent->think = q1_explode;
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
gi.linkentity (ent);
|
|
}
|
|
|
|
|
|
void q1rocketTrail_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
G_FreeEdict (ent);
|
|
}
|
|
|
|
// Rocket Trails
|
|
// needed to give the yellow part of the Rocket trail
|
|
|
|
void q1rocket_trail (edict_t *self, vec3_t start, vec3_t dir)
|
|
{
|
|
edict_t *bolt;
|
|
VectorNormalize (dir);
|
|
|
|
bolt = G_Spawn();
|
|
VectorCopy (start, bolt->s.origin);
|
|
VectorCopy (start, bolt->s.old_origin);
|
|
vectoangles (dir, bolt->s.angles);
|
|
VectorScale (dir, 950, bolt->velocity);
|
|
bolt->movetype = MOVETYPE_FLYMISSILE;
|
|
bolt->clipmask = MASK_SHOT;
|
|
bolt->solid = SOLID_BBOX;
|
|
bolt->s.effects = EF_BLASTER;
|
|
bolt->svflags |= SVF_DEADMONSTER;
|
|
VectorClear (bolt->mins);
|
|
VectorClear (bolt->maxs);
|
|
bolt->s.modelindex = gi.modelindex ("models/objects/laser/tris.md2");
|
|
bolt->owner = self;
|
|
bolt->touch = q1rocketTrail_touch;
|
|
bolt->nextthink = level.time + 8000/950;
|
|
bolt->think = G_FreeEdict;
|
|
bolt->classname = "bolt";
|
|
gi.linkentity (bolt);
|
|
|
|
}
|
|
|
|
|
|
void q1_fire_rocket (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
|
|
{
|
|
edict_t *rocket;
|
|
|
|
rocket = G_Spawn();
|
|
VectorCopy (start, rocket->s.origin);
|
|
VectorCopy (dir, rocket->movedir);
|
|
vectoangles (dir, rocket->s.angles);
|
|
VectorScale (dir, speed, rocket->velocity);
|
|
rocket->movetype = MOVETYPE_FLYMISSILE;
|
|
rocket->clipmask = MASK_SHOT;
|
|
rocket->solid = SOLID_BBOX;
|
|
rocket->s.effects |= EF_GRENADE;
|
|
VectorClear (rocket->mins);
|
|
VectorClear (rocket->maxs);
|
|
rocket->s.modelindex = gi.modelindex ("models/objects/rocket/tris.md2");
|
|
rocket->owner = self;
|
|
rocket->touch = q1_rocket_touch;
|
|
rocket->nextthink = level.time + 8000/speed;
|
|
rocket->think = G_FreeEdict;
|
|
rocket->dmg = damage;
|
|
rocket->radius_dmg = radius_damage;
|
|
rocket->dmg_radius = damage_radius;
|
|
rocket->s.sound = gi.soundindex ("weapons/rockfly.wav");
|
|
rocket->classname = "rocket";
|
|
|
|
q1rocket_trail (rocket, start, dir);
|
|
|
|
rocket->common_name = "Quake Rocket";
|
|
rocket->class_id = ENTITY_Q1_ROCKET;
|
|
|
|
gi.linkentity (rocket);
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
q1_fire_lightning
|
|
|
|
Fires a lighting bolt. Used by ?
|
|
=================
|
|
*/
|
|
void q1_fire_lightning (edict_t *self, vec3_t start, vec3_t dir, int damage)
|
|
{
|
|
vec3_t end;
|
|
trace_t tr;
|
|
|
|
|
|
VectorNormalize(dir);
|
|
VectorMA(start,600,dir,end);
|
|
|
|
// Initial Trace - damage if close enough
|
|
tr = gi.trace (self->s.origin, NULL, NULL, start, self, MASK_SHOT);
|
|
if (tr.fraction < 1.0)
|
|
{
|
|
if(tr.ent && (tr.ent !=self) && (tr.ent->takedamage))
|
|
T_Damage (tr.ent, self, self, dir, tr.endpos, tr.plane.normal, damage, 0, DAMAGE_ENERGY, MOD_Q1_LG);
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// trace 2
|
|
tr = gi.trace (start, NULL, NULL, end, self, MASK_SHOT);
|
|
|
|
if (self->client->chasetoggle)
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
|
|
// gi.WriteByte (TE_HEATBEAM);
|
|
gi.WriteShort (self->client->oldplayer - g_edicts);
|
|
gi.WritePosition (start);
|
|
gi.WritePosition (tr.endpos);
|
|
gi.multicast (self->client->oldplayer->s.origin, MULTICAST_PVS);
|
|
// gi.multicast (self->client->oldplayer->s.origin, MULTICAST_ALL);
|
|
}
|
|
else
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_MEDIC_CABLE_ATTACK);
|
|
// gi.WriteByte (TE_HEATBEAM);
|
|
gi.WriteShort (self - g_edicts);
|
|
gi.WritePosition (start);
|
|
gi.WritePosition (tr.endpos);
|
|
gi.multicast (self->s.origin, MULTICAST_PVS);
|
|
// gi.multicast (self->s.origin, MULTICAST_ALL);
|
|
}
|
|
|
|
if ((tr.ent != self) && (tr.ent->takedamage))
|
|
T_Damage (tr.ent, self, self, dir, tr.endpos, tr.plane.normal, damage, 0, DAMAGE_ENERGY, MOD_Q1_LG);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
=================
|
|
q1_fire_firepod
|
|
|
|
Fires a homing fire pod. Used by the Vore (shalrath).
|
|
=================
|
|
*/
|
|
void q1_firepod_touch (edict_t *self, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
// int mod;
|
|
vec3_t origin;
|
|
|
|
if (other == self->owner)
|
|
return;
|
|
|
|
if ( (Q_stricmp(other->classname, "q1_monster_zombie") == 0) || (Q_stricmp(other->classname, "monster_q1_zombie") == 0) )
|
|
T_Damage (other, self, self->owner, vec3_origin, other->s.origin, vec3_origin, 200, 0, 0, 0);
|
|
T_RadiusDamage (self, self->owner, 40, NULL, 40, MOD_Q1_FIREPOD);
|
|
|
|
gi.sound (self,CHAN_AUTO , gi.soundindex ("q1weapons/r_exp3.wav"), 1.0, ATTN_NORM, 0);
|
|
|
|
VectorMA (self->s.origin, -0.02, self->velocity, origin);
|
|
|
|
// gi.WriteByte (svc_temp_entity);
|
|
// gi.WriteByte (TE_Q1_EXPLOSION);
|
|
// FX Paril
|
|
// gi.WriteByte (TE_ROCKET_EXPLOSION);
|
|
// gi.WritePosition (origin);
|
|
// gi.multicast (self->s.origin, MULTICAST_PVS);
|
|
|
|
gi.unlinkentity (self);
|
|
self->solid = SOLID_NOT;
|
|
self->touch = NULL;
|
|
VectorCopy (origin, self->s.origin);
|
|
VectorCopy (origin, self->s.old_origin);
|
|
VectorClear (self->velocity);
|
|
self->s.modelindex = gi.modelindex ("sprites/s_explod.sp2");
|
|
self->s.frame = 0;
|
|
self->s.sound = 0;
|
|
self->s.effects &= ~EF_ANIM_ALLFAST;
|
|
self->think = q1_explode;
|
|
self->nextthink = level.time + FRAMETIME;
|
|
gi.linkentity (self);
|
|
|
|
// q1_explo_particles (self, origin);
|
|
// if (Q_stricmp(self->classname, "freed"))
|
|
// G_FreeEdict (self);
|
|
}
|
|
|
|
|
|
void q1_firepod_home (edict_t *self)
|
|
{
|
|
vec3_t dir, vtemp;
|
|
VectorClear (self->velocity);
|
|
VectorCopy (self->enemy->s.origin, vtemp);
|
|
VectorSet (dir, 0, 0, 10);
|
|
VectorAdd (vtemp, dir, vtemp);
|
|
VectorClear (dir);
|
|
if (self->enemy->health < 1)
|
|
{
|
|
G_FreeEdict(self);
|
|
return;
|
|
}
|
|
if (self->enemy->client && (self->enemy->client->ps.pmove.pm_flags & PMF_DUCKED))
|
|
vtemp[2] -= 10;
|
|
VectorSubtract (vtemp, self->s.origin, dir);
|
|
VectorNormalize (dir);
|
|
if (skill->value >= 2)
|
|
VectorMA (self->velocity, 350, dir, self->velocity);
|
|
else
|
|
VectorMA (self->velocity, 250, dir, self->velocity);
|
|
self->nextthink = level.time + 0.2;
|
|
}
|
|
|
|
|
|
void q1_fire_firepod (edict_t *self, vec3_t dir)
|
|
{
|
|
edict_t *pod;
|
|
trace_t tr;
|
|
vec3_t start, temp;
|
|
|
|
VectorCopy (self->s.origin, start);
|
|
VectorSet (temp, 0, 0, 10);
|
|
VectorAdd (start, temp, start);
|
|
|
|
VectorNormalize (dir);
|
|
|
|
pod = G_Spawn();
|
|
pod->svflags |= SVF_DEADMONSTER;
|
|
// yes, I know it looks weird that projectiles are deadmonsters
|
|
// what this means is that when prediction is used against the object
|
|
// (blaster/hyperblaster shots), the player won't be solid clipped against
|
|
// the object. Right now trying to run into a firing hyperblaster
|
|
// is very jerky since you are predicted 'against' the shots.
|
|
|
|
VectorCopy (start, pod->s.origin);
|
|
VectorCopy (start, pod->s.old_origin);
|
|
vectoangles (dir, pod->s.angles);
|
|
VectorScale (dir, 400, pod->velocity);
|
|
pod->movetype = MOVETYPE_FLYMISSILE;
|
|
pod->clipmask = MASK_SHOT;
|
|
pod->solid = SOLID_BBOX;
|
|
VectorSet (pod->avelocity, 300, 300, 300);
|
|
#ifdef KMQUAKE2_ENGINE_MOD
|
|
pod->s.effects |= EF_FLAG1|EF_BLUEHYPERBLASTER;
|
|
#else
|
|
pod->s.effects |= EF_FLAG1|EF_FLAG2;
|
|
#endif
|
|
VectorClear (pod->mins);
|
|
VectorClear (pod->maxs);
|
|
pod->s.modelindex = gi.modelindex ("models/monsters/q1shalrath/v_spike/tris.md2");
|
|
// pod->s.sound = gi.soundindex ("misc/lasfly.wav");
|
|
pod->touch = q1_firepod_touch;
|
|
pod->nextthink = level.time +.1;
|
|
pod->think = q1_firepod_home;
|
|
pod->classname = "firepod";
|
|
pod->enemy = self->enemy;
|
|
pod->owner = self;
|
|
|
|
pod->common_name = "Firepod";
|
|
pod->class_id = ENTITY_Q1_FIREPOD;
|
|
|
|
gi.linkentity (pod);
|
|
|
|
// if (self->client)
|
|
// check_dodge (self, pod->s.origin, dir, speed);
|
|
|
|
tr = gi.trace (self->s.origin, NULL, NULL, pod->s.origin, pod, MASK_SHOT);
|
|
if (tr.fraction < 1.0)
|
|
{
|
|
VectorMA (pod->s.origin, -10, dir, pod->s.origin);
|
|
pod->touch (pod, tr.ent, NULL, NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
=================
|
|
q1_fire_lavaball
|
|
|
|
Fires a lavaball. Used by Chthon.
|
|
=================
|
|
*/
|
|
/*static*/ void q1_lavaball_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
vec3_t origin;
|
|
|
|
if (other == ent->owner)
|
|
return;
|
|
|
|
if (surf && (surf->flags & SURF_SKY))
|
|
{
|
|
G_FreeEdict (ent);
|
|
return;
|
|
}
|
|
|
|
// calculate position for the explosion entity
|
|
VectorMA (ent->s.origin, -0.02, ent->velocity, origin);
|
|
|
|
if (other->takedamage)
|
|
{
|
|
T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg,(ent->dmg*2), 0, MOD_Q1_RL);
|
|
}
|
|
|
|
T_RadiusDamage(ent, ent->owner, ent->radius_dmg, other, ent->dmg_radius, MOD_Q1_RL_SPLASH);
|
|
gi.sound (ent, CHAN_WEAPON, gi.soundindex ("q1weapons/r_exp3.wav"), 1.0, ATTN_NORM, 0);
|
|
|
|
//
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_ROCKET_EXPLOSION);
|
|
gi.WritePosition (origin);
|
|
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
|
//
|
|
// explosion sprite
|
|
gi.unlinkentity(ent);
|
|
ent->solid = SOLID_NOT;
|
|
ent->touch = NULL;
|
|
VectorCopy(ent->s.origin, origin);
|
|
VectorCopy(ent->s.origin, ent->s.old_origin);
|
|
VectorClear (ent->velocity);
|
|
ent->s.modelindex = gi.modelindex ("sprites/s_explod.sp2");
|
|
ent->s.frame = 0;
|
|
ent->s.sound = 0;
|
|
ent->s.effects &= ~EF_ANIM_ALLFAST;
|
|
ent->think = q1_explode;
|
|
ent->nextthink = level.time + FRAMETIME;
|
|
ent->enemy = other;
|
|
gi.linkentity (ent);
|
|
}
|
|
|
|
|
|
void q1_fire_lavaball (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed, float damage_radius, int radius_damage)
|
|
{
|
|
edict_t *lavaball;
|
|
|
|
lavaball = G_Spawn();
|
|
VectorCopy (start, lavaball->s.origin);
|
|
VectorCopy (dir, lavaball->movedir);
|
|
vectoangles (dir, lavaball->s.angles);
|
|
VectorScale (dir, speed, lavaball->velocity);
|
|
lavaball->movetype = MOVETYPE_FLYMISSILE;
|
|
lavaball->clipmask = MASK_SHOT;
|
|
lavaball->solid = SOLID_BBOX;
|
|
lavaball->s.effects |= EF_ROCKET; //EF_FLAG1
|
|
lavaball->s.renderfx |= RF_GLOW;
|
|
|
|
VectorClear (lavaball->mins);
|
|
VectorClear (lavaball->maxs);
|
|
lavaball->s.modelindex = gi.modelindex ("models/monsters/q1chthon/lavaball/tris.md2");
|
|
lavaball->owner = self;
|
|
lavaball->touch = q1_lavaball_touch;
|
|
lavaball->nextthink = level.time + 8000/speed;
|
|
lavaball->think = G_FreeEdict;
|
|
lavaball->dmg = damage;
|
|
lavaball->radius_dmg = radius_damage;
|
|
lavaball->dmg_radius = damage_radius;
|
|
lavaball->s.sound = gi.soundindex ("weapons/rockfly.wav");
|
|
lavaball->classname = "chthon_lavaball";
|
|
|
|
lavaball->common_name = "Chthon Lavaball";
|
|
lavaball->class_id = ENTITY_Q1_LAVABALL;
|
|
|
|
gi.linkentity (lavaball);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
q1_acidbolt_touch
|
|
|
|
Fires a bolt of acid spit. Used by the Scrag.
|
|
=================
|
|
*/
|
|
/*static*/ void q1_acidbolt_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
if (other == ent->owner)
|
|
return;
|
|
|
|
if (surf && (surf->flags & SURF_SKY))
|
|
{
|
|
G_FreeEdict (ent);
|
|
return;
|
|
}
|
|
|
|
if (other->takedamage)
|
|
{
|
|
// FIX MOD
|
|
T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_Q1_RL);
|
|
}
|
|
else
|
|
{
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_WELDING_SPARKS);
|
|
gi.WriteByte (15);
|
|
gi.WritePosition (ent->s.origin);
|
|
gi.WriteDir ((!plane) ? vec3_origin : plane->normal);
|
|
// gi.WriteByte (209);
|
|
gi.WriteByte (222);
|
|
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
|
|
|
gi.sound (ent, CHAN_VOICE, gi.soundindex ("q1scrag/hit.wav"), 1, ATTN_NORM, 0);
|
|
}
|
|
|
|
G_FreeEdict (ent);
|
|
}
|
|
|
|
/*
|
|
void G_Spawn_Trails(int type, vec3_t start, vec3_t endpos, vec3_t origin ) {
|
|
gi.WriteByte(svc_temp_entity);
|
|
gi.WriteByte(type);
|
|
gi.WritePosition(start);
|
|
gi.WritePosition(endpos);
|
|
gi.multicast(origin, MULTICAST_PVS);
|
|
}
|
|
*/
|
|
|
|
void q1_fire_acidspit (edict_t *self, vec3_t start, vec3_t dir, int damage, int speed)
|
|
{
|
|
edict_t *acidbolt;
|
|
|
|
acidbolt = G_Spawn();
|
|
VectorCopy (start, acidbolt->s.origin);
|
|
VectorCopy (dir, acidbolt->movedir);
|
|
vectoangles (dir, acidbolt->s.angles);
|
|
VectorScale (dir, speed, acidbolt->velocity);
|
|
acidbolt->movetype = MOVETYPE_FLYMISSILE;
|
|
acidbolt->clipmask = MASK_SHOT;
|
|
acidbolt->solid = SOLID_BBOX;
|
|
acidbolt->s.effects |= EF_GREENGIB; // EF_HYPERBLASTER EF_BFG EF_GREENTRAIL
|
|
acidbolt->s.renderfx |= RF_TRANSLUCENT; // FULLBRIGHT
|
|
|
|
VectorClear (acidbolt->mins);
|
|
VectorClear (acidbolt->maxs);
|
|
acidbolt->s.modelindex = gi.modelindex ("models/monsters/q1scrag/w_spike/tris.md2");
|
|
acidbolt->owner = self;
|
|
acidbolt->touch = q1_acidbolt_touch;
|
|
acidbolt->nextthink = level.time + 8000/speed;
|
|
acidbolt->think = G_FreeEdict;
|
|
acidbolt->dmg = damage;
|
|
// acidbolt->s.sound = gi.soundindex ("weapons/rockfly.wav");
|
|
acidbolt->classname = "acidbolt";
|
|
|
|
acidbolt->common_name = "Acid Bolt";
|
|
acidbolt->class_id = ENTITY_Q1_ACIDBOLT;
|
|
|
|
gi.linkentity (acidbolt);
|
|
}
|
|
|
|
/*
|
|
=================
|
|
q1_fire_gib
|
|
|
|
Fires a gib projectile. Used by the Zombie.
|
|
=================
|
|
*/
|
|
/*static*/ void q1_zombiegib_touch (edict_t *ent, edict_t *other, cplane_t *plane, csurface_t *surf)
|
|
{
|
|
if (other == ent->owner)
|
|
return;
|
|
|
|
if (surf && (surf->flags & SURF_SKY))
|
|
{
|
|
G_FreeEdict (ent);
|
|
return;
|
|
}
|
|
|
|
if (other->takedamage)
|
|
{
|
|
// FIX MOD
|
|
T_Damage (other, ent, ent->owner, ent->velocity, ent->s.origin, plane->normal, ent->dmg, 0, 0, MOD_Q1_RL);
|
|
gi.sound (ent, CHAN_RELIABLE|CHAN_WEAPON, gi.soundindex ("q1zombie/z_hit.wav"), 1.0, ATTN_NORM, 0);
|
|
}
|
|
else
|
|
{
|
|
gi.sound (ent, CHAN_RELIABLE|CHAN_WEAPON, gi.soundindex ("q1zombie/z_miss.wav"), 1.0, ATTN_NORM, 0);
|
|
gi.WriteByte (svc_temp_entity);
|
|
gi.WriteByte (TE_BLOOD);
|
|
gi.WritePosition (ent->s.origin);
|
|
gi.WriteDir (plane->normal);
|
|
gi.multicast (ent->s.origin, MULTICAST_PVS);
|
|
}
|
|
|
|
// no more touches
|
|
ent->touch = NULL;
|
|
|
|
ent->nextthink = level.time + 3;
|
|
ent->think = G_FreeEdict;
|
|
// G_FreeEdict (ent);
|
|
}
|
|
|
|
|
|
void q1_fire_gib (edict_t *self, vec3_t start, vec3_t aimdir, int damage, int speed)
|
|
{
|
|
edict_t *gib;
|
|
vec3_t dir;
|
|
vec3_t up; //forward, right,
|
|
|
|
vectoangles (aimdir, dir);
|
|
AngleVectors (dir, NULL, NULL, up);
|
|
|
|
gib = G_Spawn();
|
|
VectorCopy (start, gib->s.origin);
|
|
VectorScale (aimdir, speed, gib->velocity);
|
|
VectorMA (gib->velocity, 200, up, gib->velocity);
|
|
// VectorMA (gib->velocity, 20, right, gib->velocity);
|
|
|
|
VectorSet (gib->avelocity, 3000, 1000, 2000);
|
|
gib->movetype = MOVETYPE_BOUNCE;
|
|
gib->clipmask = MASK_SHOT;
|
|
gib->solid = SOLID_BBOX;
|
|
gib->s.effects |= EF_GIB;
|
|
VectorClear (gib->mins);
|
|
VectorClear (gib->maxs);
|
|
gib->s.modelindex = gi.modelindex ("models/monsters/q1zombie/gib/tris.md2");
|
|
gib->owner = self;
|
|
gib->touch = q1_zombiegib_touch;
|
|
gib->nextthink = level.time + 2.5;
|
|
// gib->think = G_FreeEdict;
|
|
gib->think = gib_fade; // use gib_fade() instead of directly removing
|
|
gib->dmg = damage;
|
|
gib->classname = "gib";
|
|
|
|
gib->common_name = "Gib Projectile";
|
|
gib->class_id = ENTITY_Q1_ZOMBIE_GIB;
|
|
|
|
gi.linkentity (gib);
|
|
}
|