codemp/game/g_log.c

Go to the documentation of this file.
00001 #include "g_local.h"
00002 
00003 #define LOGGING_WEAPONS 
00004 
00005 // Weapon statistic logging.
00006 // Nothing super-fancy here, I just want to keep track of, per player:
00007 //              --hom many times a weapon/item is picked up
00008 //              --how many times a weapon/item is used/fired
00009 //              --the total damage done by that weapon
00010 //              --the number of kills by that weapon
00011 //              --the number of deaths while holding that weapon
00012 //              --the time spent with each weapon
00013 //
00014 // Additionally,
00015 //              --how many times each powerup or item is picked up
00016 
00017 
00018 #ifdef LOGGING_WEAPONS
00019 int G_WeaponLogPickups[MAX_CLIENTS][WP_NUM_WEAPONS];
00020 int G_WeaponLogFired[MAX_CLIENTS][WP_NUM_WEAPONS];
00021 int G_WeaponLogDamage[MAX_CLIENTS][MOD_MAX];
00022 int G_WeaponLogKills[MAX_CLIENTS][MOD_MAX];
00023 int G_WeaponLogDeaths[MAX_CLIENTS][WP_NUM_WEAPONS];
00024 int G_WeaponLogFrags[MAX_CLIENTS][MAX_CLIENTS];
00025 int G_WeaponLogTime[MAX_CLIENTS][WP_NUM_WEAPONS];
00026 int G_WeaponLogLastTime[MAX_CLIENTS];
00027 qboolean G_WeaponLogClientTouch[MAX_CLIENTS];
00028 int G_WeaponLogPowerups[MAX_CLIENTS][HI_NUM_HOLDABLE];
00029 int     G_WeaponLogItems[MAX_CLIENTS][PW_NUM_POWERUPS];
00030 
00031 extern vmCvar_t g_statLog;
00032 extern vmCvar_t g_statLogFile;
00033 
00034 // MOD-weapon mapping array.
00035 int weaponFromMOD[MOD_MAX] =
00036 {
00037         WP_NONE,                                //MOD_UNKNOWN,
00038         WP_STUN_BATON,                  //MOD_STUN_BATON,
00039         WP_MELEE,                               //MOD_MELEE,
00040         WP_SABER,                               //MOD_SABER,
00041         WP_BRYAR_PISTOL,                //MOD_BRYAR_PISTOL,
00042         WP_BRYAR_PISTOL,                //MOD_BRYAR_PISTOL_ALT,
00043         WP_BLASTER,                             //MOD_BLASTER,
00044         WP_TURRET,                              //MOD_TURBLAST
00045         WP_DISRUPTOR,                   //MOD_DISRUPTOR,
00046         WP_DISRUPTOR,                   //MOD_DISRUPTOR_SPLASH,
00047         WP_DISRUPTOR,                   //MOD_DISRUPTOR_SNIPER,
00048         WP_BOWCASTER,                   //MOD_BOWCASTER,
00049         WP_REPEATER,                    //MOD_REPEATER,
00050         WP_REPEATER,                    //MOD_REPEATER_ALT,
00051         WP_REPEATER,                    //MOD_REPEATER_ALT_SPLASH,
00052         WP_DEMP2,                               //MOD_DEMP2,
00053         WP_DEMP2,                               //MOD_DEMP2_ALT,
00054         WP_FLECHETTE,                   //MOD_FLECHETTE,
00055         WP_FLECHETTE,                   //MOD_FLECHETTE_ALT_SPLASH,
00056         WP_ROCKET_LAUNCHER,             //MOD_ROCKET,
00057         WP_ROCKET_LAUNCHER,             //MOD_ROCKET_SPLASH,
00058         WP_ROCKET_LAUNCHER,             //MOD_ROCKET_HOMING,
00059         WP_ROCKET_LAUNCHER,             //MOD_ROCKET_HOMING_SPLASH,
00060         WP_THERMAL,                             //MOD_THERMAL,
00061         WP_THERMAL,                             //MOD_THERMAL_SPLASH,
00062         WP_TRIP_MINE,                   //MOD_TRIP_MINE_SPLASH,
00063         WP_TRIP_MINE,                   //MOD_TIMED_MINE_SPLASH,
00064         WP_DET_PACK,                    //MOD_DET_PACK_SPLASH,
00065         WP_NONE,                                //MOD_FORCE_DARK,
00066         WP_NONE,                                //MOD_SENTRY,
00067         WP_NONE,                                //MOD_WATER,
00068         WP_NONE,                                //MOD_SLIME,
00069         WP_NONE,                                //MOD_LAVA,
00070         WP_NONE,                                //MOD_CRUSH,
00071         WP_NONE,                                //MOD_TELEFRAG,
00072         WP_NONE,                                //MOD_FALLING,
00073         WP_NONE,                                //MOD_SUICIDE,
00074         WP_NONE,                                //MOD_TARGET_LASER,
00075         WP_NONE,                                //MOD_TRIGGER_HURT,
00076 };
00077 
00078 char *weaponNameFromIndex[WP_NUM_WEAPONS] = 
00079 {
00080         "No Weapon",
00081         "Stun Baton",                           
00082         "Saber",        
00083         "Bryar Pistol",                         
00084         "Blaster",              
00085         "Disruptor",                            
00086         "Bowcaster",    
00087         "Repeater",     
00088         "Demp2",
00089         "Flechette",
00090         "Rocket Launcher",
00091         "Thermal",
00092         "Tripmine",
00093         "Detpack",
00094         "Emplaced gun",
00095         "Turret"
00096 };
00097 
00098 extern char     *modNames[];
00099 
00100 #endif //LOGGING_WEAPONS
00101 
00102 /*
00103 =================
00104 G_LogWeaponInit
00105 =================
00106 */
00107 void G_LogWeaponInit(void) {
00108 #ifdef LOGGING_WEAPONS
00109         memset(G_WeaponLogPickups, 0, sizeof(G_WeaponLogPickups));
00110         memset(G_WeaponLogFired, 0, sizeof(G_WeaponLogFired));
00111         memset(G_WeaponLogDamage, 0, sizeof(G_WeaponLogDamage));
00112         memset(G_WeaponLogKills, 0, sizeof(G_WeaponLogKills));
00113         memset(G_WeaponLogDeaths, 0, sizeof(G_WeaponLogDeaths));
00114         memset(G_WeaponLogFrags, 0, sizeof(G_WeaponLogFrags));
00115         memset(G_WeaponLogTime, 0, sizeof(G_WeaponLogTime));
00116         memset(G_WeaponLogLastTime, 0, sizeof(G_WeaponLogLastTime));
00117         memset(G_WeaponLogPowerups, 0, sizeof(G_WeaponLogPowerups));
00118         memset(G_WeaponLogItems, 0, sizeof(G_WeaponLogItems));
00119 #endif //LOGGING_WEAPONS
00120 }
00121 
00122 void QDECL G_LogWeaponPickup(int client, int weaponid)
00123 {
00124 #ifdef LOGGING_WEAPONS
00125         G_WeaponLogPickups[client][weaponid]++;
00126         G_WeaponLogClientTouch[client] = qtrue;
00127 #endif //_LOGGING_WEAPONS
00128 }
00129 
00130 void QDECL G_LogWeaponFire(int client, int weaponid)
00131 {
00132 #ifdef LOGGING_WEAPONS
00133         int dur;
00134 
00135         G_WeaponLogFired[client][weaponid]++;
00136         dur = level.time - G_WeaponLogLastTime[client];
00137         if (dur > 5000)         // 5 second max.
00138                 G_WeaponLogTime[client][weaponid] += 5000;
00139         else
00140                 G_WeaponLogTime[client][weaponid] += dur;
00141         G_WeaponLogLastTime[client] = level.time;
00142         G_WeaponLogClientTouch[client] = qtrue;
00143 #endif //_LOGGING_WEAPONS
00144 }
00145 
00146 void QDECL G_LogWeaponDamage(int client, int mod, int amount)
00147 {
00148 #ifdef LOGGING_WEAPONS
00149         if (client>=MAX_CLIENTS)
00150                 return;
00151         G_WeaponLogDamage[client][mod] += amount;
00152         G_WeaponLogClientTouch[client] = qtrue;
00153 #endif //_LOGGING_WEAPONS
00154 }
00155 
00156 void QDECL G_LogWeaponKill(int client, int mod)
00157 {
00158 #ifdef LOGGING_WEAPONS
00159         if (client>=MAX_CLIENTS)
00160                 return;
00161         G_WeaponLogKills[client][mod]++;
00162         G_WeaponLogClientTouch[client] = qtrue;
00163 #endif //_LOGGING_WEAPONS
00164 }
00165 
00166 void QDECL G_LogWeaponFrag(int attacker, int deadguy)
00167 {
00168 #ifdef LOGGING_WEAPONS
00169         if ( (attacker>=MAX_CLIENTS) || (deadguy>=MAX_CLIENTS) )
00170                 return;
00171         G_WeaponLogFrags[attacker][deadguy]++;
00172         G_WeaponLogClientTouch[attacker] = qtrue;
00173 #endif //_LOGGING_WEAPONS
00174 }
00175 
00176 void QDECL G_LogWeaponDeath(int client, int weaponid)
00177 {
00178 #ifdef LOGGING_WEAPONS
00179         if (client>=MAX_CLIENTS)
00180                 return;
00181         G_WeaponLogDeaths[client][weaponid]++;
00182         G_WeaponLogClientTouch[client] = qtrue;
00183 #endif //_LOGGING_WEAPONS
00184 }
00185 
00186 void QDECL G_LogWeaponPowerup(int client, int powerupid)
00187 {
00188 #ifdef LOGGING_WEAPONS
00189         if (client>=MAX_CLIENTS)
00190                 return;
00191         G_WeaponLogPowerups[client][powerupid]++;
00192         G_WeaponLogClientTouch[client] = qtrue;
00193 #endif //_LOGGING_WEAPONS
00194 }
00195 
00196 void QDECL G_LogWeaponItem(int client, int itemid)
00197 {
00198 #ifdef LOGGING_WEAPONS
00199         if (client>=MAX_CLIENTS)
00200                 return;
00201         G_WeaponLogItems[client][itemid]++;
00202         G_WeaponLogClientTouch[client] = qtrue;
00203 #endif //_LOGGING_WEAPONS
00204 }
00205 
00206 
00207 // Run through each player.  Print out:
00208 //      -- Most commonly picked up weapon.
00209 //  -- Weapon with which the most time was spent.
00210 //  -- Weapon that was most often died with.
00211 //  -- Damage type with which the most damage was done.
00212 //  -- Damage type with the most kills.
00213 //  -- Weapon with which the most damage was done.
00214 //      -- Weapon with which the most damage was done per shot.
00215 //
00216 // For the whole game, print out:
00217 //  -- Total pickups of each weapon.
00218 //  -- Total time spent with each weapon.
00219 //  -- Total damage done with each weapon.
00220 //  -- Total damage done for each damage type.
00221 //  -- Number of kills with each weapon.
00222 //  -- Number of kills for each damage type.
00223 //  -- Damage per shot with each weapon.
00224 //  -- Number of deaths with each weapon.
00225 
00226 void G_LogWeaponOutput(void)
00227 {
00228 #ifdef LOGGING_WEAPONS
00229         int i,j,curwp;
00230         float pershot;
00231         fileHandle_t weaponfile;
00232         char string[1024];
00233 
00234         int totalpickups[WP_NUM_WEAPONS];
00235         int totaltime[WP_NUM_WEAPONS];
00236         int totaldeaths[WP_NUM_WEAPONS];
00237         int totaldamageMOD[MOD_MAX];
00238         int totalkillsMOD[MOD_MAX];
00239         int totaldamage[WP_NUM_WEAPONS];
00240         int totalkills[WP_NUM_WEAPONS];
00241         int totalshots[WP_NUM_WEAPONS];
00242         int percharacter[WP_NUM_WEAPONS];
00243         char info[1024];
00244         char mapname[128];
00245         char *nameptr, *unknownname="<Unknown>";
00246 
00247         if (!g_statLog.integer)
00248         {
00249                 return;
00250         }
00251 
00252         G_LogPrintf("*****************************Weapon Log:\n" );
00253 
00254         memset(totalpickups, 0, sizeof(totalpickups));
00255         memset(totaltime, 0, sizeof(totaltime));
00256         memset(totaldeaths, 0, sizeof(totaldeaths));
00257         memset(totaldamageMOD, 0, sizeof(totaldamageMOD));
00258         memset(totalkillsMOD, 0, sizeof(totalkillsMOD));
00259         memset(totaldamage, 0, sizeof(totaldamage));
00260         memset(totalkills, 0, sizeof(totalkills));
00261         memset(totalshots, 0, sizeof(totalshots));
00262 
00263         for (i=0; i<MAX_CLIENTS; i++)
00264         {
00265                 if (G_WeaponLogClientTouch[i])
00266                 {       // Ignore any entity/clients we don't care about!
00267                         for (j=0;j<WP_NUM_WEAPONS;j++)
00268                         {
00269                                 totalpickups[j] += G_WeaponLogPickups[i][j];
00270                                 totaltime[j] += G_WeaponLogTime[i][j];
00271                                 totaldeaths[j] += G_WeaponLogDeaths[i][j];
00272                                 totalshots[j] += G_WeaponLogFired[i][j];
00273                         }
00274 
00275                         for (j=0;j<MOD_MAX;j++)
00276                         {
00277                                 totaldamageMOD[j] += G_WeaponLogDamage[i][j];
00278                                 totalkillsMOD[j] += G_WeaponLogKills[i][j];
00279                         }
00280                 }
00281         }
00282 
00283         // Now total the weapon data from the MOD data.
00284         for (j=0; j<MOD_MAX; j++)
00285         {
00286                 if (j <= MOD_SENTRY)
00287                 {
00288                         curwp = weaponFromMOD[j];
00289                         totaldamage[curwp] += totaldamageMOD[j];
00290                         totalkills[curwp] += totalkillsMOD[j];
00291                 }
00292         }
00293 
00294         G_LogPrintf(  "\n****Data by Weapon:\n" );
00295         for (j=0; j<WP_NUM_WEAPONS; j++)
00296         {
00297                 G_LogPrintf("%15s:  Pickups: %4d,  Time:  %5d,  Deaths: %5d\n", 
00298                                 weaponNameFromIndex[j], totalpickups[j], (int)(totaltime[j]/1000), totaldeaths[j]);
00299         }
00300 
00301         G_LogPrintf(  "\n****Combat Data by Weapon:\n" );
00302         for (j=0; j<WP_NUM_WEAPONS; j++)
00303         {
00304                 if (totalshots[j] > 0)
00305                 {
00306                         pershot = (float)(totaldamage[j])/(float)(totalshots[j]);
00307                 }
00308                 else
00309                 {
00310                         pershot = 0;
00311                 }
00312                 G_LogPrintf("%15s:  Damage: %6d,  Kills: %5d,  Dmg per Shot: %f\n", 
00313                                 weaponNameFromIndex[j], totaldamage[j], totalkills[j], pershot);
00314         }
00315 
00316         G_LogPrintf(  "\n****Combat Data By Damage Type:\n" );
00317         for (j=0; j<MOD_MAX; j++)
00318         {
00319                 G_LogPrintf("%25s:  Damage: %6d,  Kills: %5d\n", 
00320                                 modNames[j], totaldamageMOD[j], totalkillsMOD[j]);
00321         }
00322 
00323         G_LogPrintf("\n");
00324 
00325 
00326 
00327         // Write the whole weapon statistic log out to a file.
00328         trap_FS_FOpenFile( g_statLogFile.string, &weaponfile, FS_APPEND );
00329         if (!weaponfile) {      //failed to open file, let's not crash, shall we?
00330                 return;
00331         }
00332 
00333         // Write out the level name
00334         trap_GetServerinfo(info, sizeof(info));
00335         strncpy(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname)-1);
00336         mapname[sizeof(mapname)-1] = '\0';
00337 
00338         Com_sprintf(string, sizeof(string), "\n\n\nLevel:\t%s\n\n\n", mapname);
00339         trap_FS_Write( string, strlen( string ), weaponfile);
00340 
00341 
00342         // Combat data per character
00343         
00344         // Start with Pickups per character
00345         Com_sprintf(string, sizeof(string), "Weapon Pickups per Player:\n\n");
00346         trap_FS_Write( string, strlen( string ), weaponfile);
00347 
00348         Com_sprintf(string, sizeof(string), "Player");
00349         trap_FS_Write(string, strlen(string), weaponfile);
00350 
00351         for (j=0; j<WP_NUM_WEAPONS; j++)
00352         {
00353                 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
00354                 trap_FS_Write(string, strlen(string), weaponfile);
00355         }
00356         Com_sprintf(string, sizeof(string), "\n");
00357         trap_FS_Write(string, strlen(string), weaponfile);
00358 
00359         // Cycle through each player, give their name and the number of times they picked up each weapon.
00360         for (i=0; i<MAX_CLIENTS; i++)
00361         {
00362                 if (G_WeaponLogClientTouch[i])
00363                 {       // Ignore any entity/clients we don't care about!
00364                         if ( g_entities[i].client ) 
00365                         {
00366                                 nameptr = g_entities[i].client->pers.netname;
00367                         } 
00368                         else 
00369                         {
00370                                 nameptr = unknownname;
00371                         }
00372                         trap_FS_Write(nameptr, strlen(nameptr), weaponfile);
00373 
00374                         for (j=0;j<WP_NUM_WEAPONS;j++)
00375                         {
00376                                 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogPickups[i][j]);
00377                                 trap_FS_Write(string, strlen(string), weaponfile);
00378                         }
00379 
00380                         Com_sprintf(string, sizeof(string), "\n");
00381                         trap_FS_Write(string, strlen(string), weaponfile);
00382                 }
00383         }
00384 
00385         // Sum up the totals.
00386         Com_sprintf(string, sizeof(string), "\n***TOTAL:");
00387         trap_FS_Write(string, strlen(string), weaponfile);
00388 
00389         for (j=0;j<WP_NUM_WEAPONS;j++)
00390         {
00391                 Com_sprintf(string, sizeof(string), "\t%d", totalpickups[j]);
00392                 trap_FS_Write(string, strlen(string), weaponfile);
00393         }
00394 
00395         Com_sprintf(string, sizeof(string), "\n\n\n");
00396         trap_FS_Write(string, strlen(string), weaponfile);
00397 
00398         
00399         // Weapon fires per character
00400         Com_sprintf(string, sizeof(string), "Weapon Shots per Player:\n\n");
00401         trap_FS_Write( string, strlen( string ), weaponfile);
00402 
00403         Com_sprintf(string, sizeof(string), "Player");
00404         trap_FS_Write(string, strlen(string), weaponfile);
00405 
00406         for (j=0; j<WP_NUM_WEAPONS; j++)
00407         {
00408                 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
00409                 trap_FS_Write(string, strlen(string), weaponfile);
00410         }
00411         Com_sprintf(string, sizeof(string), "\n");
00412         trap_FS_Write(string, strlen(string), weaponfile);
00413 
00414         // Cycle through each player, give their name and the number of times they picked up each weapon.
00415         for (i=0; i<MAX_CLIENTS; i++)
00416         {
00417                 if (G_WeaponLogClientTouch[i])
00418                 {       // Ignore any entity/clients we don't care about!
00419                         if ( g_entities[i].client ) 
00420                         {
00421                                 nameptr = g_entities[i].client->pers.netname;
00422                         } 
00423                         else 
00424                         {
00425                                 nameptr = unknownname;
00426                         }
00427                         trap_FS_Write(nameptr, strlen(nameptr), weaponfile);
00428 
00429                         for (j=0;j<WP_NUM_WEAPONS;j++)
00430                         {
00431                                 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogFired[i][j]);
00432                                 trap_FS_Write(string, strlen(string), weaponfile);
00433                         }
00434 
00435                         Com_sprintf(string, sizeof(string), "\n");
00436                         trap_FS_Write(string, strlen(string), weaponfile);
00437                 }
00438         }
00439 
00440         // Sum up the totals.
00441         Com_sprintf(string, sizeof(string), "\n***TOTAL:");
00442         trap_FS_Write(string, strlen(string), weaponfile);
00443         
00444         for (j=0;j<WP_NUM_WEAPONS;j++)
00445         {
00446                 Com_sprintf(string, sizeof(string), "\t%d", totalshots[j]);
00447                 trap_FS_Write(string, strlen(string), weaponfile);
00448         }
00449 
00450         Com_sprintf(string, sizeof(string), "\n\n\n");
00451         trap_FS_Write(string, strlen(string), weaponfile);
00452 
00453 
00454         // Weapon time per character
00455         Com_sprintf(string, sizeof(string), "Weapon Use Time per Player:\n\n");
00456         trap_FS_Write( string, strlen( string ), weaponfile);
00457 
00458         Com_sprintf(string, sizeof(string), "Player");
00459         trap_FS_Write(string, strlen(string), weaponfile);
00460 
00461         for (j=0; j<WP_NUM_WEAPONS; j++)
00462         {
00463                 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
00464                 trap_FS_Write(string, strlen(string), weaponfile);
00465         }
00466         Com_sprintf(string, sizeof(string), "\n");
00467         trap_FS_Write(string, strlen(string), weaponfile);
00468 
00469         // Cycle through each player, give their name and the number of times they picked up each weapon.
00470         for (i=0; i<MAX_CLIENTS; i++)
00471         {
00472                 if (G_WeaponLogClientTouch[i])
00473                 {       // Ignore any entity/clients we don't care about!
00474                         if ( g_entities[i].client ) 
00475                         {
00476                                 nameptr = g_entities[i].client->pers.netname;
00477                         } 
00478                         else 
00479                         {
00480                                 nameptr = unknownname;
00481                         }
00482                         trap_FS_Write(nameptr, strlen(nameptr), weaponfile);
00483 
00484                         for (j=0;j<WP_NUM_WEAPONS;j++)
00485                         {
00486                                 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogTime[i][j]);
00487                                 trap_FS_Write(string, strlen(string), weaponfile);
00488                         }
00489 
00490                         Com_sprintf(string, sizeof(string), "\n");
00491                         trap_FS_Write(string, strlen(string), weaponfile);
00492                 }
00493         }
00494 
00495         // Sum up the totals.
00496         Com_sprintf(string, sizeof(string), "\n***TOTAL:");
00497         trap_FS_Write(string, strlen(string), weaponfile);
00498         
00499         for (j=0;j<WP_NUM_WEAPONS;j++)
00500         {
00501                 Com_sprintf(string, sizeof(string), "\t%d", totaltime[j]);
00502                 trap_FS_Write(string, strlen(string), weaponfile);
00503         }
00504 
00505         Com_sprintf(string, sizeof(string), "\n\n\n");
00506         trap_FS_Write(string, strlen(string), weaponfile);
00507 
00508 
00509         
00510         // Weapon deaths per character
00511         Com_sprintf(string, sizeof(string), "Weapon Deaths per Player:\n\n");
00512         trap_FS_Write( string, strlen( string ), weaponfile);
00513 
00514         Com_sprintf(string, sizeof(string), "Player");
00515         trap_FS_Write(string, strlen(string), weaponfile);
00516 
00517         for (j=0; j<WP_NUM_WEAPONS; j++)
00518         {
00519                 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
00520                 trap_FS_Write(string, strlen(string), weaponfile);
00521         }
00522         Com_sprintf(string, sizeof(string), "\n");
00523         trap_FS_Write(string, strlen(string), weaponfile);
00524 
00525         // Cycle through each player, give their name and the number of times they picked up each weapon.
00526         for (i=0; i<MAX_CLIENTS; i++)
00527         {
00528                 if (G_WeaponLogClientTouch[i])
00529                 {       // Ignore any entity/clients we don't care about!
00530                         if ( g_entities[i].client ) 
00531                         {
00532                                 nameptr = g_entities[i].client->pers.netname;
00533                         } 
00534                         else 
00535                         {
00536                                 nameptr = unknownname;
00537                         }
00538                         trap_FS_Write(nameptr, strlen(nameptr), weaponfile);
00539 
00540                         for (j=0;j<WP_NUM_WEAPONS;j++)
00541                         {
00542                                 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogDeaths[i][j]);
00543                                 trap_FS_Write(string, strlen(string), weaponfile);
00544                         }
00545 
00546                         Com_sprintf(string, sizeof(string), "\n");
00547                         trap_FS_Write(string, strlen(string), weaponfile);
00548                 }
00549         }
00550 
00551         // Sum up the totals.
00552         Com_sprintf(string, sizeof(string), "\n***TOTAL:");
00553         trap_FS_Write(string, strlen(string), weaponfile);
00554         
00555         for (j=0;j<WP_NUM_WEAPONS;j++)
00556         {
00557                 Com_sprintf(string, sizeof(string), "\t%d", totaldeaths[j]);
00558                 trap_FS_Write(string, strlen(string), weaponfile);
00559         }
00560 
00561         Com_sprintf(string, sizeof(string), "\n\n\n");
00562         trap_FS_Write(string, strlen(string), weaponfile);
00563 
00564 
00565 
00566         
00567         // Weapon damage per character
00568 
00569         Com_sprintf(string, sizeof(string), "Weapon Damage per Player:\n\n");
00570         trap_FS_Write( string, strlen( string ), weaponfile);
00571 
00572         Com_sprintf(string, sizeof(string), "Player");
00573         trap_FS_Write(string, strlen(string), weaponfile);
00574 
00575         for (j=0; j<WP_NUM_WEAPONS; j++)
00576         {
00577                 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
00578                 trap_FS_Write(string, strlen(string), weaponfile);
00579         }
00580         Com_sprintf(string, sizeof(string), "\n");
00581         trap_FS_Write(string, strlen(string), weaponfile);
00582 
00583         // Cycle through each player, give their name and the number of times they picked up each weapon.
00584         for (i=0; i<MAX_CLIENTS; i++)
00585         {
00586                 if (G_WeaponLogClientTouch[i])
00587                 {       // Ignore any entity/clients we don't care about!
00588 
00589                         // We must grab the totals from the damage types for the player and map them to the weapons.
00590                         memset(percharacter, 0, sizeof(percharacter));
00591                         for (j=0; j<MOD_MAX; j++)
00592                         {
00593                                 if (j <= MOD_SENTRY)
00594                                 {
00595                                         curwp = weaponFromMOD[j];
00596                                         percharacter[curwp] += G_WeaponLogDamage[i][j];
00597                                 }
00598                         }
00599 
00600                         if ( g_entities[i].client ) 
00601                         {
00602                                 nameptr = g_entities[i].client->pers.netname;
00603                         } 
00604                         else 
00605                         {
00606                                 nameptr = unknownname;
00607                         }
00608                         trap_FS_Write(nameptr, strlen(nameptr), weaponfile);
00609 
00610                         for (j=0;j<WP_NUM_WEAPONS;j++)
00611                         {
00612                                 Com_sprintf(string, sizeof(string), "\t%d", percharacter[j]);
00613                                 trap_FS_Write(string, strlen(string), weaponfile);
00614                         }
00615 
00616                         Com_sprintf(string, sizeof(string), "\n");
00617                         trap_FS_Write(string, strlen(string), weaponfile);
00618                 }
00619         }
00620 
00621         // Sum up the totals.
00622         Com_sprintf(string, sizeof(string), "\n***TOTAL:");
00623         trap_FS_Write(string, strlen(string), weaponfile);
00624         
00625         for (j=0;j<WP_NUM_WEAPONS;j++)
00626         {
00627                 Com_sprintf(string, sizeof(string), "\t%d", totaldamage[j]);
00628                 trap_FS_Write(string, strlen(string), weaponfile);
00629         }
00630 
00631         Com_sprintf(string, sizeof(string), "\n\n\n");
00632         trap_FS_Write(string, strlen(string), weaponfile);
00633 
00634 
00635         
00636         // Weapon kills per character
00637 
00638         Com_sprintf(string, sizeof(string), "Weapon Kills per Player:\n\n");
00639         trap_FS_Write( string, strlen( string ), weaponfile);
00640 
00641         Com_sprintf(string, sizeof(string), "Player");
00642         trap_FS_Write(string, strlen(string), weaponfile);
00643 
00644         for (j=0; j<WP_NUM_WEAPONS; j++)
00645         {
00646                 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
00647                 trap_FS_Write(string, strlen(string), weaponfile);
00648         }
00649         Com_sprintf(string, sizeof(string), "\n");
00650         trap_FS_Write(string, strlen(string), weaponfile);
00651 
00652         // Cycle through each player, give their name and the number of times they picked up each weapon.
00653         for (i=0; i<MAX_CLIENTS; i++)
00654         {
00655                 if (G_WeaponLogClientTouch[i])
00656                 {       // Ignore any entity/clients we don't care about!
00657 
00658                         // We must grab the totals from the damage types for the player and map them to the weapons.
00659                         memset(percharacter, 0, sizeof(percharacter));
00660                         for (j=0; j<MOD_MAX; j++)
00661                         {
00662                                 if (j <= MOD_SENTRY)
00663                                 {
00664                                         curwp = weaponFromMOD[j];
00665                                         percharacter[curwp] += G_WeaponLogKills[i][j];
00666                                 }
00667                         }
00668 
00669                         if ( g_entities[i].client ) 
00670                         {
00671                                 nameptr = g_entities[i].client->pers.netname;
00672                         } 
00673                         else 
00674                         {
00675                                 nameptr = unknownname;
00676                         }
00677                         trap_FS_Write(nameptr, strlen(nameptr), weaponfile);
00678 
00679                         for (j=0;j<WP_NUM_WEAPONS;j++)
00680                         {
00681                                 Com_sprintf(string, sizeof(string), "\t%d", percharacter[j]);
00682                                 trap_FS_Write(string, strlen(string), weaponfile);
00683                         }
00684 
00685                         Com_sprintf(string, sizeof(string), "\n");
00686                         trap_FS_Write(string, strlen(string), weaponfile);
00687                 }
00688         }
00689 
00690         // Sum up the totals.
00691         Com_sprintf(string, sizeof(string), "\n***TOTAL:");
00692         trap_FS_Write(string, strlen(string), weaponfile);
00693         
00694         for (j=0;j<WP_NUM_WEAPONS;j++)
00695         {
00696                 Com_sprintf(string, sizeof(string), "\t%d", totalkills[j]);
00697                 trap_FS_Write(string, strlen(string), weaponfile);
00698         }
00699 
00700         Com_sprintf(string, sizeof(string), "\n\n\n");
00701         trap_FS_Write(string, strlen(string), weaponfile);
00702 
00703 
00704         
00705         // Damage type damage per character
00706         Com_sprintf(string, sizeof(string), "Typed Damage per Player:\n\n");
00707         trap_FS_Write( string, strlen( string ), weaponfile);
00708 
00709         Com_sprintf(string, sizeof(string), "Player");
00710         trap_FS_Write(string, strlen(string), weaponfile);
00711 
00712         for (j=0; j<MOD_MAX; j++)
00713         {
00714                 Com_sprintf(string, sizeof(string), "\t%s", modNames[j]);
00715                 trap_FS_Write(string, strlen(string), weaponfile);
00716         }
00717         Com_sprintf(string, sizeof(string), "\n");
00718         trap_FS_Write(string, strlen(string), weaponfile);
00719 
00720         // Cycle through each player, give their name and the number of times they picked up each weapon.
00721         for (i=0; i<MAX_CLIENTS; i++)
00722         {
00723                 if (G_WeaponLogClientTouch[i])
00724                 {       // Ignore any entity/clients we don't care about!
00725                         if ( g_entities[i].client ) 
00726                         {
00727                                 nameptr = g_entities[i].client->pers.netname;
00728                         } 
00729                         else 
00730                         {
00731                                 nameptr = unknownname;
00732                         }
00733                         trap_FS_Write(nameptr, strlen(nameptr), weaponfile);
00734 
00735                         for (j=0;j<MOD_MAX;j++)
00736                         {
00737                                 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogDamage[i][j]);
00738                                 trap_FS_Write(string, strlen(string), weaponfile);
00739                         }
00740 
00741                         Com_sprintf(string, sizeof(string), "\n");
00742                         trap_FS_Write(string, strlen(string), weaponfile);
00743                 }
00744         }
00745 
00746         // Sum up the totals.
00747         Com_sprintf(string, sizeof(string), "\n***TOTAL:");
00748         trap_FS_Write(string, strlen(string), weaponfile);
00749         
00750         for (j=0;j<MOD_MAX;j++)
00751         {
00752                 Com_sprintf(string, sizeof(string), "\t%d", totaldamageMOD[j]);
00753                 trap_FS_Write(string, strlen(string), weaponfile);
00754         }
00755 
00756         Com_sprintf(string, sizeof(string), "\n\n\n");
00757         trap_FS_Write(string, strlen(string), weaponfile);
00758 
00759 
00760         
00761         // Damage type kills per character
00762         Com_sprintf(string, sizeof(string), "Damage-Typed Kills per Player:\n\n");
00763         trap_FS_Write( string, strlen( string ), weaponfile);
00764 
00765         Com_sprintf(string, sizeof(string), "Player");
00766         trap_FS_Write(string, strlen(string), weaponfile);
00767 
00768         for (j=0; j<MOD_MAX; j++)
00769         {
00770                 Com_sprintf(string, sizeof(string), "\t%s", modNames[j]);
00771                 trap_FS_Write(string, strlen(string), weaponfile);
00772         }
00773         Com_sprintf(string, sizeof(string), "\n");
00774         trap_FS_Write(string, strlen(string), weaponfile);
00775 
00776         // Cycle through each player, give their name and the number of times they picked up each weapon.
00777         for (i=0; i<MAX_CLIENTS; i++)
00778         {
00779                 if (G_WeaponLogClientTouch[i])
00780                 {       // Ignore any entity/clients we don't care about!
00781                         if ( g_entities[i].client ) 
00782                         {
00783                                 nameptr = g_entities[i].client->pers.netname;
00784                         } 
00785                         else 
00786                         {
00787                                 nameptr = unknownname;
00788                         }
00789                         trap_FS_Write(nameptr, strlen(nameptr), weaponfile);
00790 
00791                         for (j=0;j<MOD_MAX;j++)
00792                         {
00793                                 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogKills[i][j]);
00794                                 trap_FS_Write(string, strlen(string), weaponfile);
00795                         }
00796 
00797                         Com_sprintf(string, sizeof(string), "\n");
00798                         trap_FS_Write(string, strlen(string), weaponfile);
00799                 }
00800         }
00801 
00802         // Sum up the totals.
00803         Com_sprintf(string, sizeof(string), "\n***TOTAL:");
00804         trap_FS_Write(string, strlen(string), weaponfile);
00805         
00806         for (j=0;j<MOD_MAX;j++)
00807         {
00808                 Com_sprintf(string, sizeof(string), "\t%d", totalkillsMOD[j]);
00809                 trap_FS_Write(string, strlen(string), weaponfile);
00810         }
00811 
00812         Com_sprintf(string, sizeof(string), "\n\n\n");
00813         trap_FS_Write(string, strlen(string), weaponfile);
00814 
00815 
00816         trap_FS_FCloseFile(weaponfile);
00817 
00818 
00819 #endif //LOGGING_WEAPONS
00820 }
00821 
00822 // did this player earn the efficiency award?
00823 qboolean CalculateEfficiency(gentity_t *ent, int *efficiency)
00824 {
00825 #ifdef LOGGING_WEAPONS
00826         float           fAccuracyRatio = 0, fBestRatio = 0;
00827         int                     i = 0, nShotsFired = 0, nShotsHit = 0, nBestPlayer = -1, tempEff = 0;
00828         gentity_t       *player = NULL;
00829 
00830 
00831         for (i = 0; i < g_maxclients.integer; i++)
00832         {
00833                 player = g_entities + i;
00834                 if (!player->inuse)
00835                         continue;
00836                 nShotsFired = player->client->accuracy_shots; //player->client->ps.persistant[PERS_ACCURACY_SHOTS];
00837                 nShotsHit = player->client->accuracy_hits; //player->client->ps.persistant[PERS_ACCURACY_HITS];
00838                 fAccuracyRatio = ( ((float)nShotsHit)/((float)nShotsFired) );
00839                 if (fAccuracyRatio > fBestRatio)
00840                 {
00841                         fBestRatio = fAccuracyRatio;
00842                         nBestPlayer = i;
00843                 }
00844         }
00845         if (-1 == nBestPlayer)
00846         {
00847                 // huh?
00848                 return qfalse;
00849         }
00850         if (nBestPlayer == ent->s.number)
00851         {
00852                 tempEff = (int)(100*fBestRatio);
00853                 if (tempEff > 50)
00854                 {
00855                         *efficiency = tempEff;
00856                         return qtrue;
00857                 }
00858                 return qfalse;
00859         }
00860 #endif // LOGGING_WEAPONS
00861         return qfalse;
00862 }
00863 
00864 // did this player earn the sharpshooter award?
00865 qboolean CalculateSharpshooter(gentity_t *ent, int *frags)
00866 {
00867 #ifdef LOGGING_WEAPONS
00868         int                     i = 0, nBestPlayer = -1, nKills = 0, nMostKills = 0,
00869                                 playTime = (level.time - ent->client->pers.enterTime)/60000;
00870         gentity_t       *player = NULL;
00871 
00872         // if this guy didn't get one kill per minute, reject him right now
00873         if ( ((float)(G_WeaponLogKills[ent-g_entities][MOD_DISRUPTOR_SNIPER]))/((float)(playTime)) < 1.0 )
00874         {
00875                 return qfalse;
00876         }
00877 
00878         for (i = 0; i < g_maxclients.integer; i++)
00879         {
00880                 nKills = 0;
00881                 player = g_entities + i;
00882                 if (!player->inuse)
00883                         continue;
00884                 nKills = G_WeaponLogKills[i][MOD_DISRUPTOR_SNIPER];
00885                 if (nKills > nMostKills)
00886                 {
00887                         nMostKills = nKills;
00888                         nBestPlayer = i;
00889                 }
00890         }
00891         if (-1 == nBestPlayer)
00892         {
00893                 return qfalse;
00894         }
00895         if (nBestPlayer == ent->s.number)
00896         {
00897                 *frags = nMostKills;
00898                 return qtrue;
00899         }
00900 #endif // LOGGING_WEAPONS
00901         return qfalse;
00902 }
00903 
00904 // did this player earn the untouchable award?
00905 qboolean CalculateUntouchable(gentity_t *ent)
00906 {
00907 #ifdef LOGGING_WEAPONS
00908         int                     playTime;
00909         playTime = (level.time - ent->client->pers.enterTime)/60000;
00910 
00911         if ( g_gametype.integer == GT_JEDIMASTER && ent->client->ps.isJediMaster )
00912         {//Jedi Master (was Borg queen) can only be killed once anyway
00913                 return qfalse;
00914         }
00915         //------------------------------------------------------ MUST HAVE ACHIEVED 2 KILLS PER MINUTE
00916         if ( ((float)ent->client->ps.persistant[PERS_SCORE])/((float)(playTime)) < 2.0  || playTime==0)
00917                 return qfalse;
00918         //------------------------------------------------------ MUST HAVE ACHIEVED 2 KILLS PER MINUTE
00919 
00920 
00921         // if this guy was never killed...  Award Away!!!
00922         if (ent->client->ps.persistant[PERS_KILLED]==0)
00923                 return qtrue;
00924 
00925 #endif // LOGGING_WEAPONS
00926         return qfalse;
00927 }
00928 
00929 // did this player earn the logistics award?
00930 qboolean CalculateLogistics(gentity_t *ent, int *stuffUsed)
00931 {
00932 #ifdef LOGGING_WEAPONS
00933         int                     i = 0, j = 0, nBestPlayer = -1, nStuffUsed = 0, nMostStuffUsed = 0,
00934                                 nDifferent = 0, nMostDifferent = 0;
00935         gentity_t       *player = NULL;
00936 
00937         for (i = 0; i < g_maxclients.integer; i++)
00938         {
00939                 nStuffUsed = 0;
00940                 nDifferent = 0;
00941                 player = g_entities + i;
00942                 if (!player->inuse)
00943                         continue;
00944                 for (j = HI_NONE+1; j < HI_NUM_HOLDABLE; j++)
00945                 {
00946                         if (G_WeaponLogPowerups[i][j])
00947                         {
00948                                 nDifferent++;
00949                         }
00950                         nStuffUsed += G_WeaponLogPowerups[i][j];
00951                 }
00952                 for (j = PW_NONE+1; j < PW_NUM_POWERUPS; j++)
00953                 {
00954                         if (G_WeaponLogItems[i][j])
00955                         {
00956                                 nDifferent++;
00957                         }
00958                         nStuffUsed += G_WeaponLogItems[i][j];
00959                 }
00960                 if ( (nDifferent >= 4) && (nDifferent >= nMostDifferent) )
00961                 {
00962                         if (nStuffUsed > nMostStuffUsed)
00963                         {
00964                                 nMostDifferent = nDifferent;
00965                                 nMostStuffUsed = nStuffUsed;
00966                                 nBestPlayer = i;
00967                         }
00968                 }
00969         }
00970         if (-1 == nBestPlayer)
00971         {
00972                 return qfalse;
00973         }
00974         if (nBestPlayer == ent->s.number)
00975         {
00976                 *stuffUsed = nMostDifferent;
00977                 return qtrue;
00978         }
00979 #endif // LOGGING_WEAPONS
00980         return qfalse;
00981 }
00982 
00983 
00984 
00985 
00986 // did this player earn the tactician award?
00987 qboolean CalculateTactician(gentity_t *ent, int *kills)
00988 {
00989 #ifdef LOGGING_WEAPONS
00990         int                     i = 0, nBestPlayer = -1, nKills = 0, nMostKills = 0;
00991         int                     person = 0, weapon = 0;
00992         gentity_t       *player = NULL;
00993         int                     wasPickedUpBySomeone[WP_NUM_WEAPONS];
00994         int                     killsWithWeapon[WP_NUM_WEAPONS];
00995         int                     playTime = (level.time - ent->client->pers.enterTime)/60000;
00996 
00997         if ( HasSetSaberOnly() )
00998         {//duh, only 1 weapon
00999                 return qfalse;
01000         }
01001         if ( g_gametype.integer == GT_JEDIMASTER && ent->client->ps.isJediMaster )
01002         {//Jedi Master (was Borg queen) has only 1 weapon
01003                 return qfalse;
01004         }
01005         //------------------------------------------------------ MUST HAVE ACHIEVED 2 KILLS PER MINUTE
01006         if (playTime<0.3)
01007                 return qfalse;
01008 
01009         if ( ((float)ent->client->ps.persistant[PERS_SCORE])/((float)(playTime)) < 2.0 )
01010                 return qfalse;
01011         //------------------------------------------------------ MUST HAVE ACHIEVED 2 KILLS PER MINUTE
01012 
01013 
01014 
01015 
01016         //------------------------------------------------------ FOR EVERY WEAPON, ADD UP TOTAL PICKUPS
01017         for (weapon = 0; weapon<WP_NUM_WEAPONS; weapon++)
01018                         wasPickedUpBySomeone[weapon] = 0;                               // CLEAR
01019 
01020         for (person=0; person<g_maxclients.integer; person++)
01021         {
01022                 for (weapon = 0; weapon<WP_NUM_WEAPONS; weapon++)
01023                 {
01024                         if (G_WeaponLogPickups[person][weapon]>0)
01025                                 wasPickedUpBySomeone[weapon]++;
01026                 }
01027         }
01028         //------------------------------------------------------ FOR EVERY WEAPON, ADD UP TOTAL PICKUPS
01029 
01030 
01031 
01032 
01033         //------------------------------------------------------ FOR EVERY PERSON, CHECK FOR CANDIDATE
01034         for (person=0; person<g_maxclients.integer; person++)
01035         {
01036                 player = g_entities + person;
01037                 if (!player->inuse)                     continue;
01038 
01039                 nKills = 0;                                                                                     // This Persons's Kills
01040                 for (weapon=0; weapon<WP_NUM_WEAPONS; weapon++)
01041                         killsWithWeapon[weapon] = 0;                                    // CLEAR
01042 
01043                 for (i=0; i<MOD_MAX; i++)
01044                 {
01045                         weapon = weaponFromMOD[i];                                                                      // Select Weapon
01046                         killsWithWeapon[weapon] += G_WeaponLogKills[person][i];         // Store Num Kills With Weapon
01047                 }
01048 
01049                 weapon=WP_STUN_BATON;           // Start At Stun Baton
01050                 //   keep looking through weapons if weapon is not on map, or if it is and we used it
01051                 while( weapon<WP_NUM_WEAPONS && (!wasPickedUpBySomeone[weapon] || killsWithWeapon[weapon]>0) )
01052                 {
01053                         weapon++;
01054                         nKills+=killsWithWeapon[weapon];                                                        //  Update the number of kills
01055                 }
01056                 //
01057                 // At this point we have either successfully gone through every weapon on the map and saw it had
01058                 // been used, or we found one that WAS on the map and was NOT used
01059                 //
01060                 // so we look to see if the weapon==Max (i.e. we used every one) and then we check to see
01061                 // if we got the most kills out of anyone else who did this.
01062                 //
01063                 if (weapon>=WP_NUM_WEAPONS && nKills>nMostKills)
01064                 {
01065                         // WE ARE A TACTICION CANDIDATE
01066                         nMostKills  = nKills;
01067                         nBestPlayer = person;
01068                 }
01069         }
01070         //------------------------------------------------------ FOR EVERY PERSON, CHECK FOR CANDIDATE
01071 
01072         //Now, if we are the best player, return true and the number of kills we got
01073         if (nBestPlayer == ent->s.number)
01074         {
01075                 *kills = nMostKills;
01076                 return qtrue;
01077         }
01078 #endif // LOGGING_WEAPONS
01079         return qfalse;
01080 }
01081 
01082 
01083 
01084 
01085 // did this player earn the demolitionist award?
01086 qboolean CalculateDemolitionist(gentity_t *ent, int *kills)
01087 {
01088 #ifdef LOGGING_WEAPONS
01089         int                     i = 0, nBestPlayer = -1, nKills = 0, nMostKills = 0,
01090                                 playTime = (level.time - ent->client->pers.enterTime)/60000;
01091         gentity_t       *player = NULL;
01092 
01093         for (i = 0; i < g_maxclients.integer; i++)
01094         {
01095                 nKills = 0;
01096                 player = g_entities + i;
01097                 if (!player->inuse)
01098                         continue;
01099 
01100                 nKills = G_WeaponLogKills[i][MOD_THERMAL];
01101                 nKills += G_WeaponLogKills[i][MOD_THERMAL_SPLASH];
01102                 nKills += G_WeaponLogKills[i][MOD_ROCKET];
01103                 nKills += G_WeaponLogKills[i][MOD_ROCKET_SPLASH];
01104                 nKills += G_WeaponLogKills[i][MOD_ROCKET_HOMING];
01105                 nKills += G_WeaponLogKills[i][MOD_ROCKET_HOMING_SPLASH];
01106                 nKills += G_WeaponLogKills[i][MOD_TRIP_MINE_SPLASH];
01107                 nKills += G_WeaponLogKills[i][MOD_TIMED_MINE_SPLASH];
01108                 nKills += G_WeaponLogKills[i][MOD_DET_PACK_SPLASH];
01109 
01110                 // if this guy didn't get two explosive kills per minute, reject him right now
01111                 if ( ((float)nKills)/((float)(playTime)) < 2.0 )
01112                 {
01113                         continue;
01114                 }
01115 
01116                 if (nKills > nMostKills)
01117                 {
01118                         nMostKills = nKills;
01119                         nBestPlayer = i;
01120                 }
01121         }
01122         if (-1 == nBestPlayer)
01123         {
01124                 return qfalse;
01125         }
01126         if (nBestPlayer == ent->s.number)
01127         {
01128                 *kills = nMostKills;
01129                 return qtrue;
01130         }
01131 #endif // LOGGING_WEAPONS
01132         return qfalse;
01133 }
01134 
01135 int CalculateStreak(gentity_t *ent)
01136 {
01137 #if 0
01138         if (ent->client->ps.persistant[PERS_STREAK_COUNT] >= STREAK_CHAMPION)
01139         {
01140                 return STREAK_CHAMPION;
01141         }
01142         if (ent->client->ps.persistant[PERS_STREAK_COUNT] >= STREAK_MASTER)
01143         {
01144                 return STREAK_MASTER;
01145         }
01146         if (ent->client->ps.persistant[PERS_STREAK_COUNT] >= STREAK_EXPERT)
01147         {
01148                 return STREAK_EXPERT;
01149         }
01150         if (ent->client->ps.persistant[PERS_STREAK_COUNT] >= STREAK_ACE)
01151         {
01152                 return STREAK_ACE;
01153         }
01154 #endif
01155         //No streak calculation, at least for now.
01156         return 0;
01157 }
01158 
01159 qboolean CalculateTeamMVP(gentity_t *ent)
01160 {
01161         int                     i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
01162                                 team = ent->client->ps.persistant[PERS_TEAM];
01163         gentity_t       *player = NULL;
01164 
01165         for (i = 0; i < g_maxclients.integer; i++)
01166         {
01167                 nScore = 0;
01168                 player = g_entities + i;
01169                 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
01170                         continue;
01171                 nScore = player->client->ps.persistant[PERS_SCORE];
01172                 if (nScore > nHighestScore)
01173                 {
01174                         nHighestScore = nScore;
01175                         nBestPlayer = i;
01176                 }
01177         }
01178         if (-1 == nBestPlayer)
01179         {
01180                 return qfalse;
01181         }
01182         if (nBestPlayer == ent->s.number)
01183         {
01184                 return qtrue;
01185         }
01186         return qfalse;
01187 }
01188 
01189 qboolean CalculateTeamMVPByRank(gentity_t *ent)
01190 {
01191         int                     i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
01192                                 team = ent->client->ps.persistant[PERS_RANK]+1;
01193         qboolean        bTied = (team == 3);
01194         gentity_t       *player = NULL;
01195 
01196         /*
01197         if ( team == ent->client->ps.persistant[PERS_TEAM] && ent->client->ps.persistant[PERS_CLASS] == PC_BORG )
01198         {//only the queen can be the MVP
01199                 if ( borgQueenClientNum == ent->s.number )
01200                 {
01201                         return qtrue;
01202                 }
01203                 else
01204                 {
01205                         return qfalse;
01206                 }
01207         }
01208         */
01209 
01210         for (i = 0; i < g_maxclients.integer; i++)
01211         {
01212                 nScore = 0;
01213                 player = g_entities + i;
01214                 if (!player->inuse)
01215                         continue;
01216                 if (!bTied)
01217                 {
01218                          if (player->client->ps.persistant[PERS_TEAM] != team)
01219                          {
01220                                  continue;
01221                          }
01222                 }
01223                 nScore = player->client->ps.persistant[PERS_SCORE];
01224                 if (nScore > nHighestScore)
01225                 {
01226                         nHighestScore = nScore;
01227                         nBestPlayer = i;
01228                 }
01229         }
01230         if (-1 == nBestPlayer)
01231         {
01232                 return qfalse;
01233         }
01234         if (nBestPlayer == ent->s.number)
01235         {
01236                 return qtrue;
01237         }
01238         return qfalse;
01239 }
01240 
01241 qboolean CalculateTeamDefender(gentity_t *ent)
01242 {
01243         int                     i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
01244                                 team = ent->client->ps.persistant[PERS_TEAM];
01245         gentity_t       *player = NULL;
01246 
01247         /*
01248         if (CalculateTeamMVP(ent))
01249         {
01250                 return qfalse;
01251         }
01252         */
01253         for (i = 0; i < g_maxclients.integer; i++)
01254         {
01255                 nScore = 0;
01256                 player = g_entities + i;
01257                 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
01258                         continue;
01259                 nScore = player->client->pers.teamState.basedefense;
01260                 if (nScore > nHighestScore)
01261                 {
01262                         nHighestScore = nScore;
01263                         nBestPlayer = i;
01264                 }
01265         }
01266         if (-1 == nBestPlayer)
01267         {
01268                 return qfalse;
01269         }
01270         if (nBestPlayer == ent->s.number)
01271         {
01272                 return qtrue;
01273         }
01274         return qfalse;
01275 }
01276 
01277 qboolean CalculateTeamWarrior(gentity_t *ent)
01278 {
01279         int                     i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
01280                                 team = ent->client->ps.persistant[PERS_TEAM];
01281         gentity_t       *player = NULL;
01282 
01283         /*
01284         if (CalculateTeamMVP(ent) || CalculateTeamDefender(ent))
01285         {
01286                 return qfalse;
01287         }
01288         */
01289         for (i = 0; i < g_maxclients.integer; i++)
01290         {
01291                 nScore = 0;
01292                 player = g_entities + i;
01293                 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
01294                         continue;
01295                 nScore = player->client->ps.persistant[PERS_SCORE];
01296                 if (nScore > nHighestScore)
01297                 {
01298                         nHighestScore = nScore;
01299                         nBestPlayer = i;
01300                 }
01301         }
01302         if (-1 == nBestPlayer)
01303         {
01304                 return qfalse;
01305         }
01306         if (nBestPlayer == ent->s.number)
01307         {
01308                 return qtrue;
01309         }
01310         return qfalse;
01311 }
01312 
01313 qboolean CalculateTeamCarrier(gentity_t *ent)
01314 {
01315         int                     i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
01316                                 team = ent->client->ps.persistant[PERS_TEAM];
01317         gentity_t       *player = NULL;
01318 
01319         /*
01320         if (CalculateTeamMVP(ent) || CalculateTeamDefender(ent) || CalculateTeamWarrior(ent))
01321         {
01322                 return qfalse;
01323         }
01324         */
01325         for (i = 0; i < g_maxclients.integer; i++)
01326         {
01327                 nScore = 0;
01328                 player = g_entities + i;
01329                 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
01330                         continue;
01331                 nScore = player->client->pers.teamState.captures;
01332                 if (nScore > nHighestScore)
01333                 {
01334                         nHighestScore = nScore;
01335                         nBestPlayer = i;
01336                 }
01337         }
01338         if (-1 == nBestPlayer)
01339         {
01340                 return qfalse;
01341         }
01342         if (nBestPlayer == ent->s.number)
01343         {
01344                 return qtrue;
01345         }
01346         return qfalse;
01347 }
01348 
01349 qboolean CalculateTeamInterceptor(gentity_t *ent)
01350 {
01351         int                     i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
01352                                 team = ent->client->ps.persistant[PERS_TEAM];
01353         gentity_t       *player = NULL;
01354 
01355         /*
01356         if (CalculateTeamMVP(ent) || CalculateTeamDefender(ent) || CalculateTeamWarrior(ent) ||
01357                 CalculateTeamCarrier(ent))
01358         {
01359                 return qfalse;
01360         }
01361         */
01362         for (i = 0; i < g_maxclients.integer; i++)
01363         {
01364                 nScore = 0;
01365                 player = g_entities + i;
01366                 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
01367                         continue;
01368                 nScore = player->client->pers.teamState.flagrecovery;
01369                 nScore += player->client->pers.teamState.fragcarrier;
01370                 if (nScore > nHighestScore)
01371                 {
01372                         nHighestScore = nScore;
01373                         nBestPlayer = i;
01374                 }
01375         }
01376         if (-1 == nBestPlayer)
01377         {
01378                 return qfalse;
01379         }
01380         if (nBestPlayer == ent->s.number)
01381         {
01382                 return qtrue;
01383         }
01384         return qfalse;
01385 }
01386 
01387 qboolean CalculateTeamRedShirt(gentity_t *ent)
01388 {
01389         int                     i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
01390                                 team = ent->client->ps.persistant[PERS_TEAM];
01391         gentity_t       *player = NULL;
01392 
01393         /*
01394         if (CalculateTeamMVP(ent) || CalculateTeamDefender(ent) || CalculateTeamWarrior(ent) ||
01395                 CalculateTeamCarrier(ent) || CalculateTeamInterceptor(ent))
01396         {
01397                 return qfalse;
01398         }
01399         */
01400         for (i = 0; i < g_maxclients.integer; i++)
01401         {
01402                 nScore = 0;
01403                 player = g_entities + i;
01404                 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
01405                         continue;
01406                 nScore = player->client->ps.persistant[PERS_KILLED];
01407                 nScore -= player->client->ps.fd.suicides; // suicides don't count, you big cheater.
01408                 if (nScore > nHighestScore)
01409                 {
01410                         nHighestScore = nScore;
01411                         nBestPlayer = i;
01412                 }
01413         }
01414         if (-1 == nBestPlayer)
01415         {
01416                 return qfalse;
01417         }
01418         if (nBestPlayer == ent->s.number)
01419         {
01420                 return qtrue;
01421         }
01422         return qfalse;
01423 }
01424 
01425 typedef enum {
01426         AWARD_EFFICIENCY,               // Accuracy
01427         AWARD_SHARPSHOOTER,             // Most compression rifle frags
01428         AWARD_UNTOUCHABLE,              // Perfect (no deaths)
01429         AWARD_LOGISTICS,                // Most pickups
01430         AWARD_TACTICIAN,                // Kills with all weapons
01431         AWARD_DEMOLITIONIST,    // Most explosive damage kills
01432         AWARD_STREAK,                   // Ace/Expert/Master/Champion
01433         AWARD_TEAM,                             // MVP/Defender/Warrior/Carrier/Interceptor/Bravery
01434         AWARD_SECTION31,                // All-around god
01435         AWARD_MAX
01436 } awardType_t;
01437 
01438 typedef enum
01439 {
01440         TEAM_NONE = 0,                  // ha ha! you suck!
01441         TEAM_MVP,                               // most overall points
01442         TEAM_DEFENDER,                  // killed the most baddies near your flag
01443         TEAM_WARRIOR,                   // most frags
01444         TEAM_CARRIER,                   // infected the most people with plague
01445         TEAM_INTERCEPTOR,               // returned your own flag the most
01446         TEAM_BRAVERY,                   // Red Shirt Award (tm). you died more than anybody. 
01447         TEAM_MAX
01448 } teamAward_e;
01449 
01450 int CalculateTeamAward(gentity_t *ent)
01451 {
01452         int teamAwards = 0;
01453 
01454         if (CalculateTeamMVP(ent))
01455         {
01456                 teamAwards |= (1<<TEAM_MVP);
01457         }
01458         if (GT_CTF == g_gametype.integer ||
01459                 GT_CTY == g_gametype.integer)
01460         {
01461                 if (CalculateTeamDefender(ent))
01462                 {
01463                         teamAwards |= (1<<TEAM_DEFENDER);
01464                 }
01465                 if (CalculateTeamWarrior(ent))
01466                 {
01467                         teamAwards |= (1<<TEAM_WARRIOR);
01468                 }
01469                 if (CalculateTeamCarrier(ent))
01470                 {
01471                         teamAwards |= (1<<TEAM_CARRIER);
01472                 }
01473                 if (CalculateTeamInterceptor(ent))
01474                 {
01475                         teamAwards |= (1<<TEAM_INTERCEPTOR);
01476                 }
01477         }
01478         if ( !teamAwards && CalculateTeamRedShirt(ent) )
01479         {//if you got nothing else and died a lot, at least get bravery
01480                 teamAwards |= (1<<TEAM_BRAVERY);
01481         }
01482         return teamAwards;
01483 }
01484 
01485 qboolean CalculateSection31Award(gentity_t *ent)
01486 {
01487         int                     i = 0, frags = 0, efficiency = 0;
01488         gentity_t       *player = NULL;
01489 
01490         for (i = 0; i < g_maxclients.integer; i++)
01491         {
01492                 player = g_entities + i;
01493                 if (!player->inuse)
01494                         continue;
01495 //
01496 //      kef -- heh.
01497 //
01498 //              if (strcmp("JaxxonPhred", ent->client->pers.netname))
01499 //              {
01500 //                      continue;
01501 //              }
01502                 CalculateEfficiency(ent, &efficiency);
01503                 if (!CalculateSharpshooter(ent, &frags) ||
01504                         !CalculateUntouchable(ent) ||
01505                         /*(CalculateStreak(ent) < STREAK_CHAMPION) ||*/
01506                         (efficiency < 75))
01507                 {
01508                         continue;
01509                 }
01510                 return qtrue;
01511         }
01512         return qfalse;
01513 }
01514 
01515 #define AWARDS_MSG_LENGTH               256
01516 
01517 void CalculateAwards(gentity_t *ent, char *msg)
01518 {
01519 #ifdef LOGGING_WEAPONS
01520         char            buf1[AWARDS_MSG_LENGTH], buf2[AWARDS_MSG_LENGTH];
01521         int                     awardFlags = 0, efficiency = 0, stuffUsed = 0, kills = 0, streak = 0, teamAwards = 0;
01522 
01523         memset(buf1, 0, AWARDS_MSG_LENGTH);
01524         memset(buf2, 0, AWARDS_MSG_LENGTH);
01525         if (CalculateEfficiency(ent, &efficiency))
01526         {
01527                 awardFlags |= (1<<AWARD_EFFICIENCY);
01528                 Com_sprintf(buf1, AWARDS_MSG_LENGTH, " %d", efficiency);
01529         }
01530         if (CalculateSharpshooter(ent, &kills))
01531         {
01532                 awardFlags |= (1<<AWARD_SHARPSHOOTER);
01533                 strcpy(buf2, buf1);
01534                 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, kills);
01535         }
01536         if (CalculateUntouchable(ent))
01537         {
01538                 awardFlags |= (1<<AWARD_UNTOUCHABLE);
01539                 strcpy(buf2, buf1);
01540                 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, 0);
01541         }
01542         if (CalculateLogistics(ent, &stuffUsed))
01543         {
01544                 awardFlags |= (1<<AWARD_LOGISTICS);
01545                 strcpy(buf2, buf1);
01546                 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, stuffUsed);
01547         }
01548         if (CalculateTactician(ent, &kills))
01549         {
01550                 awardFlags |= (1<<AWARD_TACTICIAN);
01551                 strcpy(buf2, buf1);
01552                 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, kills);
01553         }
01554         if (CalculateDemolitionist(ent, &kills))
01555         {
01556                 awardFlags |= (1<<AWARD_DEMOLITIONIST);
01557                 strcpy(buf2, buf1);
01558                 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, kills);
01559         }
01560         streak = CalculateStreak(ent);
01561         if (streak)
01562         {
01563                 awardFlags |= (1<<AWARD_STREAK);
01564                 strcpy(buf2, buf1);
01565                 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, streak);
01566         }
01567         if (g_gametype.integer >= GT_TEAM)
01568         {
01569                 teamAwards = CalculateTeamAward(ent);
01570                 if (teamAwards)
01571                 {
01572                         awardFlags |= (1<<AWARD_TEAM);
01573                         strcpy(buf2, buf1);
01574                         Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, teamAwards);
01575                 }
01576         }
01577         if (CalculateSection31Award(ent))
01578         {
01579                 awardFlags |= (1<<AWARD_SECTION31);
01580                 strcpy(buf2, buf1);
01581                 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, 0);
01582         }
01583         strcpy(buf2, msg);
01584         Com_sprintf( msg, AWARDS_MSG_LENGTH, "%s %d%s", buf2, awardFlags, buf1);
01585 #endif // LOGGING_WEAPONS
01586 }
01587 
01588 int GetMaxDeathsForClient(int nClient)
01589 {
01590         int i = 0, nMostDeaths = 0;
01591 
01592         if ((nClient < 0) || (nClient >= MAX_CLIENTS))
01593         {
01594                 return 0;
01595         }
01596         for (i = 0; i < MAX_CLIENTS; i++)
01597         {
01598                 if (G_WeaponLogFrags[i][nClient] > nMostDeaths)
01599                 {
01600                         nMostDeaths = G_WeaponLogFrags[i][nClient];
01601                 }
01602         }
01603         return nMostDeaths;
01604 }
01605 
01606 int GetMaxKillsForClient(int nClient)
01607 {
01608         int i = 0, nMostKills = 0;
01609 
01610         if ((nClient < 0) || (nClient >= MAX_CLIENTS))
01611         {
01612                 return 0;
01613         }
01614         for (i = 0; i < MAX_CLIENTS; i++)
01615         {
01616                 if (G_WeaponLogFrags[nClient][i] > nMostKills)
01617                 {
01618                         nMostKills = G_WeaponLogFrags[nClient][i];
01619                 }
01620         }
01621         return nMostKills;
01622 }
01623 
01624 int GetFavoriteTargetForClient(int nClient)
01625 {
01626         int i = 0, nMostKills = 0, nFavoriteTarget = -1;
01627 
01628         if ((nClient < 0) || (nClient >= MAX_CLIENTS))
01629         {
01630                 return 0;
01631         }
01632         for (i = 0; i < MAX_CLIENTS; i++)
01633         {
01634                 if (G_WeaponLogFrags[nClient][i] > nMostKills)
01635                 {
01636                         nMostKills = G_WeaponLogFrags[nClient][i];
01637                         nFavoriteTarget = i;
01638                 }
01639         }
01640         return nFavoriteTarget;
01641 }
01642 
01643 int GetWorstEnemyForClient(int nClient)
01644 {
01645         int i = 0, nMostDeaths = 0, nWorstEnemy = -1;
01646 
01647         if ((nClient < 0) || (nClient >= MAX_CLIENTS))
01648         {
01649                 return 0;
01650         }
01651         for (i = 0; i < MAX_CLIENTS; i++)
01652         {
01653                 // If there is a tie for most deaths, we want to choose anybody else
01654                 // over the client...  I.E. Most deaths should not tie with yourself and
01655                 // have yourself show up...
01656 
01657                 if ( G_WeaponLogFrags[i][nClient] > nMostDeaths ||
01658                         (G_WeaponLogFrags[i][nClient]== nMostDeaths && i!=nClient && nMostDeaths!=0) )
01659                 {
01660                         nMostDeaths = G_WeaponLogFrags[i][nClient];
01661                         nWorstEnemy = i;
01662                 }
01663         }
01664         return nWorstEnemy;
01665 }
01666 
01667 int GetFavoriteWeaponForClient(int nClient)
01668 {
01669         int i = 0, nMostKills = 0, fav=0, weapon=WP_STUN_BATON;
01670         int     killsWithWeapon[WP_NUM_WEAPONS];
01671 
01672 
01673         // First thing we need to do is cycle through all the MOD types and convert
01674         // number of kills to a single weapon.
01675         //----------------------------------------------------------------
01676         for (weapon=0; weapon<WP_NUM_WEAPONS; weapon++)
01677                 killsWithWeapon[weapon] = 0;                                    // CLEAR
01678 
01679         for (i=MOD_STUN_BATON; i<=MOD_FORCE_DARK; i++)
01680         {
01681                 weapon = weaponFromMOD[i];                                                                      // Select Weapon
01682 
01683                 if (weapon != WP_NONE)
01684                 {
01685                         killsWithWeapon[weapon] += G_WeaponLogKills[nClient][i];        // Store Num Kills With Weapon
01686                 }
01687         }
01688 
01689         // now look through our list of kills per weapon and pick the biggest
01690         //----------------------------------------------------------------
01691         nMostKills=0;
01692         for (weapon=WP_STUN_BATON; weapon<WP_NUM_WEAPONS; weapon++)
01693         {
01694                 if (killsWithWeapon[weapon]>nMostKills)
01695                 {
01696                         nMostKills = killsWithWeapon[weapon];
01697                         fav = weapon;
01698                 }
01699         }
01700         return fav;
01701 }
01702 
01703 // kef -- if a client leaves the game, clear out all counters he may have set
01704 void QDECL G_ClearClientLog(int client)
01705 {
01706         int i = 0;
01707 
01708         for (i = 0; i < WP_NUM_WEAPONS; i++)
01709         {
01710                 G_WeaponLogPickups[client][i] = 0;
01711         }
01712         for (i = 0; i < WP_NUM_WEAPONS; i++)
01713         {
01714                 G_WeaponLogFired[client][i] = 0;
01715         }
01716         for (i = 0; i < MOD_MAX; i++)
01717         {
01718                 G_WeaponLogDamage[client][i] = 0;
01719         }
01720         for (i = 0; i < MOD_MAX; i++)
01721         {
01722                 G_WeaponLogKills[client][i] = 0;
01723         }
01724         for (i = 0; i < WP_NUM_WEAPONS; i++)
01725         {
01726                 G_WeaponLogDeaths[client][i] = 0;
01727         }
01728         for (i = 0; i < MAX_CLIENTS; i++)
01729         {
01730                 G_WeaponLogFrags[client][i] = 0;
01731         }
01732         for (i = 0; i < MAX_CLIENTS; i++)
01733         {
01734                 G_WeaponLogFrags[i][client] = 0;
01735         }
01736         for (i = 0; i < WP_NUM_WEAPONS; i++)
01737         {
01738                 G_WeaponLogTime[client][i] = 0;
01739         }
01740         G_WeaponLogLastTime[client] = 0;
01741         G_WeaponLogClientTouch[client] = qfalse;
01742         for (i = 0; i < HI_NUM_HOLDABLE; i++)
01743         {
01744                 G_WeaponLogPowerups[client][i] = 0;
01745         }
01746         for (i = 0; i < PW_NUM_POWERUPS; i++)
01747         {
01748                 G_WeaponLogItems[client][i] = 0;
01749         }
01750 }
01751