diff options
Diffstat (limited to 'src/game')
-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 |
6 files changed, 207 insertions, 87 deletions
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 |