Gold
Source: src/gold.c · 193 lines · 23 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
gold_millis() · source line 38
static uint32_t gold_millis(void)
- Exit this function
return (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS);
Read original function source
static uint32_t gold_millis(void)
{
return (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS);
}checksum_word() · source line 43
static void checksum_word(uint32_t *checksum, uint32_t value)
- FOR loop
unsigned shift = 0; shift < 32; shift += 8Repeat body while the loop condition permits; then continue below.
- Execute
*checksum ^= (uint8_t)(value >> shift); - Execute
*checksum *= 16777619U;
Read original function source
static void checksum_word(uint32_t *checksum, uint32_t value)
{
for (unsigned shift = 0; shift < 32; shift += 8) {
*checksum ^= (uint8_t)(value >> shift);
*checksum *= 16777619U;
}
}record_checksum() · source line 51
static uint32_t record_checksum(const gold_record_t *record)
Calls into this documentation:
- Execute
uint32_t checksum = 2166136261U ^ device_key; - Execute
checksum_word(&checksum, record->version); - Execute
checksum_word(&checksum, record->encoded_balance); - Execute
checksum_word(&checksum, record->nonce); - Execute
const uint64_t totals[] = { record->user_won, record->user_lost, record->ai_won, record->ai_lost, }; - FOR loop
size_t index = 0; index < 4; ++indexRepeat body while the loop condition permits; then continue below.
- Execute
checksum_word(&checksum, (uint32_t)totals[index]); - Execute
checksum_word(&checksum, (uint32_t)(totals[index] >> 32));
- Execute
checksum_word(&checksum, GOLD_SALT); - Exit this function
return checksum;
Read original function source
static uint32_t record_checksum(const gold_record_t *record)
{
uint32_t checksum = 2166136261U ^ device_key;
checksum_word(&checksum, record->version);
checksum_word(&checksum, record->encoded_balance);
checksum_word(&checksum, record->nonce);
const uint64_t totals[] = {
record->user_won, record->user_lost, record->ai_won, record->ai_lost,
};
for (size_t index = 0; index < 4; ++index) {
checksum_word(&checksum, (uint32_t)totals[index]);
checksum_word(&checksum, (uint32_t)(totals[index] >> 32));
}
checksum_word(&checksum, GOLD_SALT);
return checksum;
}persist() · source line 68
static bool persist(gold_record_t next, uint32_t next_balance, GoldChangeType change)
Calls into this documentation:
- Decision
!readyTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
next.version = 1; - Execute
next.nonce = esp_random(); - Execute
next.encoded_balance = next_balance ^ device_key ^ next.nonce; - Execute
next.checksum = record_checksum(&next); - Execute
storage_healthy = game_storage_write(GOLD_NAMESPACE, "record", &next, sizeof(next)); - Decision
!storage_healthyTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
saved = next; - Execute
balance = next_balance; - Decision
change != GOLD_CHANGE_NONETrue- Execute
change_type = change; - Execute
change_started = gold_millis(); - Execute
++change_sequence;
FalseContinue after this decision.
- Exit this function
return true;
Read original function source
static bool persist(gold_record_t next, uint32_t next_balance, GoldChangeType change)
{
if (!ready) {
return false;
}
next.version = 1;
next.nonce = esp_random();
next.encoded_balance = next_balance ^ device_key ^ next.nonce;
next.checksum = record_checksum(&next);
// Balance and lifetime totals are committed together in a single record.
storage_healthy = game_storage_write(GOLD_NAMESPACE, "record", &next, sizeof(next));
if (!storage_healthy) {
return false;
}
saved = next;
balance = next_balance;
if (change != GOLD_CHANGE_NONE) {
change_type = change;
change_started = gold_millis();
++change_sequence;
}
return true;
}initGold() · source line 92
bool initGold(void)
Calls into this documentation:
- Execute
ready = false; - Execute
storage_healthy = false; - Execute
balance = 0; - Execute
saved = (gold_record_t){0}; - Execute
uint8_t mac[6]; - Decision
esp_efuse_mac_get_default(mac) != ESP_OKTrue- Execute
ESP_LOGE("gold", "Cannot read device identifier"); - Exit this function
return false;
FalseContinue after this decision.
- Execute
device_key = GOLD_SALT; - FOR loop
size_t index = 0; index < sizeof(mac); ++indexRepeat body while the loop condition permits; then continue below.
- Execute
device_key = (device_key ^ mac[index]) * 16777619U;
- Execute
bool found = false; - Decision
!game_storage_read(GOLD_NAMESPACE, "record", &saved, sizeof(saved), &found)True- Exit this function
return false;
FalseContinue after this decision.
- Decision
foundTrue- Decision
saved.version != 1 || saved.checksum != record_checksum(&saved)True- Execute
ESP_LOGE("gold", "Invalid Gold record; stored data left intact"); - Execute
saved = (gold_record_t){0}; - Exit this function
return false;
FalseContinue after this decision.
- Execute
balance = saved.encoded_balance ^ device_key ^ saved.nonce;
FalseContinue after this decision.
- Execute
change_type = GOLD_CHANGE_NONE; - Execute
change_started = 0; - Execute
change_sequence = 0; - Execute
ready = true; - Execute
storage_healthy = true; - Exit this function
return true;
Read original function source
bool initGold(void)
{
ready = false;
storage_healthy = false;
balance = 0;
saved = (gold_record_t){0};
uint8_t mac[6];
if (esp_efuse_mac_get_default(mac) != ESP_OK) {
ESP_LOGE("gold", "Cannot read device identifier");
return false;
}
device_key = GOLD_SALT;
for (size_t index = 0; index < sizeof(mac); ++index) {
device_key = (device_key ^ mac[index]) * 16777619U;
}
bool found = false;
if (!game_storage_read(GOLD_NAMESPACE, "record", &saved, sizeof(saved), &found)) {
return false;
}
if (found) {
if (saved.version != 1 || saved.checksum != record_checksum(&saved)) {
ESP_LOGE("gold", "Invalid Gold record; stored data left intact");
saved = (gold_record_t){0};
return false;
}
balance = saved.encoded_balance ^ device_key ^ saved.nonce;
}
change_type = GOLD_CHANGE_NONE;
change_started = 0;
change_sequence = 0;
ready = true;
storage_healthy = true;
return true;
}goldStorageHealthy() · source line 127
bool goldStorageHealthy(void)
- Exit this function
return ready && storage_healthy;
Read original function source
bool goldStorageHealthy(void) { return ready && storage_healthy; }getGold() · source line 128
uint32_t getGold(void)
- Exit this function
return balance;
Read original function source
uint32_t getGold(void) { return balance; }getUserGoldWon() · source line 129
uint64_t getUserGoldWon(void)
- Exit this function
return saved.user_won;
Read original function source
uint64_t getUserGoldWon(void) { return saved.user_won; }getUserGoldLost() · source line 130
uint64_t getUserGoldLost(void)
- Exit this function
return saved.user_lost;
Read original function source
uint64_t getUserGoldLost(void) { return saved.user_lost; }getAIGoldWon() · source line 131
uint64_t getAIGoldWon(void)
- Exit this function
return saved.ai_won;
Read original function source
uint64_t getAIGoldWon(void) { return saved.ai_won; }getAIGoldLost() · source line 132
uint64_t getAIGoldLost(void)
- Exit this function
return saved.ai_lost;
Read original function source
uint64_t getAIGoldLost(void) { return saved.ai_lost; }getGoldChangeType() · source line 133
GoldChangeType getGoldChangeType(void)
- Exit this function
return change_type;
Read original function source
GoldChangeType getGoldChangeType(void) { return change_type; }getGoldChangeStarted() · source line 134
uint32_t getGoldChangeStarted(void)
- Exit this function
return change_started;
Read original function source
uint32_t getGoldChangeStarted(void) { return change_started; }getGoldChangeSequence() · source line 135
uint32_t getGoldChangeSequence(void)
- Exit this function
return change_sequence;
Read original function source
uint32_t getGoldChangeSequence(void) { return change_sequence; }addGold() · source line 137
bool addGold(uint32_t amount)
Calls into this documentation:
- Decision
!ready || amount > UINT32_MAX - balanceTrue- Exit this function
return false;
FalseContinue after this decision.
- Exit this function
return amount == 0 || persist(saved, balance + amount, GOLD_CHANGE_ADDED);
Read original function source
bool addGold(uint32_t amount)
{
if (!ready || amount > UINT32_MAX - balance) {
return false;
}
return amount == 0 || persist(saved, balance + amount, GOLD_CHANGE_ADDED);
}add_winnings() · source line 145
static bool add_winnings(uint32_t amount, bool ai)
Calls into this documentation:
- Execute
gold_record_t next = saved; - Execute
uint64_t *total = ai ? &next.ai_won : &next.user_won; - Decision
!ready || amount > UINT32_MAX - balance || amount > UINT64_MAX - *totalTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
*total += amount; - Exit this function
return amount == 0 || persist(next, balance + amount, GOLD_CHANGE_ADDED);
Read original function source
static bool add_winnings(uint32_t amount, bool ai)
{
gold_record_t next = saved;
uint64_t *total = ai ? &next.ai_won : &next.user_won;
if (!ready || amount > UINT32_MAX - balance || amount > UINT64_MAX - *total) {
return false;
}
*total += amount;
return amount == 0 || persist(next, balance + amount, GOLD_CHANGE_ADDED);
}addUserGoldWon() · source line 156
bool addUserGoldWon(uint32_t amount)
Calls into this documentation:
- Exit this function
return add_winnings(amount, false);
Read original function source
bool addUserGoldWon(uint32_t amount) { return add_winnings(amount, false); }addAIGold() · source line 157
bool addAIGold(uint32_t amount)
Calls into this documentation:
- Exit this function
return add_winnings(amount, true);
Read original function source
bool addAIGold(uint32_t amount) { return add_winnings(amount, true); }record_loss() · source line 159
static bool record_loss(uint32_t amount, bool ai)
Calls into this documentation:
- Execute
gold_record_t next = saved; - Execute
uint64_t *total = ai ? &next.ai_lost : &next.user_lost; - Decision
!ready || amount > UINT64_MAX - *totalTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
*total += amount; - Exit this function
return amount == 0 || persist(next, balance, GOLD_CHANGE_NONE);
Read original function source
static bool record_loss(uint32_t amount, bool ai)
{
gold_record_t next = saved;
uint64_t *total = ai ? &next.ai_lost : &next.user_lost;
if (!ready || amount > UINT64_MAX - *total) {
return false;
}
*total += amount;
return amount == 0 || persist(next, balance, GOLD_CHANGE_NONE);
}recordUserGoldLost() · source line 170
bool recordUserGoldLost(uint32_t amount)
Calls into this documentation:
- Exit this function
return record_loss(amount, false);
Read original function source
bool recordUserGoldLost(uint32_t amount) { return record_loss(amount, false); }recordAIGoldLost() · source line 171
bool recordAIGoldLost(uint32_t amount)
Calls into this documentation:
- Exit this function
return record_loss(amount, true);
Read original function source
bool recordAIGoldLost(uint32_t amount) { return record_loss(amount, true); }spendGold() · source line 173
bool spendGold(uint32_t amount)
Calls into this documentation:
- Decision
!ready || amount > balanceTrue- Exit this function
return false;
FalseContinue after this decision.
- Exit this function
return amount == 0 || persist(saved, balance - amount, GOLD_CHANGE_REMOVED);
Read original function source
bool spendGold(uint32_t amount)
{
if (!ready || amount > balance) {
return false;
}
return amount == 0 || persist(saved, balance - amount, GOLD_CHANGE_REMOVED);
}drawGameGold() · source line 181
void drawGameGold(uint16_t *frame, int x, int y, int width, bool compact)
Calls into this documentation:
- Decision
!goldStorageHealthy()True- Execute
draw_text(frame, x + 2, y + 2, "SAVE ERR", 1, RGB565(255, 70, 70)); - Exit this function
return;
FalseContinue after this decision.
- Execute
char value[16]; - Execute
snprintf(value, sizeof(value), "%" PRIu32, balance); - Execute
draw_text(frame, x + 2, y + 2, "GOLD", 1, RGB565(255, 210, 65)); - Execute
const int scale = !compact && width >= 124 ? 2 : 1; - Execute
draw_text(frame, x + 2, y + 13, value, scale, RGB565(240, 240, 240));
Read original function source
void drawGameGold(uint16_t *frame, int x, int y, int width, bool compact)
{
if (!goldStorageHealthy()) {
draw_text(frame, x + 2, y + 2, "SAVE ERR", 1, RGB565(255, 70, 70));
return;
}
char value[16];
snprintf(value, sizeof(value), "%" PRIu32, balance);
draw_text(frame, x + 2, y + 2, "GOLD", 1, RGB565(255, 210, 65));
const int scale = !compact && width >= 124 ? 2 : 1;
draw_text(frame, x + 2, y + 13, value, scale, RGB565(240, 240, 240));
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "gold.h"
#include "game_graphics.h"
#include "PET2001_font.h"
#include "game_storage.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "esp_random.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include <inttypes.h>
#include <stdio.h>
// Mini Arcade owns its namespace; the other firmware's Gold is not overwritten.
#define GOLD_NAMESPACE "arcade_gold"
#define GOLD_SALT 0x6D2B79F5U
typedef struct {
uint32_t version;
uint32_t encoded_balance;
uint32_t nonce;
uint32_t checksum;
uint64_t user_won;
uint64_t user_lost;
uint64_t ai_won;
uint64_t ai_lost;
} gold_record_t;
_Static_assert(sizeof(gold_record_t) == 48, "Gold record layout changed");
static gold_record_t saved = {0};
static uint32_t balance = 0;
static uint32_t device_key = 0;
static uint32_t change_started = 0;
static uint32_t change_sequence = 0;
static GoldChangeType change_type = GOLD_CHANGE_NONE;
static bool ready = false;
static bool storage_healthy = false;
static uint32_t gold_millis(void)
{
return (uint32_t)(xTaskGetTickCount() * portTICK_PERIOD_MS);
}
static void checksum_word(uint32_t *checksum, uint32_t value)
{
for (unsigned shift = 0; shift < 32; shift += 8) {
*checksum ^= (uint8_t)(value >> shift);
*checksum *= 16777619U;
}
}
static uint32_t record_checksum(const gold_record_t *record)
{
uint32_t checksum = 2166136261U ^ device_key;
checksum_word(&checksum, record->version);
checksum_word(&checksum, record->encoded_balance);
checksum_word(&checksum, record->nonce);
const uint64_t totals[] = {
record->user_won, record->user_lost, record->ai_won, record->ai_lost,
};
for (size_t index = 0; index < 4; ++index) {
checksum_word(&checksum, (uint32_t)totals[index]);
checksum_word(&checksum, (uint32_t)(totals[index] >> 32));
}
checksum_word(&checksum, GOLD_SALT);
return checksum;
}
static bool persist(gold_record_t next, uint32_t next_balance, GoldChangeType change)
{
if (!ready) {
return false;
}
next.version = 1;
next.nonce = esp_random();
next.encoded_balance = next_balance ^ device_key ^ next.nonce;
next.checksum = record_checksum(&next);
// Balance and lifetime totals are committed together in a single record.
storage_healthy = game_storage_write(GOLD_NAMESPACE, "record", &next, sizeof(next));
if (!storage_healthy) {
return false;
}
saved = next;
balance = next_balance;
if (change != GOLD_CHANGE_NONE) {
change_type = change;
change_started = gold_millis();
++change_sequence;
}
return true;
}
bool initGold(void)
{
ready = false;
storage_healthy = false;
balance = 0;
saved = (gold_record_t){0};
uint8_t mac[6];
if (esp_efuse_mac_get_default(mac) != ESP_OK) {
ESP_LOGE("gold", "Cannot read device identifier");
return false;
}
device_key = GOLD_SALT;
for (size_t index = 0; index < sizeof(mac); ++index) {
device_key = (device_key ^ mac[index]) * 16777619U;
}
bool found = false;
if (!game_storage_read(GOLD_NAMESPACE, "record", &saved, sizeof(saved), &found)) {
return false;
}
if (found) {
if (saved.version != 1 || saved.checksum != record_checksum(&saved)) {
ESP_LOGE("gold", "Invalid Gold record; stored data left intact");
saved = (gold_record_t){0};
return false;
}
balance = saved.encoded_balance ^ device_key ^ saved.nonce;
}
change_type = GOLD_CHANGE_NONE;
change_started = 0;
change_sequence = 0;
ready = true;
storage_healthy = true;
return true;
}
bool goldStorageHealthy(void) { return ready && storage_healthy; }
uint32_t getGold(void) { return balance; }
uint64_t getUserGoldWon(void) { return saved.user_won; }
uint64_t getUserGoldLost(void) { return saved.user_lost; }
uint64_t getAIGoldWon(void) { return saved.ai_won; }
uint64_t getAIGoldLost(void) { return saved.ai_lost; }
GoldChangeType getGoldChangeType(void) { return change_type; }
uint32_t getGoldChangeStarted(void) { return change_started; }
uint32_t getGoldChangeSequence(void) { return change_sequence; }
bool addGold(uint32_t amount)
{
if (!ready || amount > UINT32_MAX - balance) {
return false;
}
return amount == 0 || persist(saved, balance + amount, GOLD_CHANGE_ADDED);
}
static bool add_winnings(uint32_t amount, bool ai)
{
gold_record_t next = saved;
uint64_t *total = ai ? &next.ai_won : &next.user_won;
if (!ready || amount > UINT32_MAX - balance || amount > UINT64_MAX - *total) {
return false;
}
*total += amount;
return amount == 0 || persist(next, balance + amount, GOLD_CHANGE_ADDED);
}
bool addUserGoldWon(uint32_t amount) { return add_winnings(amount, false); }
bool addAIGold(uint32_t amount) { return add_winnings(amount, true); }
static bool record_loss(uint32_t amount, bool ai)
{
gold_record_t next = saved;
uint64_t *total = ai ? &next.ai_lost : &next.user_lost;
if (!ready || amount > UINT64_MAX - *total) {
return false;
}
*total += amount;
return amount == 0 || persist(next, balance, GOLD_CHANGE_NONE);
}
bool recordUserGoldLost(uint32_t amount) { return record_loss(amount, false); }
bool recordAIGoldLost(uint32_t amount) { return record_loss(amount, true); }
bool spendGold(uint32_t amount)
{
if (!ready || amount > balance) {
return false;
}
return amount == 0 || persist(saved, balance - amount, GOLD_CHANGE_REMOVED);
}
void drawGameGold(uint16_t *frame, int x, int y, int width, bool compact)
{
if (!goldStorageHealthy()) {
drawPet2001TextTransparent(frame, x + 2, y + 2, "SAVE ERR", RGB565(255, 70, 70), 1);
return;
}
char value[16];
snprintf(value, sizeof(value), "%" PRIu32, balance);
drawPet2001TextTransparent(frame, x + 2, y + 2, "GOLD", RGB565(255, 210, 65), 1);
const int scale = !compact && width >= 124 ? 2 : 1;
drawPet2001TextTransparent(frame, x + 2, y + 13, value, RGB565(240, 240, 240), scale);
}