diff options
author | Roman Tetelman <kevlarman@gmail.com> | 2009-10-03 12:38:09 +0000 |
---|---|---|
committer | Tim Angus <tim@ngus.net> | 2013-01-03 00:16:07 +0000 |
commit | 5ac8f1a7907d7c4d9ddd5ae30ddaff872ff32edd (patch) | |
tree | 4d76d153295a4bbb670a081ce207cedc3d404209 | |
parent | 919e7694290b4ac307034a9e0bfd4e8ab41c4663 (diff) |
* New zap (fixes #40)
FIXME: currently limited to 3 targets due to netcode restrictions
FIXME: this code could probably use some general cleanup as well
-rw-r--r-- | src/cgame/cg_draw.c | 1 | ||||
-rw-r--r-- | src/cgame/cg_ents.c | 105 | ||||
-rw-r--r-- | src/game/bg_public.h | 1 | ||||
-rw-r--r-- | src/game/g_active.c | 2 | ||||
-rw-r--r-- | src/game/g_local.h | 2 | ||||
-rw-r--r-- | src/game/g_main.c | 1 | ||||
-rw-r--r-- | src/game/g_weapon.c | 279 | ||||
-rw-r--r-- | src/game/tremulous.h | 9 |
8 files changed, 282 insertions, 118 deletions
diff --git a/src/cgame/cg_draw.c b/src/cgame/cg_draw.c index 9469410f..82d0aff2 100644 --- a/src/cgame/cg_draw.c +++ b/src/cgame/cg_draw.c @@ -1905,7 +1905,6 @@ static void CG_DrawLagometer( rectDef_t *rect, float text_x, float text_y, int color; vec4_t adjustedColor; float vscale; - vec4_t white = { 1.0f, 1.0f, 1.0f, 1.0f }; char *ping; if( cg.snap->ps.pm_type == PM_INTERMISSION ) diff --git a/src/cgame/cg_ents.c b/src/cgame/cg_ents.c index 54409aee..1cdcfde7 100644 --- a/src/cgame/cg_ents.c +++ b/src/cgame/cg_ents.c @@ -216,8 +216,6 @@ Add continuous entity effects, like local entity emission and lighting */ static void CG_EntityEffects( centity_t *cent ) { - int i; - // update sound origins CG_SetEntitySoundPosition( cent ); @@ -253,7 +251,7 @@ static void CG_EntityEffects( centity_t *cent ) if( CG_IsTrailSystemValid( ¢->muzzleTS ) ) { - //FIXME hack to prevent tesla trails reaching too far + //FIXME hack to prevent tesla trails reaching too far if( cent->currentState.eType == ET_BUILDABLE ) { vec3_t front, back; @@ -268,33 +266,6 @@ static void CG_EntityEffects( centity_t *cent ) if( cg.time > cent->muzzleTSDeathTime && CG_IsTrailSystemValid( ¢->muzzleTS ) ) CG_DestroyTrailSystem( ¢->muzzleTS ); } - - - if( cent->currentState.eType == ET_PLAYER ) - { - centity_t *pcent = cent;; - - // predicted entity doesn't have local cgame vars - if( cent == &cg.predictedPlayerEntity ) - pcent = &cg_entities[ cg.clientNum ]; - - for( i = 0; i <= 2; i++ ) - { - if( CG_IsTrailSystemValid( &pcent->level2ZapTS[ i ] ) ) - { - vec3_t front, back; - - CG_AttachmentPoint( &pcent->level2ZapTS[ i ]->frontAttachment, front ); - CG_AttachmentPoint( &pcent->level2ZapTS[ i ]->backAttachment, back ); - - if( cg.time - pcent->level2ZapTime > 100 || - Distance( front, back ) > LEVEL2_AREAZAP_CUTOFF ) - { - CG_DestroyTrailSystem( &pcent->level2ZapTS[ i ] ); - } - } - } - } } @@ -831,6 +802,63 @@ void CG_LinkLocation( centity_t *cent ) /* ========================= +CG_Lev2ZapChain +========================= +*/ +static void CG_Lev2ZapChain( centity_t *cent ) +{ + int i; + entityState_t *es; + centity_t *source = NULL, *target = NULL; + + es = ¢->currentState; + + //FIXME: find a better way to send zap targets + for( i = 0; i <= 2; i++ ) + { + switch( i ) + { + case 0: + if( es->time <= 0 ) + continue; + + source = &cg_entities[ es->misc ]; + target = &cg_entities[ es->time ]; + break; + + case 1: + if( es->time2 <= 0 ) + continue; + + source = &cg_entities[ es->time ]; + target = &cg_entities[ es->time2 ]; + break; + + case 2: + if( es->constantLight <= 0 ) + continue; + + source = &cg_entities[ es->time ]; + target = &cg_entities[ es->constantLight ]; + break; + + } + + if( !CG_IsTrailSystemValid( ¢->level2ZapTS[ i ] ) ) + cent->level2ZapTS[ i ] = CG_SpawnNewTrailSystem( cgs.media.level2ZapTS ); + + if( CG_IsTrailSystemValid( ¢->level2ZapTS[ i ] ) ) + { + CG_SetAttachmentCent( ¢->level2ZapTS[ i ]->frontAttachment, source ); + CG_SetAttachmentCent( ¢->level2ZapTS[ i ]->backAttachment, target ); + CG_AttachToCent( ¢->level2ZapTS[ i ]->frontAttachment ); + CG_AttachToCent( ¢->level2ZapTS[ i ]->backAttachment ); + } + } +} + +/* +========================= CG_AdjustPositionForMover Also called by client movement prediction code @@ -1025,8 +1053,21 @@ CG_CEntityPVSLeave */ static void CG_CEntityPVSLeave( centity_t *cent ) { + int i; + entityState_t *es = ¢->currentState; + if( cg_debugPVS.integer ) CG_Printf( "Entity %d left PVS\n", cent->currentState.number ); + switch( es->eType ) + { + case ET_LEV2_ZAP_CHAIN: + for( i = 0; i <= 2; i++ ) + { + if( CG_IsTrailSystemValid( ¢->level2ZapTS[ i ] ) ) + CG_DestroyTrailSystem( ¢->level2ZapTS[ i ] ); + } + break; + } } @@ -1111,6 +1152,10 @@ static void CG_AddCEntity( centity_t *cent ) CG_LightFlare( cent ); break; + case ET_LEV2_ZAP_CHAIN: + CG_Lev2ZapChain( cent ); + break; + case ET_LOCATION: CG_LinkLocation( cent ); break; diff --git a/src/game/bg_public.h b/src/game/bg_public.h index 7f7f576f..2c0d1b31 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -1190,6 +1190,7 @@ typedef enum ET_ANIMMAPOBJ, ET_MODELDOOR, ET_LIGHTFLARE, + ET_LEV2_ZAP_CHAIN, ET_EVENTS // any of the EV_* events can be added freestanding // by setting eType to ET_EVENTS + eventNum diff --git a/src/game/g_active.c b/src/game/g_active.c index c74dda37..29b57c4f 100644 --- a/src/game/g_active.c +++ b/src/game/g_active.c @@ -1917,8 +1917,6 @@ void ClientEndFrame( gentity_t *ent ) G_SetClientSound( ent ); - G_UpdateZaps( ent ); - // set the latest infor if( g_smoothClients.integer ) BG_PlayerStateToEntityStateExtraPolate( &ent->client->ps, &ent->s, ent->client->ps.commandTime, qtrue ); diff --git a/src/game/g_local.h b/src/game/g_local.h index f1432ebc..c7b8dcd0 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -895,7 +895,7 @@ qboolean CheckPounceAttack( gentity_t *ent ); 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( gentity_t *ent ); +void G_UpdateZaps( int msec ); // diff --git a/src/game/g_main.c b/src/game/g_main.c index 63b8930d..0b1c639c 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -2552,6 +2552,7 @@ void G_RunFrame( int levelTime ) G_SpawnClients( TEAM_ALIENS ); G_SpawnClients( TEAM_HUMANS ); G_CalculateAvgPlayers( ); + G_UpdateZaps( msec ); // see if it is time to end the level CheckExitRules( ); diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 5ef638a5..1c58e212 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -1084,49 +1084,23 @@ LEVEL2 ====================================================================== */ +#define MAX_ZAPS 64 -static vec3_t sortReference; -static int QDECL G_SortDistance( const void *a, const void *b ) -{ - gentity_t *aent, *bent; - float adist, bdist; - - aent = &g_entities[ *(int *)a ]; - bent = &g_entities[ *(int *)b ]; - adist = Distance( sortReference, aent->s.origin ); - bdist = Distance( sortReference, bent->s.origin ); - if( adist > bdist ) - return -1; - else if( adist < bdist ) - return 1; - else - return 0; -} +static zap_t zaps[ MAX_CLIENTS ]; /* =============== -G_UpdateZaps +G_FindNewZapTarget =============== */ -void G_UpdateZaps( gentity_t *ent ) +static gentity_t *G_FindNewZapTarget( gentity_t *ent ) { int entityList[ MAX_GENTITIES ]; - int hitList[ MAX_GENTITIES ]; - vec3_t range = { LEVEL2_AREAZAP_CUTOFF, - LEVEL2_AREAZAP_CUTOFF, - LEVEL2_AREAZAP_CUTOFF }; + vec3_t range = { LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE }; vec3_t mins, maxs; - int i, j; - int hit = 0; - int num; + int i, j, k, num; gentity_t *enemy; - gentity_t *effect; trace_t tr; - qboolean alreadyTargeted = qfalse; - int damage; - - if( !ent->zapping || ent->health <= 0 ) - return; VectorScale( range, 1.0f / M_ROOT3, range ); VectorAdd( ent->s.origin, range, maxs ); @@ -1138,86 +1112,227 @@ void G_UpdateZaps( gentity_t *ent ) { enemy = &g_entities[ entityList[ i ] ]; - if( ( ( enemy->client && - enemy->client->ps.stats[ STAT_TEAM ] == TEAM_HUMANS ) || + 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 ) + BG_Buildable( enemy->s.modelindex )->team == TEAM_HUMANS ) ) && enemy->health > 0 ) { + 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; - alreadyTargeted = qfalse; - for( j = 0; j < LEVEL2_AREAZAP_MAX_TARGETS; j++ ) + for( j = 0; j < MAX_ZAPS; j++ ) { - if( ent->zapTargets[ j ] == entityList[ i ] ) + zap_t *zap = &zaps[ j ]; + + for( k = 0; k < zap->numTargets; k++ ) { - alreadyTargeted = qtrue; + if( zap->targets[ k ] == enemy ) + { + foundOldTarget = qtrue; break; + } } + + if( foundOldTarget ) + break; } - if( !alreadyTargeted && - Distance( ent->s.origin, enemy->s.origin ) > LEVEL2_AREAZAP_RANGE ) - { + // enemy is already targetted + if( foundOldTarget ) continue; - } - trap_Trace( &tr, ent->s.origin, NULL, NULL, enemy->s.origin, - ent-g_entities, MASK_SHOT ); - if( tr.entityNum == enemy-g_entities ) - hitList[ hit++ ] = tr.entityNum; + return enemy; } } - for( i = 0; i < LEVEL2_AREAZAP_MAX_TARGETS; i++ ) - ent->zapTargets[ i ] = -1; - - if( !hit ) - return; - - ent->zapDmg += ( (float)( level.time - level.previousTime ) / 1000.0f ) - * LEVEL2_AREAZAP_DMG; - damage = (int)ent->zapDmg; - // wait until we've accumulated enough damage for bsuit to take at - // least 1 HP - if( damage < 5 ) - damage = 0; - else - ent->zapDmg -= (int)damage; + return NULL; +} +/* +=============== +G_UpdateZapEffect +=============== +*/ +static void G_UpdateZapEffect( zap_t *zap ) +{ + int j; + gentity_t *effect = zap->effectChannel; - VectorCopy( ent->s.origin, sortReference ); - qsort( hitList, hit, sizeof( int ), G_SortDistance ); + effect->s.eType = ET_LEV2_ZAP_CHAIN; + effect->classname = "lev2zapchain"; + G_SetOrigin( effect, zap->creator->s.origin ); + effect->s.misc = zap->creator->s.number; - effect = G_TempEntity( ent->s.origin, EV_LEV2_ZAP ); - effect->s.misc = ent-g_entities; effect->s.time = effect->s.time2 = effect->s.constantLight = -1; - for( i = 0; i < hit; i++ ) + + for( j = 0; j < zap->numTargets; j++ ) { - if( i >= LEVEL2_AREAZAP_MAX_TARGETS ) - break; + int number = zap->targets[ j ]->s.number; - ent->zapTargets[ i ] = hitList[ i ]; + switch( j ) + { + case 0: effect->s.time = number; break; + case 1: effect->s.time2 = number; break; + case 2: effect->s.constantLight = number; break; + default: break; + } + } - enemy = &g_entities[ hitList[ i ] ]; + trap_LinkEntity( effect ); +} +/* +=============== +G_CreateNewZap +=============== +*/ +static void G_CreateNewZap( gentity_t *creator, gentity_t *target ) +{ + int i, j; + zap_t *zap; + + for( i = 0; i < MAX_ZAPS; i++ ) + { + zap = &zaps[ i ]; - if( damage > 0 ) + if( !zap->used ) { - G_Damage( enemy, ent, ent, NULL, enemy->s.origin, - damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP ); + zap->used = qtrue; + + zap->timeToLive = LEVEL2_AREAZAP_TIME; + zap->damageUsed = 0; + + zap->creator = creator; + + zap->targets[ 0 ] = target; + zap->numTargets = 1; + + for( j = 1; j < MAX_ZAP_TARGETS && zap->targets[ j - 1 ]; j++ ) + { + zap->targets[ j ] = G_FindNewZapTarget( zap->targets[ 0 ] ); + + if( zap->targets[ j ] ) + zap->numTargets++; + } + + zap->effectChannel = G_Spawn( ); + G_UpdateZapEffect( zap ); + + return; } + } +} + + +/* +=============== +G_UpdateZaps +=============== +*/ +void G_UpdateZaps( int msec ) +{ + int i, j; + zap_t *zap; + int damage; + + for( i = 0; i < MAX_ZAPS; i++ ) + { + zap = &zaps[ i ]; - switch( i ) + if( zap->used ) { - case 0: effect->s.time = hitList[ i ]; break; - case 1: effect->s.time2 = hitList[ i ]; break; - case 2: effect->s.constantLight = hitList[ i ]; break; - default: break; + //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 ); + } + } + + if( zap->numTargets ) + { + damage = ceil( ( (float)msec / LEVEL2_AREAZAP_TIME ) * + LEVEL2_AREAZAP_DMG ); + + // don't let a high msec value inflate the total damage + if( damage + zap->damageUsed > LEVEL2_AREAZAP_DMG ) + damage = LEVEL2_AREAZAP_DMG - zap->damageUsed; + + for( j = 0; j < zap->numTargets; j++ ) + { + gentity_t *source; + gentity_t *target = zap->targets[ j ]; + vec3_t forward; + + if( j == 0 ) + source = zap->creator; + else + source = zap->targets[ 0 ]; + + VectorSubtract( target->s.origin, source->s.origin, forward ); + VectorNormalize( forward ); + + //do the damage + if( damage ) + { + G_Damage( target, source, zap->creator, forward, target->s.origin, + damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP ); + } + } + } + + G_UpdateZapEffect( zap ); + + zap->timeToLive -= msec; + + if( zap->timeToLive <= 0 || zap->numTargets == 0 || zap->creator->health <= 0 ) + { + zap->used = qfalse; + G_FreeEntity( zap->effectChannel ); + } } } } /* +=============== +areaZapFire +=============== +*/ +void areaZapFire( gentity_t *ent ) +{ + trace_t tr; + gentity_t *traceEnt; + + G_WideTrace( &tr, ent, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH, &traceEnt ); + + if( traceEnt == NULL ) + return; + + 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 ) + { + G_CreateNewZap( ent, traceEnt ); + } +} + + +/* ====================================================================== LEVEL3 @@ -1462,6 +1577,10 @@ void FireWeapon2( gentity_t *ent ) LCChargeFire( ent, qtrue ); break; + case WP_ALEVEL2_UPG: + areaZapFire( ent ); + break; + case WP_ABUILD: case WP_ABUILD2: case WP_HBUILD: diff --git a/src/game/tremulous.h b/src/game/tremulous.h index 55db6bce..7c414e89 100644 --- a/src/game/tremulous.h +++ b/src/game/tremulous.h @@ -77,10 +77,11 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #define LEVEL2_CLAW_K_SCALE 1.0f #define LEVEL2_CLAW_U_REPEAT 400 #define LEVEL2_CLAW_U_K_SCALE 1.0f -#define LEVEL2_AREAZAP_DMG ADM(40) -#define LEVEL2_AREAZAP_RANGE 120.0f -#define LEVEL2_AREAZAP_CUTOFF 300.0f -#define LEVEL2_AREAZAP_REPEAT 500 +#define LEVEL2_AREAZAP_DMG ADM(60) +#define LEVEL2_AREAZAP_RANGE 200.0f +#define LEVEL2_AREAZAP_WIDTH 15.0f +#define LEVEL2_AREAZAP_REPEAT 1500 +#define LEVEL2_AREAZAP_TIME 1000 #define LEVEL2_AREAZAP_MAX_TARGETS 5 #define LEVEL2_WALLJUMP_MAXSPEED 1000.0f |