104 lines
3.4 KiB
C++
104 lines
3.4 KiB
C++
|
|
#include "debug/metrics.h"
|
|||
|
|
|
|||
|
|
void Metrics::LogFriendlyHit(int shooter, int victim, Vec2 pos, bool victimAdvancing)
|
|||
|
|
{
|
|||
|
|
++friendlyHits;
|
|||
|
|
if (hitLogCount < HIT_LOG_MAX)
|
|||
|
|
hitLog[hitLogCount++] = FriendlyHitEvent{clock, shooter, victim, pos, victimAdvancing};
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Metrics::Reset()
|
|||
|
|
{
|
|||
|
|
friendlyHits = 0;
|
|||
|
|
hitLogCount = 0;
|
|||
|
|
clock = 0.0f;
|
|||
|
|
targetsKilled = 0;
|
|||
|
|
shotsFired = 0;
|
|||
|
|
meleeSwings = 0;
|
|||
|
|
meleeHits = 0;
|
|||
|
|
meleeAborts = 0;
|
|||
|
|
for (int& v : meleeComboSwings) v = 0;
|
|||
|
|
meleeMaxHitExcessDeg = 0.0f;
|
|||
|
|
reloads = 0;
|
|||
|
|
|
|||
|
|
for (int i = 0; i < NUM_AGENTS; ++i)
|
|||
|
|
{
|
|||
|
|
laneCount[i] = 0;
|
|||
|
|
uptimePct[i] = 0.0f;
|
|||
|
|
for (int k = 0; k < UPTIME_SAMPLES; ++k) ring[i][k] = 0;
|
|||
|
|
}
|
|||
|
|
ringPos = 0;
|
|||
|
|
ringFill = 0;
|
|||
|
|
uptimeAvg = 0.0f;
|
|||
|
|
meleeUptimeAvg = 0.0f;
|
|||
|
|
|
|||
|
|
settleArmed = true; // старт — отряд уже стоит, замеряем первое расхождение
|
|||
|
|
settleClock = 0.0f;
|
|||
|
|
lastSettle = -1.0f;
|
|||
|
|
prevState = AgentState::HOLDING;
|
|||
|
|
simMs = 0.0f;
|
|||
|
|
renderMs = 0.0f;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void Metrics::Sample(const Squad& squad, float dt)
|
|||
|
|
{
|
|||
|
|
clock += dt;
|
|||
|
|
|
|||
|
|
// --- FIRE UPTIME (скользящее окно) ---
|
|||
|
|
const int window = std::min(UPTIME_SAMPLES,
|
|||
|
|
std::max(1, int(g_tune.uptimeWindow / FIXED_DT)));
|
|||
|
|
if (ringPos >= window) ringPos = 0;
|
|||
|
|
|
|||
|
|
// «В бою» для стрелка — валидная линия огня, для клинка — цель в зоне удара.
|
|||
|
|
// Считаются они одинаково, а усредняются раздельно: смешивать доли времени
|
|||
|
|
// двух разных занятий в одно число бессмысленно.
|
|||
|
|
int readyNow = 0;
|
|||
|
|
for (int i = 0; i < NUM_AGENTS; ++i)
|
|||
|
|
{
|
|||
|
|
const Agent& a = squad.agents[i];
|
|||
|
|
const bool engaged = a.IsMelee() ? a.melee.inReach : a.hasLane;
|
|||
|
|
const unsigned char v = engaged ? 1u : 0u;
|
|||
|
|
|
|||
|
|
laneCount[i] -= ring[i][ringPos];
|
|||
|
|
ring[i][ringPos] = v;
|
|||
|
|
laneCount[i] += v;
|
|||
|
|
|
|||
|
|
// Для SETTLE TIME клинку достаточно ИМЕТЬ цель: он к ней ещё идёт,
|
|||
|
|
// но отряд уже разобрал обстановку, а именно это метрика и меряет.
|
|||
|
|
if (a.IsMelee() ? (a.melee.targetId >= 0) : a.hasLane) ++readyNow;
|
|||
|
|
}
|
|||
|
|
ringPos = (ringPos + 1) % window;
|
|||
|
|
ringFill = std::min(ringFill + 1, window);
|
|||
|
|
|
|||
|
|
float rangedSum = 0.0f;
|
|||
|
|
float meleeSum = 0.0f;
|
|||
|
|
for (int i = 0; i < NUM_AGENTS; ++i)
|
|||
|
|
{
|
|||
|
|
uptimePct[i] = (ringFill > 0) ? (100.0f * float(laneCount[i]) / float(ringFill)) : 0.0f;
|
|||
|
|
if (squad.agents[i].IsMelee()) meleeSum += uptimePct[i];
|
|||
|
|
else rangedSum += uptimePct[i];
|
|||
|
|
}
|
|||
|
|
const int ranged = squad.RangedCount();
|
|||
|
|
uptimeAvg = (ranged > 0) ? rangedSum / float(ranged) : 0.0f;
|
|||
|
|
meleeUptimeAvg = (squad.meleeCount > 0) ? meleeSum / float(squad.meleeCount) : 0.0f;
|
|||
|
|
|
|||
|
|
// --- SETTLE TIME ---
|
|||
|
|
if (squad.state == AgentState::HOLDING && prevState == AgentState::ADVANCING)
|
|||
|
|
{
|
|||
|
|
settleArmed = true;
|
|||
|
|
settleClock = 0.0f;
|
|||
|
|
}
|
|||
|
|
if (squad.state == AgentState::ADVANCING) settleArmed = false;
|
|||
|
|
|
|||
|
|
if (settleArmed)
|
|||
|
|
{
|
|||
|
|
settleClock += dt;
|
|||
|
|
if (float(readyNow) >= g_tune.settleQuorum)
|
|||
|
|
{
|
|||
|
|
lastSettle = settleClock;
|
|||
|
|
settleArmed = false;
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
prevState = squad.state;
|
|||
|
|
}
|