#include "accuracy.qh"
-#include "../mutators/_mod.qh"
+#include <server/mutators/_mod.qh>
#include <common/constants.qh>
+#include <common/net_linked.qh>
#include <common/teams.qh>
#include <common/util.qh>
#include <common/weapons/_all.qh>
entity a = this.owner;
if (IS_SPEC(a)) a = a.enemy;
- a = a.accuracy;
+ a = CS(a).accuracy;
if (to != a.owner)
- if (!autocvar_sv_accuracy_data_share && !a.owner.cvar_cl_accuracy_data_share)
+ if (!autocvar_sv_accuracy_data_share && !CS(a.owner).cvar_cl_accuracy_data_share)
sf = 0;
// note: zero sendflags can never be sent... so we can use that to say that we send no accuracy!
WriteInt24_t(MSG_ENTITY, sf);
// init/free
void accuracy_init(entity e)
{
- entity a = e.accuracy = new_pure(accuracy);
+ entity a = CS(e).accuracy = new_pure(accuracy);
a.owner = e;
a.drawonlytoclient = e;
Net_LinkEntity(a, false, 0, accuracy_send);
void accuracy_free(entity e)
{
- delete(e.accuracy);
+ delete(CS(e).accuracy);
}
// force a resend of a player's accuracy stats
void accuracy_resend(entity e)
{
- e.accuracy.SendFlags = 0xFFFFFF;
+ CS(e).accuracy.SendFlags = 0xFFFFFF;
}
// update accuracy stats
void accuracy_add(entity this, int w, int fired, int hit)
{
if (IS_INDEPENDENT_PLAYER(this)) return;
- entity a = this.accuracy;
+ entity a = CS(this).accuracy;
if (!a) return;
if (!hit && !fired) return;
+ if (w == WEP_Null.m_id) return;
w -= WEP_FIRST;
int b = accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w]);
if (hit) a.accuracy_hit [w] += hit;
if (fired) a.accuracy_fired[w] += fired;
- if (hit && a.hit_time != time) { // only run this once per frame
+ if (hit && STAT(HIT_TIME, a) != time) { // only run this once per frame
a.accuracy_cnt_hit[w] += 1;
- a.hit_time = time;
+ STAT(HIT_TIME, a) = time;
}
if (fired && a.fired_time != time) { // only run this once per frame
if (b == accuracy_byte(a.accuracy_hit[w], a.accuracy_fired[w])) return; // no change
int sf = 1 << (w % 24);
a.SendFlags |= sf;
- FOREACH_CLIENT(IS_SPEC(it) && it.enemy == this, LAMBDA(it.accuracy.SendFlags |= sf));
+ FOREACH_CLIENT(IS_SPEC(it) && it.enemy == this, { CS(it).accuracy.SendFlags |= sf; });
}
bool accuracy_isgooddamage(entity attacker, entity targ)
int mutator_check = MUTATOR_CALLHOOK(AccuracyTargetValid, attacker, targ);
if (warmup_stage) return false;
- if (IS_DEAD(targ)) return false;
- if (STAT(FROZEN, targ)) return false;
+ if (game_stopped) return false;
+
+ // damage to dead/frozen players is good only if it happens in the frame they get killed / frozen
+ // so that stats for weapons that shoot multiple projectiles per shot are properly counted
+ if (IS_DEAD(targ) && time > targ.death_time) return false;
+ if (STAT(FROZEN, targ) && time > targ.freeze_time) return false;
if (SAME_TEAM(attacker, targ)) return false;
if (mutator_check == MUT_ACCADD_INVALID) return true;