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
|