diff options
Diffstat (limited to 'src/game/g_weapon.c')
-rw-r--r-- | src/game/g_weapon.c | 1553 |
1 files changed, 0 insertions, 1553 deletions
diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c deleted file mode 100644 index a18a8c39..00000000 --- a/src/game/g_weapon.c +++ /dev/null @@ -1,1553 +0,0 @@ -// Copyright (C) 1999-2000 Id Software, Inc. -// -// g_weapon.c -// perform the server side effects of a weapon firing - -/* - * Portions Copyright (C) 2000-2001 Tim Angus - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the OSML - Open Source Modification License v1.0 as - * described in the file COPYING which is distributed with this source - * code. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. - */ - -#include "g_local.h" - -static vec3_t forward, right, up; -static vec3_t muzzle; - -/* -================ -G_ForceWeaponChange -================ -*/ -void G_ForceWeaponChange( gentity_t *ent, weapon_t weapon ) -{ - int i; - - if( ent ) - { - ent->client->ps.pm_flags |= PMF_WEAPON_SWITCH; - - if( weapon == WP_NONE ) - { - //switch to the first non blaster weapon - for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) - { - if( i == WP_BLASTER ) - continue; - - if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) ) - { - ent->client->ps.persistant[ PERS_NEWWEAPON ] = i; - break; - } - } - - //only got the blaster to switch to - if( i == WP_NUM_WEAPONS ) - ent->client->ps.persistant[ PERS_NEWWEAPON ] = WP_BLASTER; - } - else - ent->client->ps.persistant[ PERS_NEWWEAPON ] = weapon; - } -} - -/* -================= -G_GiveClientMaxAmmo -================= -*/ -void G_GiveClientMaxAmmo( gentity_t *ent, qboolean buyingEnergyAmmo ) -{ - int i; - int maxAmmo, maxClips; - qboolean weaponType, restoredAmmo = qfalse; - - for( i = WP_NONE + 1; i < WP_NUM_WEAPONS; i++ ) - { - if( buyingEnergyAmmo ) - weaponType = BG_FindUsesEnergyForWeapon( i ); - else - weaponType = !BG_FindUsesEnergyForWeapon( i ); - - if( BG_InventoryContainsWeapon( i, ent->client->ps.stats ) && - weaponType && !BG_FindInfinteAmmoForWeapon( i ) && - !BG_WeaponIsFull( i, ent->client->ps.stats, - ent->client->ps.ammo, ent->client->ps.powerups ) ) - { - BG_FindAmmoForWeapon( i, &maxAmmo, &maxClips ); - - if( buyingEnergyAmmo ) - { - G_AddEvent( ent, EV_RPTUSE_SOUND, 0 ); - - if( BG_InventoryContainsUpgrade( UP_BATTPACK, ent->client->ps.stats ) ) - maxAmmo = (int)( (float)maxAmmo * BATTPACK_MODIFIER ); - } - - BG_PackAmmoArray( i, ent->client->ps.ammo, ent->client->ps.powerups, - maxAmmo, maxClips ); - - restoredAmmo = qtrue; - } - } - - if( restoredAmmo ) - G_ForceWeaponChange( ent, ent->client->ps.weapon ); -} - -/* -================ -G_BounceProjectile -================ -*/ -void G_BounceProjectile( vec3_t start, vec3_t impact, vec3_t dir, vec3_t endout ) -{ - vec3_t v, newv; - float dot; - - VectorSubtract( impact, start, v ); - dot = DotProduct( v, dir ); - VectorMA( v, -2 * dot, dir, newv ); - - VectorNormalize(newv); - VectorMA(impact, 8192, newv, endout); -} - -/* -====================== -SnapVectorTowards - -Round a vector to integers for more efficient network -transmission, but make sure that it rounds towards a given point -rather than blindly truncating. This prevents it from truncating -into a wall. -====================== -*/ -void SnapVectorTowards( vec3_t v, vec3_t to ) -{ - int i; - - for( i = 0 ; i < 3 ; i++ ) - { - if( to[ i ] <= v[ i ] ) - v[ i ] = (int)v[ i ]; - else - v[ i ] = (int)v[ i ] + 1; - } -} - -/* -=============== -meleeAttack -=============== -*/ -void meleeAttack( gentity_t *ent, float range, float width, int damage, meansOfDeath_t mod ) -{ - trace_t tr; - vec3_t end; - gentity_t *tent; - gentity_t *traceEnt; - vec3_t mins, maxs; - - VectorSet( mins, -width, -width, -width ); - VectorSet( maxs, width, width, width ); - - // set aiming directions - AngleVectors( ent->client->ps.viewangles, forward, right, up ); - - CalcMuzzlePoint( ent, forward, right, up, muzzle ); - - VectorMA( muzzle, range, forward, end ); - - trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT ); - if( tr.surfaceFlags & SURF_NOIMPACT ) - return; - - traceEnt = &g_entities[ tr.entityNum ]; - - // send blood impact - if( traceEnt->takedamage && traceEnt->client ) - { - tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); - tent->s.otherEntityNum = traceEnt->s.number; - tent->s.eventParm = DirToByte( tr.plane.normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - - if( traceEnt->takedamage ) - G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, mod ); -} - -/* -====================================================================== - -MACHINEGUN - -====================================================================== -*/ - -void bulletFire( gentity_t *ent, float spread, int damage, int mod ) -{ - trace_t tr; - vec3_t end; - float r; - float u; - gentity_t *tent; - gentity_t *traceEnt; - - r = random( ) * M_PI * 2.0f; - u = sin( r ) * crandom( ) * spread * 16; - r = cos( r ) * crandom( ) * spread * 16; - VectorMA( muzzle, 8192 * 16, forward, end ); - VectorMA( end, r, right, end ); - VectorMA( end, u, up, end ); - - trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); - if( tr.surfaceFlags & SURF_NOIMPACT ) - return; - - traceEnt = &g_entities[ tr.entityNum ]; - - // snap the endpos to integers, but nudged towards the line - SnapVectorTowards( tr.endpos, muzzle ); - - // send bullet impact - if( traceEnt->takedamage && traceEnt->client ) - { - tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_FLESH ); - tent->s.eventParm = traceEnt->s.number; - } - else - { - tent = G_TempEntity( tr.endpos, EV_BULLET_HIT_WALL ); - tent->s.eventParm = DirToByte( tr.plane.normal ); - } - tent->s.otherEntityNum = ent->s.number; - - if( traceEnt->takedamage ) - { - G_Damage( traceEnt, ent, ent, forward, tr.endpos, - damage, 0, mod ); - } -} - -/* -====================================================================== - -SHOTGUN - -====================================================================== -*/ - -// this should match CG_ShotgunPattern -void ShotgunPattern( vec3_t origin, vec3_t origin2, int seed, gentity_t *ent ) -{ - int i; - float r, u; - vec3_t end; - vec3_t forward, right, up; - trace_t tr; - gentity_t *traceEnt; - - // derive the right and up vectors from the forward vector, because - // the client won't have any other information - VectorNormalize2( origin2, forward ); - PerpendicularVector( right, forward ); - CrossProduct( forward, right, up ); - - // generate the "random" spread pattern - for( i = 0; i < SHOTGUN_PELLETS; i++ ) - { - r = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; - u = Q_crandom( &seed ) * SHOTGUN_SPREAD * 16; - VectorMA( origin, 8192 * 16, forward, end ); - VectorMA( end, r, right, end ); - VectorMA( end, u, up, end ); - - trap_Trace( &tr, origin, NULL, NULL, end, ent->s.number, MASK_SHOT ); - traceEnt = &g_entities[ tr.entityNum ]; - - // send bullet impact - if( !( tr.surfaceFlags & SURF_NOIMPACT ) ) - { - if( traceEnt->takedamage ) - G_Damage( traceEnt, ent, ent, forward, tr.endpos, SHOTGUN_DMG, 0, MOD_SHOTGUN ); - } - } -} - - -void shotgunFire( gentity_t *ent ) -{ - gentity_t *tent; - - // send shotgun blast - tent = G_TempEntity( muzzle, EV_SHOTGUN ); - VectorScale( forward, 4096, tent->s.origin2 ); - SnapVector( tent->s.origin2 ); - tent->s.eventParm = rand() & 255; // seed for spread pattern - tent->s.otherEntityNum = ent->s.number; - - ShotgunPattern( tent->s.pos.trBase, tent->s.origin2, tent->s.eventParm, ent ); -} - -/* -====================================================================== - -MASS DRIVER - -====================================================================== -*/ - -void massDriverFire( gentity_t *ent ) -{ - trace_t tr; - vec3_t end; - gentity_t *tent; - gentity_t *traceEnt; - - VectorMA( muzzle, 8192 * 16, forward, end ); - - trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); - if( tr.surfaceFlags & SURF_NOIMPACT ) - return; - - traceEnt = &g_entities[ tr.entityNum ]; - - // snap the endpos to integers, but nudged towards the line - SnapVectorTowards( tr.endpos, muzzle ); - - // send impact - if( traceEnt->takedamage && traceEnt->client ) - { - tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); - tent->s.otherEntityNum = traceEnt->s.number; - tent->s.eventParm = DirToByte( tr.plane.normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - else - { - tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS ); - tent->s.eventParm = DirToByte( tr.plane.normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - - if( traceEnt->takedamage ) - { - G_Damage( traceEnt, ent, ent, forward, tr.endpos, - MDRIVER_DMG, 0, MOD_MDRIVER ); - } -} - -/* -====================================================================== - -LOCKBLOB - -====================================================================== -*/ - -void lockBlobLauncherFire( gentity_t *ent ) -{ - gentity_t *m; - - m = fire_lockblob( ent, muzzle, forward ); - -// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics -} - -/* -====================================================================== - -HIVE - -====================================================================== -*/ - -void hiveFire( gentity_t *ent ) -{ - gentity_t *m; - - m = fire_hive( ent, muzzle, forward ); - -// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics -} - -/* -====================================================================== - -BLASTER PISTOL - -====================================================================== -*/ - -void blasterFire( gentity_t *ent ) -{ - gentity_t *m; - - m = fire_blaster( ent, muzzle, forward ); - -// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics -} - -/* -====================================================================== - -PULSE RIFLE - -====================================================================== -*/ - -void pulseRifleFire( gentity_t *ent ) -{ - gentity_t *m; - - m = fire_pulseRifle( ent, muzzle, forward ); - -// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics -} - -/* -====================================================================== - -FLAME THROWER - -====================================================================== -*/ - -void flamerFire( gentity_t *ent ) -{ - gentity_t *m; - - m = fire_flamer( ent, muzzle, forward ); -} - -/* -====================================================================== - -GRENADE - -====================================================================== -*/ - -void throwGrenade( gentity_t *ent ) -{ - gentity_t *m; - - m = launch_grenade( ent, muzzle, forward ); -} - -/* -====================================================================== - -LAS GUN - -====================================================================== -*/ - -/* -=============== -lasGunFire -=============== -*/ -void lasGunFire( gentity_t *ent ) -{ - trace_t tr; - vec3_t end; - gentity_t *tent; - gentity_t *traceEnt; - - VectorMA( muzzle, 8192 * 16, forward, end ); - - trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); - if( tr.surfaceFlags & SURF_NOIMPACT ) - return; - - traceEnt = &g_entities[ tr.entityNum ]; - - // snap the endpos to integers, but nudged towards the line - SnapVectorTowards( tr.endpos, muzzle ); - - // send impact - if( traceEnt->takedamage && traceEnt->client ) - { - tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); - tent->s.otherEntityNum = traceEnt->s.number; - tent->s.eventParm = DirToByte( tr.plane.normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - else - { - tent = G_TempEntity( tr.endpos, EV_MISSILE_MISS ); - tent->s.eventParm = DirToByte( tr.plane.normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - - if( traceEnt->takedamage ) - G_Damage( traceEnt, ent, ent, forward, tr.endpos, LASGUN_DAMAGE, 0, MOD_LASGUN ); -} - -/* -====================================================================== - -PAIN SAW - -====================================================================== -*/ - -void painSawFire( gentity_t *ent ) -{ - trace_t tr; - vec3_t end; - gentity_t *tent; - gentity_t *traceEnt; - - // set aiming directions - AngleVectors( ent->client->ps.viewangles, forward, right, up ); - - CalcMuzzlePoint( ent, forward, right, up, muzzle ); - - VectorMA( muzzle, PAINSAW_RANGE, forward, end ); - - trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); - if( tr.surfaceFlags & SURF_NOIMPACT ) - return; - - traceEnt = &g_entities[ tr.entityNum ]; - - // send blood impact - if( traceEnt->takedamage ) - { - vec3_t temp; - - //hack to get the particle system to line up with the weapon - VectorCopy( tr.endpos, temp ); - temp[ 2 ] -= 10.0f; - - if( traceEnt->client ) - { - tent = G_TempEntity( temp, EV_MISSILE_HIT ); - tent->s.otherEntityNum = traceEnt->s.number; - } - else - tent = G_TempEntity( temp, EV_MISSILE_MISS ); - - tent->s.eventParm = DirToByte( tr.plane.normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - - if( traceEnt->takedamage ) - G_Damage( traceEnt, ent, ent, forward, tr.endpos, PAINSAW_DAMAGE, DAMAGE_NO_KNOCKBACK, MOD_PAINSAW ); -} - -/* -====================================================================== - -LUCIFER CANNON - -====================================================================== -*/ - -/* -=============== -LCChargeFire -=============== -*/ -void LCChargeFire( gentity_t *ent, qboolean secondary ) -{ - gentity_t *m; - - if( secondary ) - m = fire_luciferCannon( ent, muzzle, forward, LCANNON_SECONDARY_DAMAGE, LCANNON_SECONDARY_RADIUS ); - else - m = fire_luciferCannon( ent, muzzle, forward, ent->client->ps.stats[ STAT_MISC ], LCANNON_RADIUS ); - - ent->client->ps.stats[ STAT_MISC ] = 0; -} - -/* -====================================================================== - -TESLA GENERATOR - -====================================================================== -*/ - - -void teslaFire( gentity_t *ent ) -{ - trace_t tr; - vec3_t end; - gentity_t *traceEnt, *tent; - - VectorMA( muzzle, TESLAGEN_RANGE, forward, end ); - - trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); - - if( tr.entityNum == ENTITYNUM_NONE ) - return; - - traceEnt = &g_entities[ tr.entityNum ]; - - if( !traceEnt->client ) - return; - - if( traceEnt->client && traceEnt->client->ps.stats[ STAT_PTEAM ] != PTE_ALIENS ) - return; - - //so the client side knows - ent->s.eFlags |= EF_FIRING; - - if( traceEnt->takedamage ) - { - G_Damage( traceEnt, ent, ent, forward, tr.endpos, - TESLAGEN_DMG, 0, MOD_TESLAGEN ); - } - - // snap the endpos to integers to save net bandwidth, but nudged towards the line - SnapVectorTowards( tr.endpos, muzzle ); - - // send railgun beam effect - tent = G_TempEntity( tr.endpos, EV_TESLATRAIL ); - - VectorCopy( muzzle, tent->s.origin2 ); - - tent->s.generic1 = ent->s.number; //src - tent->s.clientNum = traceEnt->s.number; //dest - - // move origin a bit to come closer to the drawn gun muzzle - VectorMA( tent->s.origin2, 28, up, tent->s.origin2 ); -} - - -/* -====================================================================== - -BUILD GUN - -====================================================================== -*/ - -/* -=============== -cancelBuildFire -=============== -*/ -void cancelBuildFire( gentity_t *ent ) -{ - vec3_t forward, end; - trace_t tr; - gentity_t *traceEnt; - int bHealth; - - if( ent->client->ps.stats[ STAT_BUILDABLE ] != BA_NONE ) - { - ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; - return; - } - - //repair buildable - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - AngleVectors( ent->client->ps.viewangles, forward, NULL, NULL ); - VectorMA( ent->client->ps.origin, 100, forward, end ); - - trap_Trace( &tr, ent->client->ps.origin, NULL, NULL, end, ent->s.number, MASK_PLAYERSOLID ); - traceEnt = &g_entities[ tr.entityNum ]; - - if( tr.fraction < 1.0 && - ( traceEnt->s.eType == ET_BUILDABLE ) && - ( traceEnt->biteam == ent->client->ps.stats[ STAT_PTEAM ] ) && - ( ( ent->client->ps.weapon >= WP_HBUILD2 ) && - ( ent->client->ps.weapon <= WP_HBUILD ) ) && - traceEnt->spawned && traceEnt->health > 0 ) - { - if( ent->client->ps.stats[ STAT_MISC ] > 0 ) - { - G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum ); - return; - } - - bHealth = BG_FindHealthForBuildable( traceEnt->s.modelindex ); - - traceEnt->health += HBUILD_HEALRATE; - - if( traceEnt->health > bHealth ) - traceEnt->health = bHealth; - - if( traceEnt->health == bHealth ) - G_AddEvent( ent, EV_BUILD_REPAIRED, 0 ); - else - G_AddEvent( ent, EV_BUILD_REPAIR, 0 ); - } - } - else if( ent->client->ps.weapon == WP_ABUILD2 ) - meleeAttack( ent, ABUILDER_CLAW_RANGE, ABUILDER_CLAW_WIDTH, - ABUILDER_CLAW_DMG, MOD_ABUILDER_CLAW ); //melee attack for alien builder -} - -/* -=============== -buildFire -=============== -*/ -void buildFire( gentity_t *ent, dynMenu_t menu ) -{ - if( ( ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) > BA_NONE ) - { - if( ent->client->ps.stats[ STAT_MISC ] > 0 ) - { - G_AddEvent( ent, EV_BUILD_DELAY, ent->client->ps.clientNum ); - return; - } - - if( G_ValidateBuild( ent, ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) ) - { - if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS && !G_isOvermind( ) ) - { - ent->client->ps.stats[ STAT_MISC ] += - BG_FindBuildDelayForWeapon( ent->s.weapon ) * 2; - } - else if( ent->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS && !G_isPower( muzzle ) && - ( ent->client->ps.stats[ STAT_BUILDABLE ] & ~SB_VALID_TOGGLEBIT ) != BA_H_REPEATER ) //hack - { - ent->client->ps.stats[ STAT_MISC ] += - BG_FindBuildDelayForWeapon( ent->s.weapon ) * 2; - } - else - ent->client->ps.stats[ STAT_MISC ] += - BG_FindBuildDelayForWeapon( ent->s.weapon ); - - ent->client->ps.stats[ STAT_BUILDABLE ] = BA_NONE; - - // don't want it bigger than 32k - if( ent->client->ps.stats[ STAT_MISC ] > 30000 ) - ent->client->ps.stats[ STAT_MISC ] = 30000; - } - return; - } - - G_TriggerMenu( ent->client->ps.clientNum, menu ); -} - -void slowBlobFire( gentity_t *ent ) -{ - gentity_t *m; - - m = fire_slowBlob( ent, muzzle, forward ); - -// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics -} - - -/* -====================================================================== - -LEVEL0 - -====================================================================== -*/ - -/* -=============== -CheckVenomAttack -=============== -*/ -qboolean CheckVenomAttack( gentity_t *ent ) -{ - trace_t tr; - vec3_t end; - gentity_t *tent; - gentity_t *traceEnt; - vec3_t mins, maxs; - int damage = LEVEL0_BITE_DMG; - - VectorSet( mins, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH, -LEVEL0_BITE_WIDTH ); - VectorSet( maxs, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH, LEVEL0_BITE_WIDTH ); - - // set aiming directions - AngleVectors( ent->client->ps.viewangles, forward, right, up ); - - CalcMuzzlePoint( ent, forward, right, up, muzzle ); - - VectorMA( muzzle, LEVEL0_BITE_RANGE, forward, end ); - - trap_Trace( &tr, muzzle, mins, maxs, end, ent->s.number, MASK_SHOT ); - - if( tr.surfaceFlags & SURF_NOIMPACT ) - return qfalse; - - traceEnt = &g_entities[ tr.entityNum ]; - - if( !traceEnt->takedamage ) - return qfalse; - - if( !traceEnt->client && !traceEnt->s.eType == ET_BUILDABLE ) - return qfalse; - - //allow bites to work against defensive buildables only - if( traceEnt->s.eType == ET_BUILDABLE ) - { - if( traceEnt->s.modelindex != BA_H_MGTURRET && - traceEnt->s.modelindex != BA_H_TESLAGEN ) - return qfalse; - - //hackery - damage *= 0.5f; - } - - if( traceEnt->client ) - { - if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - return qfalse; - if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) - return qfalse; - } - - // send blood impact - if( traceEnt->takedamage && traceEnt->client ) - { - tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); - tent->s.otherEntityNum = traceEnt->s.number; - tent->s.eventParm = DirToByte( tr.plane.normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - - G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, DAMAGE_NO_KNOCKBACK, MOD_LEVEL0_BITE ); - - return qtrue; -} - -/* -====================================================================== - -LEVEL1 - -====================================================================== -*/ - -/* -=============== -CheckGrabAttack -=============== -*/ -void CheckGrabAttack( gentity_t *ent ) -{ - trace_t tr; - vec3_t end, dir; - gentity_t *traceEnt; - - // set aiming directions - AngleVectors( ent->client->ps.viewangles, forward, right, up ); - - CalcMuzzlePoint( ent, forward, right, up, muzzle ); - - VectorMA( muzzle, LEVEL1_GRAB_RANGE, forward, end ); - - trap_Trace( &tr, muzzle, NULL, NULL, end, ent->s.number, MASK_SHOT ); - if( tr.surfaceFlags & SURF_NOIMPACT ) - return; - - traceEnt = &g_entities[ tr.entityNum ]; - - if( !traceEnt->takedamage ) - return; - - if( traceEnt->client ) - { - if( traceEnt->client->ps.stats[ STAT_PTEAM ] == PTE_ALIENS ) - return; - - if( traceEnt->client->ps.stats[ STAT_HEALTH ] <= 0 ) - return; - - if( !( traceEnt->client->ps.stats[ STAT_STATE ] & SS_GRABBED ) ) - { - AngleVectors( traceEnt->client->ps.viewangles, dir, NULL, NULL ); - traceEnt->client->ps.stats[ STAT_VIEWLOCK ] = DirToByte( dir ); - - //event for client side grab effect - G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 ); - } - - traceEnt->client->ps.stats[ STAT_STATE ] |= SS_GRABBED; - - if( ent->client->ps.weapon == WP_ALEVEL1 ) - traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_TIME; - else if( ent->client->ps.weapon == WP_ALEVEL1_UPG ) - traceEnt->client->grabExpiryTime = level.time + LEVEL1_GRAB_U_TIME; - } - else if( traceEnt->s.eType == ET_BUILDABLE && - traceEnt->s.modelindex == BA_H_MGTURRET ) - { - if( !traceEnt->lev1Grabbed ) - G_AddPredictableEvent( ent, EV_LEV1_GRAB, 0 ); - - traceEnt->lev1Grabbed = qtrue; - traceEnt->lev1GrabTime = level.time; - } -} - -/* -=============== -poisonCloud -=============== -*/ -void poisonCloud( gentity_t *ent ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range = { LEVEL1_PCLOUD_RANGE, LEVEL1_PCLOUD_RANGE, LEVEL1_PCLOUD_RANGE }; - vec3_t mins, maxs; - int i, num; - gentity_t *humanPlayer; - trace_t tr; - - VectorAdd( ent->client->ps.origin, range, maxs ); - VectorSubtract( ent->client->ps.origin, range, mins ); - - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - for( i = 0; i < num; i++ ) - { - humanPlayer = &g_entities[ entityList[ i ] ]; - - if( humanPlayer->client && humanPlayer->client->ps.stats[ STAT_PTEAM ] == PTE_HUMANS ) - { - if( BG_InventoryContainsUpgrade( UP_LIGHTARMOUR, humanPlayer->client->ps.stats ) ) - continue; - - if( BG_InventoryContainsUpgrade( UP_BATTLESUIT, humanPlayer->client->ps.stats ) ) - continue; - - trap_Trace( &tr, muzzle, NULL, NULL, humanPlayer->s.origin, humanPlayer->s.number, MASK_SHOT ); - - //can't see target from here - if( tr.entityNum == ENTITYNUM_WORLD ) - continue; - - if( !( humanPlayer->client->ps.stats[ STAT_STATE ] & SS_POISONCLOUDED ) ) - { - humanPlayer->client->ps.stats[ STAT_STATE ] |= SS_POISONCLOUDED; - humanPlayer->client->lastPoisonCloudedTime = level.time; - humanPlayer->client->lastPoisonCloudedClient = ent; - G_SendCommandFromServer( humanPlayer->client->ps.clientNum, "poisoncloud" ); - } - } - } -} - - -/* -====================================================================== - -LEVEL2 - -====================================================================== -*/ - -#define MAX_ZAPS 64 - -static zap_t zaps[ MAX_CLIENTS ]; - -/* -=============== -G_FindNewZapTarget -=============== -*/ -static gentity_t *G_FindNewZapTarget( gentity_t *ent ) -{ - int entityList[ MAX_GENTITIES ]; - vec3_t range = { LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_RANGE }; - vec3_t mins, maxs; - int i, j, k, 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 ); - - num = trap_EntitiesInBox( mins, maxs, entityList, MAX_GENTITIES ); - - for( i = 0; i < num; i++ ) - { - 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 ) ) && 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; - - 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; - } - } - - return NULL; -} - -/* -=============== -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; - - 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 - Distance( 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; - vec3_t forward; - - if( j == 0 ) - source = zap->creator; - else - source = zap->targets[ j - 1 ]; - - damage = ceil( ( (float)msec / LEVEL2_AREAZAP_TIME ) * - LEVEL2_AREAZAP_DMG * damageFraction ); - - 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; - vec3_t end; - gentity_t *traceEnt; - vec3_t mins, maxs; - - VectorSet( mins, -LEVEL2_AREAZAP_WIDTH, -LEVEL2_AREAZAP_WIDTH, -LEVEL2_AREAZAP_WIDTH ); - VectorSet( maxs, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH ); - - // 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, mins, maxs, end, ent->s.number, MASK_SHOT ); - - if( tr.surfaceFlags & SURF_NOIMPACT ) - return; - - 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 ); - } -} - - -/* -====================================================================== - -LEVEL3 - -====================================================================== -*/ - -/* -=============== -CheckPounceAttack -=============== -*/ -qboolean CheckPounceAttack( gentity_t *ent ) -{ - trace_t tr; - vec3_t end; - gentity_t *tent; - gentity_t *traceEnt; - int damage; - vec3_t mins, maxs; - - VectorSet( mins, -LEVEL3_POUNCE_WIDTH, -LEVEL3_POUNCE_WIDTH, -LEVEL3_POUNCE_WIDTH ); - VectorSet( maxs, LEVEL3_POUNCE_WIDTH, LEVEL3_POUNCE_WIDTH, LEVEL3_POUNCE_WIDTH ); - - if( !ent->client->allowedToPounce ) - return qfalse; - - if( ent->client->ps.groundEntityNum != ENTITYNUM_NONE ) - { - ent->client->allowedToPounce = qfalse; - return qfalse; - } - - if( ent->client->ps.weaponTime ) - return qfalse; - - // set aiming directions - AngleVectors( ent->client->ps.viewangles, forward, right, up ); - - CalcMuzzlePoint( ent, forward, right, up, muzzle ); - - VectorMA( muzzle, LEVEL3_POUNCE_RANGE, forward, end ); - - trap_Trace( &tr, ent->s.origin, mins, maxs, end, ent->s.number, MASK_SHOT ); - - //miss - if( tr.fraction >= 1.0 ) - return qfalse; - - if( tr.surfaceFlags & SURF_NOIMPACT ) - return qfalse; - - traceEnt = &g_entities[ tr.entityNum ]; - - // send blood impact - if( traceEnt->takedamage && traceEnt->client ) - { - tent = G_TempEntity( tr.endpos, EV_MISSILE_HIT ); - tent->s.otherEntityNum = traceEnt->s.number; - tent->s.eventParm = DirToByte( tr.plane.normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - - if( !traceEnt->takedamage ) - return qfalse; - - damage = (int)( ( (float)ent->client->pouncePayload / (float)LEVEL3_POUNCE_SPEED ) * LEVEL3_POUNCE_DMG ); - - G_Damage( traceEnt, ent, ent, forward, tr.endpos, damage, - DAMAGE_NO_KNOCKBACK|DAMAGE_NO_LOCDAMAGE, MOD_LEVEL3_POUNCE ); - - ent->client->ps.weaponTime += LEVEL3_POUNCE_TIME; - ent->client->allowedToPounce = qfalse; - - return qtrue; -} - -void bounceBallFire( gentity_t *ent ) -{ - gentity_t *m; - - m = fire_bounceBall( ent, muzzle, forward ); - -// VectorAdd( m->s.pos.trDelta, ent->client->ps.velocity, m->s.pos.trDelta ); // "real" physics -} - - -/* -====================================================================== - -LEVEL4 - -====================================================================== -*/ - -/* -=============== -ChargeAttack -=============== -*/ -void ChargeAttack( gentity_t *ent, gentity_t *victim ) -{ - gentity_t *tent; - int damage; - vec3_t forward, normal; - - if( level.time < victim->chargeRepeat ) - return; - - victim->chargeRepeat = level.time + LEVEL4_CHARGE_REPEAT; - - VectorSubtract( victim->s.origin, ent->s.origin, forward ); - VectorNormalize( forward ); - VectorNegate( forward, normal ); - - if( victim->client ) - { - tent = G_TempEntity( victim->s.origin, EV_MISSILE_HIT ); - tent->s.otherEntityNum = victim->s.number; - tent->s.eventParm = DirToByte( normal ); - tent->s.weapon = ent->s.weapon; - tent->s.generic1 = ent->s.generic1; //weaponMode - } - - if( !victim->takedamage ) - return; - - damage = (int)( ( (float)ent->client->ps.stats[ STAT_MISC ] / (float)LEVEL4_CHARGE_TIME ) * LEVEL4_CHARGE_DMG ); - - G_Damage( victim, ent, ent, forward, victim->s.origin, damage, 0, MOD_LEVEL4_CHARGE ); -} - -//====================================================================== - -/* -=============== -CalcMuzzlePoint - -set muzzle location relative to pivoting eye -=============== -*/ -void CalcMuzzlePoint( gentity_t *ent, vec3_t forward, vec3_t right, vec3_t up, vec3_t muzzlePoint ) -{ - VectorCopy( ent->s.pos.trBase, muzzlePoint ); - muzzlePoint[ 2 ] += ent->client->ps.viewheight; - VectorMA( muzzlePoint, 1, forward, muzzlePoint ); - VectorMA( muzzlePoint, 1, right, muzzlePoint ); - // snap to integer coordinates for more efficient network bandwidth usage - SnapVector( muzzlePoint ); -} - -/* -=============== -FireWeapon3 -=============== -*/ -void FireWeapon3( gentity_t *ent ) -{ - if( ent->client ) - { - // set aiming directions - AngleVectors( ent->client->ps.viewangles, forward, right, up ); - CalcMuzzlePoint( ent, forward, right, up, muzzle ); - } - else - { - AngleVectors( ent->s.angles2, forward, right, up ); - VectorCopy( ent->s.pos.trBase, muzzle ); - } - - // fire the specific weapon - switch( ent->s.weapon ) - { - case WP_ALEVEL3_UPG: - bounceBallFire( ent ); - break; - - case WP_ABUILD2: - slowBlobFire( ent ); - break; - - default: - break; - } -} - -/* -=============== -FireWeapon2 -=============== -*/ -void FireWeapon2( gentity_t *ent ) -{ - if( ent->client ) - { - // set aiming directions - AngleVectors( ent->client->ps.viewangles, forward, right, up ); - CalcMuzzlePoint( ent, forward, right, up, muzzle ); - } - else - { - AngleVectors( ent->s.angles2, forward, right, up ); - VectorCopy( ent->s.pos.trBase, muzzle ); - } - - // fire the specific weapon - switch( ent->s.weapon ) - { - case WP_ALEVEL1_UPG: - poisonCloud( ent ); - break; - case WP_ALEVEL2_UPG: - areaZapFire( ent ); - break; - - case WP_LUCIFER_CANNON: - LCChargeFire( ent, qtrue ); - break; - - case WP_ABUILD: - case WP_ABUILD2: - case WP_HBUILD: - case WP_HBUILD2: - cancelBuildFire( ent ); - break; - default: - break; - } -} - -/* -=============== -FireWeapon -=============== -*/ -void FireWeapon( gentity_t *ent ) -{ - if( ent->client ) - { - // set aiming directions - AngleVectors( ent->client->ps.viewangles, forward, right, up ); - CalcMuzzlePoint( ent, forward, right, up, muzzle ); - } - else - { - AngleVectors( ent->turretAim, forward, right, up ); - VectorCopy( ent->s.pos.trBase, muzzle ); - } - - // fire the specific weapon - switch( ent->s.weapon ) - { - case WP_ALEVEL1: - case WP_ALEVEL1_UPG: - meleeAttack( ent, LEVEL1_CLAW_RANGE, LEVEL1_CLAW_WIDTH, LEVEL1_CLAW_DMG, MOD_LEVEL1_CLAW ); - break; - case WP_ALEVEL3: - case WP_ALEVEL3_UPG: - meleeAttack( ent, LEVEL3_CLAW_RANGE, LEVEL3_CLAW_WIDTH, LEVEL3_CLAW_DMG, MOD_LEVEL3_CLAW ); - break; - case WP_ALEVEL2: - meleeAttack( ent, LEVEL2_CLAW_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW ); - break; - case WP_ALEVEL2_UPG: - meleeAttack( ent, LEVEL2_CLAW_RANGE, LEVEL2_CLAW_WIDTH, LEVEL2_CLAW_DMG, MOD_LEVEL2_CLAW ); - break; - case WP_ALEVEL4: - meleeAttack( ent, LEVEL4_CLAW_RANGE, LEVEL4_CLAW_WIDTH, LEVEL4_CLAW_DMG, MOD_LEVEL4_CLAW ); - break; - - case WP_BLASTER: - blasterFire( ent ); - break; - case WP_MACHINEGUN: - bulletFire( ent, RIFLE_SPREAD, RIFLE_DMG, MOD_MACHINEGUN ); - break; - case WP_SHOTGUN: - shotgunFire( ent ); - break; - case WP_CHAINGUN: - bulletFire( ent, CHAINGUN_SPREAD, CHAINGUN_DMG, MOD_CHAINGUN ); - break; - case WP_FLAMER: - flamerFire( ent ); - break; - case WP_PULSE_RIFLE: - pulseRifleFire( ent ); - break; - case WP_MASS_DRIVER: - massDriverFire( ent ); - break; - case WP_LUCIFER_CANNON: - LCChargeFire( ent, qfalse ); - break; - case WP_LAS_GUN: - lasGunFire( ent ); - break; - case WP_PAIN_SAW: - painSawFire( ent ); - break; - case WP_GRENADE: - throwGrenade( ent ); - break; - - case WP_LOCKBLOB_LAUNCHER: - lockBlobLauncherFire( ent ); - break; - case WP_HIVE: - hiveFire( ent ); - break; - case WP_TESLAGEN: - teslaFire( ent ); - break; - case WP_MGTURRET: - bulletFire( ent, MGTURRET_SPREAD, MGTURRET_DMG, MOD_MGTURRET ); - break; - - case WP_ABUILD: - case WP_ABUILD2: - buildFire( ent, MN_A_BUILD ); - break; - case WP_HBUILD: - case WP_HBUILD2: - buildFire( ent, MN_H_BUILD ); - break; - default: - break; - } -} - |