Licar/mods/stats.diff

243 lines
7.9 KiB
Diff
Raw Normal View History

2025-07-07 07:41:36 +02:00
Simple mod that will print run stats (such as maximum speed or acceleration) to
the console upon finishing (in normal run or replay).
diff --git a/frontend_helper.h b/frontend_helper.h
2025-07-07 08:05:32 +02:00
index f95b078..f006fe4 100644
2025-07-07 07:41:36 +02:00
--- a/frontend_helper.h
+++ b/frontend_helper.h
2025-07-07 08:05:32 +02:00
@@ -128,3 +128,63 @@ void closeDataFile(void)
2025-07-07 07:41:36 +02:00
fclose(dataFile);
#endif
}
+
+void _printStatVal(int val, int divisor)
+{
+ if (val < 0)
+ {
+ putchar('-');
+ val *= -1;
+ }
+
+ printf("%d",val / divisor);
+
+ if (divisor > 1)
+ printf(".%d",val % divisor);
+}
+
+void LCR_presentStats(const int *stats)
+{
+ printf("run stats: ");
+ printf("speed (max/avg): ");
+ _printStatVal(stats[0],1);
+ putchar(' ');
+ _printStatVal(stats[1],1000);
+
+ printf("; accel (min/max/avg/avgAbs): ");
+ _printStatVal(stats[2],1);
+ putchar(' ');
+ _printStatVal(stats[3],1);
+ putchar(' ');
+ _printStatVal(stats[4],1000);
+ putchar(' ');
+ _printStatVal(stats[5],1000);
+
+ printf("; dist: ");
+ _printStatVal(stats[6],100);
+
+ printf("; surface %% (concr./grass/dirt/ice/air): ");
+
+ for (int i = 7; i <= 11; ++i)
+ {
+ _printStatVal(stats[i],1);
+ putchar(i == 11 ? ';' : ' ');
+ }
+
+ printf(" keys (U/D/R/L/avg): ");
+
+ _printStatVal(stats[12],1);
+ putchar(' ');
+ _printStatVal(stats[13],1);
+ putchar(' ');
+ _printStatVal(stats[14],1);
+ putchar(' ');
+ _printStatVal(stats[15],1);
+ putchar(' ');
+ _printStatVal(stats[16],100);
+
2025-07-07 08:05:32 +02:00
+ printf("; drift: ");
+ _printStatVal(stats[17],1);
+
2025-07-07 07:41:36 +02:00
+ putchar('\n');
+}
diff --git a/game.h b/game.h
2025-07-07 08:05:32 +02:00
index 1ad5131..0ec623d 100644
2025-07-07 07:41:36 +02:00
--- a/game.h
+++ b/game.h
2025-07-07 08:05:32 +02:00
@@ -167,6 +167,33 @@ uint8_t LCR_gameMusicOn(void);
2025-07-07 07:41:36 +02:00
*/
uint8_t LCR_gameGetNextAudioSample(void);
+#define LCR_STATS_SPEED_KMH_MAX 0
+#define LCR_STATS_SPEED_MH_AVG 1
+#define LCR_STATS_ACCEL_KMH_MIN 2
+#define LCR_STATS_ACCEL_KMH_MAX 3
+#define LCR_STATS_ACCEL_MHS_AVG 4
+#define LCR_STATS_ACCEL_ABS_MHS_AVG 5
+#define LCR_STATS_DIST_CM 6
+#define LCR_STATS_SURF_PERC_CONCR 7
+#define LCR_STATS_SURF_PERC_GRASS 8
+#define LCR_STATS_SURF_PERC_DIRT 9
+#define LCR_STATS_SURF_PERC_ICE 10
+#define LCR_STATS_SURF_PERC_AIR 11
+#define LCR_STATS_KEY_FRAMES_U 12
+#define LCR_STATS_KEY_FRAMES_D 13
+#define LCR_STATS_KEY_FRAMES_R 14
+#define LCR_STATS_KEY_FRAMES_L 15
+#define LCR_STATS_KEYS_AVG_X100 16
2025-07-07 08:05:32 +02:00
+#define LCR_STATS_DRIFT_FRAMES 17
+#define _LCR_STATS_TOTAL 18
2025-07-07 07:41:36 +02:00
+
+/**
+ Will be called to present run stats, implement the presentation however you
+ want (e.g. by printing to standard output). The stats array holds individual
+ stats values, their meaning is described by the LCR_STATS_* constants.
+*/
+void LCR_presentStats(const int *stats);
+
/**
This macro may be redefined by frontend to a command that will be periodically
performed during map loading. This exists to prevent making the program seem
2025-07-07 08:05:32 +02:00
@@ -386,6 +413,9 @@ struct
2025-07-07 07:41:36 +02:00
uint8_t renderFramesMeasured;
uint8_t physicsFramesMeasured;
#endif
+
+ LCR_GameUnit prevSpeed;
+ int stats[_LCR_STATS_TOTAL];
} LCR_game;
uint8_t LCR_gameMusicOn(void)
2025-07-07 08:05:32 +02:00
@@ -494,6 +524,11 @@ void LCR_gameResetRun(uint8_t replay, uint8_t ghost)
2025-07-07 07:41:36 +02:00
LCR_racingGetCarTransform(carTransform,carTransform + 3,0);
LCR_rendererSetCarTransform(carTransform,carTransform + 3);
+ LCR_game.prevSpeed = 0;
+
+ for (int i = 0; i < _LCR_STATS_TOTAL; ++i)
+ LCR_game.stats[i] = 0;
+
if (LCR_game.cameraMode != LCR_CAMERA_MODE_FREE)
{
LCR_rendererCameraReset();
2025-07-07 08:05:32 +02:00
@@ -1776,6 +1811,63 @@ uint8_t LCR_gameStep(uint32_t time)
2025-07-07 07:41:36 +02:00
uint32_t events = paused ? 0 : LCR_racingStep(input);
+ // collect stats:
+
+ int stat = LCR_carSpeedKMH();
+
+ if (stat > LCR_game.stats[LCR_STATS_SPEED_KMH_MAX])
+ LCR_game.stats[LCR_STATS_SPEED_KMH_MAX] = stat;
+
+ LCR_game.stats[LCR_STATS_SPEED_MH_AVG] += stat;
+
2025-07-07 08:05:32 +02:00
+ LCR_game.stats[LCR_STATS_DRIFT_FRAMES] += LCR_racing.carDrifting;
+
2025-07-07 07:41:36 +02:00
+ if ((LCR_racing.wheelCollisions & 0x0f) == 0)
+ LCR_game.stats[LCR_STATS_SURF_PERC_AIR]++;
+ else if (LCR_racingCurrentGroundMaterial() == LCR_BLOCK_MATERIAL_GRASS)
+ LCR_game.stats[LCR_STATS_SURF_PERC_GRASS]++;
+ else if (LCR_racingCurrentGroundMaterial() == LCR_BLOCK_MATERIAL_DIRT)
+ LCR_game.stats[LCR_STATS_SURF_PERC_DIRT]++;
+ else if (LCR_racingCurrentGroundMaterial() == LCR_BLOCK_MATERIAL_ICE)
+ LCR_game.stats[LCR_STATS_SURF_PERC_ICE]++;
+ else
+ LCR_game.stats[LCR_STATS_SURF_PERC_CONCR]++;
+
+ LCR_game.stats[LCR_STATS_KEY_FRAMES_U] +=
+ (LCR_racing.currentInputs & LCR_RACING_INPUT_FORW) != 0;
+ LCR_game.stats[LCR_STATS_KEY_FRAMES_D] +=
+ (LCR_racing.currentInputs & LCR_RACING_INPUT_BACK) != 0;
+ LCR_game.stats[LCR_STATS_KEY_FRAMES_R] +=
+ (LCR_racing.currentInputs & LCR_RACING_INPUT_RIGHT) != 0;
+ LCR_game.stats[LCR_STATS_KEY_FRAMES_L] +=
+ (LCR_racing.currentInputs & LCR_RACING_INPUT_LEFT) != 0;
+
+ LCR_game.stats[LCR_STATS_KEYS_AVG_X100] +=
+ ((LCR_racing.currentInputs & LCR_RACING_INPUT_FORW) != 0) +
+ ((LCR_racing.currentInputs & LCR_RACING_INPUT_BACK) != 0) +
+ ((LCR_racing.currentInputs & LCR_RACING_INPUT_RIGHT) != 0) +
+ ((LCR_racing.currentInputs & LCR_RACING_INPUT_LEFT) != 0);
+
+ stat = LCR_carSpeedKMH() - LCR_game.prevSpeed;
+
+ if (LCR_game.runTime <= 1 ||
+ stat > LCR_game.stats[LCR_STATS_ACCEL_KMH_MAX])
+ LCR_game.stats[LCR_STATS_ACCEL_KMH_MAX] = stat;
+
+ if (LCR_game.runTime <= 1 ||
+ stat < LCR_game.stats[LCR_STATS_ACCEL_KMH_MIN])
+ LCR_game.stats[LCR_STATS_ACCEL_KMH_MIN] = stat;
+
+ LCR_game.stats[LCR_STATS_ACCEL_MHS_AVG] += stat;
+
+ if (stat < 0)
+ stat *= -1;
+
+ LCR_game.stats[LCR_STATS_ACCEL_ABS_MHS_AVG] += stat;
+ LCR_game.stats[LCR_STATS_DIST_CM] += LCR_racingGetCarSpeedUnsigned();
+
+ LCR_game.prevSpeed = LCR_carSpeedKMH();
+
#if LCR_SETTING_PARTICLES
LCR_rendererSetParticles(0);
2025-07-07 08:05:32 +02:00
@@ -1816,6 +1908,46 @@ uint8_t LCR_gameStep(uint32_t time)
2025-07-07 07:41:36 +02:00
LCR_LOG1("finished, time:");
LCR_LOG1_NUM(LCR_game.runTime);
+ // now convert collected stats to correct units:
+
+ LCR_game.stats[LCR_STATS_SPEED_MH_AVG] =
+ (LCR_game.stats[LCR_STATS_SPEED_MH_AVG] * 1000) / LCR_game.runTime;
+
+ LCR_game.stats[LCR_STATS_ACCEL_MHS_AVG] =
+ (LCR_game.stats[LCR_STATS_ACCEL_MHS_AVG] * 1000 * LCR_RACING_FPS) /
+ LCR_game.runTime;
+
+ LCR_game.stats[LCR_STATS_ACCEL_ABS_MHS_AVG] =
+ (LCR_game.stats[LCR_STATS_ACCEL_ABS_MHS_AVG] * 1000 * LCR_RACING_FPS)
+ / LCR_game.runTime;
+
+ int tmp =
+ LCR_game.stats[LCR_STATS_SURF_PERC_CONCR] +
+ LCR_game.stats[LCR_STATS_SURF_PERC_GRASS] +
+ LCR_game.stats[LCR_STATS_SURF_PERC_DIRT] +
+ LCR_game.stats[LCR_STATS_SURF_PERC_ICE] +
+ LCR_game.stats[LCR_STATS_SURF_PERC_AIR];
+
+ LCR_game.stats[LCR_STATS_SURF_PERC_CONCR] =
+ (100 * LCR_game.stats[LCR_STATS_SURF_PERC_CONCR]) / tmp;
+ LCR_game.stats[LCR_STATS_SURF_PERC_GRASS] =
+ (100 * LCR_game.stats[LCR_STATS_SURF_PERC_GRASS]) / tmp;
+ LCR_game.stats[LCR_STATS_SURF_PERC_DIRT] =
+ (100 * LCR_game.stats[LCR_STATS_SURF_PERC_DIRT]) / tmp;
+ LCR_game.stats[LCR_STATS_SURF_PERC_ICE] =
+ (100 * LCR_game.stats[LCR_STATS_SURF_PERC_ICE]) / tmp;
+ LCR_game.stats[LCR_STATS_SURF_PERC_AIR] =
+ (100 * LCR_game.stats[LCR_STATS_SURF_PERC_AIR]) / tmp;
+
+ LCR_game.stats[LCR_STATS_KEYS_AVG_X100] =
+ (LCR_game.stats[LCR_STATS_KEYS_AVG_X100] * 100)/ LCR_game.runTime;
+
+ LCR_game.stats[LCR_STATS_DIST_CM] =
+ (LCR_game.stats[LCR_STATS_DIST_CM] * LCR_SETTING_CMS_PER_BLOCK)
+ / LCR_GAME_UNIT;
+
+ LCR_presentStats(LCR_game.stats);
+
if (LCR_game.runTime <= LCR_currentMap.targetTime
#if LCR_SETTING_REPLAY_MAX_SIZE != 0
&& !LCR_racing.replay.on