1 /*
2 ===========================================================================
3 Copyright (C) 2000 - 2013, Raven Software, Inc.
4 Copyright (C) 2001 - 2013, Activision, Inc.
5 Copyright (C) 2013 - 2015, OpenJK contributors
6
7 This file is part of the OpenJK source code.
8
9 OpenJK is free software; you can redistribute it and/or modify it
10 under the terms of the GNU General Public License version 2 as
11 published by the Free Software Foundation.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, see <http://www.gnu.org/licenses/>.
20 ===========================================================================
21 */
22
23 #include "g_local.h"
24
25 #define LOGGING_WEAPONS
26
27 // Weapon statistic logging.
28 // Nothing super-fancy here, I just want to keep track of, per player:
29 // --hom many times a weapon/item is picked up
30 // --how many times a weapon/item is used/fired
31 // --the total damage done by that weapon
32 // --the number of kills by that weapon
33 // --the number of deaths while holding that weapon
34 // --the time spent with each weapon
35 //
36 // Additionally,
37 // --how many times each powerup or item is picked up
38
39
40 #ifdef LOGGING_WEAPONS
41 int G_WeaponLogPickups[MAX_CLIENTS][WP_NUM_WEAPONS];
42 int G_WeaponLogFired[MAX_CLIENTS][WP_NUM_WEAPONS];
43 int G_WeaponLogDamage[MAX_CLIENTS][MOD_MAX];
44 int G_WeaponLogKills[MAX_CLIENTS][MOD_MAX];
45 int G_WeaponLogDeaths[MAX_CLIENTS][WP_NUM_WEAPONS];
46 int G_WeaponLogFrags[MAX_CLIENTS][MAX_CLIENTS];
47 int G_WeaponLogTime[MAX_CLIENTS][WP_NUM_WEAPONS];
48 int G_WeaponLogLastTime[MAX_CLIENTS];
49 qboolean G_WeaponLogClientTouch[MAX_CLIENTS];
50 int G_WeaponLogPowerups[MAX_CLIENTS][HI_NUM_HOLDABLE];
51 int G_WeaponLogItems[MAX_CLIENTS][PW_NUM_POWERUPS];
52
53 // MOD-weapon mapping array.
54 int weaponFromMOD[MOD_MAX] =
55 {
56 WP_NONE, //MOD_UNKNOWN,
57 WP_STUN_BATON, //MOD_STUN_BATON,
58 WP_MELEE, //MOD_MELEE,
59 WP_SABER, //MOD_SABER,
60 WP_BRYAR_PISTOL, //MOD_BRYAR_PISTOL,
61 WP_BRYAR_PISTOL, //MOD_BRYAR_PISTOL_ALT,
62 WP_BLASTER, //MOD_BLASTER,
63 WP_TURRET, //MOD_TURBLAST
64 WP_DISRUPTOR, //MOD_DISRUPTOR,
65 WP_DISRUPTOR, //MOD_DISRUPTOR_SPLASH,
66 WP_DISRUPTOR, //MOD_DISRUPTOR_SNIPER,
67 WP_BOWCASTER, //MOD_BOWCASTER,
68 WP_REPEATER, //MOD_REPEATER,
69 WP_REPEATER, //MOD_REPEATER_ALT,
70 WP_REPEATER, //MOD_REPEATER_ALT_SPLASH,
71 WP_DEMP2, //MOD_DEMP2,
72 WP_DEMP2, //MOD_DEMP2_ALT,
73 WP_FLECHETTE, //MOD_FLECHETTE,
74 WP_FLECHETTE, //MOD_FLECHETTE_ALT_SPLASH,
75 WP_ROCKET_LAUNCHER, //MOD_ROCKET,
76 WP_ROCKET_LAUNCHER, //MOD_ROCKET_SPLASH,
77 WP_ROCKET_LAUNCHER, //MOD_ROCKET_HOMING,
78 WP_ROCKET_LAUNCHER, //MOD_ROCKET_HOMING_SPLASH,
79 WP_THERMAL, //MOD_THERMAL,
80 WP_THERMAL, //MOD_THERMAL_SPLASH,
81 WP_TRIP_MINE, //MOD_TRIP_MINE_SPLASH,
82 WP_TRIP_MINE, //MOD_TIMED_MINE_SPLASH,
83 WP_DET_PACK, //MOD_DET_PACK_SPLASH,
84 WP_NONE, //MOD_FORCE_DARK,
85 WP_NONE, //MOD_SENTRY,
86 WP_NONE, //MOD_WATER,
87 WP_NONE, //MOD_SLIME,
88 WP_NONE, //MOD_LAVA,
89 WP_NONE, //MOD_CRUSH,
90 WP_NONE, //MOD_TELEFRAG,
91 WP_NONE, //MOD_FALLING,
92 WP_NONE, //MOD_SUICIDE,
93 WP_NONE, //MOD_TARGET_LASER,
94 WP_NONE, //MOD_TRIGGER_HURT,
95 };
96
97 char *weaponNameFromIndex[WP_NUM_WEAPONS] =
98 {
99 "No Weapon",
100 "Stun Baton",
101 "Saber",
102 "Bryar Pistol",
103 "Blaster",
104 "Disruptor",
105 "Bowcaster",
106 "Repeater",
107 "Demp2",
108 "Flechette",
109 "Rocket Launcher",
110 "Thermal",
111 "Tripmine",
112 "Detpack",
113 "Emplaced gun",
114 "Turret"
115 };
116
117 extern char *modNames[];
118
119 #endif //LOGGING_WEAPONS
120
121 /*
122 =================
123 G_LogWeaponInit
124 =================
125 */
G_LogWeaponInit(void)126 void G_LogWeaponInit(void) {
127 #ifdef LOGGING_WEAPONS
128 memset(G_WeaponLogPickups, 0, sizeof(G_WeaponLogPickups));
129 memset(G_WeaponLogFired, 0, sizeof(G_WeaponLogFired));
130 memset(G_WeaponLogDamage, 0, sizeof(G_WeaponLogDamage));
131 memset(G_WeaponLogKills, 0, sizeof(G_WeaponLogKills));
132 memset(G_WeaponLogDeaths, 0, sizeof(G_WeaponLogDeaths));
133 memset(G_WeaponLogFrags, 0, sizeof(G_WeaponLogFrags));
134 memset(G_WeaponLogTime, 0, sizeof(G_WeaponLogTime));
135 memset(G_WeaponLogLastTime, 0, sizeof(G_WeaponLogLastTime));
136 memset(G_WeaponLogPowerups, 0, sizeof(G_WeaponLogPowerups));
137 memset(G_WeaponLogItems, 0, sizeof(G_WeaponLogItems));
138 #endif //LOGGING_WEAPONS
139 }
140
G_LogWeaponPickup(int client,int weaponid)141 void QDECL G_LogWeaponPickup(int client, int weaponid)
142 {
143 #ifdef LOGGING_WEAPONS
144 if (client>=MAX_CLIENTS)
145 return;
146
147 G_WeaponLogPickups[client][weaponid]++;
148 G_WeaponLogClientTouch[client] = qtrue;
149 #endif //_LOGGING_WEAPONS
150 }
151
G_LogWeaponFire(int client,int weaponid)152 void QDECL G_LogWeaponFire(int client, int weaponid)
153 {
154 #ifdef LOGGING_WEAPONS
155 int dur;
156
157 if (client>=MAX_CLIENTS)
158 return;
159
160 G_WeaponLogFired[client][weaponid]++;
161 dur = level.time - G_WeaponLogLastTime[client];
162 if (dur > 5000) // 5 second max.
163 G_WeaponLogTime[client][weaponid] += 5000;
164 else
165 G_WeaponLogTime[client][weaponid] += dur;
166 G_WeaponLogLastTime[client] = level.time;
167 G_WeaponLogClientTouch[client] = qtrue;
168 #endif //_LOGGING_WEAPONS
169 }
170
G_LogWeaponDamage(int client,int mod,int amount)171 void QDECL G_LogWeaponDamage(int client, int mod, int amount)
172 {
173 #ifdef LOGGING_WEAPONS
174 if (client>=MAX_CLIENTS)
175 return;
176 G_WeaponLogDamage[client][mod] += amount;
177 G_WeaponLogClientTouch[client] = qtrue;
178 #endif //_LOGGING_WEAPONS
179 }
180
G_LogWeaponKill(int client,int mod)181 void QDECL G_LogWeaponKill(int client, int mod)
182 {
183 #ifdef LOGGING_WEAPONS
184 if (client>=MAX_CLIENTS)
185 return;
186 G_WeaponLogKills[client][mod]++;
187 G_WeaponLogClientTouch[client] = qtrue;
188 #endif //_LOGGING_WEAPONS
189 }
190
G_LogWeaponFrag(int attacker,int deadguy)191 void QDECL G_LogWeaponFrag(int attacker, int deadguy)
192 {
193 #ifdef LOGGING_WEAPONS
194 if ( (attacker>=MAX_CLIENTS) || (deadguy>=MAX_CLIENTS) )
195 return;
196 G_WeaponLogFrags[attacker][deadguy]++;
197 G_WeaponLogClientTouch[attacker] = qtrue;
198 #endif //_LOGGING_WEAPONS
199 }
200
G_LogWeaponDeath(int client,int weaponid)201 void QDECL G_LogWeaponDeath(int client, int weaponid)
202 {
203 #ifdef LOGGING_WEAPONS
204 if (client>=MAX_CLIENTS)
205 return;
206 G_WeaponLogDeaths[client][weaponid]++;
207 G_WeaponLogClientTouch[client] = qtrue;
208 #endif //_LOGGING_WEAPONS
209 }
210
G_LogWeaponPowerup(int client,int powerupid)211 void QDECL G_LogWeaponPowerup(int client, int powerupid)
212 {
213 #ifdef LOGGING_WEAPONS
214 if (client>=MAX_CLIENTS)
215 return;
216 G_WeaponLogPowerups[client][powerupid]++;
217 G_WeaponLogClientTouch[client] = qtrue;
218 #endif //_LOGGING_WEAPONS
219 }
220
G_LogWeaponItem(int client,int itemid)221 void QDECL G_LogWeaponItem(int client, int itemid)
222 {
223 #ifdef LOGGING_WEAPONS
224 if (client>=MAX_CLIENTS)
225 return;
226 G_WeaponLogItems[client][itemid]++;
227 G_WeaponLogClientTouch[client] = qtrue;
228 #endif //_LOGGING_WEAPONS
229 }
230
231
232 // Run through each player. Print out:
233 // -- Most commonly picked up weapon.
234 // -- Weapon with which the most time was spent.
235 // -- Weapon that was most often died with.
236 // -- Damage type with which the most damage was done.
237 // -- Damage type with the most kills.
238 // -- Weapon with which the most damage was done.
239 // -- Weapon with which the most damage was done per shot.
240 //
241 // For the whole game, print out:
242 // -- Total pickups of each weapon.
243 // -- Total time spent with each weapon.
244 // -- Total damage done with each weapon.
245 // -- Total damage done for each damage type.
246 // -- Number of kills with each weapon.
247 // -- Number of kills for each damage type.
248 // -- Damage per shot with each weapon.
249 // -- Number of deaths with each weapon.
250
G_LogWeaponOutput(void)251 void G_LogWeaponOutput(void)
252 {
253 #ifdef LOGGING_WEAPONS
254 int i,j,curwp;
255 float pershot;
256 fileHandle_t weaponfile;
257 char string[1024];
258
259 int totalpickups[WP_NUM_WEAPONS];
260 int totaltime[WP_NUM_WEAPONS];
261 int totaldeaths[WP_NUM_WEAPONS];
262 int totaldamageMOD[MOD_MAX];
263 int totalkillsMOD[MOD_MAX];
264 int totaldamage[WP_NUM_WEAPONS];
265 int totalkills[WP_NUM_WEAPONS];
266 int totalshots[WP_NUM_WEAPONS];
267 int percharacter[WP_NUM_WEAPONS];
268 char info[1024];
269 char mapname[128];
270 char *nameptr, *unknownname="<Unknown>";
271
272 if (!g_statLog.integer)
273 {
274 return;
275 }
276
277 G_LogPrintf("*****************************Weapon Log:\n" );
278
279 memset(totalpickups, 0, sizeof(totalpickups));
280 memset(totaltime, 0, sizeof(totaltime));
281 memset(totaldeaths, 0, sizeof(totaldeaths));
282 memset(totaldamageMOD, 0, sizeof(totaldamageMOD));
283 memset(totalkillsMOD, 0, sizeof(totalkillsMOD));
284 memset(totaldamage, 0, sizeof(totaldamage));
285 memset(totalkills, 0, sizeof(totalkills));
286 memset(totalshots, 0, sizeof(totalshots));
287
288 for (i=0; i<MAX_CLIENTS; i++)
289 {
290 if (G_WeaponLogClientTouch[i])
291 { // Ignore any entity/clients we don't care about!
292 for (j=0;j<WP_NUM_WEAPONS;j++)
293 {
294 totalpickups[j] += G_WeaponLogPickups[i][j];
295 totaltime[j] += G_WeaponLogTime[i][j];
296 totaldeaths[j] += G_WeaponLogDeaths[i][j];
297 totalshots[j] += G_WeaponLogFired[i][j];
298 }
299
300 for (j=0;j<MOD_MAX;j++)
301 {
302 totaldamageMOD[j] += G_WeaponLogDamage[i][j];
303 totalkillsMOD[j] += G_WeaponLogKills[i][j];
304 }
305 }
306 }
307
308 // Now total the weapon data from the MOD data.
309 for (j=0; j<MOD_MAX; j++)
310 {
311 if (j <= MOD_SENTRY)
312 {
313 curwp = weaponFromMOD[j];
314 totaldamage[curwp] += totaldamageMOD[j];
315 totalkills[curwp] += totalkillsMOD[j];
316 }
317 }
318
319 G_LogPrintf( "\n****Data by Weapon:\n" );
320 for (j=0; j<WP_NUM_WEAPONS; j++)
321 {
322 G_LogPrintf("%15s: Pickups: %4d, Time: %5d, Deaths: %5d\n",
323 weaponNameFromIndex[j], totalpickups[j], (int)(totaltime[j]/1000), totaldeaths[j]);
324 }
325
326 G_LogPrintf( "\n****Combat Data by Weapon:\n" );
327 for (j=0; j<WP_NUM_WEAPONS; j++)
328 {
329 if (totalshots[j] > 0)
330 {
331 pershot = (float)(totaldamage[j])/(float)(totalshots[j]);
332 }
333 else
334 {
335 pershot = 0;
336 }
337 G_LogPrintf("%15s: Damage: %6d, Kills: %5d, Dmg per Shot: %f\n",
338 weaponNameFromIndex[j], totaldamage[j], totalkills[j], pershot);
339 }
340
341 G_LogPrintf( "\n****Combat Data By Damage Type:\n" );
342 for (j=0; j<MOD_MAX; j++)
343 {
344 G_LogPrintf("%25s: Damage: %6d, Kills: %5d\n",
345 modNames[j], totaldamageMOD[j], totalkillsMOD[j]);
346 }
347
348 G_LogPrintf("\n");
349
350 // Write the whole weapon statistic log out to a file.
351 trap->FS_Open( g_statLogFile.string, &weaponfile, FS_APPEND );
352 if (!weaponfile) { //failed to open file, let's not crash, shall we?
353 return;
354 }
355
356 // Write out the level name
357 trap->GetServerinfo(info, sizeof(info));
358 Q_strncpyz(mapname, Info_ValueForKey( info, "mapname" ), sizeof(mapname));
359
360 Com_sprintf(string, sizeof(string), "\n\n\nLevel:\t%s\n\n\n", mapname);
361 trap->FS_Write( string, strlen( string ), weaponfile);
362
363
364 // Combat data per character
365
366 // Start with Pickups per character
367 Com_sprintf(string, sizeof(string), "Weapon Pickups per Player:\n\n");
368 trap->FS_Write( string, strlen( string ), weaponfile);
369
370 Com_sprintf(string, sizeof(string), "Player");
371 trap->FS_Write(string, strlen(string), weaponfile);
372
373 for (j=0; j<WP_NUM_WEAPONS; j++)
374 {
375 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
376 trap->FS_Write(string, strlen(string), weaponfile);
377 }
378 Com_sprintf(string, sizeof(string), "\n");
379 trap->FS_Write(string, strlen(string), weaponfile);
380
381 // Cycle through each player, give their name and the number of times they picked up each weapon.
382 for (i=0; i<MAX_CLIENTS; i++)
383 {
384 if (G_WeaponLogClientTouch[i])
385 { // Ignore any entity/clients we don't care about!
386 if ( g_entities[i].client )
387 {
388 nameptr = g_entities[i].client->pers.netname;
389 }
390 else
391 {
392 nameptr = unknownname;
393 }
394 trap->FS_Write(nameptr, strlen(nameptr), weaponfile);
395
396 for (j=0;j<WP_NUM_WEAPONS;j++)
397 {
398 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogPickups[i][j]);
399 trap->FS_Write(string, strlen(string), weaponfile);
400 }
401
402 Com_sprintf(string, sizeof(string), "\n");
403 trap->FS_Write(string, strlen(string), weaponfile);
404 }
405 }
406
407 // Sum up the totals.
408 Com_sprintf(string, sizeof(string), "\n***TOTAL:");
409 trap->FS_Write(string, strlen(string), weaponfile);
410
411 for (j=0;j<WP_NUM_WEAPONS;j++)
412 {
413 Com_sprintf(string, sizeof(string), "\t%d", totalpickups[j]);
414 trap->FS_Write(string, strlen(string), weaponfile);
415 }
416
417 Com_sprintf(string, sizeof(string), "\n\n\n");
418 trap->FS_Write(string, strlen(string), weaponfile);
419
420
421 // Weapon fires per character
422 Com_sprintf(string, sizeof(string), "Weapon Shots per Player:\n\n");
423 trap->FS_Write( string, strlen( string ), weaponfile);
424
425 Com_sprintf(string, sizeof(string), "Player");
426 trap->FS_Write(string, strlen(string), weaponfile);
427
428 for (j=0; j<WP_NUM_WEAPONS; j++)
429 {
430 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
431 trap->FS_Write(string, strlen(string), weaponfile);
432 }
433 Com_sprintf(string, sizeof(string), "\n");
434 trap->FS_Write(string, strlen(string), weaponfile);
435
436 // Cycle through each player, give their name and the number of times they picked up each weapon.
437 for (i=0; i<MAX_CLIENTS; i++)
438 {
439 if (G_WeaponLogClientTouch[i])
440 { // Ignore any entity/clients we don't care about!
441 if ( g_entities[i].client )
442 {
443 nameptr = g_entities[i].client->pers.netname;
444 }
445 else
446 {
447 nameptr = unknownname;
448 }
449 trap->FS_Write(nameptr, strlen(nameptr), weaponfile);
450
451 for (j=0;j<WP_NUM_WEAPONS;j++)
452 {
453 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogFired[i][j]);
454 trap->FS_Write(string, strlen(string), weaponfile);
455 }
456
457 Com_sprintf(string, sizeof(string), "\n");
458 trap->FS_Write(string, strlen(string), weaponfile);
459 }
460 }
461
462 // Sum up the totals.
463 Com_sprintf(string, sizeof(string), "\n***TOTAL:");
464 trap->FS_Write(string, strlen(string), weaponfile);
465
466 for (j=0;j<WP_NUM_WEAPONS;j++)
467 {
468 Com_sprintf(string, sizeof(string), "\t%d", totalshots[j]);
469 trap->FS_Write(string, strlen(string), weaponfile);
470 }
471
472 Com_sprintf(string, sizeof(string), "\n\n\n");
473 trap->FS_Write(string, strlen(string), weaponfile);
474
475
476 // Weapon time per character
477 Com_sprintf(string, sizeof(string), "Weapon Use Time per Player:\n\n");
478 trap->FS_Write( string, strlen( string ), weaponfile);
479
480 Com_sprintf(string, sizeof(string), "Player");
481 trap->FS_Write(string, strlen(string), weaponfile);
482
483 for (j=0; j<WP_NUM_WEAPONS; j++)
484 {
485 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
486 trap->FS_Write(string, strlen(string), weaponfile);
487 }
488 Com_sprintf(string, sizeof(string), "\n");
489 trap->FS_Write(string, strlen(string), weaponfile);
490
491 // Cycle through each player, give their name and the number of times they picked up each weapon.
492 for (i=0; i<MAX_CLIENTS; i++)
493 {
494 if (G_WeaponLogClientTouch[i])
495 { // Ignore any entity/clients we don't care about!
496 if ( g_entities[i].client )
497 {
498 nameptr = g_entities[i].client->pers.netname;
499 }
500 else
501 {
502 nameptr = unknownname;
503 }
504 trap->FS_Write(nameptr, strlen(nameptr), weaponfile);
505
506 for (j=0;j<WP_NUM_WEAPONS;j++)
507 {
508 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogTime[i][j]);
509 trap->FS_Write(string, strlen(string), weaponfile);
510 }
511
512 Com_sprintf(string, sizeof(string), "\n");
513 trap->FS_Write(string, strlen(string), weaponfile);
514 }
515 }
516
517 // Sum up the totals.
518 Com_sprintf(string, sizeof(string), "\n***TOTAL:");
519 trap->FS_Write(string, strlen(string), weaponfile);
520
521 for (j=0;j<WP_NUM_WEAPONS;j++)
522 {
523 Com_sprintf(string, sizeof(string), "\t%d", totaltime[j]);
524 trap->FS_Write(string, strlen(string), weaponfile);
525 }
526
527 Com_sprintf(string, sizeof(string), "\n\n\n");
528 trap->FS_Write(string, strlen(string), weaponfile);
529
530
531
532 // Weapon deaths per character
533 Com_sprintf(string, sizeof(string), "Weapon Deaths per Player:\n\n");
534 trap->FS_Write( string, strlen( string ), weaponfile);
535
536 Com_sprintf(string, sizeof(string), "Player");
537 trap->FS_Write(string, strlen(string), weaponfile);
538
539 for (j=0; j<WP_NUM_WEAPONS; j++)
540 {
541 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
542 trap->FS_Write(string, strlen(string), weaponfile);
543 }
544 Com_sprintf(string, sizeof(string), "\n");
545 trap->FS_Write(string, strlen(string), weaponfile);
546
547 // Cycle through each player, give their name and the number of times they picked up each weapon.
548 for (i=0; i<MAX_CLIENTS; i++)
549 {
550 if (G_WeaponLogClientTouch[i])
551 { // Ignore any entity/clients we don't care about!
552 if ( g_entities[i].client )
553 {
554 nameptr = g_entities[i].client->pers.netname;
555 }
556 else
557 {
558 nameptr = unknownname;
559 }
560 trap->FS_Write(nameptr, strlen(nameptr), weaponfile);
561
562 for (j=0;j<WP_NUM_WEAPONS;j++)
563 {
564 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogDeaths[i][j]);
565 trap->FS_Write(string, strlen(string), weaponfile);
566 }
567
568 Com_sprintf(string, sizeof(string), "\n");
569 trap->FS_Write(string, strlen(string), weaponfile);
570 }
571 }
572
573 // Sum up the totals.
574 Com_sprintf(string, sizeof(string), "\n***TOTAL:");
575 trap->FS_Write(string, strlen(string), weaponfile);
576
577 for (j=0;j<WP_NUM_WEAPONS;j++)
578 {
579 Com_sprintf(string, sizeof(string), "\t%d", totaldeaths[j]);
580 trap->FS_Write(string, strlen(string), weaponfile);
581 }
582
583 Com_sprintf(string, sizeof(string), "\n\n\n");
584 trap->FS_Write(string, strlen(string), weaponfile);
585
586
587
588
589 // Weapon damage per character
590
591 Com_sprintf(string, sizeof(string), "Weapon Damage per Player:\n\n");
592 trap->FS_Write( string, strlen( string ), weaponfile);
593
594 Com_sprintf(string, sizeof(string), "Player");
595 trap->FS_Write(string, strlen(string), weaponfile);
596
597 for (j=0; j<WP_NUM_WEAPONS; j++)
598 {
599 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
600 trap->FS_Write(string, strlen(string), weaponfile);
601 }
602 Com_sprintf(string, sizeof(string), "\n");
603 trap->FS_Write(string, strlen(string), weaponfile);
604
605 // Cycle through each player, give their name and the number of times they picked up each weapon.
606 for (i=0; i<MAX_CLIENTS; i++)
607 {
608 if (G_WeaponLogClientTouch[i])
609 { // Ignore any entity/clients we don't care about!
610
611 // We must grab the totals from the damage types for the player and map them to the weapons.
612 memset(percharacter, 0, sizeof(percharacter));
613 for (j=0; j<MOD_MAX; j++)
614 {
615 if (j <= MOD_SENTRY)
616 {
617 curwp = weaponFromMOD[j];
618 percharacter[curwp] += G_WeaponLogDamage[i][j];
619 }
620 }
621
622 if ( g_entities[i].client )
623 {
624 nameptr = g_entities[i].client->pers.netname;
625 }
626 else
627 {
628 nameptr = unknownname;
629 }
630 trap->FS_Write(nameptr, strlen(nameptr), weaponfile);
631
632 for (j=0;j<WP_NUM_WEAPONS;j++)
633 {
634 Com_sprintf(string, sizeof(string), "\t%d", percharacter[j]);
635 trap->FS_Write(string, strlen(string), weaponfile);
636 }
637
638 Com_sprintf(string, sizeof(string), "\n");
639 trap->FS_Write(string, strlen(string), weaponfile);
640 }
641 }
642
643 // Sum up the totals.
644 Com_sprintf(string, sizeof(string), "\n***TOTAL:");
645 trap->FS_Write(string, strlen(string), weaponfile);
646
647 for (j=0;j<WP_NUM_WEAPONS;j++)
648 {
649 Com_sprintf(string, sizeof(string), "\t%d", totaldamage[j]);
650 trap->FS_Write(string, strlen(string), weaponfile);
651 }
652
653 Com_sprintf(string, sizeof(string), "\n\n\n");
654 trap->FS_Write(string, strlen(string), weaponfile);
655
656
657
658 // Weapon kills per character
659
660 Com_sprintf(string, sizeof(string), "Weapon Kills per Player:\n\n");
661 trap->FS_Write( string, strlen( string ), weaponfile);
662
663 Com_sprintf(string, sizeof(string), "Player");
664 trap->FS_Write(string, strlen(string), weaponfile);
665
666 for (j=0; j<WP_NUM_WEAPONS; j++)
667 {
668 Com_sprintf(string, sizeof(string), "\t%s", weaponNameFromIndex[j]);
669 trap->FS_Write(string, strlen(string), weaponfile);
670 }
671 Com_sprintf(string, sizeof(string), "\n");
672 trap->FS_Write(string, strlen(string), weaponfile);
673
674 // Cycle through each player, give their name and the number of times they picked up each weapon.
675 for (i=0; i<MAX_CLIENTS; i++)
676 {
677 if (G_WeaponLogClientTouch[i])
678 { // Ignore any entity/clients we don't care about!
679
680 // We must grab the totals from the damage types for the player and map them to the weapons.
681 memset(percharacter, 0, sizeof(percharacter));
682 for (j=0; j<MOD_MAX; j++)
683 {
684 if (j <= MOD_SENTRY)
685 {
686 curwp = weaponFromMOD[j];
687 percharacter[curwp] += G_WeaponLogKills[i][j];
688 }
689 }
690
691 if ( g_entities[i].client )
692 {
693 nameptr = g_entities[i].client->pers.netname;
694 }
695 else
696 {
697 nameptr = unknownname;
698 }
699 trap->FS_Write(nameptr, strlen(nameptr), weaponfile);
700
701 for (j=0;j<WP_NUM_WEAPONS;j++)
702 {
703 Com_sprintf(string, sizeof(string), "\t%d", percharacter[j]);
704 trap->FS_Write(string, strlen(string), weaponfile);
705 }
706
707 Com_sprintf(string, sizeof(string), "\n");
708 trap->FS_Write(string, strlen(string), weaponfile);
709 }
710 }
711
712 // Sum up the totals.
713 Com_sprintf(string, sizeof(string), "\n***TOTAL:");
714 trap->FS_Write(string, strlen(string), weaponfile);
715
716 for (j=0;j<WP_NUM_WEAPONS;j++)
717 {
718 Com_sprintf(string, sizeof(string), "\t%d", totalkills[j]);
719 trap->FS_Write(string, strlen(string), weaponfile);
720 }
721
722 Com_sprintf(string, sizeof(string), "\n\n\n");
723 trap->FS_Write(string, strlen(string), weaponfile);
724
725
726
727 // Damage type damage per character
728 Com_sprintf(string, sizeof(string), "Typed Damage per Player:\n\n");
729 trap->FS_Write( string, strlen( string ), weaponfile);
730
731 Com_sprintf(string, sizeof(string), "Player");
732 trap->FS_Write(string, strlen(string), weaponfile);
733
734 for (j=0; j<MOD_MAX; j++)
735 {
736 Com_sprintf(string, sizeof(string), "\t%s", modNames[j]);
737 trap->FS_Write(string, strlen(string), weaponfile);
738 }
739 Com_sprintf(string, sizeof(string), "\n");
740 trap->FS_Write(string, strlen(string), weaponfile);
741
742 // Cycle through each player, give their name and the number of times they picked up each weapon.
743 for (i=0; i<MAX_CLIENTS; i++)
744 {
745 if (G_WeaponLogClientTouch[i])
746 { // Ignore any entity/clients we don't care about!
747 if ( g_entities[i].client )
748 {
749 nameptr = g_entities[i].client->pers.netname;
750 }
751 else
752 {
753 nameptr = unknownname;
754 }
755 trap->FS_Write(nameptr, strlen(nameptr), weaponfile);
756
757 for (j=0;j<MOD_MAX;j++)
758 {
759 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogDamage[i][j]);
760 trap->FS_Write(string, strlen(string), weaponfile);
761 }
762
763 Com_sprintf(string, sizeof(string), "\n");
764 trap->FS_Write(string, strlen(string), weaponfile);
765 }
766 }
767
768 // Sum up the totals.
769 Com_sprintf(string, sizeof(string), "\n***TOTAL:");
770 trap->FS_Write(string, strlen(string), weaponfile);
771
772 for (j=0;j<MOD_MAX;j++)
773 {
774 Com_sprintf(string, sizeof(string), "\t%d", totaldamageMOD[j]);
775 trap->FS_Write(string, strlen(string), weaponfile);
776 }
777
778 Com_sprintf(string, sizeof(string), "\n\n\n");
779 trap->FS_Write(string, strlen(string), weaponfile);
780
781
782
783 // Damage type kills per character
784 Com_sprintf(string, sizeof(string), "Damage-Typed Kills per Player:\n\n");
785 trap->FS_Write( string, strlen( string ), weaponfile);
786
787 Com_sprintf(string, sizeof(string), "Player");
788 trap->FS_Write(string, strlen(string), weaponfile);
789
790 for (j=0; j<MOD_MAX; j++)
791 {
792 Com_sprintf(string, sizeof(string), "\t%s", modNames[j]);
793 trap->FS_Write(string, strlen(string), weaponfile);
794 }
795 Com_sprintf(string, sizeof(string), "\n");
796 trap->FS_Write(string, strlen(string), weaponfile);
797
798 // Cycle through each player, give their name and the number of times they picked up each weapon.
799 for (i=0; i<MAX_CLIENTS; i++)
800 {
801 if (G_WeaponLogClientTouch[i])
802 { // Ignore any entity/clients we don't care about!
803 if ( g_entities[i].client )
804 {
805 nameptr = g_entities[i].client->pers.netname;
806 }
807 else
808 {
809 nameptr = unknownname;
810 }
811 trap->FS_Write(nameptr, strlen(nameptr), weaponfile);
812
813 for (j=0;j<MOD_MAX;j++)
814 {
815 Com_sprintf(string, sizeof(string), "\t%d", G_WeaponLogKills[i][j]);
816 trap->FS_Write(string, strlen(string), weaponfile);
817 }
818
819 Com_sprintf(string, sizeof(string), "\n");
820 trap->FS_Write(string, strlen(string), weaponfile);
821 }
822 }
823
824 // Sum up the totals.
825 Com_sprintf(string, sizeof(string), "\n***TOTAL:");
826 trap->FS_Write(string, strlen(string), weaponfile);
827
828 for (j=0;j<MOD_MAX;j++)
829 {
830 Com_sprintf(string, sizeof(string), "\t%d", totalkillsMOD[j]);
831 trap->FS_Write(string, strlen(string), weaponfile);
832 }
833
834 Com_sprintf(string, sizeof(string), "\n\n\n");
835 trap->FS_Write(string, strlen(string), weaponfile);
836
837
838 trap->FS_Close(weaponfile);
839
840
841 #endif //LOGGING_WEAPONS
842 }
843
844 // did this player earn the efficiency award?
CalculateEfficiency(gentity_t * ent,int * efficiency)845 qboolean CalculateEfficiency(gentity_t *ent, int *efficiency)
846 {
847 #ifdef LOGGING_WEAPONS
848 float fAccuracyRatio = 0, fBestRatio = 0;
849 int i = 0, nShotsFired = 0, nShotsHit = 0, nBestPlayer = -1, tempEff = 0;
850 gentity_t *player = NULL;
851
852
853 for (i = 0; i < sv_maxclients.integer; i++)
854 {
855 player = g_entities + i;
856 if (!player->inuse)
857 continue;
858 nShotsFired = player->client->accuracy_shots; //player->client->ps.persistant[PERS_ACCURACY_SHOTS];
859 nShotsHit = player->client->accuracy_hits; //player->client->ps.persistant[PERS_ACCURACY_HITS];
860 fAccuracyRatio = ( ((float)nShotsHit)/((float)nShotsFired) );
861 if (fAccuracyRatio > fBestRatio)
862 {
863 fBestRatio = fAccuracyRatio;
864 nBestPlayer = i;
865 }
866 }
867 if (-1 == nBestPlayer)
868 {
869 // huh?
870 return qfalse;
871 }
872 if (nBestPlayer == ent->s.number)
873 {
874 tempEff = (int)(100*fBestRatio);
875 if (tempEff > 50)
876 {
877 *efficiency = tempEff;
878 return qtrue;
879 }
880 return qfalse;
881 }
882 #endif // LOGGING_WEAPONS
883 return qfalse;
884 }
885
886 // did this player earn the sharpshooter award?
CalculateSharpshooter(gentity_t * ent,int * frags)887 qboolean CalculateSharpshooter(gentity_t *ent, int *frags)
888 {
889 #ifdef LOGGING_WEAPONS
890 int i = 0, nBestPlayer = -1, nKills = 0, nMostKills = 0,
891 playTime = (level.time - ent->client->pers.enterTime)/60000;
892 gentity_t *player = NULL;
893
894 // if this guy didn't get one kill per minute, reject him right now
895 if ( ((float)(G_WeaponLogKills[ent-g_entities][MOD_DISRUPTOR_SNIPER]))/((float)(playTime)) < 1.0 )
896 {
897 return qfalse;
898 }
899
900 for (i = 0; i < sv_maxclients.integer; i++)
901 {
902 nKills = 0;
903 player = g_entities + i;
904 if (!player->inuse)
905 continue;
906 nKills = G_WeaponLogKills[i][MOD_DISRUPTOR_SNIPER];
907 if (nKills > nMostKills)
908 {
909 nMostKills = nKills;
910 nBestPlayer = i;
911 }
912 }
913 if (-1 == nBestPlayer)
914 {
915 return qfalse;
916 }
917 if (nBestPlayer == ent->s.number)
918 {
919 *frags = nMostKills;
920 return qtrue;
921 }
922 #endif // LOGGING_WEAPONS
923 return qfalse;
924 }
925
926 // did this player earn the untouchable award?
CalculateUntouchable(gentity_t * ent)927 qboolean CalculateUntouchable(gentity_t *ent)
928 {
929 #ifdef LOGGING_WEAPONS
930 int playTime;
931 playTime = (level.time - ent->client->pers.enterTime)/60000;
932
933 if ( level.gametype == GT_JEDIMASTER && ent->client->ps.isJediMaster )
934 {//Jedi Master can only be killed once anyway
935 return qfalse;
936 }
937 //------------------------------------------------------ MUST HAVE ACHIEVED 2 KILLS PER MINUTE
938 if ( ((float)ent->client->ps.persistant[PERS_SCORE])/((float)(playTime)) < 2.0 || playTime==0)
939 return qfalse;
940 //------------------------------------------------------ MUST HAVE ACHIEVED 2 KILLS PER MINUTE
941
942
943 // if this guy was never killed... Award Away!!!
944 if (ent->client->ps.persistant[PERS_KILLED]==0)
945 return qtrue;
946
947 #endif // LOGGING_WEAPONS
948 return qfalse;
949 }
950
951 // did this player earn the logistics award?
CalculateLogistics(gentity_t * ent,int * stuffUsed)952 qboolean CalculateLogistics(gentity_t *ent, int *stuffUsed)
953 {
954 #ifdef LOGGING_WEAPONS
955 int i = 0, j = 0, nBestPlayer = -1, nStuffUsed = 0, nMostStuffUsed = 0,
956 nDifferent = 0, nMostDifferent = 0;
957 gentity_t *player = NULL;
958
959 for (i = 0; i < sv_maxclients.integer; i++)
960 {
961 nStuffUsed = 0;
962 nDifferent = 0;
963 player = g_entities + i;
964 if (!player->inuse)
965 continue;
966 for (j = HI_NONE+1; j < HI_NUM_HOLDABLE; j++)
967 {
968 if (G_WeaponLogPowerups[i][j])
969 {
970 nDifferent++;
971 }
972 nStuffUsed += G_WeaponLogPowerups[i][j];
973 }
974 for (j = PW_NONE+1; j < PW_NUM_POWERUPS; j++)
975 {
976 if (G_WeaponLogItems[i][j])
977 {
978 nDifferent++;
979 }
980 nStuffUsed += G_WeaponLogItems[i][j];
981 }
982 if ( (nDifferent >= 4) && (nDifferent >= nMostDifferent) )
983 {
984 if (nStuffUsed > nMostStuffUsed)
985 {
986 nMostDifferent = nDifferent;
987 nMostStuffUsed = nStuffUsed;
988 nBestPlayer = i;
989 }
990 }
991 }
992 if (-1 == nBestPlayer)
993 {
994 return qfalse;
995 }
996 if (nBestPlayer == ent->s.number)
997 {
998 *stuffUsed = nMostDifferent;
999 return qtrue;
1000 }
1001 #endif // LOGGING_WEAPONS
1002 return qfalse;
1003 }
1004
1005
1006
1007
1008 // did this player earn the tactician award?
CalculateTactician(gentity_t * ent,int * kills)1009 qboolean CalculateTactician(gentity_t *ent, int *kills)
1010 {
1011 #ifdef LOGGING_WEAPONS
1012 int i = 0, nBestPlayer = -1, nKills = 0, nMostKills = 0;
1013 int person = 0, weapon = 0;
1014 gentity_t *player = NULL;
1015 int wasPickedUpBySomeone[WP_NUM_WEAPONS];
1016 int killsWithWeapon[WP_NUM_WEAPONS];
1017 int playTime = (level.time - ent->client->pers.enterTime)/60000;
1018
1019 if ( HasSetSaberOnly() )
1020 {//duh, only 1 weapon
1021 return qfalse;
1022 }
1023 if ( level.gametype == GT_JEDIMASTER && ent->client->ps.isJediMaster )
1024 {//Jedi Master has only 1 weapon
1025 return qfalse;
1026 }
1027 //------------------------------------------------------ MUST HAVE ACHIEVED 2 KILLS PER MINUTE
1028 if (playTime<0.3)
1029 return qfalse;
1030
1031 if ( ((float)ent->client->ps.persistant[PERS_SCORE])/((float)(playTime)) < 2.0 )
1032 return qfalse;
1033 //------------------------------------------------------ MUST HAVE ACHIEVED 2 KILLS PER MINUTE
1034
1035
1036
1037
1038 //------------------------------------------------------ FOR EVERY WEAPON, ADD UP TOTAL PICKUPS
1039 for (weapon = 0; weapon<WP_NUM_WEAPONS; weapon++)
1040 wasPickedUpBySomeone[weapon] = 0; // CLEAR
1041
1042 for (person=0; person<sv_maxclients.integer; person++)
1043 {
1044 for (weapon = 0; weapon<WP_NUM_WEAPONS; weapon++)
1045 {
1046 if (G_WeaponLogPickups[person][weapon]>0)
1047 wasPickedUpBySomeone[weapon]++;
1048 }
1049 }
1050 //------------------------------------------------------ FOR EVERY WEAPON, ADD UP TOTAL PICKUPS
1051
1052
1053
1054
1055 //------------------------------------------------------ FOR EVERY PERSON, CHECK FOR CANDIDATE
1056 for (person=0; person<sv_maxclients.integer; person++)
1057 {
1058 player = g_entities + person;
1059 if (!player->inuse) continue;
1060
1061 nKills = 0; // This Persons's Kills
1062 for (weapon=0; weapon<WP_NUM_WEAPONS; weapon++)
1063 killsWithWeapon[weapon] = 0; // CLEAR
1064
1065 for (i=0; i<MOD_MAX; i++)
1066 {
1067 weapon = weaponFromMOD[i]; // Select Weapon
1068 killsWithWeapon[weapon] += G_WeaponLogKills[person][i]; // Store Num Kills With Weapon
1069 }
1070
1071 weapon=WP_STUN_BATON; // Start At Stun Baton
1072 // keep looking through weapons if weapon is not on map, or if it is and we used it
1073 while( weapon<WP_NUM_WEAPONS && (!wasPickedUpBySomeone[weapon] || killsWithWeapon[weapon]>0) )
1074 {
1075 weapon++;
1076 nKills+=killsWithWeapon[weapon]; // Update the number of kills
1077 }
1078 //
1079 // At this point we have either successfully gone through every weapon on the map and saw it had
1080 // been used, or we found one that WAS on the map and was NOT used
1081 //
1082 // so we look to see if the weapon==Max (i.e. we used every one) and then we check to see
1083 // if we got the most kills out of anyone else who did this.
1084 //
1085 if (weapon>=WP_NUM_WEAPONS && nKills>nMostKills)
1086 {
1087 // WE ARE A TACTICION CANDIDATE
1088 nMostKills = nKills;
1089 nBestPlayer = person;
1090 }
1091 }
1092 //------------------------------------------------------ FOR EVERY PERSON, CHECK FOR CANDIDATE
1093
1094 //Now, if we are the best player, return true and the number of kills we got
1095 if (nBestPlayer == ent->s.number)
1096 {
1097 *kills = nMostKills;
1098 return qtrue;
1099 }
1100 #endif // LOGGING_WEAPONS
1101 return qfalse;
1102 }
1103
1104
1105
1106
1107 // did this player earn the demolitionist award?
CalculateDemolitionist(gentity_t * ent,int * kills)1108 qboolean CalculateDemolitionist(gentity_t *ent, int *kills)
1109 {
1110 #ifdef LOGGING_WEAPONS
1111 int i = 0, nBestPlayer = -1, nKills = 0, nMostKills = 0,
1112 playTime = (level.time - ent->client->pers.enterTime)/60000;
1113 gentity_t *player = NULL;
1114
1115 for (i = 0; i < sv_maxclients.integer; i++)
1116 {
1117 nKills = 0;
1118 player = g_entities + i;
1119 if (!player->inuse)
1120 continue;
1121
1122 nKills = G_WeaponLogKills[i][MOD_THERMAL];
1123 nKills += G_WeaponLogKills[i][MOD_THERMAL_SPLASH];
1124 nKills += G_WeaponLogKills[i][MOD_ROCKET];
1125 nKills += G_WeaponLogKills[i][MOD_ROCKET_SPLASH];
1126 nKills += G_WeaponLogKills[i][MOD_ROCKET_HOMING];
1127 nKills += G_WeaponLogKills[i][MOD_ROCKET_HOMING_SPLASH];
1128 nKills += G_WeaponLogKills[i][MOD_TRIP_MINE_SPLASH];
1129 nKills += G_WeaponLogKills[i][MOD_TIMED_MINE_SPLASH];
1130 nKills += G_WeaponLogKills[i][MOD_DET_PACK_SPLASH];
1131
1132 // if this guy didn't get two explosive kills per minute, reject him right now
1133 if ( ((float)nKills)/((float)(playTime)) < 2.0 )
1134 {
1135 continue;
1136 }
1137
1138 if (nKills > nMostKills)
1139 {
1140 nMostKills = nKills;
1141 nBestPlayer = i;
1142 }
1143 }
1144 if (-1 == nBestPlayer)
1145 {
1146 return qfalse;
1147 }
1148 if (nBestPlayer == ent->s.number)
1149 {
1150 *kills = nMostKills;
1151 return qtrue;
1152 }
1153 #endif // LOGGING_WEAPONS
1154 return qfalse;
1155 }
1156
CalculateStreak(gentity_t * ent)1157 int CalculateStreak(gentity_t *ent)
1158 {
1159 #if 0
1160 if (ent->client->ps.persistant[PERS_STREAK_COUNT] >= STREAK_CHAMPION)
1161 {
1162 return STREAK_CHAMPION;
1163 }
1164 if (ent->client->ps.persistant[PERS_STREAK_COUNT] >= STREAK_MASTER)
1165 {
1166 return STREAK_MASTER;
1167 }
1168 if (ent->client->ps.persistant[PERS_STREAK_COUNT] >= STREAK_EXPERT)
1169 {
1170 return STREAK_EXPERT;
1171 }
1172 if (ent->client->ps.persistant[PERS_STREAK_COUNT] >= STREAK_ACE)
1173 {
1174 return STREAK_ACE;
1175 }
1176 #endif
1177 //No streak calculation, at least for now.
1178 return 0;
1179 }
1180
CalculateTeamMVP(gentity_t * ent)1181 qboolean CalculateTeamMVP(gentity_t *ent)
1182 {
1183 int i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
1184 team = ent->client->ps.persistant[PERS_TEAM];
1185 gentity_t *player = NULL;
1186
1187 for (i = 0; i < sv_maxclients.integer; i++)
1188 {
1189 nScore = 0;
1190 player = g_entities + i;
1191 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
1192 continue;
1193 nScore = player->client->ps.persistant[PERS_SCORE];
1194 if (nScore > nHighestScore)
1195 {
1196 nHighestScore = nScore;
1197 nBestPlayer = i;
1198 }
1199 }
1200 if (-1 == nBestPlayer)
1201 {
1202 return qfalse;
1203 }
1204 if (nBestPlayer == ent->s.number)
1205 {
1206 return qtrue;
1207 }
1208 return qfalse;
1209 }
1210
CalculateTeamDefender(gentity_t * ent)1211 qboolean CalculateTeamDefender(gentity_t *ent)
1212 {
1213 int i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
1214 team = ent->client->ps.persistant[PERS_TEAM];
1215 gentity_t *player = NULL;
1216
1217 /*
1218 if (CalculateTeamMVP(ent))
1219 {
1220 return qfalse;
1221 }
1222 */
1223 for (i = 0; i < sv_maxclients.integer; i++)
1224 {
1225 nScore = 0;
1226 player = g_entities + i;
1227 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
1228 continue;
1229 nScore = player->client->pers.teamState.basedefense;
1230 if (nScore > nHighestScore)
1231 {
1232 nHighestScore = nScore;
1233 nBestPlayer = i;
1234 }
1235 }
1236 if (-1 == nBestPlayer)
1237 {
1238 return qfalse;
1239 }
1240 if (nBestPlayer == ent->s.number)
1241 {
1242 return qtrue;
1243 }
1244 return qfalse;
1245 }
1246
CalculateTeamWarrior(gentity_t * ent)1247 qboolean CalculateTeamWarrior(gentity_t *ent)
1248 {
1249 int i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
1250 team = ent->client->ps.persistant[PERS_TEAM];
1251 gentity_t *player = NULL;
1252
1253 /*
1254 if (CalculateTeamMVP(ent) || CalculateTeamDefender(ent))
1255 {
1256 return qfalse;
1257 }
1258 */
1259 for (i = 0; i < sv_maxclients.integer; i++)
1260 {
1261 nScore = 0;
1262 player = g_entities + i;
1263 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
1264 continue;
1265 nScore = player->client->ps.persistant[PERS_SCORE];
1266 if (nScore > nHighestScore)
1267 {
1268 nHighestScore = nScore;
1269 nBestPlayer = i;
1270 }
1271 }
1272 if (-1 == nBestPlayer)
1273 {
1274 return qfalse;
1275 }
1276 if (nBestPlayer == ent->s.number)
1277 {
1278 return qtrue;
1279 }
1280 return qfalse;
1281 }
1282
CalculateTeamCarrier(gentity_t * ent)1283 qboolean CalculateTeamCarrier(gentity_t *ent)
1284 {
1285 int i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
1286 team = ent->client->ps.persistant[PERS_TEAM];
1287 gentity_t *player = NULL;
1288
1289 /*
1290 if (CalculateTeamMVP(ent) || CalculateTeamDefender(ent) || CalculateTeamWarrior(ent))
1291 {
1292 return qfalse;
1293 }
1294 */
1295 for (i = 0; i < sv_maxclients.integer; i++)
1296 {
1297 nScore = 0;
1298 player = g_entities + i;
1299 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
1300 continue;
1301 nScore = player->client->pers.teamState.captures;
1302 if (nScore > nHighestScore)
1303 {
1304 nHighestScore = nScore;
1305 nBestPlayer = i;
1306 }
1307 }
1308 if (-1 == nBestPlayer)
1309 {
1310 return qfalse;
1311 }
1312 if (nBestPlayer == ent->s.number)
1313 {
1314 return qtrue;
1315 }
1316 return qfalse;
1317 }
1318
CalculateTeamInterceptor(gentity_t * ent)1319 qboolean CalculateTeamInterceptor(gentity_t *ent)
1320 {
1321 int i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
1322 team = ent->client->ps.persistant[PERS_TEAM];
1323 gentity_t *player = NULL;
1324
1325 /*
1326 if (CalculateTeamMVP(ent) || CalculateTeamDefender(ent) || CalculateTeamWarrior(ent) ||
1327 CalculateTeamCarrier(ent))
1328 {
1329 return qfalse;
1330 }
1331 */
1332 for (i = 0; i < sv_maxclients.integer; i++)
1333 {
1334 nScore = 0;
1335 player = g_entities + i;
1336 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
1337 continue;
1338 nScore = player->client->pers.teamState.flagrecovery;
1339 nScore += player->client->pers.teamState.fragcarrier;
1340 if (nScore > nHighestScore)
1341 {
1342 nHighestScore = nScore;
1343 nBestPlayer = i;
1344 }
1345 }
1346 if (-1 == nBestPlayer)
1347 {
1348 return qfalse;
1349 }
1350 if (nBestPlayer == ent->s.number)
1351 {
1352 return qtrue;
1353 }
1354 return qfalse;
1355 }
1356
CalculateTeamRedShirt(gentity_t * ent)1357 qboolean CalculateTeamRedShirt(gentity_t *ent)
1358 {
1359 int i = 0, nBestPlayer = -1, nScore = 0, nHighestScore = 0,
1360 team = ent->client->ps.persistant[PERS_TEAM];
1361 gentity_t *player = NULL;
1362
1363 /*
1364 if (CalculateTeamMVP(ent) || CalculateTeamDefender(ent) || CalculateTeamWarrior(ent) ||
1365 CalculateTeamCarrier(ent) || CalculateTeamInterceptor(ent))
1366 {
1367 return qfalse;
1368 }
1369 */
1370 for (i = 0; i < sv_maxclients.integer; i++)
1371 {
1372 nScore = 0;
1373 player = g_entities + i;
1374 if (!player->inuse || (player->client->ps.persistant[PERS_TEAM] != team))
1375 continue;
1376 nScore = player->client->ps.persistant[PERS_KILLED];
1377 nScore -= player->client->ps.fd.suicides; // suicides don't count, you big cheater.
1378 if (nScore > nHighestScore)
1379 {
1380 nHighestScore = nScore;
1381 nBestPlayer = i;
1382 }
1383 }
1384 if (-1 == nBestPlayer)
1385 {
1386 return qfalse;
1387 }
1388 if (nBestPlayer == ent->s.number)
1389 {
1390 return qtrue;
1391 }
1392 return qfalse;
1393 }
1394
1395 typedef enum {
1396 AWARD_EFFICIENCY, // Accuracy
1397 AWARD_SHARPSHOOTER, // Most compression rifle frags
1398 AWARD_UNTOUCHABLE, // Perfect (no deaths)
1399 AWARD_LOGISTICS, // Most pickups
1400 AWARD_TACTICIAN, // Kills with all weapons
1401 AWARD_DEMOLITIONIST, // Most explosive damage kills
1402 AWARD_STREAK, // Ace/Expert/Master/Champion
1403 AWARD_TEAM, // MVP/Defender/Warrior/Carrier/Interceptor/Bravery
1404 AWARD_SECTION31, // All-around god
1405 AWARD_MAX
1406 } awardType_t;
1407
1408 typedef enum
1409 {
1410 TEAM_NONE = 0, // ha ha! you suck!
1411 TEAM_MVP, // most overall points
1412 TEAM_DEFENDER, // killed the most baddies near your flag
1413 TEAM_WARRIOR, // most frags
1414 TEAM_CARRIER, // infected the most people with plague
1415 TEAM_INTERCEPTOR, // returned your own flag the most
1416 TEAM_BRAVERY, // Red Shirt Award (tm). you died more than anybody.
1417 TEAM_MAX
1418 } teamAward_e;
1419
CalculateTeamAward(gentity_t * ent)1420 int CalculateTeamAward(gentity_t *ent)
1421 {
1422 int teamAwards = 0;
1423
1424 if (CalculateTeamMVP(ent))
1425 {
1426 teamAwards |= (1<<TEAM_MVP);
1427 }
1428 if (GT_CTF == level.gametype ||
1429 GT_CTY == level.gametype)
1430 {
1431 if (CalculateTeamDefender(ent))
1432 {
1433 teamAwards |= (1<<TEAM_DEFENDER);
1434 }
1435 if (CalculateTeamWarrior(ent))
1436 {
1437 teamAwards |= (1<<TEAM_WARRIOR);
1438 }
1439 if (CalculateTeamCarrier(ent))
1440 {
1441 teamAwards |= (1<<TEAM_CARRIER);
1442 }
1443 if (CalculateTeamInterceptor(ent))
1444 {
1445 teamAwards |= (1<<TEAM_INTERCEPTOR);
1446 }
1447 }
1448 if ( !teamAwards && CalculateTeamRedShirt(ent) )
1449 {//if you got nothing else and died a lot, at least get bravery
1450 teamAwards |= (1<<TEAM_BRAVERY);
1451 }
1452 return teamAwards;
1453 }
1454
CalculateSection31Award(gentity_t * ent)1455 qboolean CalculateSection31Award(gentity_t *ent)
1456 {
1457 int i = 0, frags = 0, efficiency = 0;
1458 gentity_t *player = NULL;
1459
1460 for (i = 0; i < sv_maxclients.integer; i++)
1461 {
1462 player = g_entities + i;
1463 if (!player->inuse)
1464 continue;
1465 //
1466 // kef -- heh.
1467 //
1468 // if (strcmp("JaxxonPhred", ent->client->pers.netname))
1469 // {
1470 // continue;
1471 // }
1472 CalculateEfficiency(ent, &efficiency);
1473 if (!CalculateSharpshooter(ent, &frags) ||
1474 !CalculateUntouchable(ent) ||
1475 /*(CalculateStreak(ent) < STREAK_CHAMPION) ||*/
1476 (efficiency < 75))
1477 {
1478 continue;
1479 }
1480 return qtrue;
1481 }
1482 return qfalse;
1483 }
1484
1485 #if 0
1486
1487 #define AWARDS_MSG_LENGTH 256
1488
1489 void CalculateAwards(gentity_t *ent, char *msg)
1490 {
1491 #ifdef LOGGING_WEAPONS
1492 char buf1[AWARDS_MSG_LENGTH], buf2[AWARDS_MSG_LENGTH];
1493 int awardFlags = 0, efficiency = 0, stuffUsed = 0, kills = 0, streak = 0, teamAwards = 0;
1494
1495 memset(buf1, 0, AWARDS_MSG_LENGTH);
1496 memset(buf2, 0, AWARDS_MSG_LENGTH);
1497 if (CalculateEfficiency(ent, &efficiency))
1498 {
1499 awardFlags |= (1<<AWARD_EFFICIENCY);
1500 Com_sprintf(buf1, AWARDS_MSG_LENGTH, " %d", efficiency);
1501 }
1502 if (CalculateSharpshooter(ent, &kills))
1503 {
1504 awardFlags |= (1<<AWARD_SHARPSHOOTER);
1505 strcpy(buf2, buf1);
1506 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, kills);
1507 }
1508 if (CalculateUntouchable(ent))
1509 {
1510 awardFlags |= (1<<AWARD_UNTOUCHABLE);
1511 strcpy(buf2, buf1);
1512 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, 0);
1513 }
1514 if (CalculateLogistics(ent, &stuffUsed))
1515 {
1516 awardFlags |= (1<<AWARD_LOGISTICS);
1517 strcpy(buf2, buf1);
1518 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, stuffUsed);
1519 }
1520 if (CalculateTactician(ent, &kills))
1521 {
1522 awardFlags |= (1<<AWARD_TACTICIAN);
1523 strcpy(buf2, buf1);
1524 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, kills);
1525 }
1526 if (CalculateDemolitionist(ent, &kills))
1527 {
1528 awardFlags |= (1<<AWARD_DEMOLITIONIST);
1529 strcpy(buf2, buf1);
1530 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, kills);
1531 }
1532 streak = CalculateStreak(ent);
1533 if (streak)
1534 {
1535 awardFlags |= (1<<AWARD_STREAK);
1536 strcpy(buf2, buf1);
1537 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, streak);
1538 }
1539 if (level.gametype >= GT_TEAM)
1540 {
1541 teamAwards = CalculateTeamAward(ent);
1542 if (teamAwards)
1543 {
1544 awardFlags |= (1<<AWARD_TEAM);
1545 strcpy(buf2, buf1);
1546 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, teamAwards);
1547 }
1548 }
1549 if (CalculateSection31Award(ent))
1550 {
1551 awardFlags |= (1<<AWARD_SECTION31);
1552 strcpy(buf2, buf1);
1553 Com_sprintf(buf1, AWARDS_MSG_LENGTH, "%s %d", buf2, 0);
1554 }
1555 Q_strncpyz( buf2, msg, sizeof( buf2 ) );
1556 Com_sprintf( msg, AWARDS_MSG_LENGTH, "%s %d%s", buf2, awardFlags, buf1);
1557 #endif // LOGGING_WEAPONS
1558 }
1559
1560 int GetMaxDeathsForClient(int nClient)
1561 {
1562 int i = 0, nMostDeaths = 0;
1563
1564 if ((nClient < 0) || (nClient >= MAX_CLIENTS))
1565 {
1566 return 0;
1567 }
1568 for (i = 0; i < MAX_CLIENTS; i++)
1569 {
1570 if (G_WeaponLogFrags[i][nClient] > nMostDeaths)
1571 {
1572 nMostDeaths = G_WeaponLogFrags[i][nClient];
1573 }
1574 }
1575 return nMostDeaths;
1576 }
1577
1578 int GetMaxKillsForClient(int nClient)
1579 {
1580 int i = 0, nMostKills = 0;
1581
1582 if ((nClient < 0) || (nClient >= MAX_CLIENTS))
1583 {
1584 return 0;
1585 }
1586 for (i = 0; i < MAX_CLIENTS; i++)
1587 {
1588 if (G_WeaponLogFrags[nClient][i] > nMostKills)
1589 {
1590 nMostKills = G_WeaponLogFrags[nClient][i];
1591 }
1592 }
1593 return nMostKills;
1594 }
1595
1596 int GetFavoriteTargetForClient(int nClient)
1597 {
1598 int i = 0, nMostKills = 0, nFavoriteTarget = -1;
1599
1600 if ((nClient < 0) || (nClient >= MAX_CLIENTS))
1601 {
1602 return 0;
1603 }
1604 for (i = 0; i < MAX_CLIENTS; i++)
1605 {
1606 if (G_WeaponLogFrags[nClient][i] > nMostKills)
1607 {
1608 nMostKills = G_WeaponLogFrags[nClient][i];
1609 nFavoriteTarget = i;
1610 }
1611 }
1612 return nFavoriteTarget;
1613 }
1614
1615 int GetWorstEnemyForClient(int nClient)
1616 {
1617 int i = 0, nMostDeaths = 0, nWorstEnemy = -1;
1618
1619 if ((nClient < 0) || (nClient >= MAX_CLIENTS))
1620 {
1621 return 0;
1622 }
1623 for (i = 0; i < MAX_CLIENTS; i++)
1624 {
1625 // If there is a tie for most deaths, we want to choose anybody else
1626 // over the client... I.E. Most deaths should not tie with yourself and
1627 // have yourself show up...
1628
1629 if ( G_WeaponLogFrags[i][nClient] > nMostDeaths ||
1630 (G_WeaponLogFrags[i][nClient]== nMostDeaths && i!=nClient && nMostDeaths!=0) )
1631 {
1632 nMostDeaths = G_WeaponLogFrags[i][nClient];
1633 nWorstEnemy = i;
1634 }
1635 }
1636 return nWorstEnemy;
1637 }
1638
1639 int GetFavoriteWeaponForClient(int nClient)
1640 {
1641 int i = 0, nMostKills = 0, fav=0, weapon=WP_STUN_BATON;
1642 int killsWithWeapon[WP_NUM_WEAPONS];
1643
1644
1645 // First thing we need to do is cycle through all the MOD types and convert
1646 // number of kills to a single weapon.
1647 //----------------------------------------------------------------
1648 for (weapon=0; weapon<WP_NUM_WEAPONS; weapon++)
1649 killsWithWeapon[weapon] = 0; // CLEAR
1650
1651 for (i=MOD_STUN_BATON; i<=MOD_FORCE_DARK; i++)
1652 {
1653 weapon = weaponFromMOD[i]; // Select Weapon
1654
1655 if (weapon != WP_NONE)
1656 {
1657 killsWithWeapon[weapon] += G_WeaponLogKills[nClient][i]; // Store Num Kills With Weapon
1658 }
1659 }
1660
1661 // now look through our list of kills per weapon and pick the biggest
1662 //----------------------------------------------------------------
1663 nMostKills=0;
1664 for (weapon=WP_STUN_BATON; weapon<WP_NUM_WEAPONS; weapon++)
1665 {
1666 if (killsWithWeapon[weapon]>nMostKills)
1667 {
1668 nMostKills = killsWithWeapon[weapon];
1669 fav = weapon;
1670 }
1671 }
1672 return fav;
1673 }
1674 #endif
1675
1676 // kef -- if a client leaves the game, clear out all counters he may have set
G_ClearClientLog(int client)1677 void QDECL G_ClearClientLog(int client)
1678 {
1679 int i = 0;
1680
1681 for (i = 0; i < WP_NUM_WEAPONS; i++)
1682 {
1683 G_WeaponLogPickups[client][i] = 0;
1684 }
1685 for (i = 0; i < WP_NUM_WEAPONS; i++)
1686 {
1687 G_WeaponLogFired[client][i] = 0;
1688 }
1689 for (i = 0; i < MOD_MAX; i++)
1690 {
1691 G_WeaponLogDamage[client][i] = 0;
1692 }
1693 for (i = 0; i < MOD_MAX; i++)
1694 {
1695 G_WeaponLogKills[client][i] = 0;
1696 }
1697 for (i = 0; i < WP_NUM_WEAPONS; i++)
1698 {
1699 G_WeaponLogDeaths[client][i] = 0;
1700 }
1701 for (i = 0; i < MAX_CLIENTS; i++)
1702 {
1703 G_WeaponLogFrags[client][i] = 0;
1704 }
1705 for (i = 0; i < MAX_CLIENTS; i++)
1706 {
1707 G_WeaponLogFrags[i][client] = 0;
1708 }
1709 for (i = 0; i < WP_NUM_WEAPONS; i++)
1710 {
1711 G_WeaponLogTime[client][i] = 0;
1712 }
1713 G_WeaponLogLastTime[client] = 0;
1714 G_WeaponLogClientTouch[client] = qfalse;
1715 for (i = 0; i < HI_NUM_HOLDABLE; i++)
1716 {
1717 G_WeaponLogPowerups[client][i] = 0;
1718 }
1719 for (i = 0; i < PW_NUM_POWERUPS; i++)
1720 {
1721 G_WeaponLogItems[client][i] = 0;
1722 }
1723 }
1724
1725