Skip to content

Commit

Permalink
Make force fields apply forces smoothly and continuously.
Browse files Browse the repository at this point in the history
  • Loading branch information
enneract committed Apr 12, 2015
1 parent eca487d commit 622ecb7
Show file tree
Hide file tree
Showing 7 changed files with 151 additions and 68 deletions.
17 changes: 17 additions & 0 deletions src/cgame/cg_predict.c
Expand Up @@ -620,6 +620,23 @@ void CG_PredictPlayerState( void )

cg_pmove.noFootsteps = 0;

/* for( i = 0; i < cg.snap->numEntities; i++ )
{
cent = &cg_entities[ cg.snap->entities[ i ].number ];
es = &cent->currentState;*/

for( cg_pmove.numForceFields = 0, i = 0; i < cg.snap->numEntities; i++ )
{
centity_t *cent = cg_entities + cg.snap->entities[ i ].number;

if( BG_ForceFieldForEntity( &cg.predictedPlayerState, &cent->currentState,
cg_pmove.forceFields + cg_pmove.numForceFields ) )
cg_pmove.numForceFields++;

if( cg_pmove.numForceFields == MAX_FORCE_FIELDS )
break;
}

// save the state before the pmove so we can detect transitions
oldPlayerState = cg.predictedPlayerState;

Expand Down
37 changes: 37 additions & 0 deletions src/game/bg_misc.c
Expand Up @@ -5449,3 +5449,40 @@ int cmdcmp( const void *a, const void *b )
{
return Q_stricmp( (const char *)a, ((dummyCmd_t *)b)->name );
}

/*
============
BG_ForceFieldForEntity
============
*/
qboolean BG_ForceFieldForEntity( playerState_t *ps, entityState_t *es, forceField_t *ff )
{
if( es->eType == ET_BUILDABLE )
{
if( !( es->eFlags & EF_B_POWERED ) )
return qfalse;

if( !( es->eFlags & EF_B_SPAWNED ) )
return qfalse;

// health
if( es->generic1 <= 0 )
return qfalse;

switch( es->modelindex )
{
case BA_H_LIGHT: //force field
if( ps && ps->stats[ STAT_TEAM ] != TEAM_ALIENS )
return qfalse;

ff->type = 0;
VectorCopy( es->origin, ff->origin );
ff->range = LIGHT_RANGE;
ff->force = LIGHT_FORCE;

return qtrue;
}
}

return qfalse;
}
41 changes: 41 additions & 0 deletions src/game/bg_pmove.c
Expand Up @@ -3901,6 +3901,45 @@ void PM_UpdateViewAngles( playerState_t *ps, const usercmd_t *cmd )
}
}

/*
================
PM_ForceFields
================
*/

void PM_ForceFields( void )
{
int i;
float dt = pml.msec * 0.001f;
forceField_t *ff;
vec3_t total = { 0 };

for( i = 0; i < pm->numForceFields; i++ )
{
vec3_t delta;
float distance, force;
trace_t tr;

ff = pm->forceFields + i;

VectorSubtract( ff->origin, pm->ps->origin, delta );
distance = VectorNormalize( delta );

if( distance > ff->range )
continue;

pm->trace( &tr, pm->ps->origin, NULL, NULL, ff->origin, pm->ps->clientNum, MASK_SOLID );

if( tr.fraction < 1.0f )
continue;

force = ff->force / distance * ( 1.0f - distance / ff->range );

VectorMA( total, force, delta, total );
}

VectorMA( pm->ps->velocity, dt, total, pm->ps->velocity );
}

/*
================
Expand Down Expand Up @@ -4062,6 +4101,8 @@ void PmoveSingle( pmove_t *pmove )

PM_DropTimers( );

PM_ForceFields( );

if( pm->ps->pm_type == PM_JETPACK )
PM_JetPackMove( );
else if( pm->ps->pm_type == PM_HUMMEL )
Expand Down
14 changes: 14 additions & 0 deletions src/game/bg_public.h
Expand Up @@ -161,6 +161,15 @@ typedef enum

#define PMF_ALL_TIMES (PMF_TIME_WATERJUMP|PMF_TIME_LAND|PMF_TIME_KNOCKBACK|PMF_TIME_WALLJUMP)

#define MAX_FORCE_FIELDS 100
typedef struct
{
int type;
vec3_t origin;
float force;
float range;
} forceField_t;

typedef struct
{
int pouncePayload;
Expand Down Expand Up @@ -205,6 +214,9 @@ typedef struct pmove_s


int (*pointcontents)( const vec3_t point, int passEntityNum );

forceField_t forceFields[ MAX_FORCE_FIELDS ];
int numForceFields;
} pmove_t;

// if a full pmove isn't done on the client, you can just update the angles
Expand Down Expand Up @@ -1249,3 +1261,5 @@ int cmdcmp( const void *a, const void *b );
#define DIF_BUILDABLE 0x0002 // has to be 2
#define DIF_FRIENDLY 0x0004
#define DIF_PERSISTENT 0x0008 // poison and infection

qboolean BG_ForceFieldForEntity( playerState_t *ps, entityState_t *es, forceField_t *ff );
13 changes: 13 additions & 0 deletions src/game/g_active.c
Expand Up @@ -1663,6 +1663,7 @@ void ClientThink_real( gentity_t *ent )
int oldEventSequence;
int msec;
usercmd_t *ucmd;
int i;

client = ent->client;

Expand Down Expand Up @@ -1992,6 +1993,18 @@ void ClientThink_real( gentity_t *ent )
pm.debugLevel = g_debugMove.integer;
pm.noFootsteps = 0;

for( i = 0; i < level.num_entities; i++ )
{
gentity_t *ent = g_entities + i;

if( BG_ForceFieldForEntity( pm.ps, &ent->s,
pm.forceFields + pm.numForceFields ) )
pm.numForceFields++;

if( pm.numForceFields == MAX_FORCE_FIELDS )
break;
}

pm.pmove_fixed = pmove_fixed.integer | client->pers.pmoveFixed;
pm.pmove_msec = pmove_msec.integer;

Expand Down
83 changes: 21 additions & 62 deletions src/game/g_buildable.c
Expand Up @@ -1642,21 +1642,16 @@ for forcefield
*/
void G_Push( gentity_t *self )
{
#define PUSH_REPEAT 400
#define PUSH_RANGE 140
#define PUSH_FORCE -900
#define WEAK_PUSH_FORCE -675

int entityList[ MAX_GENTITIES ];
vec3_t range = { PUSH_RANGE, PUSH_RANGE, PUSH_RANGE };
vec3_t range = { LIGHT_RANGE, LIGHT_RANGE, LIGHT_RANGE };
vec3_t mins, maxs;
int i, num;
gentity_t *enemy;
vec3_t start,dir,end;
float force;
qboolean active = qfalse;

self->nextthink = level.time + PUSH_REPEAT;
self->nextthink = level.time + 500;

VectorAdd( self->s.origin, range, maxs );
VectorSubtract( self->s.origin, range, mins );
Expand All @@ -1682,80 +1677,44 @@ void G_Push( gentity_t *self )

if( enemy->flags & FL_NOTARGET )
continue;

if( !G_Visible( self, enemy, CONTENTS_SOLID ) )
continue;
continue;

if (enemy->client && enemy->client->notrackEndTime >= level.time)
continue;
continue;

if( Distance( enemy->r.currentOrigin, self->r.currentOrigin ) > LIGHT_RANGE )
continue;

if( enemy->client && enemy->client->ps.stats[ STAT_TEAM ] != TEAM_HUMANS )
{
if (enemy == self)
continue;
if (enemy == self)
continue;

if (!enemy->client)
continue;
if (!enemy->client)
continue;

if (enemy == self->parent)
continue;
if (enemy == self->parent)
continue;

if (!enemy->takedamage)
continue;
if (!enemy->takedamage)
continue;

active = qtrue;
break;
active = qtrue;
break;
}
}

if (active)
{
for( i = 0; i < num; i++ )
{
enemy = &g_entities[ entityList[ i ] ];

if( enemy->flags & FL_NOTARGET )
continue;

if( !G_Visible( self, enemy, CONTENTS_SOLID ) )
continue;

if (enemy->client && enemy->client->notrackEndTime >= level.time)
continue;

if( enemy->client && enemy->client->ps.stats[ STAT_TEAM ] != TEAM_NONE )
{
if (enemy == self)
continue;

if (!enemy->client)
continue;

if (enemy == self->parent)
continue;

if (!enemy->takedamage)
continue;

if ( enemy->client->ps.stats[ STAT_CLASS ] == PCL_ALIEN_LEVEL5 )
force = PUSH_FORCE;
else
force = WEAK_PUSH_FORCE;

VectorCopy(enemy->r.currentOrigin, start);
VectorCopy(self->r.currentOrigin, end);
VectorSubtract(end, start, dir);
VectorNormalize(dir);
VectorScale(dir, force, enemy->client->ps.velocity);
VectorCopy(dir, enemy->movedir);
}
}

// start the attack animation
G_AddEvent( self, EV_FORCE_FIELD, DirToByte( self->s.origin2 ) );

if( level.time >= self->timestamp + 500 )
{
self->timestamp = level.time;
G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
self->timestamp = level.time;
G_SetBuildableAnim( self, BANIM_ATTACK1, qfalse );
}
}
}
Expand Down
14 changes: 8 additions & 6 deletions src/game/tremulous.h
Expand Up @@ -1111,12 +1111,14 @@ TREMULOUS EDGE MOD SRC FILE
#define BARREL_SPLASHRADIUS 150
#define BARREL_VALUE HBVM(BARREL_BP)

#define LIGHT_BP 12
#define LIGHT_BT 12000
#define LIGHT_HEALTH HBHM(200)
#define LIGHT_SPLASHDAMAGE 15
#define LIGHT_SPLASHRADIUS 180
#define LIGHT_VALUE HBVM(LIGHT_BP)
#define LIGHT_BP 12
#define LIGHT_BT 12000
#define LIGHT_HEALTH HBHM(200)
#define LIGHT_SPLASHDAMAGE 15
#define LIGHT_SPLASHRADIUS 180
#define LIGHT_VALUE HBVM(LIGHT_BP)
#define LIGHT_RANGE 220
#define LIGHT_FORCE -1.5e+6

#define COVER_BP 20
#define COVER_BT 20000
Expand Down

0 comments on commit 622ecb7

Please sign in to comment.