Cleanup g_turret.c and add sanity checks

This commit is contained in:
Yamagi Burmeister 2014-01-28 17:30:13 +01:00
parent 695d83441e
commit 2f89dd8382

View file

@ -1,69 +1,108 @@
// g_turret.c
#include "header/local.h"
void SpawnTargetingSystem (edict_t *turret); // PGM
qboolean FindTarget(edict_t *self);
void infantry_die(edict_t *self, edict_t *inflictor, edict_t *attacker, int damage);
void infantry_stand(edict_t *self);
void monster_use(edict_t *self, edict_t *other, edict_t *activator);
void SpawnTargetingSystem(edict_t *turret);
void AnglesNormalize(vec3_t vec)
void
AnglesNormalize(vec3_t vec)
{
while (vec[0] > 360)
{
vec[0] -= 360;
while(vec[0] < 0)
vec[0] += 360;
while(vec[1] > 360)
vec[1] -= 360;
while(vec[1] < 0)
vec[1] += 360;
}
float SnapToEights(float x)
while (vec[0] < 0)
{
vec[0] += 360;
}
while (vec[1] > 360)
{
vec[1] -= 360;
}
while (vec[1] < 0)
{
vec[1] += 360;
}
}
float
SnapToEights(float x)
{
x *= 8.0;
if (x > 0.0)
{
x += 0.5;
}
else
{
x -= 0.5;
}
return 0.125 * (int)x;
}
void turret_blocked(edict_t *self, edict_t *other)
void
turret_blocked(edict_t *self, edict_t *other)
{
if (!self || !other)
{
return;
}
edict_t *attacker;
if (other->takedamage)
{
if (self->teammaster->owner)
{
attacker = self->teammaster->owner;
}
else
{
attacker = self->teammaster;
T_Damage (other, self, attacker, vec3_origin, other->s.origin, vec3_origin, self->teammaster->dmg, 10, 0, MOD_CRUSH);
}
T_Damage(other, self, attacker, vec3_origin, other->s.origin,
vec3_origin, self->teammaster->dmg, 10, 0, MOD_CRUSH);
}
}
/*QUAKED turret_breach (0 0 0) ?
This portion of the turret can change both pitch and yaw.
The model should be made with a flat pitch.
It (and the associated base) need to be oriented towards 0.
Use "angle" to set the starting angle.
"speed" default 50
"dmg" default 10
"angle" point this forward
"target" point this at an info_notnull at the muzzle tip
"minpitch" min acceptable pitch angle : default -30
"maxpitch" max acceptable pitch angle : default 30
"minyaw" min acceptable yaw angle : default 0
"maxyaw" max acceptable yaw angle : default 360
/*
* QUAKED turret_breach (0 0 0) ?
* This portion of the turret can change both pitch and yaw.
* The model should be made with a flat pitch.
* It (and the associated base) need to be oriented towards 0.
* Use "angle" to set the starting angle.
*
* "speed" default 50
* "dmg" default 10
* "angle" point this forward
* "target" point this at an info_notnull at the muzzle tip
* "minpitch" min acceptable pitch angle : default -30
* "maxpitch" max acceptable pitch angle : default 30
* "minyaw" min acceptable yaw angle : default 0
* "maxyaw" max acceptable yaw angle : default 360
*/
void turret_breach_fire (edict_t *self)
void
turret_breach_fire(edict_t *self)
{
vec3_t f, r, u;
vec3_t start;
int damage;
int speed;
if (!self)
{
return;
}
AngleVectors(self->s.angles, f, r, u);
VectorMA(self->s.origin, self->move_origin[0], f, start);
VectorMA(start, self->move_origin[1], r, start);
@ -75,73 +114,127 @@ void turret_breach_fire (edict_t *self)
gi.positioned_sound(start, self, CHAN_WEAPON, gi.soundindex("weapons/rocklf1a.wav"), 1, ATTN_NORM, 0);
}
void turret_breach_think (edict_t *self)
void
turret_breach_think(edict_t *self)
{
edict_t *ent;
vec3_t current_angles;
vec3_t delta;
if (!self)
{
return;
}
VectorCopy(self->s.angles, current_angles);
AnglesNormalize(current_angles);
AnglesNormalize(self->move_angles);
if (self->move_angles[PITCH] > 180)
{
self->move_angles[PITCH] -= 360;
}
// clamp angles to mins & maxs
/* clamp angles to mins & maxs */
if (self->move_angles[PITCH] > self->pos1[PITCH])
{
self->move_angles[PITCH] = self->pos1[PITCH];
}
else if (self->move_angles[PITCH] < self->pos2[PITCH])
{
self->move_angles[PITCH] = self->pos2[PITCH];
}
if ((self->move_angles[YAW] < self->pos1[YAW]) || (self->move_angles[YAW] > self->pos2[YAW]))
if ((self->move_angles[YAW] < self->pos1[YAW]) ||
(self->move_angles[YAW] > self->pos2[YAW]))
{
float dmin, dmax;
dmin = fabs(self->pos1[YAW] - self->move_angles[YAW]);
if (dmin < -180)
{
dmin += 360;
}
else if (dmin > 180)
{
dmin -= 360;
}
dmax = fabs(self->pos2[YAW] - self->move_angles[YAW]);
if (dmax < -180)
{
dmax += 360;
}
else if (dmax > 180)
{
dmax -= 360;
}
if (fabs(dmin) < fabs(dmax))
{
self->move_angles[YAW] = self->pos1[YAW];
}
else
{
self->move_angles[YAW] = self->pos2[YAW];
}
}
VectorSubtract(self->move_angles, current_angles, delta);
if (delta[0] < -180)
{
delta[0] += 360;
}
else if (delta[0] > 180)
{
delta[0] -= 360;
}
if (delta[1] < -180)
{
delta[1] += 360;
}
else if (delta[1] > 180)
{
delta[1] -= 360;
}
delta[2] = 0;
if (delta[0] > self->speed * FRAMETIME)
{
delta[0] = self->speed * FRAMETIME;
}
if (delta[0] < -1 * self->speed * FRAMETIME)
{
delta[0] = -1 * self->speed * FRAMETIME;
}
if (delta[1] > self->speed * FRAMETIME)
{
delta[1] = self->speed * FRAMETIME;
}
if (delta[1] < -1 * self->speed * FRAMETIME)
{
delta[1] = -1 * self->speed * FRAMETIME;
}
VectorScale(delta, 1.0 / FRAMETIME, self->avelocity);
self->nextthink = level.time + FRAMETIME;
for (ent = self->teammaster; ent; ent = ent->teamchain)
{
ent->avelocity[1] = self->avelocity[1];
}
// if we have adriver, adjust his velocities
/* if we have adriver, adjust his velocities */
if (self->owner)
{
float angle;
@ -150,11 +243,11 @@ void turret_breach_think (edict_t *self)
vec3_t target;
vec3_t dir;
// angular is easy, just copy ours
/* angular is easy, just copy ours */
self->owner->avelocity[0] = self->avelocity[0];
self->owner->avelocity[1] = self->avelocity[1];
// x & y
/* x & y */
angle = self->s.angles[1] + self->owner->move_origin[1];
angle *= (M_PI * 2 / 360);
target[0] = SnapToEights(self->s.origin[0] + cos(angle) * self->owner->move_origin[0]);
@ -165,7 +258,7 @@ void turret_breach_think (edict_t *self)
self->owner->velocity[0] = dir[0] * 1.0 / FRAMETIME;
self->owner->velocity[1] = dir[1] * 1.0 / FRAMETIME;
// z
/* z */
angle = self->s.angles[PITCH] * (M_PI * 2 / 360);
target_z = SnapToEights(self->s.origin[2] + self->owner->move_origin[0] * tan(angle) + self->owner->move_origin[2]);
@ -180,9 +273,15 @@ void turret_breach_think (edict_t *self)
}
}
void turret_breach_finish_init (edict_t *self)
void
turret_breach_finish_init(edict_t *self)
{
// get and save info for muzzle location
if (!self)
{
return;
}
/* get and save info for muzzle location */
if (!self->target)
{
gi.dprintf("%s at %s needs a target\n", self->classname, vtos(self->s.origin));
@ -190,37 +289,59 @@ void turret_breach_finish_init (edict_t *self)
else
{
self->target_ent = G_PickTarget(self->target);
if (self->target_ent)
{
VectorSubtract(self->target_ent->s.origin, self->s.origin, self->move_origin);
G_FreeEdict(self->target_ent);
}
else
{
gi.dprintf("could not find target entity for %s at %s\n", self->classname, vtos(self->s.origin));
}
}
self->teammaster->dmg = self->dmg;
self->think = turret_breach_think;
self->think(self);
}
void SP_turret_breach (edict_t *self)
void
SP_turret_breach(edict_t *self)
{
if (!self)
{
return;
}
self->solid = SOLID_BSP;
self->movetype = MOVETYPE_PUSH;
gi.setmodel(self, self->model);
if (!self->speed)
{
self->speed = 50;
}
if (!self->dmg)
{
self->dmg = 10;
}
if (!st.minpitch)
{
st.minpitch = -30;
}
if (!st.maxpitch)
{
st.maxpitch = 30;
}
if (!st.maxyaw)
{
st.maxyaw = 360;
}
self->pos1[PITCH] = -1 * st.minpitch;
self->pos1[YAW] = st.minyaw;
@ -237,14 +358,20 @@ void SP_turret_breach (edict_t *self)
gi.linkentity(self);
}
/*QUAKED turret_base (0 0 0) ?
This portion of the turret changes yaw only.
MUST be teamed with a turret_breach.
/*
* QUAKED turret_base (0 0 0) ?
* This portion of the turret changes yaw only.
* MUST be teamed with a turret_breach.
*/
void SP_turret_base (edict_t *self)
void
SP_turret_base(edict_t *self)
{
if (!self)
{
return;
}
self->solid = SOLID_BSP;
self->movetype = MOVETYPE_PUSH;
gi.setmodel(self, self->model);
@ -252,26 +379,32 @@ void SP_turret_base (edict_t *self)
gi.linkentity(self);
}
/*QUAKED turret_driver (1 .5 0) (-16 -16 -24) (16 16 32)
Must NOT be on the team with the rest of the turret parts.
Instead it must target the turret_breach.
/*
* QUAKED turret_driver (1 .5 0) (-16 -16 -24) (16 16 32)
* Must NOT be on the team with the rest of the turret parts.
* Instead it must target the turret_breach.
*/
void infantry_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage);
void infantry_stand (edict_t *self);
void monster_use (edict_t *self, edict_t *other, edict_t *activator);
void turret_driver_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
void
turret_driver_die(edict_t *self, edict_t *inflictor, edict_t *attacker,
int damage, vec3_t point)
{
edict_t *ent;
// level the gun
if (!self || !inflictor || !attacker)
{
return;
}
/* level the gun */
self->target_ent->move_angles[0] = 0;
// remove the driver from the end of them team chain
for (ent = self->target_ent->teammaster; ent->teamchain != self; ent = ent->teamchain)
;
/* remove the driver from the end of them team chain */
for (ent = self->target_ent->teammaster;
ent->teamchain != self;
ent = ent->teamchain)
{
}
ent->teamchain = NULL;
self->teammaster = NULL;
self->flags &= ~FL_TEAMSLAVE;
@ -282,23 +415,32 @@ void turret_driver_die (edict_t *self, edict_t *inflictor, edict_t *attacker, in
infantry_die(self, inflictor, attacker, damage);
}
qboolean FindTarget (edict_t *self);
void turret_driver_think (edict_t *self)
void
turret_driver_think(edict_t *self)
{
vec3_t target;
vec3_t dir;
float reaction_time;
if (!self)
{
return;
}
self->nextthink = level.time + FRAMETIME;
if (self->enemy && (!self->enemy->inuse || self->enemy->health <= 0))
if (self->enemy && (!self->enemy->inuse || (self->enemy->health <= 0)))
{
self->enemy = NULL;
}
if (!self->enemy)
{
if (!FindTarget(self))
{
return;
}
self->monsterinfo.trail_time = level.time;
self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
}
@ -319,30 +461,40 @@ void turret_driver_think (edict_t *self)
}
}
// let the turret know where we want it to aim
/* let the turret know where we want it to aim */
VectorCopy(self->enemy->s.origin, target);
target[2] += self->enemy->viewheight;
VectorSubtract(target, self->target_ent->s.origin, dir);
vectoangles(dir, self->target_ent->move_angles);
// decide if we should shoot
/* decide if we should shoot */
if (level.time < self->monsterinfo.attack_finished)
{
return;
}
reaction_time = (3 - skill->value) * 1.0;
if ((level.time - self->monsterinfo.trail_time) < reaction_time)
{
return;
}
self->monsterinfo.attack_finished = level.time + reaction_time + 1.0;
//FIXME how do we really want to pass this along?
self->target_ent->spawnflags |= 65536;
}
void turret_driver_link (edict_t *self)
void
turret_driver_link(edict_t *self)
{
vec3_t vec;
edict_t *ent;
if (!self)
{
return;
}
self->think = turret_driver_think;
self->nextthink = level.time + FRAMETIME;
@ -363,16 +515,24 @@ void turret_driver_link (edict_t *self)
self->move_origin[2] = self->s.origin[2] - self->target_ent->s.origin[2];
// add the driver to the end of them team chain
/* add the driver to the end of them team chain */
for (ent = self->target_ent->teammaster; ent->teamchain; ent = ent->teamchain)
;
{
}
ent->teamchain = self;
self->teammaster = self->target_ent->teammaster;
self->flags |= FL_TEAMSLAVE;
}
void SP_turret_driver (edict_t *self)
void
SP_turret_driver(edict_t *self)
{
if (!self)
{
return;
}
if (deathmatch->value)
{
G_FreeEdict(self);
@ -408,9 +568,12 @@ void SP_turret_driver (edict_t *self)
if (st.item)
{
self->item = FindItemByClassname(st.item);
if (!self->item)
{
gi.dprintf("%s at %s has bad item: %s\n", self->classname, vtos(self->s.origin), st.item);
}
}
self->think = turret_driver_link;
self->nextthink = level.time + FRAMETIME;
@ -418,15 +581,14 @@ void SP_turret_driver (edict_t *self)
gi.linkentity(self);
}
//============
// ROGUE
/*
* invisible turret drivers so we can have unmanned turrets.
* originally designed to shoot at func_trains and such, so they
* fire at the center of the bounding box, rather than the entity's
* origin. */
// invisible turret drivers so we can have unmanned turrets.
// originally designed to shoot at func_trains and such, so they
// fire at the center of the bounding box, rather than the entity's
// origin.
void turret_brain_think (edict_t *self)
void
turret_brain_think(edict_t *self)
{
vec3_t target;
vec3_t dir;
@ -434,20 +596,32 @@ void turret_brain_think (edict_t *self)
float reaction_time;
trace_t trace;
if (!self)
{
return;
}
self->nextthink = level.time + FRAMETIME;
if (self->enemy)
{
if (!self->enemy->inuse)
{
self->enemy = NULL;
else if(self->enemy->takedamage && self->enemy->health <= 0)
}
else if (self->enemy->takedamage && (self->enemy->health <= 0))
{
self->enemy = NULL;
}
}
if (!self->enemy)
{
if (!FindTarget(self))
{
return;
}
self->monsterinfo.trail_time = level.time;
self->monsterinfo.aiflags &= ~AI_LOST_SIGHT;
}
@ -456,8 +630,10 @@ void turret_brain_think (edict_t *self)
VectorAdd(self->enemy->absmax, self->enemy->absmin, endpos);
VectorScale(endpos, 0.5, endpos);
trace = gi.trace (self->target_ent->s.origin, vec3_origin, vec3_origin, endpos, self->target_ent, MASK_SHOT);
if(trace.fraction == 1 || trace.ent == self->enemy)
trace = gi.trace(self->target_ent->s.origin, vec3_origin, vec3_origin,
endpos, self->target_ent, MASK_SHOT);
if ((trace.fraction == 1) || (trace.ent == self->enemy))
{
if (self->monsterinfo.aiflags & AI_LOST_SIGHT)
{
@ -472,33 +648,46 @@ void turret_brain_think (edict_t *self)
}
}
// let the turret know where we want it to aim
/* let the turret know where we want it to aim */
VectorCopy(endpos, target);
VectorSubtract(target, self->target_ent->s.origin, dir);
vectoangles(dir, self->target_ent->move_angles);
// decide if we should shoot
/* decide if we should shoot */
if (level.time < self->monsterinfo.attack_finished)
{
return;
}
if (self->delay)
{
reaction_time = self->delay;
}
else
{
reaction_time = (3 - skill->value) * 1.0;
}
if ((level.time - self->monsterinfo.trail_time) < reaction_time)
{
return;
}
self->monsterinfo.attack_finished = level.time + reaction_time + 1.0;
//FIXME how do we really want to pass this along?
self->target_ent->spawnflags |= 65536;
}
// =================
void turret_brain_link (edict_t *self)
void
turret_brain_link(edict_t *self)
{
vec3_t vec;
edict_t *ent;
if (!self)
{
return;
}
if (self->killtarget)
{
self->enemy = G_PickTarget(self->killtarget);
@ -524,30 +713,42 @@ void turret_brain_link (edict_t *self)
self->move_origin[2] = self->s.origin[2] - self->target_ent->s.origin[2];
// add the driver to the end of them team chain
/* add the driver to the end of them team chain */
for (ent = self->target_ent->teammaster; ent->teamchain; ent = ent->teamchain)
;
{
}
ent->teamchain = self;
self->teammaster = self->target_ent->teammaster;
self->flags |= FL_TEAMSLAVE;
}
// =================
void turret_brain_deactivate (edict_t *self, edict_t *other, edict_t *activator)
void
turret_brain_deactivate(edict_t *self, edict_t *other /* unused */, edict_t *activator /* unused */)
{
if (!self)
{
return;
}
self->think = NULL;
self->nextthink = 0;
}
// =================
void turret_brain_activate (edict_t *self, edict_t *other, edict_t *activator)
void
turret_brain_activate(edict_t *self, edict_t *other /* unused */, edict_t *activator)
{
if (!self || !activator)
{
return;
}
if (!self->enemy)
{
self->enemy = activator;
}
// wait at least 3 seconds to fire.
/* wait at least 3 seconds to fire. */
self->monsterinfo.attack_finished = level.time + 3;
self->use = turret_brain_deactivate;
@ -555,26 +756,34 @@ void turret_brain_activate (edict_t *self, edict_t *other, edict_t *activator)
self->nextthink = level.time + FRAMETIME;
}
/*QUAKED turret_invisible_brain (1 .5 0) (-16 -16 -16) (16 16 16)
Invisible brain to drive the turret.
Does not search for targets. If targeted, can only be turned on once
and then off once. After that they are completely disabled.
"delay" the delay between firing (default ramps for skill level)
"Target" the turret breach
"Killtarget" the item you want it to attack.
Target the brain if you want it activated later, instead of immediately. It will wait 3 seconds
before firing to acquire the target.
/*
* QUAKED turret_invisible_brain (1 .5 0) (-16 -16 -16) (16 16 16)
* Invisible brain to drive the turret.
*
* Does not search for targets. If targeted, can only be turned on once
* and then off once. After that they are completely disabled.
*
* "delay" the delay between firing (default ramps for skill level)
* "Target" the turret breach
* "Killtarget" the item you want it to attack.
* Target the brain if you want it activated later, instead of immediately. It will wait 3 seconds
* before firing to acquire the target.
*/
void SP_turret_invisible_brain (edict_t *self)
void
SP_turret_invisible_brain(edict_t *self)
{
if (!self)
{
return;
}
if (!self->killtarget)
{
gi.dprintf("turret_invisible_brain with no killtarget!\n");
G_FreeEdict(self);
return;
}
if (!self->target)
{
gi.dprintf("turret_invisible_brain with no target!\n");
@ -595,7 +804,3 @@ void SP_turret_invisible_brain (edict_t *self)
self->movetype = MOVETYPE_PUSH;
gi.linkentity(self);
}
// ROGUE
//============