From c8594a164c74219056c0188174b811440ed05bf2 Mon Sep 17 00:00:00 2001 From: fruitiex Date: Mon, 16 Nov 2009 21:47:45 +0000 Subject: [PATCH] Patch by Spaceman: Allow viewing the accuracy stats of spectated players (client and serverside setting, default off) git-svn-id: svn://svn.icculus.org/nexuiz/trunk@8291 f962a42d-fe04-0410-a3ab-8c8b0445ebaa --- data/defaultNexuiz.cfg | 6 + data/qcsrc/client/Main.qc | 7 + data/qcsrc/client/sbar.qc | 28 ++-- data/qcsrc/server/cl_client.qc | 54 ++++++- data/qcsrc/server/cl_weaponsystem.qc | 13 +- data/qcsrc/server/clientcommands.qc | 1 + data/qcsrc/server/defs.qh | 18 ++- data/qcsrc/server/g_damage.qc | 17 +-- data/qcsrc/server/g_world.qc | 77 ++++++---- data/qcsrc/server/miscfunctions.qc | 209 +++++++++++++++------------ data/qcsrc/server/w_common.qc | 98 +++++-------- data/qcsrc/server/w_shotgun.qc | 1 - 12 files changed, 303 insertions(+), 226 deletions(-) diff --git a/data/defaultNexuiz.cfg b/data/defaultNexuiz.cfg index 063e348b7..5fef4fb71 100644 --- a/data/defaultNexuiz.cfg +++ b/data/defaultNexuiz.cfg @@ -1682,3 +1682,9 @@ set sv_pitch_max 35 "maximum aiming angle for shooting direction display of the set sv_pitch_fixyaw 1 "workaround to fix the aiming direction on stupidly made player models, FIXME fix the models and set this to 0" set rescan_pending 0 "set to 1 to schedule a fs_rescan at the end of this match" + +// weapon accuracy stats +set sv_accuracy_data_share 1 "1 send weapon accuracy data statistics to spectating clients, depends on cl_accuracy_data_share" +set sv_accuracy_data_send 1 "1 send weapon accuracy data statistics and improved score info to all the clients at the end of the match, depends on cl_accuracy_data_receive, 0 send the current 'player has won' to all the clients" +set cl_accuracy_data_share 0 "1 share my weapon accuracy data statistics with other players, 0 keep my weapon accuracy data statistics hidden" +set cl_accuracy_data_receive 0 "1 receive weapon accuracy data statistics at the end of the match" diff --git a/data/qcsrc/client/Main.qc b/data/qcsrc/client/Main.qc index 5222e917a..05cc74745 100644 --- a/data/qcsrc/client/Main.qc +++ b/data/qcsrc/client/Main.qc @@ -720,6 +720,13 @@ void Ent_ClientData() if(newspectatee_status != spectatee_status) { + float i; + // clear the weapon accuracy stats + for(i = WEP_FIRST; i <= WEP_LAST; ++i) { + weapon_hits[i] = 0; + weapon_fired[i] = 0; + } + // clear race stuff race_laptime = 0; race_checkpointtime = 0; diff --git a/data/qcsrc/client/sbar.qc b/data/qcsrc/client/sbar.qc index 83bbe7578..410097607 100644 --- a/data/qcsrc/client/sbar.qc +++ b/data/qcsrc/client/sbar.qc @@ -132,7 +132,8 @@ void Sbar_DrawWeapon(float nr, float fade, float active, float wc) if(sbar_accuracy_hud) { if(weapon_damage) - weapon_stats = rint(100*weapon_hit/weapon_damage); + weapon_stats = floor(100 * weapon_hit / weapon_damage); + fill_colour = Sbar_AccuracyColor(weapon_stats); if(weapon_damage) drawpic(pos - '2 0 0' + '0 1 0' * (w_height - accuracybar_height), "gfx/hud/sb_accuracy_bar.tga", '1 0 0' * w_width + '0 1 0' * accuracybar_height, fill_colour, sbar_alpha_fg, DRAWFLAG_NORMAL); @@ -1190,7 +1191,7 @@ vector Sbar_DrawScoreboardAccuracyStats(vector pos, vector rgb, vector bg_size) weapon_hit = weapon_hits[i]; weapon_damage = weapon_fired[i]; if(weapon_damage) - weapon_stats = bound(0, rint(100 * weapon_hit / weapon_damage), 100); + weapon_stats = bound(0, floor(100 * weapon_hit / weapon_damage), 100); self = get_weaponinfo(i); float weapon_alpha; @@ -2227,6 +2228,7 @@ void Sbar_DrawAccuracyStats() float left_border; // position where the weapons start, the description is in the border vector fill_colour, fill_size; vector pos; + vector border_colour; float col_margin = 20; // pixels between the columns float row_margin = 20; // pixels between the rows @@ -2264,11 +2266,11 @@ void Sbar_DrawAccuracyStats() weapon_hit = weapon_hits[i]; weapon_damage = weapon_fired[i]; self = get_weaponinfo(i); + border_colour = (i == activeweapon) ? '1 1 1' : '0 0 0'; // white or black border - //if ((weapon_number != 42)) // print them all :) if (weapon_damage) { if (self.weapon_type == WEP_TYPE_SPLASH) { - weapon_stats = bound(0, rint(100 * weapon_hit / weapon_damage), 100); + weapon_stats = bound(0, floor(100 * weapon_hit / weapon_damage), 100); fill_colour_x = 1 - 0.015 * weapon_stats; fill_colour_y = 1 - 0.015 * (100 - weapon_stats); @@ -2299,7 +2301,7 @@ void Sbar_DrawAccuracyStats() // background drawpic(pos, "gfx/hud/sb_accuracy", fill_size , fill_colour, sbar_alpha_bg, DRAWFLAG_NORMAL); - drawborderlines(sbar_border_thickness, pos, fill_size, '0 0 0', sbar_alpha_bg, DRAWFLAG_NORMAL); + drawborderlines(sbar_border_thickness, pos, fill_size, border_colour, sbar_alpha_bg, DRAWFLAG_NORMAL); // the weapon drawpic(pos, strcat("gfx/hud/inv_weapon", ftos(i-1)), '1 0.5 0' * fill_size_x , '1 1 1', sbar_alpha_fg, DRAWFLAG_NORMAL); @@ -2317,8 +2319,8 @@ void Sbar_DrawAccuracyStats() drawstringright(pos + '4.5 0 0' * sbar_fontsize_x + '0 9 0' * sbar_fontsize_y, ftos(max(0, weapon_damage - weapon_hit)), sbar_fontsize, '1 1 1', sbar_alpha_fg, DRAWFLAG_NORMAL); ++count_splash; - } else if ((self.weapon_type == WEP_TYPE_HITSCAN) && (weapon_damage)) { - weapon_stats = bound(0, rint(100 * weapon_hit / weapon_damage), 100); + } else if (self.weapon_type == WEP_TYPE_HITSCAN) { + weapon_stats = bound(0, floor(100 * weapon_hit / weapon_damage), 100); fill_colour_x = 1 - 0.015 * weapon_stats; fill_colour_y = 1 - 0.015 * (100 - weapon_stats); @@ -2349,7 +2351,7 @@ void Sbar_DrawAccuracyStats() // background drawpic(pos, "gfx/hud/sb_accuracy", fill_size , fill_colour, sbar_alpha_bg, DRAWFLAG_NORMAL); - drawborderlines(sbar_border_thickness, pos, fill_size, '0 0 0', sbar_alpha_bg, DRAWFLAG_NORMAL); + drawborderlines(sbar_border_thickness, pos, fill_size, border_colour, sbar_alpha_bg, DRAWFLAG_NORMAL); // the weapon drawpic(pos, strcat("gfx/hud/inv_weapon", ftos(i-1)), '1 0.5 0' * fill_size_x , '1 1 1', sbar_alpha_fg, DRAWFLAG_NORMAL); @@ -2467,12 +2469,12 @@ void Sbar_Draw (void) float stat_items, stat_weapons; weapon_stats = getstati(STAT_DAMAGE_HITS); - weapon_number = weapon_stats & 63; - weapon_hits[weapon_number] = rint(weapon_stats / 64); + weapon_number = weapon_stats & 63; + weapon_hits[weapon_number] = floor(weapon_stats / 64); - weapon_stats = getstati(STAT_DAMAGE_FIRED); - weapon_number = weapon_stats & 63; - weapon_fired[weapon_number] = rint(weapon_stats / 64); + weapon_stats = getstati(STAT_DAMAGE_FIRED); + weapon_number = weapon_stats & 63; + weapon_fired[weapon_number] = floor(weapon_stats / 64); vector o; o = '1 0 0' * vid_conwidth; o_y = 28; // move spectator text slightly down to prevent overlapping the timer diff --git a/data/qcsrc/server/cl_client.qc b/data/qcsrc/server/cl_client.qc index 1dff10b29..7c324f10b 100644 --- a/data/qcsrc/server/cl_client.qc +++ b/data/qcsrc/server/cl_client.qc @@ -2037,12 +2037,33 @@ void GetPressedKeys(void) { self.pressedkeys &~= KEY_CROUCH; } +void update_stats (float number, float hit, float fired) { +// self.stat_hit = number + ((number==0) ? 1 : 64) * hit * sv_accuracy_data_share; +// self.stat_fired = number + ((number==0) ? 1 : 64) * fired * sv_accuracy_data_share; + + if(number) { + self.stat_hit = number + 64 * hit * sv_accuracy_data_share; + self.stat_fired = number + 64 * fired * sv_accuracy_data_share; + } else { + self.stat_hit = hit * sv_accuracy_data_share; + self.stat_fired = fired * sv_accuracy_data_share; + } +} + /* ====================== spectate mode routines ====================== */ + +.float weapon_count; void SpectateCopy(entity spectatee) { + if(spectatee.weapon_count < WEP_LAST) { + update_stats (spectatee.weapon_count, spectatee.cvar_cl_accuracy_data_share * floor(spectatee.stats_hit[spectatee.weapon_count - 1]), spectatee.cvar_cl_accuracy_data_share * floor(spectatee.stats_fired[spectatee.weapon_count - 1])); + spectatee.weapon_count ++; + } else + update_stats (0, spectatee.cvar_cl_accuracy_data_share * spectatee.stat_hit, spectatee.cvar_cl_accuracy_data_share * spectatee.stat_fired); + self.kh_state = spectatee.kh_state; self.armortype = spectatee.armortype; self.armorvalue = spectatee.armorvalue; @@ -2093,20 +2114,25 @@ float SpectateUpdate() { float SpectateNext() { other = find(self.enemy, classname, "player"); - if (!other) { + + if (!other) other = find(other, classname, "player"); - } - if (other) { + + if (other) self.enemy = other; - } + if(self.enemy.classname == "player") { msg_entity = self; WriteByte(MSG_ONE, SVC_SETVIEW); WriteEntity(MSG_ONE, self.enemy); //stuffcmd(self, "set viewsize $tmpviewsize \n"); self.movetype = MOVETYPE_NONE; + + self.enemy.weapon_count = 0; + if(!SpectateUpdate()) PutObserverInServer(); + return 1; } else { return 0; @@ -2144,15 +2170,23 @@ void LeaveSpectatorMode() if(isJoinAllowed()) { if(!teams_matter || cvar("g_campaign") || cvar("g_balance_teams") || (self.wasplayer && cvar("g_changeteam_banned"))) { self.classname = "player"; + if(cvar("g_campaign") || cvar("g_balance_teams") || cvar("g_balance_teams_force")) JoinBestTeam(self, FALSE, TRUE); + if(cvar("g_campaign")) campaign_bots_may_start = 1; + + self.stat_count = WEP_LAST; + PutClientInServer(); + if(self.classname == "player") bprint ("^4", self.netname, "^4 is playing now\n"); + if(!cvar("g_campaign")) centerprint(self,""); // clear MOTD + return; } else { if (g_ca && self.caplayer) { @@ -2289,12 +2323,14 @@ void SpectatorThink() self.classname = "spectator"; } else { self.classname = "observer"; + self.stat_count = WEP_LAST; PutClientInServer(); } } else if (self.BUTTON_ATCK2) { self.welcomemessage_time = 0; self.flags &~= FL_JUMPRELEASED; self.classname = "observer"; + self.stat_count = WEP_LAST; PutClientInServer(); } else { if(!SpectateUpdate()) @@ -2311,6 +2347,7 @@ void SpectatorThink() } } } + PrintWelcomeMessage(self); self.flags |= FL_CLIENT | FL_NOTARGET; } @@ -2839,6 +2876,15 @@ void PlayerPostThink (void) stuffcmd(self, "seta _cl_name Player\n"); } + // send the clients accuracy stats to the client + if(self.stat_count > 0) + if(frametime) + { + self.stat_hit = self.stat_count + 64 * floor(self.(stats_hit[self.stat_count - 1])); + self.stat_fired = self.stat_count + 64 * floor(self.(stats_fired[self.stat_count - 1])); + self.stat_count -= 1; + } + if(sv_maxidle && frametime) { // WORKAROUND: only use dropclient in server frames (frametime set). Never use it in cl_movement frames (frametime zero). diff --git a/data/qcsrc/server/cl_weaponsystem.qc b/data/qcsrc/server/cl_weaponsystem.qc index 9c39182a8..a86093976 100644 --- a/data/qcsrc/server/cl_weaponsystem.qc +++ b/data/qcsrc/server/cl_weaponsystem.qc @@ -147,11 +147,14 @@ void W_SetupShot_Dir_ProjectileSize(entity ent, vector s_forward, vector mi, vec ent.dphitcontentsmask = DPCONTENTS_SOLID | DPCONTENTS_BODY | DPCONTENTS_CORPSE; trueaimpoint = trace_endpos; - // Track max damage and set the stat to be sent later in g_world.qc - if not(inWarmupStage) - { - ent.max_damage[ent.weapon] += maxdamage; - ent.maxdamage_fired = ent.weapon + 64 * rint(ent.max_damage[ent.weapon]); + // track max damage + if not(inWarmupStage) { + entity w; + w = get_weaponinfo(ent.weapon); + if(w.weapon_type == WEP_TYPE_SPLASH) { // splash damage + ent.stats_fired[ent.weapon - 1] += maxdamage; + ent.stat_fired = ent.weapon + 64 * floor(ent.stats_fired[ent.weapon - 1]); + } } W_HitPlotAnalysis(ent, v_forward, v_right, v_up); diff --git a/data/qcsrc/server/clientcommands.qc b/data/qcsrc/server/clientcommands.qc index 5f0bfd1ab..c756f8acb 100644 --- a/data/qcsrc/server/clientcommands.qc +++ b/data/qcsrc/server/clientcommands.qc @@ -275,6 +275,7 @@ void SV_ParseClientCommand(string s) { self.caplayer = 1; PlayerScore_Clear(self); bprint ("^4", self.netname, "^4 is playing now\n"); + self.stat_count = WEP_LAST; PutClientInServer(); if(cvar("g_campaign")) campaign_bots_may_start = 1; diff --git a/data/qcsrc/server/defs.qh b/data/qcsrc/server/defs.qh index eb1e68238..8bc5b551d 100644 --- a/data/qcsrc/server/defs.qh +++ b/data/qcsrc/server/defs.qh @@ -389,7 +389,7 @@ void centerprint(entity e, string s); float bot_waypoints_for_items; -.float attack_finished_for[WEP_COUNT]; +.float attack_finished_for[WEP_COUNT]; .float attack_finished_single; #ifdef INDEPENDENT_ATTACK_FINISHED #define ATTACK_FINISHED_FOR(ent,w) ((ent).(attack_finished_for[(w) - WEP_FIRST])) @@ -598,7 +598,16 @@ string matchid; .float hitplotfh; .string noise4; -.float damage_hits, maxdamage_fired; +.float stat_hit; +.float stat_fired; +.float stat_count; + +.float stats_hit[WEP_LAST - WEP_FIRST + 1]; // for hitscan bullets hit +.float stats_fired[WEP_LAST - WEP_FIRST + 1]; // for hitscan bullets fired + +FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(stats_hit); +FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(stats_fired); + .float maycheat; .float stat_leadlimit; @@ -624,3 +633,8 @@ float client_cefc_accumulatortime; .entity personal; string deathmessage; + + + +.float cvar_cl_accuracy_data_share; +.float cvar_cl_accuracy_data_receive; \ No newline at end of file diff --git a/data/qcsrc/server/g_damage.qc b/data/qcsrc/server/g_damage.qc index 9d43a5160..f738dcbfc 100644 --- a/data/qcsrc/server/g_damage.qc +++ b/data/qcsrc/server/g_damage.qc @@ -1009,23 +1009,16 @@ vector NearestPointOnBox(entity box, vector org) return nearest; } -.float actual_damage[WEP_COUNT]; //amount of damage done -.float max_damage[WEP_COUNT]; //the maximum damage of the weapon - -FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(actual_damage); -FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(max_damage); - void Damage_RecordDamage(entity attacker, float deathtype, float damage) { float weaponid; weaponid = DEATH_WEAPONOF(deathtype); + if not(inWarmupStage) - if(weaponid) - if(clienttype(attacker) == CLIENTTYPE_REAL) - { - // Track damage done and update the stat to be sent later in g_world.qc - attacker.actual_damage[weaponid] += damage; - attacker.damage_hits = weaponid + 64 * rint(attacker.actual_damage[weaponid]); + if (weaponid) + if ((clienttype(attacker) == CLIENTTYPE_REAL) | (clienttype(attacker) == CLIENTTYPE_BOT)) { + attacker.stats_hit[weaponid - 1] += damage; + attacker.stat_hit = weaponid + 64 * floor(attacker.stats_hit[weaponid - 1]); } } diff --git a/data/qcsrc/server/g_world.qc b/data/qcsrc/server/g_world.qc index 7687b9a90..b9c34b618 100644 --- a/data/qcsrc/server/g_world.qc +++ b/data/qcsrc/server/g_world.qc @@ -601,8 +601,8 @@ void spawnfunc_worldspawn (void) addstat(STAT_INVINCIBLE_FINISHED, AS_FLOAT, invincible_finished); addstat(STAT_PRESSED_KEYS, AS_FLOAT, pressedkeys); addstat(STAT_FUEL, AS_INT, ammo_fuel); - addstat(STAT_DAMAGE_HITS, AS_INT, damage_hits); - addstat(STAT_DAMAGE_FIRED, AS_INT, maxdamage_fired); + addstat(STAT_DAMAGE_HITS, AS_INT, stat_hit); + addstat(STAT_DAMAGE_FIRED, AS_INT, stat_fired); addstat(STAT_SHOTORG, AS_INT, stat_shotorg); addstat(STAT_LEADLIMIT, AS_FLOAT, stat_leadlimit); addstat(STAT_BULLETS_LOADED, AS_INT, campingrifle_bulletcounter); @@ -1297,10 +1297,7 @@ only called if a time or frag limit has expired */ void NextLevel() { - float minTotalFrags; - float maxTotalFrags; - float score; - float f; + float i; gameover = TRUE; @@ -1330,31 +1327,51 @@ void NextLevel() GameLogClose(); - FOR_EACH_CLIENT(other) - { - FixIntermissionClient(other); +// TO DO - if(other.winning) - bprint(other.netname, " ^7wins.\n"); - } +// save the stats to a text file on the client +// stuffcmd(other, log_stats "stats/file_name"); +// bprint stats +// stuffcmd(other, log_stats ""); +// use a filename similar to the demo name + // string file_name; + // file_name = strcat("\nlog_file \"stats/", strftime(TRUE, "%Y-%m-%d_%H-%M"), "_", mapname, ".txt\""); // open the log file - minTotalFrags = 0; - maxTotalFrags = 0; - FOR_EACH_PLAYER(other) - { - if(maxTotalFrags < other.totalfrags) - maxTotalFrags = other.totalfrags; - if(minTotalFrags > other.totalfrags) - minTotalFrags = other.totalfrags; - } +// write a stats parser for the menu - if(!currentbots) - { - FOR_EACH_PLAYER(other) - { - score = (other.totalfrags - minTotalFrags) / max(maxTotalFrags - minTotalFrags, 1); - f = bound(0, other.play_time / max(time, 1), 1); - // store some statistics? + if(cvar("sv_accuracy_data_send")) { + string stats_to_send; + + FOR_EACH_PLAYER(other) { // make the string to send + FixIntermissionClient(other); + + if(other.cvar_cl_accuracy_data_share) { + stats_to_send = strcat(stats_to_send, ":hits:", other.netname); + + for(i = WEP_FIRST; i <= WEP_LAST; ++i) + stats_to_send = strcat(stats_to_send, ":", ftos(other.stats_hit[i-1])); + + stats_to_send = strcat(stats_to_send, "\n:fired:", other.netname); + + for(i = WEP_FIRST; i <= WEP_LAST; ++i) + stats_to_send = strcat(stats_to_send, ":", ftos(other.stats_fired[i-1])); + + stats_to_send = strcat(stats_to_send, "\n"); + } + } + + FOR_EACH_PLAYER(other) { // send the stats string to all the willing clients + Score_NicePrint(other); // print the score + + if(other.cvar_cl_accuracy_data_receive) + bprint(stats_to_send); + } + } else { // ye olde message + FOR_EACH_PLAYER(other) { + FixIntermissionClient(other); + + if(other.winning) + bprint(other.netname, " ^7wins.\n"); } } @@ -1362,9 +1379,7 @@ void NextLevel() CampaignPreIntermission(); localcmd("\nsv_hook_gameend;"); - - // WriteByte (MSG_ALL, SVC_INTERMISSION); -}; +} /* ============ diff --git a/data/qcsrc/server/miscfunctions.qc b/data/qcsrc/server/miscfunctions.qc index 2adcbdde1..46ec339c9 100644 --- a/data/qcsrc/server/miscfunctions.qc +++ b/data/qcsrc/server/miscfunctions.qc @@ -495,10 +495,15 @@ string formatmessage(string msg) replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1')); else if (escape == "S") replacement = ftos(vlen(self.velocity)); - msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2))); - p = p + strlen(replacement); - } - return msg; + msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2))); + p = p + strlen(replacement); + } + + return msg; +} + +float boolean(float value) { // if value is 0 return FALSE (0), otherwise return TRUE (1) + return (value == 0) ? FALSE : TRUE; } /* @@ -610,13 +615,18 @@ void GetCvars(float f) GetCvars_handleFloat(s, f, cvar_cl_voice_directional, "cl_voice_directional"); GetCvars_handleFloat(s, f, cvar_cl_voice_directional_taunt_attenuation, "cl_voice_directional_taunt_attenuation"); GetCvars_handleFloat(s, f, cvar_cl_hitsound, "cl_hitsound"); + GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_share, "cl_accuracy_data_share"); + GetCvars_handleFloat(s, f, cvar_cl_accuracy_data_receive, "cl_accuracy_data_receive"); + + self.cvar_cl_accuracy_data_share = boolean(self.cvar_cl_accuracy_data_share); + self.cvar_cl_accuracy_data_receive = boolean(self.cvar_cl_accuracy_data_receive); + #ifdef ALLOW_FORCEMODELS GetCvars_handleFloat(s, f, cvar_cl_forceplayermodels, "cl_forceplayermodels"); GetCvars_handleFloat(s, f, cvar_cl_forceplayermodelsfromnexuiz, "cl_forceplayermodelsfromnexuiz"); #endif GetCvars_handleFloatOnce(s, f, cvar_cl_gunalign, "cl_gunalign"); - // fixup of switchweapon (needed for LMS or when spectating is disabled, as PutClientInServer comes too early) if (f > 0) { @@ -1103,6 +1113,8 @@ float sv_pitch_min; float sv_pitch_max; float sv_pitch_fixyaw; +float sv_accuracy_data_share; + void readlevelcvars(void) { g_bugrigs = cvar("g_bugrigs"); @@ -1128,112 +1140,119 @@ void readlevelcvars(void) g_touchexplode_force = cvar("g_touchexplode_force"); #ifdef ALLOW_FORCEMODELS - sv_clforceplayermodels = cvar("sv_clforceplayermodels"); + sv_clforceplayermodels = cvar("sv_clforceplayermodels"); #endif - sv_loddistance1 = cvar("sv_loddistance1"); - sv_loddistance2 = cvar("sv_loddistance2"); + sv_loddistance1 = cvar("sv_loddistance1"); + sv_loddistance2 = cvar("sv_loddistance2"); + if(sv_loddistance2 <= sv_loddistance1) sv_loddistance2 = 1073741824; // enough to turn off LOD 2 reliably - sv_clones = cvar("sv_clones"); - sv_cheats = cvar("sv_cheats"); - sv_gentle = cvar("sv_gentle"); - sv_foginterval = cvar("sv_foginterval"); - g_cloaked = cvar("g_cloaked"); - g_jump_grunt = cvar("g_jump_grunt"); - g_footsteps = cvar("g_footsteps"); - g_grappling_hook = cvar("g_grappling_hook"); - g_jetpack = cvar("g_jetpack"); - g_laserguided_missile = cvar("g_laserguided_missile"); - g_midair = cvar("g_midair"); - g_minstagib = cvar("g_minstagib"); - g_nixnex = cvar("g_nixnex"); - g_nixnex_with_laser = cvar("g_nixnex_with_laser"); - g_norecoil = cvar("g_norecoil"); - g_vampire = cvar("g_vampire"); - g_bloodloss = cvar("g_bloodloss"); - sv_maxidle = cvar("sv_maxidle"); - sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle"); - sv_pogostick = cvar("sv_pogostick"); - sv_doublejump = cvar("sv_doublejump"); - g_ctf_reverse = cvar("g_ctf_reverse"); + + sv_clones = cvar("sv_clones"); + sv_cheats = cvar("sv_cheats"); + sv_gentle = cvar("sv_gentle"); + sv_foginterval = cvar("sv_foginterval"); + g_cloaked = cvar("g_cloaked"); + g_jump_grunt = cvar("g_jump_grunt"); + g_footsteps = cvar("g_footsteps"); + g_grappling_hook = cvar("g_grappling_hook"); + g_jetpack = cvar("g_jetpack"); + g_laserguided_missile = cvar("g_laserguided_missile"); + g_midair = cvar("g_midair"); + g_minstagib = cvar("g_minstagib"); + g_nixnex = cvar("g_nixnex"); + g_nixnex_with_laser = cvar("g_nixnex_with_laser"); + g_norecoil = cvar("g_norecoil"); + g_vampire = cvar("g_vampire"); + g_bloodloss = cvar("g_bloodloss"); + sv_maxidle = cvar("sv_maxidle"); + sv_maxidle_spectatorsareidle = cvar("sv_maxidle_spectatorsareidle"); + sv_pogostick = cvar("sv_pogostick"); + sv_doublejump = cvar("sv_doublejump"); + g_ctf_reverse = cvar("g_ctf_reverse"); sv_autotaunt = cvar("sv_autotaunt"); sv_taunt = cvar("sv_taunt"); - inWarmupStage = cvar("g_warmup"); - g_warmup_limit = cvar("g_warmup_limit"); - g_warmup_allguns = cvar("g_warmup_allguns"); - g_warmup_allow_timeout = cvar("g_warmup_allow_timeout"); - - if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign")) - inWarmupStage = 0; // these modes cannot work together, sorry - - g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon"); - g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo"); - g_pickup_respawntime_short = cvar("g_pickup_respawntime_short"); - g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium"); - g_pickup_respawntime_long = cvar("g_pickup_respawntime_long"); - g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup"); - g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon"); - g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo"); - g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short"); - g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium"); - g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long"); - g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup"); - - if (g_minstagib) g_nixnex = g_weaponarena = 0; - if (g_nixnex) g_weaponarena = 0; - g_weaponarena = 0; + inWarmupStage = cvar("g_warmup"); + g_warmup_limit = cvar("g_warmup_limit"); + g_warmup_allguns = cvar("g_warmup_allguns"); + g_warmup_allow_timeout = cvar("g_warmup_allow_timeout"); + + if ((g_race && g_race_qualifying == 2) || g_runematch || g_arena || g_assault || cvar("g_campaign")) + inWarmupStage = 0; // these modes cannot work together, sorry + + g_pickup_respawntime_weapon = cvar("g_pickup_respawntime_weapon"); + g_pickup_respawntime_ammo = cvar("g_pickup_respawntime_ammo"); + g_pickup_respawntime_short = cvar("g_pickup_respawntime_short"); + g_pickup_respawntime_medium = cvar("g_pickup_respawntime_medium"); + g_pickup_respawntime_long = cvar("g_pickup_respawntime_long"); + g_pickup_respawntime_powerup = cvar("g_pickup_respawntime_powerup"); + g_pickup_respawntimejitter_weapon = cvar("g_pickup_respawntimejitter_weapon"); + g_pickup_respawntimejitter_ammo = cvar("g_pickup_respawntimejitter_ammo"); + g_pickup_respawntimejitter_short = cvar("g_pickup_respawntimejitter_short"); + g_pickup_respawntimejitter_medium = cvar("g_pickup_respawntimejitter_medium"); + g_pickup_respawntimejitter_long = cvar("g_pickup_respawntimejitter_long"); + g_pickup_respawntimejitter_powerup = cvar("g_pickup_respawntimejitter_powerup"); + + if (g_minstagib) g_nixnex = g_weaponarena = 0; + if (g_nixnex) g_weaponarena = 0; + g_weaponarena = 0; + + g_weaponspeedfactor = cvar("g_weaponspeedfactor"); + g_weaponratefactor = cvar("g_weaponratefactor"); + g_weapondamagefactor = cvar("g_weapondamagefactor"); + g_weaponforcefactor = cvar("g_weaponforcefactor"); + + g_pickup_shells = cvar("g_pickup_shells"); + g_pickup_shells_max = cvar("g_pickup_shells_max"); + g_pickup_nails = cvar("g_pickup_nails"); + g_pickup_nails_max = cvar("g_pickup_nails_max"); + g_pickup_rockets = cvar("g_pickup_rockets"); + g_pickup_rockets_max = cvar("g_pickup_rockets_max"); + g_pickup_cells = cvar("g_pickup_cells"); + g_pickup_cells_max = cvar("g_pickup_cells_max"); + g_pickup_fuel = cvar("g_pickup_fuel"); + g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack"); + g_pickup_fuel_max = cvar("g_pickup_fuel_max"); + g_pickup_armorsmall = cvar("g_pickup_armorsmall"); + g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max"); + g_pickup_armormedium = cvar("g_pickup_armormedium"); + g_pickup_armormedium_max = cvar("g_pickup_armormedium_max"); + g_pickup_armorbig = cvar("g_pickup_armorbig"); + g_pickup_armorbig_max = cvar("g_pickup_armorbig_max"); + g_pickup_armorlarge = cvar("g_pickup_armorlarge"); + g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max"); + g_pickup_healthsmall = cvar("g_pickup_healthsmall"); + g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max"); + g_pickup_healthmedium = cvar("g_pickup_healthmedium"); + g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max"); + g_pickup_healthlarge = cvar("g_pickup_healthlarge"); + g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max"); + g_pickup_healthmega = cvar("g_pickup_healthmega"); + g_pickup_healthmega_max = cvar("g_pickup_healthmega_max"); + + g_pinata = cvar("g_pinata"); + + g_weapon_stay = cvar("g_weapon_stay"); + + if (!g_weapon_stay && (cvar("deathmatch") == 2)) + g_weapon_stay = 1; - g_weaponspeedfactor = cvar("g_weaponspeedfactor"); - g_weaponratefactor = cvar("g_weaponratefactor"); - g_weapondamagefactor = cvar("g_weapondamagefactor"); - g_weaponforcefactor = cvar("g_weaponforcefactor"); - - g_pickup_shells = cvar("g_pickup_shells"); - g_pickup_shells_max = cvar("g_pickup_shells_max"); - g_pickup_nails = cvar("g_pickup_nails"); - g_pickup_nails_max = cvar("g_pickup_nails_max"); - g_pickup_rockets = cvar("g_pickup_rockets"); - g_pickup_rockets_max = cvar("g_pickup_rockets_max"); - g_pickup_cells = cvar("g_pickup_cells"); - g_pickup_cells_max = cvar("g_pickup_cells_max"); - g_pickup_fuel = cvar("g_pickup_fuel"); - g_pickup_fuel_jetpack = cvar("g_pickup_fuel_jetpack"); - g_pickup_fuel_max = cvar("g_pickup_fuel_max"); - g_pickup_armorsmall = cvar("g_pickup_armorsmall"); - g_pickup_armorsmall_max = cvar("g_pickup_armorsmall_max"); - g_pickup_armormedium = cvar("g_pickup_armormedium"); - g_pickup_armormedium_max = cvar("g_pickup_armormedium_max"); - g_pickup_armorbig = cvar("g_pickup_armorbig"); - g_pickup_armorbig_max = cvar("g_pickup_armorbig_max"); - g_pickup_armorlarge = cvar("g_pickup_armorlarge"); - g_pickup_armorlarge_max = cvar("g_pickup_armorlarge_max"); - g_pickup_healthsmall = cvar("g_pickup_healthsmall"); - g_pickup_healthsmall_max = cvar("g_pickup_healthsmall_max"); - g_pickup_healthmedium = cvar("g_pickup_healthmedium"); - g_pickup_healthmedium_max = cvar("g_pickup_healthmedium_max"); - g_pickup_healthlarge = cvar("g_pickup_healthlarge"); - g_pickup_healthlarge_max = cvar("g_pickup_healthlarge_max"); - g_pickup_healthmega = cvar("g_pickup_healthmega"); - g_pickup_healthmega_max = cvar("g_pickup_healthmega_max"); - - g_pinata = cvar("g_pinata"); - - g_weapon_stay = cvar("g_weapon_stay"); - if (!g_weapon_stay && (cvar("deathmatch") == 2)) - g_weapon_stay = 1; g_ghost_items = cvar("g_ghost_items"); + if(g_ghost_items >= 1) g_ghost_items = 0.13; // default alpha value - if not(inWarmupStage) - game_starttime = cvar("g_start_delay"); + if not(inWarmupStage) + game_starttime = cvar("g_start_delay"); sv_pitch_min = cvar("sv_pitch_min"); sv_pitch_max = cvar("sv_pitch_max"); sv_pitch_fixyaw = cvar("sv_pitch_fixyaw"); - readplayerstartcvars(); + sv_accuracy_data_share = boolean(cvar("sv_accuracy_data_share")); + + readplayerstartcvars(); } /* diff --git a/data/qcsrc/server/w_common.qc b/data/qcsrc/server/w_common.qc index 4a1c4989a..e0ba807c7 100644 --- a/data/qcsrc/server/w_common.qc +++ b/data/qcsrc/server/w_common.qc @@ -1,9 +1,3 @@ -.float bullets_hit[WEP_COUNT]; //for hitscan bullets hit -.float bullets_fired[WEP_COUNT]; //for hitscan bullets fired - -FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(bullets_hit); -FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(bullets_fired); - void W_GiveWeapon (entity e, float wep, string name) { entity oldself; @@ -32,15 +26,14 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f local vector hitloc, force, endpoint, dir; local entity ent, endent; local float endq3surfaceflags; - //local entity explosion; - float did_hit; + float length; vector beampos; string snd; entity pseudoprojectile; float f, ffs; - did_hit = 0; + float hit; railgun_start = start; railgun_end = end; @@ -131,11 +124,11 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f //for stats so that team hit will count as a miss if(ent.flags & FL_CLIENT) if(ent.deadflag == DEAD_NO) - did_hit = 1; + hit = 1; if(teams_matter) if(ent.team == self.team) - did_hit = 0; + hit = 0; f = ExponentialFalloff(mindist, maxdist, halflifedist, (ent.origin - start) * dir); ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, (ent.origin - start) * dir); @@ -152,23 +145,18 @@ void FireRailgunBullet (vector start, vector end, float bdamage, float bforce, f ent = findfloat(ent, railgunhit, TRUE); } - //calculate hits and fired shots for hitscan + // calculate hits and fired shots for hitscan if not(inWarmupStage) - if not(self.isbot) { - self.bullets_fired[self.weapon] += 1; - - if(did_hit) - self.bullets_hit[self.weapon] += 1; + self.stats_fired[self.weapon - 1] += 1; + self.stat_fired = self.weapon + 64 * floor(self.stats_fired[self.weapon - 1]); - // update the client and store in addstat() in g_world - self.damage_hits = self.weapon + 64 * rint(self.bullets_hit[self.weapon]); - self.maxdamage_fired = self.weapon + 64 * rint(self.bullets_fired[self.weapon]); + if(hit) { + self.stats_hit[self.weapon - 1] += 1; + self.stat_hit = self.weapon + 64 * floor(self.stats_hit[self.weapon - 1]); + } } - // we're done with the explosion entity, remove it - //remove(explosion); - trace_endpos = endpoint; trace_ent = endent; trace_dphitq3surfaceflags = endq3surfaceflags; @@ -181,9 +169,6 @@ void W_BallisticBullet_Hit (void) { float f; - float hit; - hit = 0; - f = pow(bound(0, vlen(self.velocity) / vlen(self.oldvelocity), 1), 2); // energy multiplier if(other.solid == SOLID_BSP) @@ -199,14 +184,6 @@ void W_BallisticBullet_Hit (void) railgun_start = self.origin - 2 * frametime * self.velocity; railgun_end = self.origin + 2 * frametime * self.velocity; - if(other.flags & FL_CLIENT) - if(other.deadflag == DEAD_NO) - hit = 1; - - if(teamplay) - if(other.team == self.owner.team) - hit = 0; - Damage(other, self, self.owner, self.dmg * f, self.projectiledeathtype, self.origin, self.dmg_force * normalize(self.velocity) * f); damage_headshotbonus = 0; @@ -218,17 +195,15 @@ void W_BallisticBullet_Hit (void) announce(self.owner, "announcer/male/awesome.wav"); } - //calculate hits for ballistic weapons - if not(inWarmupStage) - if not(self.owner.isbot) + // calculate hits for ballistic weapons + if (other.flags & FL_CLIENT) // is the player a client + if (other.deadflag == DEAD_NO) // is the victim a corpse + if ((!(teamplay)) | (other.team != self.owner.team)) // not teamplay (ctf, kh, tdm etc) or the victim is in the same team + if not(inWarmupStage) // not in warm up stage { - if(hit) - self.owner.bullets_hit[self.owner.weapon] += 1; - // update the client - self.owner.damage_hits = self.owner.weapon + 64 * rint(self.owner.bullets_hit[self.owner.weapon]); + self.owner.stats_hit[self.owner.weapon - 1] += 1; + self.owner.stat_hit = self.owner.weapon + 64 * floor(self.owner.stats_hit[self.owner.weapon - 1]); } - - //sound (self, CHAN_PROJECTILE, "weapons/electro_impact.wav", VOL_BASE, ATTN_NORM); } self.enemy = other; // don't hit the same player twice with the same bullet @@ -342,6 +317,7 @@ void endFireBallisticBullet() { endzcurveparticles(); } + void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, float lifetime, float damage, float headshotbonus, float force, float dtype, float tracereffects, float gravityfactor, float bulletconstant) { float lag, dt, savetime; @@ -376,14 +352,6 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f proj.oldvelocity = proj.velocity; - //calculate fired bullets for ballistics - if not(inWarmupStage) - if not(self.isbot) - { - self.bullets_fired[self.weapon] += 1; - self.maxdamage_fired = self.weapon + 64 * rint(self.bullets_fired[self.weapon]); - } - if(cvar("g_antilag_bullets")) if(pSpeed >= cvar("g_antilag_bullets")) { @@ -413,6 +381,13 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f savetime = frametime; frametime = 0.05; + // update the accuracy stats - increase shots fired by 1 + if not(inWarmupStage) + { + oldself.stats_fired[oldself.weapon - 1] += 1; + oldself.stat_fired = oldself.weapon + 64 * floor(oldself.stats_fired[oldself.weapon - 1]); + } + for(;;) { // DP tracetoss is stupid and always traces in 0.05s @@ -429,13 +404,6 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f self.velocity = v0; self.gravity = g0; - if not(inWarmupStage) - if not(self.isbot) - { - self.bullets_fired[self.weapon] += 1; - self.maxdamage_fired = self.weapon + 64 * rint(self.bullets_fired[self.weapon]); - } - if(vlen(trace_endpos - self.origin) > 16) zcurveparticles_from_tracetoss(eff, self.origin, trace_endpos, self.velocity); if(trace_fraction == 1) @@ -455,7 +423,7 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f break; // hit the player - W_BallisticBullet_Hit (); + W_BallisticBullet_Hit(); } // go through solid! @@ -476,6 +444,13 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f return; } + // update the accuracy stats + if not(inWarmupStage) + { + self.stats_fired[self.weapon - 1] += 1; + self.stat_fired = self.weapon + 64 * floor(self.stats_fired[self.weapon - 1]); + } + if(tracereffects & EF_RED) CSQCProjectile(proj, TRUE, PROJECTILE_BULLET_GLOWING_TRACER, TRUE); else if(tracereffects & EF_BLUE) @@ -484,11 +459,9 @@ void fireBallisticBullet(vector start, vector dir, float spread, float pSpeed, f CSQCProjectile(proj, TRUE, PROJECTILE_BULLET, TRUE); } - void fireBullet (vector start, vector dir, float spread, float damage, float force, float dtype, float tracer) { vector end; - //local entity e; dir = normalize(dir + randomvec() * spread); end = start + dir * MAX_SHOT_DISTANCE; @@ -497,7 +470,7 @@ void fireBullet (vector start, vector dir, float spread, float damage, float for else traceline_antilag (self, start, end, FALSE, self, ANTILAG_LATENCY(self)); - end = trace_endpos; + end = trace_endpos; if ((trace_fraction != 1.0) && (pointcontents (trace_endpos) != CONTENT_SKY)) { @@ -510,7 +483,6 @@ void fireBullet (vector start, vector dir, float spread, float damage, float for trace_endpos = end; } - void W_PrepareExplosionByDamage(entity attacker, void() explode) { self.takedamage = DAMAGE_NO; diff --git a/data/qcsrc/server/w_shotgun.qc b/data/qcsrc/server/w_shotgun.qc index 24ad5cf35..300a48255 100644 --- a/data/qcsrc/server/w_shotgun.qc +++ b/data/qcsrc/server/w_shotgun.qc @@ -1,4 +1,3 @@ - void W_Shotgun_Attack (void) { float sc; -- 2.39.2