const float ENT_CLIENT_HOOK = 27;
const float ENT_CLIENT_LGBEAM = 28;
const float ENT_CLIENT_GAUNTLET = 29;
+const float ENT_CLIENT_ACCURACY = 30;
const float ENT_CLIENT_TURRET = 40;
const float STAT_GAMESTARTTIME = 37;
const float STAT_STRENGTH_FINISHED = 38;
const float STAT_INVINCIBLE_FINISHED = 39;
-const float STAT_DAMAGE_HITS = 40; // Used by the weapon stats code, represents the total amount of damage done to other players
-const float STAT_DAMAGE_FIRED = 41;// Used by the weapon stats code, represents the total amount of potential damage fired
const float STAT_PRESSED_KEYS = 42;
const float STAT_ALLOW_OLDNEXBEAM = 43; // this stat could later contain some other bits of info, like, more server-side particle config
const float STAT_FUEL = 44;
.entity accuracy;
.float accuracy_hit[WEP_MAXCOUNT];
.float accuracy_fired[WEP_MAXCOUNT];
+FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(accuracy_hit);
+FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(accuracy_fired);
-void accuracy_send(entity to, float sf)
+float accuracy_send(entity to, float sf)
{
float w, f;
+ entity a;
WriteByte(MSG_ENTITY, ENT_CLIENT_ACCURACY);
- if(to != self.owner)
+
+ a = self.owner;
+ if(a.classname == "spectator")
+ a = a.enemy;
+ a = a.accuracy;
+
+ if(to != a.owner)
if not(self.owner.cvar_cl_accuracy_data_share && autocvar_sv_accuracy_data_share)
sf = 0;
// note: zero sendflags can never be sent... so we can use that to say that we send no accuracy!
e.accuracy.owner = e;
e.accuracy.classname = "accuracy";
e.accuracy.SendEntity = accuracy_send;
+ e.accuracy.drawonlytoclient = e;
}
void accuracy_free(entity e)
// update accuracy stats
void accuracy_set(entity e, float w, float hit, float fired)
{
- e = e.accuracy;
+ entity a;
+ a = e.accuracy;
+ if(!a)
+ return;
w -= WEP_FIRST;
- e.(accuracy_hit[w]) = hit;
- e.(accuracy_fired[w]) = fired;
- e.SendFlags |= pow(2, w);
+ a.(accuracy_hit[w]) = hit;
+ a.(accuracy_fired[w]) = fired;
+ w = pow(2, w);
+ a.SendFlags |= w;
+ FOR_EACH_CLIENT(a)
+ if(a.classname == "spectator")
+ if(a.enemy == e)
+ a.SendFlags |= w;
}
void accuracy_add(entity e, float w, float hit, float fired)
{
- e = e.accuracy;
+ entity a;
+ a = e.accuracy;
+ if(!a)
+ return;
w -= WEP_FIRST;
- e.(accuracy_hit[w]) += hit;
- e.(accuracy_fired[w]) += fired;
- e.SendFlags |= pow(2, w);
+ a.(accuracy_hit[w]) += hit;
+ a.(accuracy_fired[w]) += fired;
+ w = pow(2, w);
+ a.SendFlags |= w;
+ FOR_EACH_CLIENT(a)
+ if(a.classname == "spectator")
+ if(a.enemy == e)
+ a.SendFlags |= w;
}
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);
-
other = spectatee;
MUTATOR_CALLHOOK(SpectateCopy);
self.armortype = spectatee.armortype;
//stuffcmd(self, "set viewsize $tmpviewsize \n");
self.movetype = MOVETYPE_NONE;
- self.enemy.weapon_count = 0;
-
if(!SpectateUpdate())
PutObserverInServer();
if(cvar("g_campaign"))
campaign_bots_may_start = 1;
- self.stat_count = WEP_LAST;
-
PutClientInServer();
if(self.classname == "player")
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())
stuffcmd(self, strcat("name ", self.netname, substring(ftos(random()), 2, -1), "\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).
// track max damage
if not(inWarmupStage) {
- entity w;
- w = get_weaponinfo(ent.weapon);
- if(w.spawnflags & 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]);
- }
+ accuracy_add(ent, ent.weapon, maxdamage, 0);
}
W_HitPlotAnalysis(ent, v_forward, v_right, v_up);
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;
.float hitplotfh;
.string noise4;
-.float stat_hit;
-.float stat_fired;
-.float stat_count;
-
-.float stats_hit[WEP_MAXCOUNT]; // for hitscan bullets hit
-.float stats_fired[WEP_MAXCOUNT]; // for hitscan bullets fired
-
.float last_pickup;
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(stats_hit);
-FTEQCC_YOU_SUCK_THIS_IS_NOT_UNREFERENCED(stats_fired);
-
.float stat_leadlimit;
float radar_showennemies;
if not(inWarmupStage)
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]);
- }
+ accuracy_add(attacker, weaponid, 0, damage);
}
float RadiusDamage_running;
float tfloorforce;
float stat_damagedone;
- float stat_maxdamage;
if(RadiusDamage_running)
{
}
stat_damagedone = 0;
- stat_maxdamage = 0;
targ = WarpZone_FindRadius (blastorigin, rad, FALSE);
while (targ)
if(targ.deadflag == DEAD_NO)
if(targ != attacker)
if(!teamplay || targ.team != attacker.team)
- {
stat_damagedone += finaldmg;
- stat_maxdamage += coredamage;
- }
}
if(targ == directhitentity || DEATH_ISSPECIAL(deathtype))
RadiusDamage_running = 0;
- Damage_RecordDamage(attacker, deathtype, min(stat_maxdamage, stat_damagedone));
+ Damage_RecordDamage(attacker, deathtype, min(coredamage, stat_damagedone));
return total_damage_to_creatures;
}
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, 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);
*/
void NextLevel()
{
- float i;
-
gameover = TRUE;
intermission_running = 1;
GameLogClose();
-// TO DO
-
-// 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
-
-// write a stats parser for the menu
-
- if(cvar("sv_accuracy_data_send")) {
- string stats_to_send;
-
- FOR_EACH_CLIENT(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_REALCLIENT(other) { // only spam humans
- Score_NicePrint(other); // print the score
-
- if(other.cvar_cl_accuracy_data_receive) // send the stats string to all the willing clients
- bprint(stats_to_send);
- }
- } else { // ye olde message
- FOR_EACH_PLAYER(other) {
- FixIntermissionClient(other);
-
- if(other.winning)
- bprint(other.netname, " ^7wins.\n");
- }
+ FOR_EACH_PLAYER(other) {
+ FixIntermissionClient(other);
+ if(other.winning)
+ bprint(other.netname, " ^7wins.\n");
}
if(cvar("g_campaign"))
replacement = ftos(vlen(self.velocity - self.velocity_z * '0 0 1'));
else if (escape == "S")
replacement = ftos(vlen(self.velocity));
- else if (escape == "v") {
- float weapon_number;
- local entity stats;
-
- if(self.classname == "spectator")
- stats = self.enemy;
- else
- stats = self;
-
- weapon_number = stats.weapon;
-
- if (!weapon_number)
- weapon_number = stats.switchweapon;
-
- if (!weapon_number)
- weapon_number = stats.cnt;
-
- if(stats.cvar_cl_accuracy_data_share && stats.stats_fired[weapon_number - 1])
- replacement = ftos(bound(0, floor(100 * stats.stats_hit[weapon_number - 1] / stats.stats_fired[weapon_number - 1]), 100));
- else
- replacement = "~"; // or something to indicate NULL, not available
- }
msg = strcat(substring(msg, 0, p), replacement, substring(msg, p+2, strlen(msg) - (p+2)));
p = p + strlen(replacement);
local vector hitloc, force, endpoint, dir;
local entity ent, endent;
local float endq3surfaceflags;
+ float totaldmg;
float length;
vector beampos;
entity pseudoprojectile;
float f, ffs;
- float hit;
-
railgun_start = start;
railgun_end = end;
// go a little bit into the wall because we need to hit this wall later
end = end + dir;
+ totaldmg = 0;
+
// trace multiple times until we hit a wall, each obstacle will be made
// non-solid so we can hit the next, while doing this we spawn effects and
// note down which entities were hit so we can damage them later
// get the details we need to call the damage function
hitloc = ent.railgunhitloc;
- //for stats so that team hit will count as a miss
- if(ent.flags & FL_CLIENT)
- if(ent.deadflag == DEAD_NO)
- hit = 1;
-
- if(teams_matter)
- if(ent.team == self.team)
- hit = 0;
-
f = ExponentialFalloff(mindist, maxdist, halflifedist, ent.railgundistance);
ffs = ExponentialFalloff(mindist, maxdist, forcehalflifedist, ent.railgundistance);
+ if(ent.flags & FL_CLIENT)
+ if(ent.deadflag == DEAD_NO)
+ if(!teamplay || ent.team != self.team)
+ totaldmg += bdamage * f;
+
// apply the damage
if (ent.takedamage)
Damage (ent, self, self, bdamage * f, deathtype, hitloc, force * ffs);
// calculate hits and fired shots for hitscan
if not(inWarmupStage)
- {
- self.stats_fired[self.weapon - 1] += 1;
- self.stat_fired = self.weapon + 64 * floor(self.stats_fired[self.weapon - 1]);
-
- if(hit) {
- self.stats_hit[self.weapon - 1] += 1;
- self.stat_hit = self.weapon + 64 * floor(self.stats_hit[self.weapon - 1]);
- }
- }
+ accuracy_add(self, self.weapon, 0, min(bdamage, totaldmg));
trace_endpos = endpoint;
trace_ent = endent;
.float dmg_edge;
.float dmg_force;
.float dmg_radius;
+.float dmg_total;
void W_BallisticBullet_Hit (void)
{
- float f;
+ float f, q;
f = pow(bound(0, vlen(self.velocity) / vlen(self.oldvelocity), 1), 2); // energy multiplier
+ q = 1 + self.dmg_edge / self.dmg;
if(other.solid == SOLID_BSP)
Damage_DamageInfo(self.origin, self.dmg * f, 0, 0, max(1, self.dmg_force) * normalize(self.velocity) * f, self.projectiledeathtype, self);
if(self.dmg_edge != 0)
{
if(headshot)
+ {
+ f *= q;
AnnounceTo(self.owner, "headshot");
- if(yoda)
- AnnounceTo(self.owner, "awesome");
+ }
}
+ if(yoda)
+ AnnounceTo(self.owner, "awesome");
// calculate hits for ballistic weapons
if (other.flags & FL_CLIENT) // is the player a client
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
{
- 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]);
+ // do not exceed 100%
+ q = min(self.dmg * q, self.dmg_total + f * self.dmg) - self.dmg_total;
+ self.dmg_total += f * self.dmg;
+ accuracy_add(self.owner, self.owner.weapon, 0, q);
}
}
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
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)