diff options
-rw-r--r-- | src/cgame/cg_event.c | 8 | ||||
-rw-r--r-- | src/game/bg_mod.h | 137 | ||||
-rw-r--r-- | src/game/bg_public.h | 3 | ||||
-rw-r--r-- | src/game/g_admin.c | 118 | ||||
-rw-r--r-- | src/game/g_admin.h | 1 | ||||
-rw-r--r-- | src/game/g_client.c | 2 | ||||
-rw-r--r-- | src/game/g_combat.c | 120 | ||||
-rw-r--r-- | src/game/g_csw.h | 30 | ||||
-rw-r--r-- | src/game/g_local.h | 26 | ||||
-rw-r--r-- | src/game/g_main.c | 12 | ||||
-rw-r--r-- | src/game/g_missile.c | 4 | ||||
-rw-r--r-- | src/game/g_weapon.c | 96 |
12 files changed, 447 insertions, 110 deletions
diff --git a/src/cgame/cg_event.c b/src/cgame/cg_event.c index e5002cd..4a86235 100644 --- a/src/cgame/cg_event.c +++ b/src/cgame/cg_event.c @@ -350,13 +350,13 @@ static void CG_Obituary( entityState_t *ent ) message = "^5found^7"; message2 = "^5's ^5mine"; break; - - - case MOD_FLAMES: + + case MOD_FLAMES: + case MOD_LEVEL4_FLAMES: message = "^5tasted^7"; message2 = "^5's ^5flames"; break; - + case MOD_ABUILDER_CLAW: message = "^5should leave^7"; message2 = "^5's ^5buildings alone"; diff --git a/src/game/bg_mod.h b/src/game/bg_mod.h index 6f09037..e6b1e53 100644 --- a/src/game/bg_mod.h +++ b/src/game/bg_mod.h @@ -1,68 +1,69 @@ -MOD( MOD_UNKNOWN ), -MOD( MOD_HDOG ), -MOD( MOD_SHOTGUN ), -MOD( MOD_BLASTER ), -MOD( MOD_PAINSAW ), -MOD( MOD_MACHINEGUN ), -MOD( MOD_CHAINGUN ), -MOD( MOD_PRIFLE ), -MOD( MOD_MDRIVER ), -MOD( MOD_LASGUN ), -MOD( MOD_LIGHTNING ), -MOD( MOD_LCANNON ), -MOD( MOD_LCANNON_SPLASH ), -MOD( MOD_FLAMER ), -MOD( MOD_FLAMER_SPLASH ), -MOD( MOD_ROCKETL ), -MOD( MOD_ROCKETL_SPLASH ), -MOD( MOD_GRENADE ), -MOD( MOD_PSAWBLADE ), -MOD( MOD_MINE ), -MOD( MOD_FLAMES ), -MOD( MOD_SPITEFUL_ABCESS ), -MOD( MOD_WATER ), -MOD( MOD_SLIME ), -MOD( MOD_LAVA ), -MOD( MOD_CRUSH ), -MOD( MOD_TELEFRAG ), -MOD( MOD_FALLING ), -MOD( MOD_SUICIDE ), -MOD( MOD_TARGET_LASER ), -MOD( MOD_TRIGGER_HURT ), -MOD( MOD_ABUILDER_CLAW ), -MOD( MOD_LEVEL0_BITE ), -MOD( MOD_LEVEL1_CLAW ), -MOD( MOD_LEVEL1_PCLOUD ), -MOD( MOD_LEVEL3_CLAW ), -MOD( MOD_LEVEL3_POUNCE ), -MOD( MOD_LEVEL5_POUNCE ), -MOD( MOD_LEVEL5_PRICKLES ), -MOD( MOD_LEVEL3_BOUNCEBALL ), -MOD( MOD_LEVEL2_CLAW ), -MOD( MOD_LEVEL2_ZAP ), -MOD( MOD_LEVEL5_CLAW ), -MOD( MOD_LEVEL5_ZAP ), -MOD( MOD_LEVEL5_BOUNCEBALL ), -MOD( MOD_LEVEL2_BOUNCEBALL ), -MOD( MOD_LEVEL4_CLAW ), -MOD( MOD_LEVEL4_TRAMPLE ), -MOD( MOD_LEVEL4_CRUSH ), -MOD( MOD_SLOWBLOB ), -MOD( MOD_POISON ), -MOD( MOD_INFECTION ), -MOD( MOD_SWARM ), -MOD( MOD_MD2 ), -MOD( MOD_HSPAWN ), -MOD( MOD_TESLAGEN ), -MOD( MOD_MGTURRET ), -MOD( MOD_MGTURRET2 ), -MOD( MOD_REACTOR ), -MOD( MOD_ASPAWN ), -MOD( MOD_ATUBE ), -MOD( MOD_OVERMIND ), -MOD( MOD_SLAP ), -MOD( MOD_DECONSTRUCT ), -MOD( MOD_REPLACE ), -MOD( MOD_NOCREEP ), -MOD( MOD_NOBP ), -MOD( MOD_ABOMB ) +MOD( MOD_UNKNOWN, CSW_UNKNOWN ), +MOD( MOD_HDOG, CSW_UNKNOWN ), +MOD( MOD_SHOTGUN, CSW_SHOTGUN ), +MOD( MOD_BLASTER, CSW_BLASTER ), +MOD( MOD_PAINSAW, CSW_PAINSAW ), +MOD( MOD_MACHINEGUN, CSW_MACHINEGUN ), +MOD( MOD_CHAINGUN, CSW_CHAINGUN ), +MOD( MOD_PRIFLE, CSW_PRIFLE ), +MOD( MOD_MDRIVER, CSW_MDRIVER ), +MOD( MOD_LASGUN, CSW_LASGUN ), +MOD( MOD_LIGHTNING, CSW_LIGHTNING ), +MOD( MOD_LCANNON, CSW_LCANNON ), +MOD( MOD_LCANNON_SPLASH, CSW_LCANNON ), +MOD( MOD_FLAMER, CSW_FLAMER ), +MOD( MOD_FLAMER_SPLASH, CSW_FLAMER ), +MOD( MOD_ROCKETL, CSW_ROCKETL ), +MOD( MOD_ROCKETL_SPLASH, CSW_ROCKETL ), +MOD( MOD_GRENADE, CSW_GRENADE ), +MOD( MOD_PSAWBLADE, CSW_PAINSAW_ALT ), +MOD( MOD_MINE, CSW_UNKNOWN ), +MOD( MOD_FLAMES, CSW_UNKNOWN ), +MOD( MOD_SPITEFUL_ABCESS, CSW_UNKNOWN ), +MOD( MOD_WATER, CSW_UNKNOWN ), +MOD( MOD_SLIME, CSW_UNKNOWN ), +MOD( MOD_LAVA, CSW_UNKNOWN ), +MOD( MOD_CRUSH, CSW_UNKNOWN ), +MOD( MOD_TELEFRAG, CSW_UNKNOWN ), +MOD( MOD_FALLING, CSW_UNKNOWN ), +MOD( MOD_SUICIDE, CSW_UNKNOWN ), +MOD( MOD_TARGET_LASER, CSW_UNKNOWN ), +MOD( MOD_TRIGGER_HURT, CSW_UNKNOWN ), +MOD( MOD_ABUILDER_CLAW, CSW_ABUILDER ), +MOD( MOD_LEVEL0_BITE, CSW_UNKNOWN ), +MOD( MOD_LEVEL1_CLAW, CSW_LEVEL1 ), +MOD( MOD_LEVEL1_PCLOUD, CSW_UNKNOWN ), +MOD( MOD_LEVEL3_CLAW, CSW_LEVEL3 ), +MOD( MOD_LEVEL3_POUNCE, CSW_UNKNOWN ), +MOD( MOD_LEVEL5_POUNCE, CSW_UNKNOWN ), +MOD( MOD_LEVEL5_PRICKLES, CSW_LEVEL5_ALT ), +MOD( MOD_LEVEL3_BOUNCEBALL, CSW_LEVEL3_ALT ), +MOD( MOD_LEVEL2_CLAW, CSW_LEVEL2 ), +MOD( MOD_LEVEL2_ZAP, CSW_LEVEL2_ALT ), +MOD( MOD_LEVEL5_CLAW, CSW_LEVEL5 ), +MOD( MOD_LEVEL5_ZAP, CSW_UNKNOWN ), +MOD( MOD_LEVEL5_BOUNCEBALL, CSW_UNKNOWN ), +MOD( MOD_LEVEL2_BOUNCEBALL, CSW_UNKNOWN ), +MOD( MOD_LEVEL4_CLAW, CSW_LEVEL4 ), +MOD( MOD_LEVEL4_TRAMPLE, CSW_UNKNOWN ), +MOD( MOD_LEVEL4_CRUSH, CSW_UNKNOWN ), +MOD( MOD_LEVEL4_FLAMES, CSW_LEVEL4_ALT ), +MOD( MOD_SLOWBLOB, CSW_UNKNOWN ), +MOD( MOD_POISON, CSW_UNKNOWN ), +MOD( MOD_INFECTION, CSW_UNKNOWN ), +MOD( MOD_SWARM, CSW_UNKNOWN ), +MOD( MOD_MD2, CSW_UNKNOWN ), +MOD( MOD_HSPAWN, CSW_UNKNOWN ), +MOD( MOD_TESLAGEN, CSW_UNKNOWN ), +MOD( MOD_MGTURRET, CSW_UNKNOWN ), +MOD( MOD_MGTURRET2, CSW_UNKNOWN ), +MOD( MOD_REACTOR, CSW_UNKNOWN ), +MOD( MOD_ASPAWN, CSW_UNKNOWN ), +MOD( MOD_ATUBE, CSW_UNKNOWN ), +MOD( MOD_OVERMIND, CSW_UNKNOWN ), +MOD( MOD_SLAP, CSW_UNKNOWN ), +MOD( MOD_DECONSTRUCT, CSW_UNKNOWN ), +MOD( MOD_REPLACE, CSW_UNKNOWN ), +MOD( MOD_NOCREEP, CSW_UNKNOWN ), +MOD( MOD_NOBP, CSW_UNKNOWN ), +MOD( MOD_ABOMB, CSW_UNKNOWN ) diff --git a/src/game/bg_public.h b/src/game/bg_public.h index bbf064e..f96fd66 100644 --- a/src/game/bg_public.h +++ b/src/game/bg_public.h @@ -833,7 +833,7 @@ typedef enum // means of death typedef enum { -#define MOD(x) x +#define MOD(a,b) a #include "bg_mod.h" #undef MOD } meansOfDeath_t; @@ -1243,3 +1243,4 @@ typedef struct const char *name; } dummyCmd_t; int cmdcmp( const void *a, const void *b ); + diff --git a/src/game/g_admin.c b/src/game/g_admin.c index aa07e6f..36fa6be 100644 --- a/src/game/g_admin.c +++ b/src/game/g_admin.c @@ -249,6 +249,10 @@ g_admin_cmd_t g_admin_cmds[ ] = "move 999 pingers to the spectator team", ""}, + {"stats", G_admin_stats, qfalse, "stats", + "view combat statistics of a player", + "[^7name|slot^7]"}, + {"time", G_admin_time, qtrue, "time", "show the current local server time", ""}, @@ -4369,6 +4373,119 @@ qboolean G_admin_flag( gentity_t *ent ) return qtrue; } + + +/* +================= +G_admin_stats +================= +*/ +qboolean G_admin_stats( gentity_t *ent ) +{ + gentity_t *targ; + int i; + qboolean header = qfalse; + const static char *cswNames[ ] = + { +#define CSW(a,b) b +#include "g_csw.h" +#undef CSW + }; + + if( trap_Argc( ) > 1 ) + { + char name[ MAX_NAME_LENGTH ]; + namelog_t *vic; + + trap_Argv( 1, name, sizeof( name ) ); + + if( !( vic = G_NamelogFromString( ent, name ) ) || + vic->slot <= -1 ) + { + ADMP( "^3stats: ^7no match\n" ); + return qfalse; + } + + targ = g_entities + vic->slot; + } + else + { + if( !ent ) + { + ADMP( "^3stats: ^7console is not a combatant\n" ); + return qfalse; + } + + targ = ent; + } + + ADMBP_begin( ); + + for( i = CSW_UNKNOWN + 1; i < MAX_COMBAT_STATS_WEAPONS; i++ ) + { + combatStats_t *cs = targ->client->pers.combatStats + i; + + // skip unused weapons + if( !cs->total ) + continue; + + if( !header ) + { + ADMBP( va( "^3stats: ^7combat statistics of %s^7:\n", targ->client->pers.netname ) ); + ADMBP( va( "^3%*s Dmg Acc FAc BAC FBA^7\n", + CSW_MAX_NAME_LEN, "Weapon" ) ); + header = qtrue; + } + + ADMBP( va( "%*s %8d", CSW_MAX_NAME_LEN, cswNames[ i ], cs->total ) ); + +#define PRINT_ACC(a,b) \ +if( (b) == 0 ) \ + ADMBP( " ^0n/a" ); \ +else \ +{ \ + int _t = round( (float)(a)/(b) * 100.0f ); \ + ADMBP( va( " ^7%3d", _t ) ); \ +} + + PRINT_ACC( cs->enemy, + cs->total - + cs->friendly - + cs->enemy_buildable - + cs->friendly_buildable ) + + PRINT_ACC( cs->friendly, + cs->total - + cs->enemy - + cs->enemy_buildable - + cs->friendly_buildable ) + + PRINT_ACC( cs->enemy_buildable, + cs->total - + cs->enemy - + cs->friendly - + cs->friendly_buildable ) + + PRINT_ACC( cs->friendly_buildable, + cs->total - + cs->enemy - + cs->enemy_buildable - + cs->friendly ) + +#undef PRINT_ACC + + ADMBP( "\n" ); + } + + if( !header ) + ADMBP( va( "^3stats: ^7no combat statistics are available for %s^7\n", targ->client->pers.netname ) ); + + ADMBP_end( ); + + return qtrue; +} + + /* ================ G_admin_print @@ -4452,3 +4569,4 @@ void G_admin_cleanup( void ) g_admin_commands = NULL; BG_DefragmentMemory( ); } + diff --git a/src/game/g_admin.h b/src/game/g_admin.h index 4953cfe..61b012c 100644 --- a/src/game/g_admin.h +++ b/src/game/g_admin.h @@ -206,6 +206,7 @@ qboolean G_admin_revert( gentity_t *ent ); qboolean G_admin_flaglist( gentity_t *ent ); qboolean G_admin_flag( gentity_t *ent ); qboolean G_admin_slap( gentity_t *ent ); +qboolean G_admin_stats( gentity_t *ent ); g_admin_level_t *G_admin_find_level_for_score( int score ); void G_admin_add_score( gentity_t *ent, int score ); diff --git a/src/game/g_client.c b/src/game/g_client.c index 1d50a97..896a7fc 100644 --- a/src/game/g_client.c +++ b/src/game/g_client.c @@ -1675,6 +1675,8 @@ void ClientDisconnect( int clientNum ) tent->s.clientNum = ent->s.clientNum; } + G_LogCombatStats( ent ); + G_LogPrintf( "^5ClientDisconnect: ^7%i [%s] (%s) \"%s^7\"\n", clientNum, ent->client->pers.ip.str, ent->client->pers.guid, ent->client->pers.netname ); diff --git a/src/game/g_combat.c b/src/game/g_combat.c index e43d036..c8090d4 100644 --- a/src/game/g_combat.c +++ b/src/game/g_combat.c @@ -80,7 +80,7 @@ void LookAtKiller( gentity_t *self, gentity_t *inflictor, gentity_t *attacker ) // these are just for logging, the client prints its own messages char *modNames[ ] = { -#define MOD(x) #x +#define MOD(a,b) #a #include "bg_mod.h" #undef MOD }; @@ -1431,7 +1431,9 @@ void G_Damage( gentity_t *targ, gentity_t *inflictor, gentity_t *attacker, G_InstantRewardAttacker(attacker,targ,take); targ->credits[ attacker->client->ps.clientNum ] += take; } - + + G_CombatStats_HitMOD( attacker, targ, mod, take ); + if( targ->health <= 0 ) { if( client ) @@ -1770,3 +1772,117 @@ void G_LogDestruction( gentity_t *self, gentity_t *actor, int mod ) } } + +const static combatStatsWeapon_t modToCsw[ ] = +{ +#define MOD(a,b) b +#include "bg_mod.h" +#undef MOD +}; + +const static char *cswStrings[ ] = +{ +#define CSW(a,b) #a +#include "g_csw.h" +#undef CSW +}; + +void G_CombatStats_Fire( gentity_t *ent, combatStatsWeapon_t weapon, int damage ) +{ + combatStats_t *cs; + + if( !ent || !ent->client ) + return; + + cs = ent->client->pers.combatStats + weapon; + cs->total += damage; + + if( g_debugDamage.integer > 3 ) + Com_Printf( "player %i fired %s, damage: %i\n", + ent - g_entities, + cswStrings[ weapon ], + damage ); +} + +void G_CombatStats_FireMOD( gentity_t *ent, meansOfDeath_t mod, int damage ) +{ + G_CombatStats_Fire( ent, modToCsw[ mod ], damage ); +} + +void G_CombatStats_Hit( gentity_t *ent, gentity_t *hit, combatStatsWeapon_t weapon, int damage ) +{ + combatStats_t *cs; + int *stat; + + if( !ent || !ent->client || !hit ) + return; + + cs = ent->client->pers.combatStats + weapon; + + if( hit->s.eType == ET_BUILDABLE ) + { + if( ent->client->pers.teamSelection == hit->buildableTeam ) + stat = &cs->friendly_buildable; + else + stat = &cs->enemy_buildable; + } + else if( hit->client ) + { + if( ent->client->pers.teamSelection == + hit->client->pers.teamSelection ) + stat = &cs->friendly; + else + stat = &cs->enemy; + } + else + return; + + if( g_debugDamage.integer > 3 ) + Com_Printf( "player %i hit %s %i with %s, damage: %i\n", + ent - g_entities, + ( stat == &cs->friendly_buildable ) ? "a friendly buildable" : + ( stat == &cs->enemy_buildable ) ? "an enemy buildable" : + ( stat == &cs->friendly ) ? "a friendly player" : + "an enemy player", + hit - g_entities, + cswStrings[ weapon ], + damage ); + + (*stat) += damage; +} + +void G_CombatStats_HitMOD( gentity_t *ent, gentity_t *hit, meansOfDeath_t mod, int damage ) +{ + G_CombatStats_Hit( ent, hit, modToCsw[ mod ], damage ); +} + +void G_LogCombatStats( gentity_t *ent ) +{ + int i; + char buffer[ 4096 ], *p = buffer; + + for( i = 0; i < MAX_COMBAT_STATS_WEAPONS; i++ ) + { + combatStats_t *cs = ent->client->pers.combatStats + i; + + // skip unused weapons + if( !cs->total ) + continue; + + Com_sprintf( + p, 4096 - ( p - buffer ), + " %s %i,%i,%i,%i,%i", + cswStrings[ i ], + cs->total, + cs->enemy, + cs->friendly, + cs->enemy_buildable, + cs->friendly_buildable ); + + while( *p ) p++; + } + + if( p != buffer ) + G_LogPrintf( "CombatStats: %i%s\n", ent - g_entities, buffer ); +} + diff --git a/src/game/g_csw.h b/src/game/g_csw.h new file mode 100644 index 0000000..4f3cdf2 --- /dev/null +++ b/src/game/g_csw.h @@ -0,0 +1,30 @@ +CSW( CSW_UNKNOWN, NULL ), + +CSW( CSW_BLASTER, "Blaster" ), +CSW( CSW_MACHINEGUN, "Rifle" ), +CSW( CSW_PAINSAW, "Pain Saw" ), +CSW( CSW_PAINSAW_ALT, "Pain Saw Blade" ), +CSW( CSW_SHOTGUN, "Shotgun" ), +CSW( CSW_LASGUN, "Las Gun" ), +CSW( CSW_MDRIVER, "Mass Driver" ), +CSW( CSW_CHAINGUN, "Chaingun" ), +CSW( CSW_PRIFLE, "Pulse Rifle" ), +CSW( CSW_FLAMER, "Flame Thrower" ), +CSW( CSW_LIGHTNING, "Lightning Gun" ), +CSW( CSW_LCANNON, "Lucifer Cannon" ), +CSW( CSW_ROCKETL, "Rocket Launcher" ), +CSW( CSW_GRENADE, "Grenade" ), + +CSW( CSW_ABUILDER, "Granger" ), +CSW( CSW_ABUILDER_ALT, "Granger Spit" ), +CSW( CSW_LEVEL1, "Basilisk" ), +CSW( CSW_LEVEL2, "Marauder" ), +CSW( CSW_LEVEL2_ALT, "Marauder Zap" ), +CSW( CSW_LEVEL3, "Dragoon" ), +CSW( CSW_LEVEL3_ALT, "Dragoon Barb" ), +CSW( CSW_LEVEL4, "Tyrant" ), +CSW( CSW_LEVEL4_ALT, "Tyrant Flames" ), +CSW( CSW_LEVEL5, "Hummel" ), +CSW( CSW_LEVEL5_ALT, "Hummel Prickles" ) + +#define CSW_MAX_NAME_LEN 15 diff --git a/src/game/g_local.h b/src/game/g_local.h index 873234b..918a809 100644 --- a/src/game/g_local.h +++ b/src/game/g_local.h @@ -307,6 +307,25 @@ typedef struct namelog_s int id; } namelog_t; +typedef enum +{ +#define CSW(a,b) a +#include "g_csw.h" +#undef CSW + , + MAX_COMBAT_STATS_WEAPONS +} combatStatsWeapon_t; + +typedef struct +{ + int total; + + int enemy; + int enemy_buildable; + int friendly; + int friendly_buildable; +} combatStats_t; + // client data that stays across multiple respawns, but is cleared // on each level change or team change at ClientBegin() typedef struct @@ -356,6 +375,8 @@ typedef struct // keep track of other players' info for tinfo char cinfo[ MAX_CLIENTS ][ 16 ]; + + combatStats_t combatStats[ MAX_COMBAT_STATS_WEAPONS ]; } clientPersistant_t; #define MAX_UNLAGGED_MARKERS 10 @@ -945,6 +966,11 @@ void G_InitDamageLocations( void ); #define DAMAGE_NO_PROTECTION 0x00000008 // armor, shields, invulnerability, and godmode have no effect #define DAMAGE_NO_LOCDAMAGE 0x00000010 // do not apply locational damage +void G_CombatStats_Fire( gentity_t *ent, combatStatsWeapon_t weapon, int damage ); +void G_CombatStats_FireMOD( gentity_t *ent, meansOfDeath_t mod, int damage ); +void G_CombatStats_Hit( gentity_t *ent, gentity_t *hit, combatStatsWeapon_t weapon, int damage ); +void G_CombatStats_HitMOD( gentity_t *ent, gentity_t *hit, meansOfDeath_t mod, int damage ); + // // g_missile.c // diff --git a/src/game/g_main.c b/src/game/g_main.c index 5b6b025..fb11594 100644 --- a/src/game/g_main.c +++ b/src/game/g_main.c @@ -2235,6 +2235,18 @@ void LogExit( const char *string ) } + for( i = 0; i < MAX_CLIENTS; i++ ) + { + gentity_t *ent = g_entities + i; + + if( !ent->inuse || + !ent->client || + ent->client->pers.connected == CON_CONNECTING ) + continue; + + G_LogCombatStats( ent ); + } + for( i = 1, ent = g_entities + i ; i < level.num_entities ; i++, ent++ ) { if( !ent->inuse ) diff --git a/src/game/g_missile.c b/src/game/g_missile.c index ab0156b..8c6e36d 100644 --- a/src/game/g_missile.c +++ b/src/game/g_missile.c @@ -734,8 +734,8 @@ gentity_t *FireBreath_fire( gentity_t *self, vec3_t start, vec3_t dir, bolt->damage = LEVEL4_FIREBREATHDMG; bolt->splashDamage = 60; bolt->splashRadius = 250 ; - bolt->methodOfDeath = MOD_FLAMES; - bolt->splashMethodOfDeath = MOD_FLAMER_SPLASH; + bolt->methodOfDeath = MOD_LEVEL4_FLAMES; + bolt->splashMethodOfDeath = MOD_LEVEL4_FLAMES; bolt->clipmask = MASK_SHOT; bolt->target_ent = NULL; diff --git a/src/game/g_weapon.c b/src/game/g_weapon.c index 3bc3871..2a87754 100644 --- a/src/game/g_weapon.c +++ b/src/game/g_weapon.c @@ -300,6 +300,8 @@ void meleeAttack( gentity_t *ent, float range, float width, float height, trace_t tr; gentity_t *traceEnt; + G_CombatStats_FireMOD( ent, mod, damage ); + G_WideTrace( &tr, ent, range, width, height, &traceEnt ); if( traceEnt == NULL || !traceEnt->takedamage ) return; @@ -325,6 +327,8 @@ void bulletFire( gentity_t *ent, float spread, int damage, int mod ) gentity_t *tent; gentity_t *traceEnt; + G_CombatStats_FireMOD( ent, mod, damage ); + r = random( ) * M_PI * 2.0f; u = sin( r ) * crandom( ) * spread * 16; r = cos( r ) * crandom( ) * spread * 16; @@ -424,6 +428,8 @@ void shotgunFire( gentity_t *ent ) { gentity_t *tent; + G_CombatStats_Fire( ent, CSW_SHOTGUN, SHOTGUN_DMG * SHOTGUN_PELLETS ); + // send shotgun blast tent = G_TempEntity( muzzle, EV_SHOTGUN ); VectorScale( forward, 4096, tent->s.origin2 ); @@ -450,6 +456,8 @@ void massDriverFire( gentity_t *ent ) gentity_t *tent; gentity_t *traceEnt; + G_CombatStats_Fire( ent, CSW_MDRIVER, MDRIVER_DMG ); + VectorMA( muzzle, 8192.0f * 16.0f, forward, end ); G_UnlaggedOn( ent, muzzle, 8192.0f * 16.0f ); @@ -545,6 +553,7 @@ BLASTER PISTOL void blasterFire( gentity_t *ent ) { + G_CombatStats_Fire( ent, CSW_BLASTER, BLASTER_DMG ); fire_blaster( ent, muzzle, forward ); } @@ -558,6 +567,7 @@ PULSE RIFLE void pulseRifleFire( gentity_t *ent ) { + G_CombatStats_Fire( ent, CSW_MDRIVER, PRIFLE_DMG ); fire_pulseRifle( ent, muzzle, forward ); } @@ -585,19 +595,22 @@ Napalm Charge =============== */ void NapalmFire( gentity_t *ent, qboolean secondary ) - { - +{ + int damage; - NapalmChargeFire( ent, muzzle, forward, - ent->client->ps.stats[ STAT_MISC ] * - LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX, - LCANNON_RADIUS, LCANNON_SPEED ); + damage = ent->client->ps.stats[ STAT_MISC ] * + LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX; - NapalmChargeImp( ent, muzzle, forward, - ent->client->ps.stats[ STAT_MISC ] * - LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX, - LCANNON_RADIUS, LCANNON_SPEED ); - ent->client->ps.stats[ STAT_MISC ] = 0; + G_CombatStats_Fire( ent, CSW_FLAMER, damage ); + + NapalmChargeFire( ent, muzzle, forward, + damage, LCANNON_RADIUS, LCANNON_SPEED ); + + NapalmChargeImp( ent, muzzle, forward, + ent->client->ps.stats[ STAT_MISC ] * + damage, LCANNON_RADIUS, LCANNON_SPEED ); + + ent->client->ps.stats[ STAT_MISC ] = 0; } /* @@ -610,6 +623,8 @@ Normal { vec3_t origin; + G_CombatStats_Fire( ent, CSW_FLAMER, FLAMER_DMG ); + // Correct muzzle so that the missile does not start in the ceiling VectorMA( muzzle, -7.0f, up, origin ); @@ -625,16 +640,9 @@ FireBreath Tyrant =============== */ void FireBreath_tyrant( gentity_t *ent ) - { - vec3_t corr; - corr[0] = 0.0; - corr[1] = 0.0; - corr[2] = 10.0; - - FireBreath_fire( ent, muzzle, forward, - ent->client->ps.stats[ STAT_MISC ] * - LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX, - LCANNON_RADIUS, LCANNON_SPEED ); +{ + G_CombatStats_Fire( ent, CSW_LEVEL4_ALT, LEVEL4_FIREBREATHDMG ); + FireBreath_fire( ent, muzzle, forward, 0, LCANNON_RADIUS, LCANNON_SPEED ); } /* @@ -645,13 +653,8 @@ FlameTurret void FlameTurretFire( gentity_t *ent ) { - vec3_t corr; - corr[0] = 0.0; - corr[1] = 0.0; - corr[2] = 8.0; - - VectorAdd( muzzle, corr, muzzle ); - FlameTurretFireNormal( ent, muzzle, forward ); + muzzle[2] += 8.0f; + FlameTurretFireNormal( ent, muzzle, forward ); } /* @@ -662,6 +665,8 @@ GRENADE void throwGrenade( gentity_t *ent ) { + G_CombatStats_Fire( ent, CSW_GRENADE, GRENADE_DAMAGE ); + launch_grenade( ent, muzzle, forward ); launch_grenade_flames( ent, muzzle, forward ); } @@ -709,6 +714,8 @@ void lasGunFire( gentity_t *ent ) gentity_t *tent; gentity_t *traceEnt; + G_CombatStats_Fire( ent, CSW_LASGUN, LASGUN_DAMAGE ); + VectorMA( muzzle, 8192 * 16, forward, end ); G_UnlaggedOn( ent, muzzle, 8192 * 16 ); @@ -760,6 +767,8 @@ void painSawFire( gentity_t *ent ) vec3_t temp; gentity_t *tent, *traceEnt; + G_CombatStats_Fire( ent, CSW_PAINSAW, PAINSAW_DAMAGE ); + G_WideTrace( &tr, ent, PAINSAW_RANGE, PAINSAW_WIDTH, PAINSAW_HEIGHT, &traceEnt ); if( !traceEnt || !traceEnt->takedamage ) @@ -792,6 +801,7 @@ PSAW BLADES */ void painSawFire2( gentity_t *ent ) { + G_CombatStats_Fire( ent, CSW_PAINSAW_ALT, PAINSAW_DAMAGE2 ); launch_saw( ent, muzzle, forward ); } @@ -806,13 +816,23 @@ LUCIFER CANNON void LCChargeFire( gentity_t *ent, qboolean secondary ) { if( secondary && ent->client->ps.stats[ STAT_MISC ] <= 0 ) + { + G_CombatStats_Fire( ent, CSW_LCANNON, LCANNON_SECONDARY_DAMAGE ); fire_luciferCannon( ent, muzzle, forward, LCANNON_SECONDARY_DAMAGE, LCANNON_SECONDARY_RADIUS, LCANNON_SECONDARY_SPEED ); + } else - fire_luciferCannon( ent, muzzle, forward, - ent->client->ps.stats[ STAT_MISC ] * - LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX, - LCANNON_RADIUS, LCANNON_SPEED ); + { + int damage; + + damage = ent->client->ps.stats[ STAT_MISC ] * + LCANNON_DAMAGE / LCANNON_CHARGE_TIME_MAX; + + G_CombatStats_Fire( ent, CSW_LCANNON, damage ); + + fire_luciferCannon( ent, muzzle, forward, damage, + LCANNON_RADIUS, LCANNON_SPEED ); + } ent->client->ps.stats[ STAT_MISC ] = 0; } @@ -825,6 +845,7 @@ ROCKET LAUNCHER void rocketLauncherFire( gentity_t *ent ) { + G_CombatStats_Fire( ent, CSW_ROCKETL, ROCKETL_DAMAGE ); fire_rocket( ent, muzzle, forward ); } @@ -879,6 +900,9 @@ void lightningGunFire( gentity_t *ent ) gentity_t *target; int damage; + damage = g_lightningDamage.value / ( 1000.0f / LIGHTNING_REPEAT ); + G_CombatStats_Fire( ent, CSW_LIGHTNING, damage ); + VectorMA( muzzle, LIGHTNING_RANGE, forward, end ); G_UnlaggedOn( ent, muzzle, LIGHTNING_RANGE ); @@ -895,7 +919,6 @@ void lightningGunFire( gentity_t *ent ) target = g_entities + tr.entityNum; - damage = g_lightningDamage.value / ( 1000.0f / LIGHTNING_REPEAT ); if( target->s.eType == ET_PLAYER || target->s.eType == ET_BUILDABLE ) { @@ -1074,6 +1097,7 @@ void buildFire( gentity_t *ent, dynMenu_t menu ) void slowBlobFire( gentity_t *ent ) { + G_CombatStats_Fire( ent, CSW_ABUILDER_ALT, ABUILDER_BLOB_DMG ); fire_slowBlob( ent, muzzle, forward ); } @@ -1591,6 +1615,8 @@ void areaZapFire( gentity_t *ent ) trace_t tr; gentity_t *traceEnt; + G_CombatStats_Fire( ent, CSW_LEVEL2_ALT, LEVEL2_AREAZAP_DMG ); + G_WideTrace( &tr, ent, LEVEL2_AREAZAP_RANGE, LEVEL2_AREAZAP_WIDTH, LEVEL2_AREAZAP_WIDTH, &traceEnt ); if( traceEnt == NULL ) @@ -1681,6 +1707,7 @@ qboolean CheckPounceAttack( gentity_t *ent ) void bounceBallFire( gentity_t *ent ) { + G_CombatStats_Fire( ent, CSW_LEVEL3_ALT, LEVEL3_BOUNCEBALL_DMG ); fire_bounceBall( ent, muzzle, forward ); } @@ -1829,6 +1856,9 @@ void Prickles( gentity_t *ent ) float r; float u; + + G_CombatStats_Fire( ent, CSW_LEVEL5_ALT, LEVEL5_PRICKLES_DMG ); + r = random( ) * M_PI * 2.0f; u = sin( r ) * crandom( ) * LEVEL5_PRICKLES_SPREAD * 16; r = cos( r ) * crandom( ) * LEVEL5_PRICKLES_SPREAD * 16; |