High Scores
Source: src/high_scores.c · 278 lines · 18 functions.
Module entry points
These functions are exposed to the rest of the project. Open one to follow its decisions and the helpers it calls.
How to read these diagrams
Each function has its own expandable diagram using the actual expressions and statements from this file. Decisions split into True and False; loop bodies are indented. Returns end the function immediately; break and continue follow their C meanings. Arrows between statements show their order when execution reaches them.
These are structural source diagrams before preprocessing, not runtime traces. Conditional compilation and macros remain source expressions. Ternary choices remain inside their statement. Calls are linked separately; callback execution and task scheduling are not inferred.
Functions in this file
validGame() · source line 29
static bool validGame(high_score_game_t game)
- Exit this function
return (unsigned)game < HIGH_SCORE_GAME_COUNT;
Read original function source
static bool validGame(high_score_game_t game)
{
return (unsigned)game < HIGH_SCORE_GAME_COUNT;
}validName() · source line 34
static bool validName(const char *name)
- Decision
name == NULLTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
bool nonSpace = false; - FOR loop
size_t i = 0; i <= HIGH_SCORE_NAME_CHARS; ++iRepeat body while the loop condition permits; then continue below.
- Execute
const char ch = name[i]; - Decision
ch == '\0'True- Exit this function
return nonSpace;
FalseContinue after this decision.
- Decision
i == HIGH_SCORE_NAME_CHARSTrue- Exit this function
return false;
FalseContinue after this decision.
- Decision
(ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && ch != '_' && ch != ' 'True- Exit this function
return false;
FalseContinue after this decision.
- Decision
ch != ' 'True- Execute
nonSpace = true;
FalseContinue after this decision.
- Exit this function
return false;
Read original function source
static bool validName(const char *name)
{
if (name == NULL) return false;
bool nonSpace = false;
for (size_t i = 0; i <= HIGH_SCORE_NAME_CHARS; ++i) {
const char ch = name[i];
if (ch == '\0') return nonSpace;
if (i == HIGH_SCORE_NAME_CHARS) return false;
if ((ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && ch != '_' && ch != ' ') return false;
if (ch != ' ') nonSpace = true;
}
return false;
}validTable() · source line 48
static bool validTable(const high_score_table_t *table)
Calls into this documentation:
- Decision
table == NULL || table->count > HIGH_SCORE_COUNTTrue- Exit this function
return false;
FalseContinue after this decision.
- FOR loop
uint32_t i = 0; i < table->count; ++iRepeat body while the loop condition permits; then continue below.
- Decision
!validName(table->entries[i].name) || table->entries[i].score == 0True- Exit this function
return false;
FalseContinue after this decision.
- Decision
i != 0 && table->entries[i].score > table->entries[i - 1U].scoreTrue- Exit this function
return false;
FalseContinue after this decision.
- Exit this function
return true;
Read original function source
static bool validTable(const high_score_table_t *table)
{
if (table == NULL || table->count > HIGH_SCORE_COUNT) return false;
for (uint32_t i = 0; i < table->count; ++i) {
if (!validName(table->entries[i].name) || table->entries[i].score == 0) return false;
if (i != 0 && table->entries[i].score > table->entries[i - 1U].score) return false;
}
return true;
}readWord() · source line 59
static uint32_t readWord(const uint8_t *bytes)
- Exit this function
return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) | ((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
Read original function source
static uint32_t readWord(const uint8_t *bytes)
{
return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
}writeWord() · source line 65
static void writeWord(uint8_t *bytes, uint32_t value)
- FOR loop
unsigned i = 0; i < 4; ++iRepeat body while the loop condition permits; then continue below.
- Execute
bytes[i] = (uint8_t)(value >> (i * 8U));
Read original function source
static void writeWord(uint8_t *bytes, uint32_t value)
{
for (unsigned i = 0; i < 4; ++i) bytes[i] = (uint8_t)(value >> (i * 8U));
}encodeRecord() · source line 70
static void encodeRecord(const high_score_table_t *table, uint8_t *record)
Calls into this documentation:
- Execute
memset(record, 0, RECORD_BYTES); - Execute
writeWord(record, RECORD_VERSION); - Execute
writeWord(record + 4, table->count); - FOR loop
uint32_t i = 0; i < table->count; ++iRepeat body while the loop condition permits; then continue below.
- Execute
uint8_t *entry = record + 8U + i * ENTRY_BYTES; - Execute
memcpy(entry, table->entries[i].name, sizeof(table->entries[i].name)); - Execute
writeWord(entry + HIGH_SCORE_NAME_CHARS + 1U, table->entries[i].score);
- Execute
writeWord(record + RECORD_CRC_OFFSET, integrity_crc32(record, RECORD_CRC_OFFSET));
Read original function source
static void encodeRecord(const high_score_table_t *table, uint8_t *record)
{
memset(record, 0, RECORD_BYTES);
writeWord(record, RECORD_VERSION);
writeWord(record + 4, table->count);
for (uint32_t i = 0; i < table->count; ++i) {
uint8_t *entry = record + 8U + i * ENTRY_BYTES;
memcpy(entry, table->entries[i].name, sizeof(table->entries[i].name));
writeWord(entry + HIGH_SCORE_NAME_CHARS + 1U, table->entries[i].score);
}
writeWord(record + RECORD_CRC_OFFSET, integrity_crc32(record, RECORD_CRC_OFFSET));
}decodeRecord() · source line 83
static bool decodeRecord(const uint8_t *record, size_t record_size,
high_score_table_t *table)Calls into this documentation:
- Decision
record == NULL || table == NULLTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
const uint32_t version = readWord(record); - Decision
record_size == RECORD_BYTES && version == RECORD_VERSIONTrue- Decision
readWord(record + RECORD_CRC_OFFSET) != integrity_crc32(record, RECORD_CRC_OFFSET)True- Exit this function
return false;
FalseContinue after this decision.
False- Exit this function
return false;
- Decision
readWord(record + 4) > HIGH_SCORE_COUNTTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
high_score_table_t loaded = {0}; - Execute
loaded.count = readWord(record + 4); - FOR loop
uint32_t i = 0; i < loaded.count; ++iRepeat body while the loop condition permits; then continue below.
- Execute
const uint8_t *entry = record + 8U + i * ENTRY_BYTES; - Execute
memcpy(loaded.entries[i].name, entry, sizeof(loaded.entries[i].name)); - Execute
loaded.entries[i].score = readWord(entry + HIGH_SCORE_NAME_CHARS + 1U);
- Decision
!validTable(&loaded)True- Exit this function
return false;
FalseContinue after this decision.
- Execute
*table = loaded; - Exit this function
return true;
Read original function source
static bool decodeRecord(const uint8_t *record, size_t record_size,
high_score_table_t *table)
{
if (record == NULL || table == NULL) return false;
const uint32_t version = readWord(record);
if (record_size == RECORD_BYTES && version == RECORD_VERSION) {
if (readWord(record + RECORD_CRC_OFFSET) != integrity_crc32(record, RECORD_CRC_OFFSET)) {
return false;
}
} else {
return false;
}
if (readWord(record + 4) > HIGH_SCORE_COUNT) return false;
high_score_table_t loaded = {0};
loaded.count = readWord(record + 4);
for (uint32_t i = 0; i < loaded.count; ++i) {
const uint8_t *entry = record + 8U + i * ENTRY_BYTES;
memcpy(loaded.entries[i].name, entry, sizeof(loaded.entries[i].name));
loaded.entries[i].score = readWord(entry + HIGH_SCORE_NAME_CHARS + 1U);
}
if (!validTable(&loaded)) return false;
*table = loaded;
return true;
}high_scores_load() · source line 109
high_score_result_t high_scores_load(high_score_game_t game, high_score_table_t *table)
Calls into this documentation:
- Decision
table == NULLTrue- Exit this function
return HIGH_SCORES_INVALID;
FalseContinue after this decision.
- Execute
*table = (high_score_table_t){0}; - Decision
!validGame(game)True- Exit this function
return HIGH_SCORES_INVALID;
FalseContinue after this decision.
- Execute
uint8_t record[RECORD_BYTES] = {0}; - Execute
bool found = false; - Execute
size_t record_size = 0; - Decision
!game_storage_read_sized(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record), &record_size, &found)True- Exit this function
return HIGH_SCORES_IO_ERROR;
FalseContinue after this decision.
- Decision
!foundTrue- Exit this function
return HIGH_SCORES_OK;
FalseContinue after this decision.
- Execute
high_score_table_t loaded = {0}; - Decision
record_size == LEGACY_RECORD_BYTES && readWord(record) == 1UTrue- Execute
ESP_LOGW("high_scores", "Replacing unprotected version-one score table for game %u", (unsigned)game); - Execute
encodeRecord(&loaded, record); - Decision
!game_storage_write(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record))True- Exit this function
return HIGH_SCORES_IO_ERROR;
FalseContinue after this decision.
- Execute
*table = loaded; - Exit this function
return HIGH_SCORES_OK;
FalseContinue after this decision.
- Decision
!decodeRecord(record, record_size, &loaded)True- Exit this function
return HIGH_SCORES_INVALID;
FalseContinue after this decision.
- Execute
*table = loaded; - Exit this function
return HIGH_SCORES_OK;
Read original function source
high_score_result_t high_scores_load(high_score_game_t game, high_score_table_t *table)
{
if (table == NULL) return HIGH_SCORES_INVALID;
*table = (high_score_table_t){0};
if (!validGame(game)) return HIGH_SCORES_INVALID;
uint8_t record[RECORD_BYTES] = {0};
bool found = false;
size_t record_size = 0;
if (!game_storage_read_sized(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record),
&record_size, &found)) {
return HIGH_SCORES_IO_ERROR;
}
if (!found) return HIGH_SCORES_OK;
high_score_table_t loaded = {0};
if (record_size == LEGACY_RECORD_BYTES && readWord(record) == 1U) {
// Version-one tables were not CRC-protected, so discard them rather
// than treating unverified scores as trusted data.
ESP_LOGW("high_scores", "Replacing unprotected version-one score table for game %u",
(unsigned)game);
encodeRecord(&loaded, record);
if (!game_storage_write(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record))) {
return HIGH_SCORES_IO_ERROR;
}
*table = loaded;
return HIGH_SCORES_OK;
}
if (!decodeRecord(record, record_size, &loaded)) return HIGH_SCORES_INVALID;
*table = loaded;
return HIGH_SCORES_OK;
}high_scores_qualifies() · source line 140
bool high_scores_qualifies(const high_score_table_t *table, uint32_t score)
Calls into this documentation:
- Exit this function
return validTable(table) && score != 0 && (table->count < HIGH_SCORE_COUNT || score > table->entries[HIGH_SCORE_COUNT - 1U].score);
Read original function source
bool high_scores_qualifies(const high_score_table_t *table, uint32_t score)
{
return validTable(table) && score != 0 &&
(table->count < HIGH_SCORE_COUNT || score > table->entries[HIGH_SCORE_COUNT - 1U].score);
}high_scores_submit() · source line 146
high_score_result_t high_scores_submit(high_score_game_t game, const char *name, uint32_t score)
Calls into this documentation:
- Decision
!validGame(game) || !validName(name)True- Exit this function
return HIGH_SCORES_INVALID;
FalseContinue after this decision.
- Execute
high_score_table_t table; - Execute
const high_score_result_t loaded = high_scores_load(game, &table); - Decision
loaded != HIGH_SCORES_OKTrue- Exit this function
return loaded;
FalseContinue after this decision.
- Decision
!high_scores_qualifies(&table, score)True- Exit this function
return HIGH_SCORES_NOT_QUALIFIED;
FalseContinue after this decision.
- Execute
uint32_t position = 0; - WHILE loop
position < table.count && table.entries[position].score >= scoreRepeat body while the loop condition permits; then continue below.
- Execute
++position;
- Decision
table.count < HIGH_SCORE_COUNTTrue- Execute
++table.count;
FalseContinue after this decision.
- FOR loop
uint32_t i = table.count - 1U; i > position; --iRepeat body while the loop condition permits; then continue below.
- Execute
table.entries[i] = table.entries[i - 1U];
- Execute
table.entries[position] = (high_score_entry_t){0}; - Execute
memcpy(table.entries[position].name, name, strlen(name) + 1U); - Execute
table.entries[position].score = score; - Execute
uint8_t record[RECORD_BYTES]; - Execute
encodeRecord(&table, record); - Exit this function
return game_storage_write(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record)) ? HIGH_SCORES_OK : HIGH_SCORES_IO_ERROR;
Read original function source
high_score_result_t high_scores_submit(high_score_game_t game, const char *name, uint32_t score)
{
if (!validGame(game) || !validName(name)) return HIGH_SCORES_INVALID;
high_score_table_t table;
const high_score_result_t loaded = high_scores_load(game, &table);
if (loaded != HIGH_SCORES_OK) return loaded;
if (!high_scores_qualifies(&table, score)) return HIGH_SCORES_NOT_QUALIFIED;
uint32_t position = 0;
while (position < table.count && table.entries[position].score >= score) ++position;
if (table.count < HIGH_SCORE_COUNT) ++table.count;
for (uint32_t i = table.count - 1U; i > position; --i) {
table.entries[i] = table.entries[i - 1U];
}
table.entries[position] = (high_score_entry_t){0};
memcpy(table.entries[position].name, name, strlen(name) + 1U);
table.entries[position].score = score;
uint8_t record[RECORD_BYTES];
encodeRecord(&table, record);
return game_storage_write(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record))
? HIGH_SCORES_OK : HIGH_SCORES_IO_ERROR;
}drawHighScores() · source line 168
void drawHighScores(uint16_t *frame, high_score_game_t game,
const high_score_table_t *table, high_score_result_t status)Calls into this documentation:
- Decision
frame == NULLTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
clear(frame, COLOR_BLACK); - Execute
draw_text_centred(frame, 160, 7, validGame(game) ? titles[game] : "HIGH SCORES", 2, COLOR_CYAN); - Execute
draw_text_centred(frame, 160, 27, "TOP 5", 1, COLOR_YELLOW); - Decision
status != HIGH_SCORES_OK || !validGame(game) || !validTable(table)True- Execute
draw_text_centred(frame, 160, 77, status == HIGH_SCORES_IO_ERROR ? "SCORE STORAGE ERROR" : "SCORE DATA ERROR", 1, COLOR_RED);
False- Execute
draw_text(frame, 30, 43, "NAME", 1, COLOR_CYAN); - Execute
draw_text(frame, 272, 43, "SCORE", 1, COLOR_CYAN); - FOR loop
uint32_t i = 0; i < HIGH_SCORE_COUNT; ++iRepeat body while the loop condition permits; then continue below.
- Execute
const int y = 61 + (int)i * 17; - Execute
char rank[4]; - Execute
snprintf(rank, sizeof(rank), "%u.", (unsigned)(i + 1U)); - Execute
draw_text(frame, 8, y, rank, 1, COLOR_YELLOW); - Execute
draw_text(frame, 30, y, i < table->count ? table->entries[i].name : "---", 1, COLOR_WHITE); - Decision
i < table->countTrue- Execute
char value[11]; - Execute
snprintf(value, sizeof(value), "%u", (unsigned)table->entries[i].score); - Execute
const int width = (int)strlen(value) * 6 - 1; - Execute
draw_text(frame, 311 - width, y, value, 1, COLOR_WHITE);
FalseContinue after this decision.
- Execute
draw_text_centred(frame, 160, 155, "A CONTINUE BOOT BACK", 1, COLOR_WHITE);
Read original function source
void drawHighScores(uint16_t *frame, high_score_game_t game,
const high_score_table_t *table, high_score_result_t status)
{
if (frame == NULL) return;
clear(frame, COLOR_BLACK);
draw_text_centred(frame, 160, 7, validGame(game) ? titles[game] : "HIGH SCORES", 2, COLOR_CYAN);
draw_text_centred(frame, 160, 27, "TOP 5", 1, COLOR_YELLOW);
if (status != HIGH_SCORES_OK || !validGame(game) || !validTable(table)) {
draw_text_centred(frame, 160, 77,
status == HIGH_SCORES_IO_ERROR ? "SCORE STORAGE ERROR" : "SCORE DATA ERROR", 1, COLOR_RED);
} else {
draw_text(frame, 30, 43, "NAME", 1, COLOR_CYAN);
draw_text(frame, 272, 43, "SCORE", 1, COLOR_CYAN);
for (uint32_t i = 0; i < HIGH_SCORE_COUNT; ++i) {
const int y = 61 + (int)i * 17;
char rank[4];
snprintf(rank, sizeof(rank), "%u.", (unsigned)(i + 1U));
draw_text(frame, 8, y, rank, 1, COLOR_YELLOW);
draw_text(frame, 30, y, i < table->count ? table->entries[i].name : "---", 1, COLOR_WHITE);
if (i < table->count) {
char value[11];
snprintf(value, sizeof(value), "%u", (unsigned)table->entries[i].score);
const int width = (int)strlen(value) * 6 - 1;
draw_text(frame, 311 - width, y, value, 1, COLOR_WHITE);
}
}
}
draw_text_centred(frame, 160, 155, "A CONTINUE BOOT BACK", 1, COLOR_WHITE);
}cancelHighScoreEntry() · source line 198
void cancelHighScoreEntry(void)
Calls into this documentation:
- Execute
cancelScreenKeyboard(); - Execute
entryState = ENTRY_IDLE; - Execute
entryPressed = false;
Read original function source
void cancelHighScoreEntry(void)
{
cancelScreenKeyboard();
entryState = ENTRY_IDLE;
entryPressed = false;
}startHighScoreEntry() · source line 205
void startHighScoreEntry(high_score_game_t game, uint32_t score, uint32_t now_ms)
Calls into this documentation:
- Execute
cancelHighScoreEntry(); - Execute
entryGame = game; - Execute
entryScore = score; - Execute
entryName[0] = '\0'; - Execute
entryStatus = high_scores_load(game, &entryTable); - Execute
entryState = ENTRY_TABLE; - Decision
entryStatus == HIGH_SCORES_OK && high_scores_qualifies(&entryTable, score)True- Execute
startScreenKeyboard(NULL, 10, KEYBOARD_NAME, "ENTER NAME", now_ms); - Execute
entryState = ENTRY_NAME;
False- Decision
entryStatus != HIGH_SCORES_OKTrue- Execute
ESP_LOGE("high_scores", "Cannot load game %u scores: %d", (unsigned)game, (int)entryStatus);
FalseContinue after this decision.
Read original function source
void startHighScoreEntry(high_score_game_t game, uint32_t score, uint32_t now_ms)
{
cancelHighScoreEntry();
entryGame = game;
entryScore = score;
entryName[0] = '\0';
entryStatus = high_scores_load(game, &entryTable);
entryState = ENTRY_TABLE;
if (entryStatus == HIGH_SCORES_OK && high_scores_qualifies(&entryTable, score)) {
startScreenKeyboard(NULL, 10, KEYBOARD_NAME, "ENTER NAME", now_ms);
entryState = ENTRY_NAME;
} else if (entryStatus != HIGH_SCORES_OK) {
ESP_LOGE("high_scores", "Cannot load game %u scores: %d", (unsigned)game, (int)entryStatus);
}
}highScoreEntryActive() · source line 221
bool highScoreEntryActive(void)
- Exit this function
return entryState != ENTRY_IDLE;
Read original function source
bool highScoreEntryActive(void)
{
return entryState != ENTRY_IDLE;
}highScoreEntryAction() · source line 226
void highScoreEntryAction(bool a_pressed)
Calls into this documentation:
- Decision
highScoreEntryActive()True- Execute
entryPressed = entryPressed || a_pressed;
FalseContinue after this decision.
Read original function source
void highScoreEntryAction(bool a_pressed)
{
// Retain the event until the next controller refresh; never use held A.
if (highScoreEntryActive()) entryPressed = entryPressed || a_pressed;
}saveEntry() · source line 232
static void saveEntry(void)
Calls into this documentation:
- Execute
entryStatus = high_scores_submit(entryGame, entryName, entryScore); - Decision
entryStatus == HIGH_SCORES_OK || entryStatus == HIGH_SCORES_NOT_QUALIFIEDTrue- Execute
entryStatus = high_scores_load(entryGame, &entryTable); - Execute
entryState = ENTRY_TABLE;
False- Execute
ESP_LOGE("high_scores", "Cannot save game %u score: %d", (unsigned)entryGame, (int)entryStatus); - Execute
entryState = ENTRY_SAVE_ERROR;
Read original function source
static void saveEntry(void)
{
entryStatus = high_scores_submit(entryGame, entryName, entryScore);
if (entryStatus == HIGH_SCORES_OK || entryStatus == HIGH_SCORES_NOT_QUALIFIED) {
entryStatus = high_scores_load(entryGame, &entryTable);
entryState = ENTRY_TABLE;
} else {
ESP_LOGE("high_scores", "Cannot save game %u score: %d", (unsigned)entryGame, (int)entryStatus);
entryState = ENTRY_SAVE_ERROR;
}
}updateHighScoreEntry() · source line 244
bool updateHighScoreEntry(int x_offset, int y_offset, bool valid, uint32_t now_ms)
Calls into this documentation:
- Execute
const bool pressed = entryPressed; - Execute
entryPressed = false; - Decision
entryState == ENTRY_NAMETrue- Execute
const KeyboardResult result = updateScreenKeyboard(x_offset, y_offset, valid, pressed, now_ms); - Decision
result == KEYBOARD_DONETrue- Decision
getScreenKeyboardText(entryName, sizeof(entryName))True- Execute
saveEntry();
FalseContinue after this decision.
False- Decision
result == KEYBOARD_CANCELLEDTrue- Execute
cancelHighScoreEntry();
FalseContinue after this decision.
False- Decision
entryState == ENTRY_SAVE_ERROR && pressedTrue- Execute
saveEntry();
False- Decision
entryState == ENTRY_TABLE && pressedTrue- Execute
cancelHighScoreEntry();
FalseContinue after this decision.
- Exit this function
return entryState == ENTRY_IDLE;
Read original function source
bool updateHighScoreEntry(int x_offset, int y_offset, bool valid, uint32_t now_ms)
{
const bool pressed = entryPressed;
entryPressed = false;
if (entryState == ENTRY_NAME) {
const KeyboardResult result = updateScreenKeyboard(x_offset, y_offset, valid, pressed, now_ms);
if (result == KEYBOARD_DONE) {
if (getScreenKeyboardText(entryName, sizeof(entryName))) saveEntry();
} else if (result == KEYBOARD_CANCELLED) {
cancelHighScoreEntry();
}
} else if (entryState == ENTRY_SAVE_ERROR && pressed) {
saveEntry();
} else if (entryState == ENTRY_TABLE && pressed) {
cancelHighScoreEntry();
}
return entryState == ENTRY_IDLE;
}drawHighScoreEntry() · source line 263
void drawHighScoreEntry(uint16_t *frame)
Calls into this documentation:
- Decision
frame == NULL || entryState == ENTRY_IDLETrue- Exit this function
return;
FalseContinue after this decision.
- Decision
entryState == ENTRY_NAMETrue- Execute
drawScreenKeyboard(frame);
False- Decision
entryState == ENTRY_SAVE_ERRORTrue- Execute
clear(frame, COLOR_BLACK); - Execute
draw_text_centred(frame, 160, 35, "SCORE NOT SAVED", 2, COLOR_RED); - Execute
draw_text_centred(frame, 160, 69, entryName, 2, COLOR_WHITE); - Execute
draw_text_centred(frame, 160, 103, "A RETRY", 2, COLOR_YELLOW); - Execute
draw_text_centred(frame, 160, 155, "BOOT BACK CANCELS ENTRY", 1, COLOR_WHITE);
False- Execute
drawHighScores(frame, entryGame, &entryTable, entryStatus);
Read original function source
void drawHighScoreEntry(uint16_t *frame)
{
if (frame == NULL || entryState == ENTRY_IDLE) return;
if (entryState == ENTRY_NAME) {
drawScreenKeyboard(frame);
} else if (entryState == ENTRY_SAVE_ERROR) {
clear(frame, COLOR_BLACK);
draw_text_centred(frame, 160, 35, "SCORE NOT SAVED", 2, COLOR_RED);
draw_text_centred(frame, 160, 69, entryName, 2, COLOR_WHITE);
draw_text_centred(frame, 160, 103, "A RETRY", 2, COLOR_YELLOW);
draw_text_centred(frame, 160, 155, "BOOT BACK CANCELS ENTRY", 1, COLOR_WHITE);
} else {
drawHighScores(frame, entryGame, &entryTable, entryStatus);
}
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "high_scores.h"
#include "game_storage.h"
#include "game_graphics.h"
#include "integrity.h"
#include "PET2001_font.h"
#include "screen_keyboard.h"
#include "esp_log.h"
#include <stdio.h>
#include <string.h>
#define HIGH_SCORES_NAMESPACE "arcade_high"
#define RECORD_VERSION 2U
#define ENTRY_BYTES (HIGH_SCORE_NAME_CHARS + 1U + 4U)
#define LEGACY_RECORD_BYTES (8U + HIGH_SCORE_COUNT * ENTRY_BYTES)
#define RECORD_CRC_OFFSET LEGACY_RECORD_BYTES
#define RECORD_BYTES (RECORD_CRC_OFFSET + 4U)
static const char *keys[HIGH_SCORE_GAME_COUNT] = {"invaders", "tempest", "asteroids", "yahtzee", "missile_command", "scramble", "defender", "galaga", "breakout", "crawler", "maze_chase", "simon"};
static const char *titles[HIGH_SCORE_GAME_COUNT] = {"INVADERS", "TEMPEST", "ASTEROIDS", "YAHTZEE", "MISSILE COMMAND", "SCRAMBLE", "DEFENDER", "GALAGA", "BREAKOUT", "CRAWLER", "MAZE CHASE", "SIMON"};
typedef enum { ENTRY_IDLE, ENTRY_NAME, ENTRY_TABLE, ENTRY_SAVE_ERROR } EntryState;
static EntryState entryState;
static high_score_game_t entryGame;
static uint32_t entryScore;
static high_score_table_t entryTable;
static high_score_result_t entryStatus;
static char entryName[HIGH_SCORE_NAME_CHARS + 1];
static bool entryPressed;
static bool validGame(high_score_game_t game)
{
return (unsigned)game < HIGH_SCORE_GAME_COUNT;
}
static bool validName(const char *name)
{
if (name == NULL) return false;
bool nonSpace = false;
for (size_t i = 0; i <= HIGH_SCORE_NAME_CHARS; ++i) {
const char ch = name[i];
if (ch == '\0') return nonSpace;
if (i == HIGH_SCORE_NAME_CHARS) return false;
if ((ch < 'A' || ch > 'Z') && (ch < '0' || ch > '9') && ch != '_' && ch != ' ') return false;
if (ch != ' ') nonSpace = true;
}
return false;
}
static bool validTable(const high_score_table_t *table)
{
if (table == NULL || table->count > HIGH_SCORE_COUNT) return false;
for (uint32_t i = 0; i < table->count; ++i) {
if (!validName(table->entries[i].name) || table->entries[i].score == 0) return false;
if (i != 0 && table->entries[i].score > table->entries[i - 1U].score) return false;
}
return true;
}
// Encode explicitly so the stored layout does not depend on struct padding.
static uint32_t readWord(const uint8_t *bytes)
{
return (uint32_t)bytes[0] | ((uint32_t)bytes[1] << 8) |
((uint32_t)bytes[2] << 16) | ((uint32_t)bytes[3] << 24);
}
static void writeWord(uint8_t *bytes, uint32_t value)
{
for (unsigned i = 0; i < 4; ++i) bytes[i] = (uint8_t)(value >> (i * 8U));
}
static void encodeRecord(const high_score_table_t *table, uint8_t *record)
{
memset(record, 0, RECORD_BYTES);
writeWord(record, RECORD_VERSION);
writeWord(record + 4, table->count);
for (uint32_t i = 0; i < table->count; ++i) {
uint8_t *entry = record + 8U + i * ENTRY_BYTES;
memcpy(entry, table->entries[i].name, sizeof(table->entries[i].name));
writeWord(entry + HIGH_SCORE_NAME_CHARS + 1U, table->entries[i].score);
}
writeWord(record + RECORD_CRC_OFFSET, integrity_crc32(record, RECORD_CRC_OFFSET));
}
static bool decodeRecord(const uint8_t *record, size_t record_size,
high_score_table_t *table)
{
if (record == NULL || table == NULL) return false;
const uint32_t version = readWord(record);
if (record_size == RECORD_BYTES && version == RECORD_VERSION) {
if (readWord(record + RECORD_CRC_OFFSET) != integrity_crc32(record, RECORD_CRC_OFFSET)) {
return false;
}
} else {
return false;
}
if (readWord(record + 4) > HIGH_SCORE_COUNT) return false;
high_score_table_t loaded = {0};
loaded.count = readWord(record + 4);
for (uint32_t i = 0; i < loaded.count; ++i) {
const uint8_t *entry = record + 8U + i * ENTRY_BYTES;
memcpy(loaded.entries[i].name, entry, sizeof(loaded.entries[i].name));
loaded.entries[i].score = readWord(entry + HIGH_SCORE_NAME_CHARS + 1U);
}
if (!validTable(&loaded)) return false;
*table = loaded;
return true;
}
high_score_result_t high_scores_load(high_score_game_t game, high_score_table_t *table)
{
if (table == NULL) return HIGH_SCORES_INVALID;
*table = (high_score_table_t){0};
if (!validGame(game)) return HIGH_SCORES_INVALID;
uint8_t record[RECORD_BYTES] = {0};
bool found = false;
size_t record_size = 0;
if (!game_storage_read_sized(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record),
&record_size, &found)) {
return HIGH_SCORES_IO_ERROR;
}
if (!found) return HIGH_SCORES_OK;
high_score_table_t loaded = {0};
if (record_size == LEGACY_RECORD_BYTES && readWord(record) == 1U) {
// Version-one tables were not CRC-protected, so discard them rather
// than treating unverified scores as trusted data.
ESP_LOGW("high_scores", "Replacing unprotected version-one score table for game %u",
(unsigned)game);
encodeRecord(&loaded, record);
if (!game_storage_write(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record))) {
return HIGH_SCORES_IO_ERROR;
}
*table = loaded;
return HIGH_SCORES_OK;
}
if (!decodeRecord(record, record_size, &loaded)) return HIGH_SCORES_INVALID;
*table = loaded;
return HIGH_SCORES_OK;
}
bool high_scores_qualifies(const high_score_table_t *table, uint32_t score)
{
return validTable(table) && score != 0 &&
(table->count < HIGH_SCORE_COUNT || score > table->entries[HIGH_SCORE_COUNT - 1U].score);
}
high_score_result_t high_scores_submit(high_score_game_t game, const char *name, uint32_t score)
{
if (!validGame(game) || !validName(name)) return HIGH_SCORES_INVALID;
high_score_table_t table;
const high_score_result_t loaded = high_scores_load(game, &table);
if (loaded != HIGH_SCORES_OK) return loaded;
if (!high_scores_qualifies(&table, score)) return HIGH_SCORES_NOT_QUALIFIED;
uint32_t position = 0;
while (position < table.count && table.entries[position].score >= score) ++position;
if (table.count < HIGH_SCORE_COUNT) ++table.count;
for (uint32_t i = table.count - 1U; i > position; --i) {
table.entries[i] = table.entries[i - 1U];
}
table.entries[position] = (high_score_entry_t){0};
memcpy(table.entries[position].name, name, strlen(name) + 1U);
table.entries[position].score = score;
uint8_t record[RECORD_BYTES];
encodeRecord(&table, record);
return game_storage_write(HIGH_SCORES_NAMESPACE, keys[game], record, sizeof(record))
? HIGH_SCORES_OK : HIGH_SCORES_IO_ERROR;
}
void drawHighScores(uint16_t *frame, high_score_game_t game,
const high_score_table_t *table, high_score_result_t status)
{
if (frame == NULL) return;
clear(frame, COLOR_BLACK);
drawPet2001TextCentredTransparent(frame, 160, 7, validGame(game) ? titles[game] : "HIGH SCORES", COLOR_CYAN, 2);
drawPet2001TextCentredTransparent(frame, 160, 27, "TOP 5", COLOR_YELLOW, 1);
if (status != HIGH_SCORES_OK || !validGame(game) || !validTable(table)) {
drawPet2001TextCentredTransparent(frame, 160, 77,
status == HIGH_SCORES_IO_ERROR ? "SCORE STORAGE ERROR" : "SCORE DATA ERROR", COLOR_RED, 1);
} else {
drawPet2001TextTransparent(frame, 30, 43, "NAME", COLOR_CYAN, 1);
drawPet2001TextTransparent(frame, 272, 43, "SCORE", COLOR_CYAN, 1);
for (uint32_t i = 0; i < HIGH_SCORE_COUNT; ++i) {
const int y = 61 + (int)i * 17;
char rank[4];
snprintf(rank, sizeof(rank), "%u.", (unsigned)(i + 1U));
drawPet2001TextTransparent(frame, 8, y, rank, COLOR_YELLOW, 1);
drawPet2001TextTransparent(frame, 30, y, i < table->count ? table->entries[i].name : "---", COLOR_WHITE, 1);
if (i < table->count) {
char value[11];
snprintf(value, sizeof(value), "%u", (unsigned)table->entries[i].score);
const int width = (int)strlen(value) * PET2001_FONT_GLYPH_WIDTH;
drawPet2001TextTransparent(frame, 312 - width, y, value, COLOR_WHITE, 1);
}
}
}
drawPet2001TextCentredTransparent(frame, 160, 155, "A CONTINUE BOOT BACK", COLOR_WHITE, 1);
}
void cancelHighScoreEntry(void)
{
cancelScreenKeyboard();
entryState = ENTRY_IDLE;
entryPressed = false;
}
void startHighScoreEntry(high_score_game_t game, uint32_t score, uint32_t now_ms)
{
cancelHighScoreEntry();
entryGame = game;
entryScore = score;
entryName[0] = '\0';
entryStatus = high_scores_load(game, &entryTable);
entryState = ENTRY_TABLE;
if (entryStatus == HIGH_SCORES_OK && high_scores_qualifies(&entryTable, score)) {
startScreenKeyboard(NULL, 10, KEYBOARD_NAME, "NAME", now_ms);
entryState = ENTRY_NAME;
} else if (entryStatus != HIGH_SCORES_OK) {
ESP_LOGE("high_scores", "Cannot load game %u scores: %d", (unsigned)game, (int)entryStatus);
}
}
bool highScoreEntryActive(void)
{
return entryState != ENTRY_IDLE;
}
void highScoreEntryAction(bool a_pressed)
{
// Retain the event until the next controller refresh; never use held A.
if (highScoreEntryActive()) entryPressed = entryPressed || a_pressed;
}
static void saveEntry(void)
{
entryStatus = high_scores_submit(entryGame, entryName, entryScore);
if (entryStatus == HIGH_SCORES_OK || entryStatus == HIGH_SCORES_NOT_QUALIFIED) {
entryStatus = high_scores_load(entryGame, &entryTable);
entryState = ENTRY_TABLE;
} else {
ESP_LOGE("high_scores", "Cannot save game %u score: %d", (unsigned)entryGame, (int)entryStatus);
entryState = ENTRY_SAVE_ERROR;
}
}
bool updateHighScoreEntry(int x_offset, int y_offset, bool valid, uint32_t now_ms)
{
const bool pressed = entryPressed;
entryPressed = false;
if (entryState == ENTRY_NAME) {
const KeyboardResult result = updateScreenKeyboard(x_offset, y_offset, valid, pressed, now_ms);
if (result == KEYBOARD_DONE) {
if (getScreenKeyboardText(entryName, sizeof(entryName))) saveEntry();
} else if (result == KEYBOARD_CANCELLED) {
cancelHighScoreEntry();
}
} else if (entryState == ENTRY_SAVE_ERROR && pressed) {
saveEntry();
} else if (entryState == ENTRY_TABLE && pressed) {
cancelHighScoreEntry();
}
return entryState == ENTRY_IDLE;
}
void drawHighScoreEntry(uint16_t *frame)
{
if (frame == NULL || entryState == ENTRY_IDLE) return;
if (entryState == ENTRY_NAME) {
drawScreenKeyboard(frame);
} else if (entryState == ENTRY_SAVE_ERROR) {
clear(frame, COLOR_BLACK);
drawPet2001TextCentredTransparent(frame, 160, 35, "SCORE NOT SAVED", COLOR_RED, 2);
drawPet2001TextCentredTransparent(frame, 160, 69, entryName, COLOR_WHITE, 2);
drawPet2001TextCentredTransparent(frame, 160, 103, "A RETRY", COLOR_YELLOW, 2);
drawPet2001TextCentredTransparent(frame, 160, 155, "BOOT BACK CANCELS ENTRY", COLOR_WHITE, 1);
} else {
drawHighScores(frame, entryGame, &entryTable, entryStatus);
}
}