Hi All, I don’t know if some players didn’t never remarks that the weapons statistics are sometime wrong, and also ur kills stats too so mangled. After looking what append in the code, I find it!
Well in the string sent to clients, a 32bits field is used to indicate which weapons have stats. But ET have more than 32 weapons. I have modified that and i provide u the new version of stats subroutine.
It can support 128 weapons… To find what is modified and to understand more, search in all files the term “weaponmask”
Regards.
<PRE>
cg_servercmds.c
// Cached stats
void CG_parseWeaponStatsGS_cmd(void)
{
clientInfo_t* ci;
gameStats_t* gs = &cgs.gamestats;
int i;
int iArg = 1;
int nClientID;
int nRounds;
unsigned int weaponMask[4];
int skillMask;
int xp = 0;
nClientID = atoi(CG_Argv(iArg++));
nRounds = atoi(CG_Argv(iArg++));
weaponMask[0] = atoi(CG_Argv(iArg++));
weaponMask[1] = atoi(CG_Argv(iArg++));
weaponMask[2] = atoi(CG_Argv(iArg++));
weaponMask[3] = atoi(CG_Argv(iArg++));
gs->cWeapons = 0;
gs->cSkills = 0;
gs->fHasStats = qfalse;
gs->nClientID = nClientID;
gs->nRounds = nRounds;
ci = &cgs.clientinfo[nClientID];
// Q_strncpyz(strName, ci->name, sizeof(strName));
// BG_cleanName(cgs.clientinfo[gs->nClientID].name, strName, sizeof(strName), qfalse);
if ((weaponMask[0] + weaponMask[1] + weaponMask[2] + weaponMask[3]))
{
char strName[MAX_STRING_CHARS];
for (i = WS_KNIFE; i < WS_MAX; i++)
{
if (weaponMask[i/32] & (1 << (i%32)))
{
int nHits = atoi(CG_Argv(iArg++));
int nShots = atoi(CG_Argv(iArg++));
int nKills = atoi(CG_Argv(iArg++));
int nDeaths = atoi(CG_Argv(iArg++));
int nHeadshots = atoi(CG_Argv(iArg++));
Q_strncpyz(strName, va("%-12s ", aWeaponInfo[i].pszName), sizeof(strName));
if(nShots > 0 || nHits > 0) {
Q_strcat(strName, sizeof(strName), va("%5.1f %4d/%-4d ",
((nShots == 0) ? 0.0 : (float)(nHits*100.0/(float)nShots)),
nHits, nShots));
} else {
Q_strcat(strName, sizeof(strName), va(" "));
}
Q_strncpyz(gs->strWS[gs->cWeapons++],
va("%s%5d %6d%s", strName, nKills, nDeaths, ((aWeaponInfo[i].fHasHeadShots) ? va(" %9d", nHeadshots) : "")),
sizeof(gs->strWS[0]));
if(nShots > 0 || nHits > 0 || nKills > 0 || nDeaths) {
gs->fHasStats = qtrue;
}
}
}
if(gs->fHasStats) {
int dmg_given = atoi(CG_Argv(iArg++));
int dmg_rcvd = atoi(CG_Argv(iArg++));
int team_dmg = atoi(CG_Argv(iArg++));
Q_strncpyz(gs->strExtra[0], va("Damage Given: %-6d Team Damage: %d", dmg_given, team_dmg), sizeof(gs->strExtra[0]));
Q_strncpyz(gs->strExtra[1], va("Damage Recvd: %d", dmg_rcvd), sizeof(gs->strExtra[0]));
}
}
// Derive XP from individual skill XP
skillMask = atoi(CG_Argv(iArg++));
for(i=SK_BATTLE_SENSE; i<SK_NUM_SKILLS; i++) {
if(skillMask & (1 << i)) {
ci->skillpoints[i] = atoi(CG_Argv(iArg++));
xp += ci->skillpoints[i];
}
}
Q_strncpyz(gs->strRank, va("%-13s %d", ((ci->team == TEAM_AXIS) ? rankNames_Axis : rankNames_Allies)[ci->rank], xp), sizeof(gs->strRank));
if(skillMask != 0) {
char *str;
for(i=SK_BATTLE_SENSE; i<SK_NUM_SKILLS; i++) {
if((skillMask & (1 << i)) == 0) {
continue;
}
if(ci->skill[i] < NUM_SKILL_LEVELS - 1) {
str = va("%4d/%-4d", ci->skillpoints[i], skillLevels[ci->skill[i]+1]);
} else {
str = va("%d", ci->skillpoints[i]);
}
if(cgs.gametype == GT_WOLF_CAMPAIGN) {
Q_strncpyz(gs->strSkillz[gs->cSkills++], va("%-15s %3d %s %12d", skillNames[i], ci->skill[i], str, ci->medals[i]), sizeof(gs->strSkillz[0]));
} else {
Q_strncpyz(gs->strSkillz[gs->cSkills++], va("%-15s %3d %s", skillNames[i], ci->skill[i], str), sizeof(gs->strSkillz[0]));
}
}
}
}
// Client-side stat presentation
void CG_parseWeaponStats_cmd(void (txt_dump)(char ))
{
clientInfo_t ci;
qboolean fFull = (txt_dump != CG_printWindow);
qboolean fHasStats = qfalse;
char strName[MAX_STRING_CHARS];
int atts;
int deaths;
int dmg_given;
int dmg_rcvd;
int hits;
int kills;
int team_dmg;
int headshots;
unsigned int i;
unsigned int iArg = 1;
unsigned int nClient;
unsigned int nRounds;
unsigned int dwSkillPointMask, xp = 0;
unsigned int dwWeaponMask[4];
nClient = atoi(CG_Argv(iArg++));
nRounds = atoi(CG_Argv(iArg++));
dwWeaponMask[0] = atoi(CG_Argv(iArg++));
dwWeaponMask[1] = atoi(CG_Argv(iArg++));
dwWeaponMask[2] = atoi(CG_Argv(iArg++));
dwWeaponMask[3] = atoi(CG_Argv(iArg++));
ci = &cgs.clientinfo[nClient];
Q_strncpyz(strName, ci->name, sizeof(strName));
BG_cleanName(cgs.clientinfo[nClient].name, strName, sizeof(strName), qfalse);
txt_dump(va("^7Overall stats for: ^3%s ^7(^2%d^7 Round%s)
“, strName, nRounds, ((nRounds != 1) ? “s” : “”)));
// txt_dump(va(”^7Overall stats for: ^3%s
", strName));
if(fFull) {
txt_dump( "Weapon Acrcy Hits/Atts Kills Deaths Headshots
");
txt_dump( "-------------------------------------------------
");
} else {
txt_dump( "Weapon Acrcy Hits/Atts Kll Dth HS
");
//txt_dump( "-------------------------------------
");
txt_dump( "
");
}
if(dwWeaponMask[0] + dwWeaponMask[1] + dwWeaponMask[2] + dwWeaponMask[3] == 0) {
txt_dump("^3No weapon info available.
");
} else {
for(i=WS_KNIFE; i<WS_MAX; i++) {
if(dwWeaponMask[i/32] & (1 << (i%32))) {
hits = atoi(CG_Argv(iArg++));
atts = atoi(CG_Argv(iArg++));
kills = atoi(CG_Argv(iArg++));
deaths = atoi(CG_Argv(iArg++));
headshots = atoi(CG_Argv(iArg++));
Q_strncpyz(strName, va("^3%-9s: ", aWeaponInfo[i].pszName), sizeof(strName));
if(atts > 0 || hits > 0) {
fHasStats = qtrue;
Q_strcat(strName, sizeof(strName), va("^7%5.1f ^5%4d/%-4d ",
((atts == 0) ? 0.0 : (float)(hits*100.0/(float)atts)),
hits, atts));
} else {
Q_strcat(strName, sizeof(strName), va(" "));
if(kills > 0 || deaths > 0) fHasStats = qtrue;
}
if(fFull)
txt_dump(va("%s^2%5d ^1%6d%s
“, strName, kills, deaths, ((aWeaponInfo[i].fHasHeadShots) ? va(” ^3%9d", headshots) : “”)));
else
txt_dump(va("%s^2%3d ^1%3d%s
“, strName, kills, deaths, ((aWeaponInfo[i].fHasHeadShots) ? va(” ^3%2d", headshots) : “”)));
}
}
if(fHasStats) {
dmg_given = atoi(CG_Argv(iArg++));
dmg_rcvd = atoi(CG_Argv(iArg++));
team_dmg = atoi(CG_Argv(iArg++));
if(!fFull) {
txt_dump("
");
}
txt_dump(va("
^3Damage Given: ^7%-6d ^3Team Damage: ^7%d
", dmg_given, team_dmg));
txt_dump(va( "^3Damage Recvd: ^7%d
", dmg_rcvd));
}
}
if(!fFull) {
txt_dump("
");
}
// Derive XP from individual skill XP
dwSkillPointMask = atoi(CG_Argv(iArg++));
for(i=SK_BATTLE_SENSE; i<SK_NUM_SKILLS; i++) {
if(dwSkillPointMask & (1 << i)) {
ci->skillpoints[i] = atoi(CG_Argv(iArg++));
xp += ci->skillpoints[i];
}
}
txt_dump(va("
^2Rank: ^7%s (%d XP)
", ((ci->team == TEAM_AXIS) ? rankNames_Axis : rankNames_Allies)[ci->rank], xp));
if(!fFull) {
txt_dump("
");
}
// Medals only in campaign mode
txt_dump( va("Skills Level/Points%s
“, ((cgs.gametype == GT_WOLF_CAMPAIGN) ? " Medals” : “”)));
if(fFull) {
txt_dump(va("---------------------------%s
“, ((cgs.gametype == GT_WOLF_CAMPAIGN) ? “--------” : “”)));
} else {
txt_dump(”
");
}
if(dwSkillPointMask == 0) {
txt_dump("^3No skills acquired!
");
} else {
char *str;
for(i=SK_BATTLE_SENSE; i<SK_NUM_SKILLS; i++) {
if((dwSkillPointMask & (1 << i)) == 0) {
continue;
}
if(ci->skill[i] < NUM_SKILL_LEVELS - 1) {
str = va("%d (%d/%d)", ci->skill[i], ci->skillpoints[i], skillLevels[ci->skill[i]+1]);
} else {
str = va("%d (%d)", ci->skill[i], ci->skillpoints[i]);
}
if(cgs.gametype == GT_WOLF_CAMPAIGN) {
txt_dump(va("%-14s ^3%-12s ^2%6d
“, skillNames[i], str, ci->medals[i]));
} else {
txt_dump(va(”%-14s ^3%-12s
", skillNames[i], str));
}
}
}
}
g_match.c
// Generates weapon stat info for given ent
char *G_createStats(gentity_t *refEnt)
{
unsigned int i;
unsigned int dwSkillPointMask = 0;
char strWeapInfo[MAX_STRING_CHARS] = {0};
char strSkillInfo[MAX_STRING_CHARS] = {0};
unsigned int dwWeaponMask[4];
if(!refEnt)
return(NULL);
memset(dwWeaponMask, 0, sizeof(dwWeaponMask));
// Add weapon stats as necessary
for(i=WS_KNIFE; i<WS_MAX; i++) {
if(refEnt->client->sess.aWeaponStats[i].atts || refEnt->client->sess.aWeaponStats[i].hits ||
refEnt->client->sess.aWeaponStats[i].deaths) {
dwWeaponMask[i/32] |= (1 << (i % 32));
Q_strcat(strWeapInfo, sizeof(strWeapInfo), va(" %d %d %d %d %d",
refEnt->client->sess.aWeaponStats[i].hits, refEnt->client->sess.aWeaponStats[i].atts,
refEnt->client->sess.aWeaponStats[i].kills, refEnt->client->sess.aWeaponStats[i].deaths,
refEnt->client->sess.aWeaponStats[i].headshots));
}
}
// Additional info
Q_strcat(strWeapInfo, sizeof(strWeapInfo), va(" %d %d %d",
refEnt->client->sess.damage_given,
refEnt->client->sess.damage_received,
refEnt->client->sess.team_damage));
// Add skillpoints as necessary
for(i=SK_BATTLE_SENSE; i<SK_NUM_SKILLS; i++) {
if(refEnt->client->sess.skillpoints[i] > 0) {
dwSkillPointMask |= (1 << i);
Q_strcat(strSkillInfo, sizeof(strSkillInfo), va(" %d", (int)refEnt->client->sess.skillpoints[i]));
}
}
return va
(
"%d %d %d %d %d %d%s %d%s",
refEnt - g_entities,
refEnt->client->sess.rounds,
dwWeaponMask[0],
dwWeaponMask[1],
dwWeaponMask[2],
dwWeaponMask[3],
strWeapInfo,
dwSkillPointMask,
strSkillInfo
);
}
// Parses weapon stat info for given ent
// —> The given string must be space delimited and contain only integers
void G_parseStats(char pszStatsInfo)
{
gclient_t cl;
const char* tmp = pszStatsInfo;
unsigned int i, dwWeaponMask[4], dwClientID = atoi(pszStatsInfo);
if (dwClientID < 0 || dwClientID > MAX_CLIENTS)
return;
cl = &level.clients[dwClientID];
#define GETVAL(x) if((tmp = strchr(tmp, ’ ')) == NULL) return; x = atoi(++tmp);
GETVAL(cl->sess.rounds);
GETVAL(dwWeaponMask[0]);
GETVAL(dwWeaponMask[1]);
GETVAL(dwWeaponMask[2]);
GETVAL(dwWeaponMask[3]);
for (i = WS_KNIFE; i < WS_MAX; i++)
{
if (dwWeaponMask[i/32] & (1 << (i%32)))
{
GETVAL(cl->sess.aWeaponStats[i].hits);
GETVAL(cl->sess.aWeaponStats[i].atts);
GETVAL(cl->sess.aWeaponStats[i].kills);
GETVAL(cl->sess.aWeaponStats[i].deaths);
GETVAL(cl->sess.aWeaponStats[i].headshots);
}
}
GETVAL(cl->sess.damage_given);
GETVAL(cl->sess.damage_received);
GETVAL(cl->sess.team_damage);
}
</PRE>




