Skip to content

Commit

Permalink
* (bug 4999) Marauder+ zap bugfixes (/dev/humancontroller)
Browse files Browse the repository at this point in the history
  - Use spherical distance checks instead of cubic
  - Fix buildables' ability to be zapped by two marauder+'s at once
  - Chain to targets visible to each other, rather than visible to the zapper
  - Fix zap effect disappearing too early when target dies
  • Loading branch information
cschwarz committed Aug 8, 2011
1 parent f9d8ca0 commit 21df1a8
Show file tree
Hide file tree
Showing 4 changed files with 121 additions and 104 deletions.
1 change: 1 addition & 0 deletions src/game/g_local.h
Expand Up @@ -953,6 +953,7 @@ void CheckCkitRepair( gentity_t *ent );
void G_ChargeAttack( gentity_t *ent, gentity_t *victim );
void G_CrushAttack( gentity_t *ent, gentity_t *victim );
void G_UpdateZaps( int msec );
void G_ClearPlayerZapEffects( gentity_t *player );


//
Expand Down
3 changes: 3 additions & 0 deletions src/game/g_misc.c
Expand Up @@ -88,6 +88,9 @@ void TeleportPlayer( gentity_t *player, vec3_t origin, vec3_t angles )
player->client->ps.eFlags ^= EF_TELEPORT_BIT;
G_UnlaggedClear( player );

// cut all relevant zap beams
G_ClearPlayerZapEffects( player );

// set angles
G_SetClientViewAngle( player, angles );

Expand Down
3 changes: 3 additions & 0 deletions src/game/g_team.c
Expand Up @@ -202,6 +202,9 @@ void G_LeaveTeam( gentity_t *self )
G_FreeEntity( ent );
}

// cut all relevant zap beams
G_ClearPlayerZapEffects( self );

G_namelog_update_score( self->client );
}

Expand Down
218 changes: 114 additions & 104 deletions src/game/g_weapon.c
Expand Up @@ -1025,25 +1025,27 @@ LEVEL2
======================================================================
*/
#define MAX_ZAPS 64
#define MAX_ZAPS MAX_CLIENTS

static zap_t zaps[ MAX_CLIENTS ];
static zap_t zaps[ MAX_ZAPS ];

/*
===============
G_FindNewZapTarget
G_FindZapChainTargets
===============
*/
static gentity_t *G_FindNewZapTarget( gentity_t *ent )
static void G_FindZapChainTargets( zap_t *zap )
{
gentity_t *ent = zap->targets[ 0 ]; // the source
int entityList[ MAX_GENTITIES ];
vec3_t range = { LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE };
vec3_t range = { LEVEL2_AREAZAP_RANGE,
LEVEL2_AREAZAP_RANGE,
LEVEL2_AREAZAP_RANGE };
vec3_t mins, maxs;
int i, j, k, num;
int i, num;
gentity_t *enemy;
trace_t tr;

VectorScale( range, 1.0f / M_ROOT3, range );
VectorAdd( ent->s.origin, range, maxs );
VectorSubtract( ent->s.origin, range, mins );

Expand All @@ -1052,45 +1054,29 @@ static gentity_t *G_FindNewZapTarget( gentity_t *ent )
for( i = 0; i < num; i++ )
{
enemy = &g_entities[ entityList[ i ] ];
// don't chain to self; noclippers can be listed, don't chain to them either
if( enemy == ent || ( enemy->client && enemy->client->noclip ) )
continue;

if( ( ( enemy->client && enemy->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) ||
( enemy->s.eType == ET_BUILDABLE &&
BG_Buildable( enemy->s.modelindex )->team == TEAM_HUMANS ) ) && enemy->health > 0 )
if( ( ( enemy->client &&
enemy->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) ||
( enemy->s.eType == ET_BUILDABLE &&
BG_Buildable( enemy->s.modelindex )->team == TEAM_HUMANS ) ) &&
enemy->health > 0 && // only chain to living targets
Distance( ent->s.origin, enemy->s.origin ) <= LEVEL2_AREAZAP_RANGE )
{
qboolean foundOldTarget = qfalse;

trap_Trace( &tr, muzzle, NULL, NULL, enemy->s.origin, ent->s.number, MASK_SHOT );

//can't see target from here
if( tr.entityNum == ENTITYNUM_WORLD )
continue;
// world-LOS check: trace against the world, ignoring other BODY entities
trap_Trace( &tr, ent->s.origin, NULL, NULL,
enemy->s.origin, ent->s.number, CONTENTS_SOLID );

for( j = 0; j < MAX_ZAPS; j++ )
if( tr.entityNum == ENTITYNUM_NONE )
{
zap_t *zap = &zaps[ j ];

for( k = 0; k < zap->numTargets; k++ )
{
if( zap->targets[ k ] == enemy )
{
foundOldTarget = qtrue;
break;
}
}

if( foundOldTarget )
break;
zap->targets[ zap->numTargets++ ] = enemy;
if( zap->numTargets >= LEVEL2_AREAZAP_MAX_TARGETS )
return;
}

// enemy is already targetted
if( foundOldTarget )
continue;

return enemy;
}
}

return &g_entities[ ENTITYNUM_NONE ];
}

/*
Expand All @@ -1100,23 +1086,19 @@ G_UpdateZapEffect
*/
static void G_UpdateZapEffect( zap_t *zap )
{
int i;
gentity_t *effect = zap->effectChannel;
int entityNums[ LEVEL2_AREAZAP_MAX_TARGETS + 1 ];

effect->s.eType = ET_LEV2_ZAP_CHAIN;
effect->classname = "lev2zapchain";
G_SetOrigin( effect, zap->creator->s.origin );
int i;
int entityNums[ LEVEL2_AREAZAP_MAX_TARGETS + 1 ];

entityNums[ 0 ] = zap->creator->s.number;

for( i = 0; i < zap->numTargets; i++ )
{
entityNums[ i + 1 ] = zap->targets[ i ]->s.number;
}

BG_PackEntityNumbers( &effect->s, entityNums, zap->numTargets + 1 );
trap_LinkEntity( effect );
BG_PackEntityNumbers( &zap->effectChannel->s,
entityNums, zap->numTargets + 1 );

VectorCopy( zap->creator->s.origin, zap->effectChannel->r.currentOrigin );
trap_LinkEntity( zap->effectChannel );
}

/*
Expand All @@ -1126,46 +1108,47 @@ G_CreateNewZap
*/
static void G_CreateNewZap( gentity_t *creator, gentity_t *target )
{
int i, j;
zap_t *zap;
int i;
zap_t *zap;

for( i = 0; i < MAX_ZAPS; i++ )
{
zap = &zaps[ i ];
if( zap->used )
continue;

if( !zap->used )
{
G_Damage( target, creator, creator, forward, target->s.origin,
LEVEL2_AREAZAP_DMG, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE,
MOD_LEVEL2_ZAP );

zap->used = qtrue;
zap->used = qtrue;
zap->timeToLive = LEVEL2_AREAZAP_TIME;

zap->timeToLive = LEVEL2_AREAZAP_TIME;
zap->creator = creator;
zap->targets[ 0 ] = target;
zap->numTargets = 1;

zap->creator = creator;
// the zap chains only through living entities
if( target->health > 0 )
{
G_Damage( target, creator, creator, forward,
target->s.origin, LEVEL2_AREAZAP_DMG,
DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE,
MOD_LEVEL2_ZAP );

zap->targets[ 0 ] = target;
zap->numTargets = 1;
G_FindZapChainTargets( zap );

for( j = 1; j < LEVEL2_AREAZAP_MAX_TARGETS; j++ )
for( i = 1; i < zap->numTargets; i++ )
{
zap->targets[ j ] = G_FindNewZapTarget( target );

if( zap->targets[ j ] )
{
zap->numTargets++;
G_Damage( zap->targets[ j ], target, zap->creator, forward,
target->s.origin, LEVEL2_AREAZAP_DMG,
DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP );
}
G_Damage( zap->targets[ i ], target, zap->creator, forward,
target->s.origin, LEVEL2_AREAZAP_DMG,
DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE,
MOD_LEVEL2_ZAP );
}
}

zap->effectChannel = G_Spawn( );
G_UpdateZapEffect( zap );
zap->effectChannel = G_Spawn( );
zap->effectChannel->s.eType = ET_LEV2_ZAP_CHAIN;
zap->effectChannel->classname = "lev2zapchain";
G_UpdateZapEffect( zap );

return;
}
return;
}
}

Expand All @@ -1183,36 +1166,63 @@ void G_UpdateZaps( int msec )
for( i = 0; i < MAX_ZAPS; i++ )
{
zap = &zaps[ i ];
if( !zap->used )
continue;

if( zap->used )
zap->timeToLive -= msec;

// first, the disappearance of players is handled immediately in G_ClearPlayerZapEffects()

// the deconstruction or gibbing of a directly targeted buildable destroys the whole zap effect
if( zap->timeToLive <= 0 || !zap->targets[ 0 ]->inuse )
{
//check each target is valid
for( j = 0; j < zap->numTargets; j++ )
{
gentity_t *source;
gentity_t *target = zap->targets[ j ];

if( j == 0 )
source = zap->creator;
else
source = zap->targets[ 0 ];

if( target->health <= 0 || !target->inuse || //early out
Distance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE )
{
target = zap->targets[ j ] = G_FindNewZapTarget( source );
}
}
G_FreeEntity( zap->effectChannel );
zap->used = qfalse;
continue;
}

// the deconstruction or gibbing of chained buildables destroy the appropriate beams
for( j = 1; j < zap->numTargets; j++ )
{
if( !zap->targets[ j ]->inuse )
zap->targets[ j-- ] = zap->targets[ --zap->numTargets ];
}

G_UpdateZapEffect( zap );
G_UpdateZapEffect( zap );
}
}

zap->timeToLive -= msec;
/*
===============
G_ClearPlayerZapEffects
if( zap->timeToLive <= 0 || zap->numTargets == 0 || zap->creator->health <= 0 )
{
zap->used = qfalse;
G_FreeEntity( zap->effectChannel );
}
called from G_LeaveTeam() and TeleportPlayer()
===============
*/
void G_ClearPlayerZapEffects( gentity_t *player )
{
int i, j;
zap_t *zap;

for( i = 0; i < MAX_ZAPS; i++ )
{
zap = &zaps[ i ];
if( !zap->used )
continue;

// the disappearance of the creator or the first target destroys the whole zap effect
if( zap->creator == player || zap->targets[ 0 ] == player )
{
G_FreeEntity( zap->effectChannel );
zap->used = qfalse;
continue;
}

// the disappearance of chained players destroy the appropriate beams
for( j = 1; j < zap->numTargets; j++ )
{
if( zap->targets[ j ] == player )
zap->targets[ j-- ] = zap->targets[ --zap->numTargets ];
}
}
}
Expand All @@ -1232,9 +1242,9 @@ void areaZapFire( gentity_t *ent )
if( traceEnt == NULL )
return;

if( ( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) ||
if( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) ||
( traceEnt->s.eType == ET_BUILDABLE &&
BG_Buildable( traceEnt->s.modelindex )->team == TEAM_HUMANS ) ) && traceEnt->health > 0 )
BG_Buildable( traceEnt->s.modelindex )->team == TEAM_HUMANS ) )
{
G_CreateNewZap( ent, traceEnt );
}
Expand Down

0 comments on commit 21df1a8

Please sign in to comment.