diff options
Diffstat (limited to 'src/game/g_weapon.c')
-rw-r--r-- | src/game/g_weapon.c | 248 |
1 files changed, 218 insertions, 30 deletions
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 7094bcdb..1dbd5c15 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -871,7 +871,7 @@ void poisonCloud( gentity_t *ent ) humanPlayer->client->ps.stats[ STAT_STATE ] |= SS_POISONCLOUDED; humanPlayer->client->lastPoisonCloudedTime = level.time; humanPlayer->client->lastPoisonCloudedClient = ent; - trap_SendServerCommand( humanPlayer->client->ps.clientNum, "poisoncloud" ); + G_SendCommandFromServer( humanPlayer->client->ps.clientNum, "poisoncloud" ); } } } @@ -886,25 +886,27 @@ LEVEL2 ====================================================================== */ +#define MAX_ZAPS 64 + +static zap_t zaps[ MAX_CLIENTS ]; + /* =============== -areaZapFire +G_FindNewZapTarget =============== */ -void areaZapFire( gentity_t *ent ) +static gentity_t *G_FindNewZapTarget( gentity_t *ent ) { int entityList[ MAX_GENTITIES ]; - int targetList[ MAX_GENTITIES ]; vec3_t range = { LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE }; - vec3_t mins, maxs, dir; - int i, num, numTargets = 0; + vec3_t mins, maxs; + int i, j, k, num; gentity_t *enemy; - gentity_t *tent; trace_t tr; - int damage; - VectorAdd( ent->client->ps.origin, range, maxs ); - VectorSubtract( ent->client->ps.origin, range, mins ); + VectorScale( range, 1.0f / M_ROOT3, range ); + VectorAdd( ent->s.origin, range, maxs ); + VectorSubtract( ent->s.origin, range, mins ); num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); @@ -912,41 +914,227 @@ void areaZapFire( gentity_t *ent ) { enemy = &g_entities[ entityList[ i ] ]; - if( ( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || - ( enemy->s.eType == ET_BUILDABLE && BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_HUMANS ) ) + if( ( ( enemy->client && enemy->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || + ( enemy->s.eType == ET_BUILDABLE && + BG_FindTeamForBuildable( enemy->s.modelindex ) == BIT_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; - targetList[ numTargets++ ] = entityList[ i ]; + for( j = 0; j < MAX_ZAPS; j++ ) + { + zap_t *zap = &zaps[ j ]; + + for( k = 0; k < zap->numTargets; k++ ) + { + if( zap->targets[ k ] == enemy ) + { + foundOldTarget = qtrue; + break; + } + } + + if( foundOldTarget ) + break; + } + + // enemy is already targetted + if( foundOldTarget ) + continue; + + return enemy; } } - damage = (int)( (float)LEVEL2_AREAZAP_DMG / (float)numTargets ); - for( i = 0; i < numTargets; i++ ) - { - enemy = &g_entities[ targetList[ i ] ]; + return NULL; +} - VectorSubtract( enemy->s.origin, muzzle, dir ); - VectorNormalize( dir ); - - //do some damage - G_Damage( enemy, ent, ent, dir, tr.endpos, - damage, DAMAGE_NO_KNOCKBACK | DAMAGE_NO_LOCDAMAGE, MOD_LEVEL2_ZAP ); +/* +=============== +G_UpdateZapEffect +=============== +*/ +static void G_UpdateZapEffect( zap_t *zap ) +{ + int j; + gentity_t *effect = zap->effectChannel; + + effect->s.eType = ET_LEV2_ZAP_CHAIN; + effect->classname = "lev2zapchain"; + G_SetOrigin( effect, zap->creator->s.origin ); + effect->s.powerups = zap->creator->s.number; + + effect->s.time = effect->s.time2 = effect->s.constantLight = -1; + + for( j = 0; j < zap->numTargets; j++ ) + { + int number = zap->targets[ j ]->s.number; - // snap the endpos to integers to save net bandwidth, but nudged towards the line - SnapVectorTowards( tr.endpos, muzzle ); + 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; + } + } + + 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( !zap->used ) + { + zap->used = qtrue; + + zap->timeToLive = LEVEL2_AREAZAP_TIME; + + 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[ j - 1 ] ); + + 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 ]; + + if( zap->used ) + { + //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[ j - 1 ]; + + if( target->health <= 0 || !target->inuse || //early out + VectorDistance( source->s.origin, target->s.origin ) > LEVEL2_AREAZAP_RANGE ) + { + target = zap->targets[ j ] = G_FindNewZapTarget( source ); + + //couldn't find a target, so forget about the rest of the chain + if( !target ) + zap->numTargets = j; + } + + } + + if( zap->numTargets ) + { + for( j = 0; j < zap->numTargets; j++ ) + { + gentity_t *source; + gentity_t *target = zap->targets[ j ]; + float r = 1.0f / zap->numTargets; + float damageFraction = 2 * r - 2 * j * r * r - r * r; + + if( j == 0 ) + source = zap->creator; + else + source = zap->targets[ j - 1 ]; + + damage = ceil( ( (float)msec / LEVEL2_AREAZAP_TIME ) * + LEVEL2_AREAZAP_DMG * damageFraction ); + + //do the damage + if( damage ) + G_Damage( target, source, zap->creator, NULL, NULL, + 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 ); + } + } + } +} - // send arc effect - tent = G_TempEntity( enemy->s.pos.trBase, EV_ALIENZAP ); +/* +=============== +areaZapFire +=============== +*/ +void areaZapFire( gentity_t *ent ) +{ + trace_t tr; + vec3_t end; + gentity_t *traceEnt; - VectorCopy( ent->client->ps.origin, tent->s.origin2 ); + // set aiming directions + AngleVectors( ent->client->ps.viewangles, forward, right, up ); + + CalcMuzzlePoint( ent, forward, right, up, muzzle ); + + VectorMA( muzzle, LEVEL2_AREAZAP_RANGE, forward, end ); + + trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); + if( tr.surfaceFlags & SURF_NOIMPACT ) + return; - tent->s.generic1 = ent->s.number; //src - tent->s.clientNum = enemy->s.number; //dest + traceEnt = &g_entities[ tr.entityNum ]; + + if( ( ( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) || + ( traceEnt->s.eType == ET_BUILDABLE && + BG_FindTeamForBuildable( traceEnt->s.modelindex ) == BIT_HUMANS ) ) && traceEnt->health > 0 ) + { + G_CreateNewZap( ent, traceEnt ); } } |