mirror of
https://github.com/yquake2/rogue.git
synced 2025-02-18 10:01:41 +00:00
Cleanup g_newdm.c and add sanity checks.
This commit is contained in:
parent
2d2c7e8222
commit
579b6cc413
1 changed files with 253 additions and 168 deletions
421
src/g_newdm.c
421
src/g_newdm.c
|
@ -1,27 +1,39 @@
|
||||||
// g_newdm.c
|
/*
|
||||||
// pmack
|
* =======================================================================
|
||||||
// june 1998
|
*
|
||||||
|
* Rogue specific deathmatch stuff.
|
||||||
|
*
|
||||||
|
* =======================================================================
|
||||||
|
*/
|
||||||
|
|
||||||
#include "header/local.h"
|
#include "header/local.h"
|
||||||
#include "monster/misc/player.h"
|
#include "monster/misc/player.h"
|
||||||
|
|
||||||
dm_game_rt DMGame;
|
#define IT_TYPE_MASK (IT_WEAPON | IT_AMMO | IT_POWERUP | IT_ARMOR | IT_KEY)
|
||||||
|
|
||||||
// ****************************
|
dm_game_rt DMGame;
|
||||||
// General DM Stuff
|
|
||||||
// ****************************
|
extern qboolean Pickup_Health(edict_t *ent, edict_t *other);
|
||||||
|
extern qboolean Pickup_Adrenaline(edict_t *ent, edict_t *other);
|
||||||
void InitGameRules(void)
|
extern qboolean Pickup_Armor(edict_t *ent, edict_t *other);
|
||||||
|
extern qboolean Pickup_PowerArmor(edict_t *ent, edict_t *other);
|
||||||
|
extern edict_t *Sphere_Spawn(edict_t *owner, int spawnflags);
|
||||||
|
extern void ED_CallSpawn(edict_t *ent);
|
||||||
|
void fire_doppleganger(edict_t *ent, vec3_t start, vec3_t aimdir);
|
||||||
|
|
||||||
|
void
|
||||||
|
InitGameRules(void)
|
||||||
{
|
{
|
||||||
int gameNum;
|
int gameNum;
|
||||||
|
|
||||||
// clear out the game rule structure before we start
|
/* clear out the game rule structure before we start */
|
||||||
memset(&DMGame, 0, sizeof(dm_game_rt));
|
memset(&DMGame, 0, sizeof(dm_game_rt));
|
||||||
|
|
||||||
if(gamerules && gamerules->value)
|
if (gamerules && gamerules->value)
|
||||||
{
|
{
|
||||||
gameNum = gamerules->value;
|
gameNum = gamerules->value;
|
||||||
switch(gameNum)
|
|
||||||
|
switch (gameNum)
|
||||||
{
|
{
|
||||||
case RDM_TAG:
|
case RDM_TAG:
|
||||||
DMGame.GameInit = Tag_GameInit;
|
DMGame.GameInit = Tag_GameInit;
|
||||||
|
@ -34,261 +46,326 @@ void InitGameRules(void)
|
||||||
DMGame.ChangeDamage = Tag_ChangeDamage;
|
DMGame.ChangeDamage = Tag_ChangeDamage;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// reset gamerules if it's not a valid number
|
/* reset gamerules if it's not a valid number */
|
||||||
default:
|
default:
|
||||||
gamerules->value = 0;
|
gamerules->value = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we're set up to play, initialize the game as needed.
|
/* if we're set up to play, initialize the game as needed. */
|
||||||
if(DMGame.GameInit)
|
if (DMGame.GameInit)
|
||||||
|
{
|
||||||
DMGame.GameInit();
|
DMGame.GameInit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//=================
|
char *
|
||||||
#define IT_TYPE_MASK (IT_WEAPON|IT_AMMO|IT_POWERUP|IT_ARMOR|IT_KEY)
|
FindSubstituteItem(edict_t *ent)
|
||||||
|
|
||||||
extern void ED_CallSpawn (edict_t *ent);
|
|
||||||
extern qboolean Pickup_Health (edict_t *ent, edict_t *other);
|
|
||||||
extern qboolean Pickup_Adrenaline (edict_t *ent, edict_t *other);
|
|
||||||
extern qboolean Pickup_Armor (edict_t *ent, edict_t *other);
|
|
||||||
extern qboolean Pickup_PowerArmor (edict_t *ent, edict_t *other);
|
|
||||||
|
|
||||||
char *FindSubstituteItem (edict_t *ent)
|
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int itflags, myflags;
|
int itflags, myflags;
|
||||||
float rnd;
|
float rnd;
|
||||||
int count;
|
int count;
|
||||||
int pick;
|
int pick;
|
||||||
gitem_t *it;
|
gitem_t *it;
|
||||||
|
|
||||||
// there are only two classes of power armor, and we don't want
|
/* there are only two classes of power armor, and we don't want
|
||||||
// to give out power screens. therefore, power shields should
|
to give out power screens. therefore, power shields should
|
||||||
// remain power shields. (powerscreens shouldn't be there at all...)
|
remain power shields. (powerscreens shouldn't be there at all...) */
|
||||||
if (ent->item->pickup == Pickup_PowerArmor)
|
if (ent->item->pickup == Pickup_PowerArmor)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
// health is special case
|
/* health is special case */
|
||||||
if ((ent->item->pickup == Pickup_Health) || (ent->item->pickup == Pickup_Adrenaline))
|
if ((ent->item->pickup == Pickup_Health) ||
|
||||||
|
(ent->item->pickup == Pickup_Adrenaline))
|
||||||
{
|
{
|
||||||
// health pellets stay health pellets
|
/* health pellets stay health pellets */
|
||||||
if(!strcmp(ent->classname, "item_health_small"))
|
if (!strcmp(ent->classname, "item_health_small"))
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
rnd = random();
|
rnd = random();
|
||||||
if(rnd < 0.6)
|
|
||||||
|
if (rnd < 0.6)
|
||||||
|
{
|
||||||
return "item_health";
|
return "item_health";
|
||||||
else if(rnd < 0.9)
|
}
|
||||||
|
else if (rnd < 0.9)
|
||||||
|
{
|
||||||
return "item_health_large";
|
return "item_health_large";
|
||||||
else if(rnd < 0.99)
|
}
|
||||||
|
else if (rnd < 0.99)
|
||||||
|
{
|
||||||
return "item_adrenaline";
|
return "item_adrenaline";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return "item_health_mega";
|
return "item_health_mega";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// armor is also special case
|
/* armor is also special case */
|
||||||
else if(ent->item->pickup == Pickup_Armor)
|
else if (ent->item->pickup == Pickup_Armor)
|
||||||
{
|
{
|
||||||
// armor shards stay armor shards
|
/* armor shards stay armor shards */
|
||||||
if (ent->item->tag == ARMOR_SHARD)
|
if (ent->item->tag == ARMOR_SHARD)
|
||||||
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
rnd = random();
|
rnd = random();
|
||||||
if(rnd < 0.6)
|
|
||||||
|
if (rnd < 0.6)
|
||||||
|
{
|
||||||
return "item_armor_jacket";
|
return "item_armor_jacket";
|
||||||
else if(rnd < 0.9)
|
}
|
||||||
|
else if (rnd < 0.9)
|
||||||
|
{
|
||||||
return "item_armor_combat";
|
return "item_armor_combat";
|
||||||
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
return "item_armor_body";
|
return "item_armor_body";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* we want to stay within the item class */
|
||||||
// we want to stay within the item class
|
|
||||||
myflags = ent->item->flags & IT_TYPE_MASK;
|
myflags = ent->item->flags & IT_TYPE_MASK;
|
||||||
|
|
||||||
if ((myflags & IT_AMMO) && (myflags & IT_WEAPON))
|
if ((myflags & IT_AMMO) && (myflags & IT_WEAPON))
|
||||||
myflags = IT_AMMO;
|
{
|
||||||
|
myflags = IT_AMMO;
|
||||||
|
}
|
||||||
|
|
||||||
count = 0;
|
count = 0;
|
||||||
|
|
||||||
// first pass, count the matching items
|
/* first pass, count the matching items */
|
||||||
it = itemlist;
|
it = itemlist;
|
||||||
for (i=0 ; i<game.num_items ; i++, it++)
|
|
||||||
|
for (i = 0; i < game.num_items; i++, it++)
|
||||||
{
|
{
|
||||||
itflags = it->flags;
|
itflags = it->flags;
|
||||||
|
|
||||||
if (!itflags || (itflags & IT_NOT_GIVEABLE))
|
if (!itflags || (itflags & IT_NOT_GIVEABLE))
|
||||||
continue;
|
|
||||||
|
|
||||||
// prox,grenades,etc should count as ammo.
|
|
||||||
if ((itflags & IT_AMMO) && (itflags & IT_WEAPON))
|
|
||||||
itflags = IT_AMMO;
|
|
||||||
|
|
||||||
// don't respawn spheres if they're dmflag disabled.
|
|
||||||
if ( (int)dmflags->value & DF_NO_SPHERES )
|
|
||||||
{
|
{
|
||||||
if (!strcmp (ent->classname, "item_sphere_vengeance") ||
|
continue;
|
||||||
!strcmp (ent->classname, "item_sphere_hunter") ||
|
}
|
||||||
!strcmp (ent->classname, "item_spehre_defender"))
|
|
||||||
|
/* prox,grenades,etc should count as ammo. */
|
||||||
|
if ((itflags & IT_AMMO) && (itflags & IT_WEAPON))
|
||||||
|
{
|
||||||
|
itflags = IT_AMMO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* don't respawn spheres if they're dmflag disabled. */
|
||||||
|
if ((int)dmflags->value & DF_NO_SPHERES)
|
||||||
|
{
|
||||||
|
if (!strcmp(ent->classname, "item_sphere_vengeance") ||
|
||||||
|
!strcmp(ent->classname, "item_sphere_hunter") ||
|
||||||
|
!strcmp(ent->classname, "item_spehre_defender"))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ((int)dmflags->value & DF_NO_NUKES) && !strcmp(ent->classname, "ammo_nuke") )
|
if (((int)dmflags->value & DF_NO_NUKES) &&
|
||||||
|
!strcmp(ent->classname, "ammo_nuke"))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ( ((int)dmflags->value & DF_NO_MINES) &&
|
if (((int)dmflags->value & DF_NO_MINES) &&
|
||||||
(!strcmp(ent->classname, "ammo_prox") || !strcmp(ent->classname, "ammo_tesla")))
|
(!strcmp(ent->classname, "ammo_prox") || !strcmp(ent->classname, "ammo_tesla")))
|
||||||
continue;
|
{
|
||||||
|
|
||||||
if ((itflags & IT_TYPE_MASK) == (myflags & IT_TYPE_MASK))
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(!count)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
pick = ceil(random() * count);
|
|
||||||
count = 0;
|
|
||||||
|
|
||||||
// second pass, pick one.
|
|
||||||
it = itemlist;
|
|
||||||
for (i=0 ; i<game.num_items ; i++, it++)
|
|
||||||
{
|
|
||||||
itflags = it->flags;
|
|
||||||
|
|
||||||
if (!itflags || (itflags & IT_NOT_GIVEABLE))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
// prox,grenades,etc should count as ammo.
|
|
||||||
if ((itflags & IT_AMMO) && (itflags & IT_WEAPON))
|
|
||||||
itflags = IT_AMMO;
|
|
||||||
|
|
||||||
if ( ((int)dmflags->value & DF_NO_NUKES) && !strcmp(ent->classname, "ammo_nuke") )
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if ( ((int)dmflags->value & DF_NO_MINES) &&
|
|
||||||
(!strcmp(ent->classname, "ammo_prox") || !strcmp(ent->classname, "ammo_tesla")))
|
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if ((itflags & IT_TYPE_MASK) == (myflags & IT_TYPE_MASK))
|
if ((itflags & IT_TYPE_MASK) == (myflags & IT_TYPE_MASK))
|
||||||
{
|
{
|
||||||
count++;
|
count++;
|
||||||
if(pick == count)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!count)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
pick = ceil(random() * count);
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
/* second pass, pick one. */
|
||||||
|
it = itemlist;
|
||||||
|
|
||||||
|
for (i = 0; i < game.num_items; i++, it++)
|
||||||
|
{
|
||||||
|
itflags = it->flags;
|
||||||
|
|
||||||
|
if (!itflags || (itflags & IT_NOT_GIVEABLE))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prox,grenades,etc should count as ammo. */
|
||||||
|
if ((itflags & IT_AMMO) && (itflags & IT_WEAPON))
|
||||||
|
{
|
||||||
|
itflags = IT_AMMO;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((int)dmflags->value & DF_NO_NUKES) &&
|
||||||
|
!strcmp(ent->classname, "ammo_nuke"))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (((int)dmflags->value & DF_NO_MINES) &&
|
||||||
|
(!strcmp(ent->classname, "ammo_prox") || !strcmp(ent->classname, "ammo_tesla")))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((itflags & IT_TYPE_MASK) == (myflags & IT_TYPE_MASK))
|
||||||
|
{
|
||||||
|
count++;
|
||||||
|
|
||||||
|
if (pick == count)
|
||||||
|
{
|
||||||
return it->classname;
|
return it->classname;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=================
|
edict_t *
|
||||||
edict_t *DoRandomRespawn (edict_t *ent)
|
DoRandomRespawn(edict_t *ent)
|
||||||
{
|
{
|
||||||
edict_t *newEnt;
|
edict_t *newEnt;
|
||||||
char *classname;
|
char *classname;
|
||||||
|
|
||||||
classname = FindSubstituteItem (ent);
|
if (!ent)
|
||||||
if (classname == NULL)
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
classname = FindSubstituteItem(ent);
|
||||||
|
|
||||||
gi.unlinkentity (ent);
|
if (classname == NULL)
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gi.unlinkentity(ent);
|
||||||
|
|
||||||
newEnt = G_Spawn();
|
newEnt = G_Spawn();
|
||||||
newEnt->classname = classname;
|
newEnt->classname = classname;
|
||||||
VectorCopy (ent->s.origin, newEnt->s.origin);
|
VectorCopy(ent->s.origin, newEnt->s.origin);
|
||||||
VectorCopy (ent->s.old_origin, newEnt->s.old_origin);
|
VectorCopy(ent->s.old_origin, newEnt->s.old_origin);
|
||||||
VectorCopy (ent->mins, newEnt->mins);
|
VectorCopy(ent->mins, newEnt->mins);
|
||||||
VectorCopy (ent->maxs, newEnt->maxs);
|
VectorCopy(ent->maxs, newEnt->maxs);
|
||||||
|
|
||||||
VectorSet (newEnt->gravityVector, 0, 0, -1);
|
|
||||||
|
|
||||||
ED_CallSpawn (newEnt);
|
VectorSet(newEnt->gravityVector, 0, 0, -1);
|
||||||
|
|
||||||
|
ED_CallSpawn(newEnt);
|
||||||
|
|
||||||
newEnt->s.renderfx |= RF_IR_VISIBLE;
|
newEnt->s.renderfx |= RF_IR_VISIBLE;
|
||||||
|
|
||||||
return newEnt;
|
return newEnt;
|
||||||
}
|
}
|
||||||
|
|
||||||
//=================
|
void
|
||||||
void PrecacheForRandomRespawn (void)
|
PrecacheForRandomRespawn(void)
|
||||||
{
|
{
|
||||||
gitem_t *it;
|
gitem_t *it;
|
||||||
int i;
|
int i;
|
||||||
int itflags;
|
int itflags;
|
||||||
|
|
||||||
it = itemlist;
|
it = itemlist;
|
||||||
for (i=0 ; i<game.num_items ; i++, it++)
|
|
||||||
|
for (i = 0; i < game.num_items; i++, it++)
|
||||||
{
|
{
|
||||||
itflags = it->flags;
|
itflags = it->flags;
|
||||||
|
|
||||||
if (!itflags || (itflags & IT_NOT_GIVEABLE))
|
if (!itflags || (itflags & IT_NOT_GIVEABLE))
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
PrecacheItem(it);
|
PrecacheItem(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ***************************
|
void
|
||||||
// DOPPLEGANGER
|
doppleganger_die(edict_t *self, edict_t *inflictor /* unused */, edict_t *attacker,
|
||||||
// ***************************
|
int damage, vec3_t point)
|
||||||
|
|
||||||
extern edict_t *Sphere_Spawn (edict_t *owner, int spawnflags);
|
|
||||||
|
|
||||||
void fire_doppleganger (edict_t *ent, vec3_t start, vec3_t aimdir);
|
|
||||||
void doppleganger_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point);
|
|
||||||
|
|
||||||
void doppleganger_die (edict_t *self, edict_t *inflictor, edict_t *attacker, int damage, vec3_t point)
|
|
||||||
{
|
{
|
||||||
edict_t *sphere;
|
edict_t *sphere;
|
||||||
float dist;
|
float dist;
|
||||||
vec3_t dir;
|
vec3_t dir;
|
||||||
|
|
||||||
if((self->enemy) && (self->enemy != self->teammaster))
|
if (!self || !attacker)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((self->enemy) && (self->enemy != self->teammaster))
|
||||||
{
|
{
|
||||||
VectorSubtract(self->enemy->s.origin, self->s.origin, dir);
|
VectorSubtract(self->enemy->s.origin, self->s.origin, dir);
|
||||||
dist = VectorLength(dir);
|
dist = VectorLength(dir);
|
||||||
|
|
||||||
if(dist > 768)
|
if (dist > 768)
|
||||||
{
|
{
|
||||||
sphere = Sphere_Spawn (self, SPHERE_HUNTER | SPHERE_DOPPLEGANGER);
|
sphere = Sphere_Spawn(self, SPHERE_HUNTER | SPHERE_DOPPLEGANGER);
|
||||||
sphere->pain(sphere, attacker, 0, 0);
|
sphere->pain(sphere, attacker, 0, 0);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
sphere = Sphere_Spawn (self, SPHERE_VENGEANCE | SPHERE_DOPPLEGANGER);
|
sphere = Sphere_Spawn(self, SPHERE_VENGEANCE | SPHERE_DOPPLEGANGER);
|
||||||
sphere->pain(sphere, attacker, 0, 0);
|
sphere->pain(sphere, attacker, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(self->teamchain)
|
if (self->teamchain)
|
||||||
|
{
|
||||||
BecomeExplosion1(self->teamchain);
|
BecomeExplosion1(self->teamchain);
|
||||||
|
}
|
||||||
|
|
||||||
BecomeExplosion1(self);
|
BecomeExplosion1(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void doppleganger_pain (edict_t *self, edict_t *other, float kick, int damage)
|
void
|
||||||
|
doppleganger_pain(edict_t *self, edict_t *other, float kick, int damage)
|
||||||
{
|
{
|
||||||
self->enemy = other;
|
self->enemy = other;
|
||||||
}
|
}
|
||||||
|
|
||||||
void doppleganger_timeout (edict_t *self)
|
void
|
||||||
|
doppleganger_timeout(edict_t *self)
|
||||||
{
|
{
|
||||||
if(self->teamchain)
|
if (self->teamchain)
|
||||||
|
{
|
||||||
BecomeExplosion1(self->teamchain);
|
BecomeExplosion1(self->teamchain);
|
||||||
|
}
|
||||||
|
|
||||||
BecomeExplosion1(self);
|
BecomeExplosion1(self);
|
||||||
}
|
}
|
||||||
|
|
||||||
void body_think (edict_t *self)
|
void
|
||||||
|
body_think(edict_t *self)
|
||||||
{
|
{
|
||||||
float r;
|
float r;
|
||||||
|
|
||||||
if(abs(self->ideal_yaw - anglemod(self->s.angles[YAW])) < 2)
|
if (abs(self->ideal_yaw - anglemod(self->s.angles[YAW])) < 2)
|
||||||
{
|
{
|
||||||
if(self->timestamp < level.time)
|
if (self->timestamp < level.time)
|
||||||
{
|
{
|
||||||
r = random();
|
r = random();
|
||||||
if(r < 0.10)
|
|
||||||
|
if (r < 0.10)
|
||||||
{
|
{
|
||||||
self->ideal_yaw = random() * 350.0;
|
self->ideal_yaw = random() * 350.0;
|
||||||
self->timestamp = level.time + 1;
|
self->timestamp = level.time + 1;
|
||||||
|
@ -296,37 +373,48 @@ void body_think (edict_t *self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
M_ChangeYaw(self);
|
M_ChangeYaw(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
self->s.frame++;
|
||||||
|
|
||||||
self->s.frame ++;
|
|
||||||
if (self->s.frame > FRAME_stand40)
|
if (self->s.frame > FRAME_stand40)
|
||||||
|
{
|
||||||
self->s.frame = FRAME_stand01;
|
self->s.frame = FRAME_stand01;
|
||||||
|
}
|
||||||
|
|
||||||
self->nextthink = level.time + 0.1;
|
self->nextthink = level.time + 0.1;
|
||||||
}
|
}
|
||||||
|
|
||||||
void fire_doppleganger (edict_t *ent, vec3_t start, vec3_t aimdir)
|
void
|
||||||
|
fire_doppleganger(edict_t *ent, vec3_t start, vec3_t aimdir)
|
||||||
{
|
{
|
||||||
edict_t *base;
|
edict_t *base;
|
||||||
edict_t *body;
|
edict_t *body;
|
||||||
vec3_t dir;
|
vec3_t dir;
|
||||||
vec3_t forward, right, up;
|
vec3_t forward, right, up;
|
||||||
int number;
|
int number;
|
||||||
|
|
||||||
vectoangles2 (aimdir, dir);
|
if (!ent)
|
||||||
AngleVectors (dir, forward, right, up);
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
vectoangles2(aimdir, dir);
|
||||||
|
AngleVectors(dir, forward, right, up);
|
||||||
|
|
||||||
base = G_Spawn();
|
base = G_Spawn();
|
||||||
VectorCopy (start, base->s.origin);
|
VectorCopy(start, base->s.origin);
|
||||||
VectorCopy (dir, base->s.angles);
|
VectorCopy(dir, base->s.angles);
|
||||||
VectorClear (base->velocity);
|
VectorClear(base->velocity);
|
||||||
VectorClear (base->avelocity);
|
VectorClear(base->avelocity);
|
||||||
base->movetype = MOVETYPE_TOSS;
|
base->movetype = MOVETYPE_TOSS;
|
||||||
base->solid = SOLID_BBOX;
|
base->solid = SOLID_BBOX;
|
||||||
base->s.renderfx |= RF_IR_VISIBLE;
|
base->s.renderfx |= RF_IR_VISIBLE;
|
||||||
base->s.angles[PITCH]=0;
|
base->s.angles[PITCH] = 0;
|
||||||
VectorSet (base->mins, -16, -16, -24);
|
VectorSet(base->mins, -16, -16, -24);
|
||||||
VectorSet (base->maxs, 16, 16, 32);
|
VectorSet(base->maxs, 16, 16, 32);
|
||||||
base->s.modelindex = 0;
|
base->s.modelindex = 0;
|
||||||
base->teammaster = ent;
|
base->teammaster = ent;
|
||||||
base->svflags |= SVF_DAMAGEABLE;
|
base->svflags |= SVF_DAMAGEABLE;
|
||||||
|
@ -335,13 +423,11 @@ void fire_doppleganger (edict_t *ent, vec3_t start, vec3_t aimdir)
|
||||||
base->pain = doppleganger_pain;
|
base->pain = doppleganger_pain;
|
||||||
base->die = doppleganger_die;
|
base->die = doppleganger_die;
|
||||||
|
|
||||||
// FIXME - remove with style
|
|
||||||
base->nextthink = level.time + 30;
|
base->nextthink = level.time + 30;
|
||||||
base->think = doppleganger_timeout;
|
base->think = doppleganger_timeout;
|
||||||
|
|
||||||
base->classname = "doppleganger";
|
base->classname = "doppleganger";
|
||||||
|
|
||||||
gi.linkentity (base);
|
gi.linkentity(base);
|
||||||
|
|
||||||
body = G_Spawn();
|
body = G_Spawn();
|
||||||
number = body->s.number;
|
number = body->s.number;
|
||||||
|
@ -351,13 +437,12 @@ void fire_doppleganger (edict_t *ent, vec3_t start, vec3_t aimdir)
|
||||||
body->s.number = number;
|
body->s.number = number;
|
||||||
body->yaw_speed = 30;
|
body->yaw_speed = 30;
|
||||||
body->ideal_yaw = 0;
|
body->ideal_yaw = 0;
|
||||||
VectorCopy (start, body->s.origin);
|
VectorCopy(start, body->s.origin);
|
||||||
body->s.origin[2] += 8;
|
body->s.origin[2] += 8;
|
||||||
body->think = body_think;
|
body->think = body_think;
|
||||||
body->nextthink = level.time + FRAMETIME;
|
body->nextthink = level.time + FRAMETIME;
|
||||||
gi.linkentity (body);
|
gi.linkentity(body);
|
||||||
|
|
||||||
base->teamchain = body;
|
base->teamchain = body;
|
||||||
body->teammaster = base;
|
body->teammaster = base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue