Ai Speed
Source: src/ai_speed.c · 112 lines · 13 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
valid_move() · source line 18
static bool valid_move(uint16_t delay_ms)
- Exit this function
return delay_ms >= AI_MOVE_DELAY_MIN_MS && delay_ms <= AI_MOVE_DELAY_MAX_MS && (delay_ms - AI_MOVE_DELAY_MIN_MS) % AI_MOVE_DELAY_STEP_MS == 0;
Read original function source
static bool valid_move(uint16_t delay_ms)
{
return delay_ms >= AI_MOVE_DELAY_MIN_MS && delay_ms <= AI_MOVE_DELAY_MAX_MS &&
(delay_ms - AI_MOVE_DELAY_MIN_MS) % AI_MOVE_DELAY_STEP_MS == 0;
}initAITiming() · source line 24
bool initAITiming(void)
Calls into this documentation:
- Execute
ready = false; - Execute
storage_healthy = false; - Execute
timing = (ai_timing_record_t){1, AI_MOVE_DELAY_DEFAULT_MS, AI_RESTART_DELAY_DEFAULT_SECONDS, 0}; - Execute
ai_timing_record_t loaded = {0}; - Execute
bool found = false; - Decision
!game_storage_read("arcade_ai", "timing", &loaded, sizeof(loaded), &found)True- Exit this function
return false;
FalseContinue after this decision.
- Decision
foundTrue- Decision
loaded.version != 1 || !valid_move(loaded.move_ms) || loaded.restart_seconds < AI_RESTART_DELAY_MIN_SECONDS || loaded.restart_seconds > AI_RESTART_DELAY_MAX_SECONDSTrue- Execute
ESP_LOGE("ai_timing", "Invalid saved timing; using defaults without overwriting it"); - Exit this function
return false;
FalseContinue after this decision.
- Execute
timing = loaded;
FalseContinue after this decision.
- Execute
ready = true; - Execute
storage_healthy = true; - Exit this function
return true;
Read original function source
bool initAITiming(void)
{
ready = false;
storage_healthy = false;
timing = (ai_timing_record_t){1, AI_MOVE_DELAY_DEFAULT_MS,
AI_RESTART_DELAY_DEFAULT_SECONDS, 0};
ai_timing_record_t loaded = {0};
bool found = false;
if (!game_storage_read("arcade_ai", "timing", &loaded, sizeof(loaded), &found)) {
return false;
}
if (found) {
if (loaded.version != 1 || !valid_move(loaded.move_ms) ||
loaded.restart_seconds < AI_RESTART_DELAY_MIN_SECONDS ||
loaded.restart_seconds > AI_RESTART_DELAY_MAX_SECONDS) {
ESP_LOGE("ai_timing", "Invalid saved timing; using defaults without overwriting it");
return false;
}
timing = loaded;
}
ready = true;
storage_healthy = true;
return true;
}aiTimingStorageHealthy() · source line 49
bool aiTimingStorageHealthy(void)
- Exit this function
return ready && storage_healthy;
Read original function source
bool aiTimingStorageHealthy(void) { return ready && storage_healthy; }getAIBaseMoveDelay() · source line 50
uint16_t getAIBaseMoveDelay(void)
- Exit this function
return timing.move_ms;
Read original function source
uint16_t getAIBaseMoveDelay(void) { return timing.move_ms; }getAIRestartDelaySeconds() · source line 51
uint8_t getAIRestartDelaySeconds(void)
- Exit this function
return timing.restart_seconds;
Read original function source
uint8_t getAIRestartDelaySeconds(void) { return timing.restart_seconds; }save_timing() · source line 53
static bool save_timing(ai_timing_record_t next)
Calls into this documentation:
- Decision
!readyTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
storage_healthy = game_storage_write("arcade_ai", "timing", &next, sizeof(next)); - Decision
storage_healthyTrue- Execute
timing = next;
FalseContinue after this decision.
- Exit this function
return storage_healthy;
Read original function source
static bool save_timing(ai_timing_record_t next)
{
if (!ready) {
return false;
}
storage_healthy = game_storage_write("arcade_ai", "timing", &next, sizeof(next));
if (storage_healthy) {
timing = next;
}
return storage_healthy;
}saveAIBaseMoveDelay() · source line 65
bool saveAIBaseMoveDelay(uint16_t delay_ms)
Calls into this documentation:
- Decision
!valid_move(delay_ms)True- Exit this function
return false;
FalseContinue after this decision.
- Execute
ai_timing_record_t next = timing; - Execute
next.move_ms = delay_ms; - Exit this function
return save_timing(next);
Read original function source
bool saveAIBaseMoveDelay(uint16_t delay_ms)
{
if (!valid_move(delay_ms)) {
return false;
}
ai_timing_record_t next = timing;
next.move_ms = delay_ms;
return save_timing(next);
}saveAIRestartDelaySeconds() · source line 75
bool saveAIRestartDelaySeconds(uint8_t seconds)
Calls into this documentation:
- Decision
seconds < AI_RESTART_DELAY_MIN_SECONDS || seconds > AI_RESTART_DELAY_MAX_SECONDSTrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
ai_timing_record_t next = timing; - Execute
next.restart_seconds = seconds; - Exit this function
return save_timing(next);
Read original function source
bool saveAIRestartDelaySeconds(uint8_t seconds)
{
if (seconds < AI_RESTART_DELAY_MIN_SECONDS || seconds > AI_RESTART_DELAY_MAX_SECONDS) {
return false;
}
ai_timing_record_t next = timing;
next.restart_seconds = seconds;
return save_timing(next);
}aiSpeedDelay() · source line 85
uint16_t aiSpeedDelay(uint8_t index)
- Decision
index >= AI_SPEED_COUNTTrue- Execute
index = AI_SPEED_DEFAULT_INDEX;
FalseContinue after this decision.
- Exit this function
return timing.move_ms / (1U << index);
Read original function source
uint16_t aiSpeedDelay(uint8_t index)
{
if (index >= AI_SPEED_COUNT) {
index = AI_SPEED_DEFAULT_INDEX;
}
return timing.move_ms / (1U << index);
}aiRestartDelay() · source line 93
uint32_t aiRestartDelay(void)
- Exit this function
return (uint32_t)timing.restart_seconds * 1000U;
Read original function source
uint32_t aiRestartDelay(void) { return (uint32_t)timing.restart_seconds * 1000U; }cycleAISpeed() · source line 95
void cycleAISpeed(uint8_t *index)
- Decision
index != NULLTrue- Execute
*index = (*index + 1) % AI_SPEED_COUNT;
FalseContinue after this decision.
Read original function source
void cycleAISpeed(uint8_t *index)
{
if (index != NULL) {
*index = (*index + 1) % AI_SPEED_COUNT;
}
}aiSpeedShortText() · source line 102
const char *aiSpeedShortText(uint8_t index)
- Execute
static const char *labels[] = {"X1", "X2", "X4", "X8"}; - Exit this function
return labels[index < AI_SPEED_COUNT ? index : AI_SPEED_DEFAULT_INDEX];
Read original function source
const char *aiSpeedShortText(uint8_t index)
{
static const char *labels[] = {"X1", "X2", "X4", "X8"};
return labels[index < AI_SPEED_COUNT ? index : AI_SPEED_DEFAULT_INDEX];
}aiSpeedText() · source line 108
const char *aiSpeedText(uint8_t index)
- Execute
static const char *labels[] = {"AI SPEED X1", "AI SPEED X2", "AI SPEED X4", "AI SPEED X8"}; - Exit this function
return labels[index < AI_SPEED_COUNT ? index : AI_SPEED_DEFAULT_INDEX];
Read original function source
const char *aiSpeedText(uint8_t index)
{
static const char *labels[] = {"AI SPEED X1", "AI SPEED X2", "AI SPEED X4", "AI SPEED X8"};
return labels[index < AI_SPEED_COUNT ? index : AI_SPEED_DEFAULT_INDEX];
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "ai_speed.h"
#include "game_storage.h"
#include "esp_log.h"
typedef struct {
uint32_t version;
uint16_t move_ms;
uint8_t restart_seconds;
uint8_t reserved;
} ai_timing_record_t;
_Static_assert(sizeof(ai_timing_record_t) == 8, "AI timing record layout changed");
static ai_timing_record_t timing = {1, AI_MOVE_DELAY_DEFAULT_MS,
AI_RESTART_DELAY_DEFAULT_SECONDS, 0};
static bool ready = false;
static bool storage_healthy = false;
static bool valid_move(uint16_t delay_ms)
{
return delay_ms >= AI_MOVE_DELAY_MIN_MS && delay_ms <= AI_MOVE_DELAY_MAX_MS &&
(delay_ms - AI_MOVE_DELAY_MIN_MS) % AI_MOVE_DELAY_STEP_MS == 0;
}
bool initAITiming(void)
{
ready = false;
storage_healthy = false;
timing = (ai_timing_record_t){1, AI_MOVE_DELAY_DEFAULT_MS,
AI_RESTART_DELAY_DEFAULT_SECONDS, 0};
ai_timing_record_t loaded = {0};
bool found = false;
if (!game_storage_read("arcade_ai", "timing", &loaded, sizeof(loaded), &found)) {
return false;
}
if (found) {
if (loaded.version != 1 || !valid_move(loaded.move_ms) ||
loaded.restart_seconds < AI_RESTART_DELAY_MIN_SECONDS ||
loaded.restart_seconds > AI_RESTART_DELAY_MAX_SECONDS) {
ESP_LOGE("ai_timing", "Invalid saved timing; using defaults without overwriting it");
return false;
}
timing = loaded;
}
ready = true;
storage_healthy = true;
return true;
}
bool aiTimingStorageHealthy(void) { return ready && storage_healthy; }
uint16_t getAIBaseMoveDelay(void) { return timing.move_ms; }
uint8_t getAIRestartDelaySeconds(void) { return timing.restart_seconds; }
static bool save_timing(ai_timing_record_t next)
{
if (!ready) {
return false;
}
storage_healthy = game_storage_write("arcade_ai", "timing", &next, sizeof(next));
if (storage_healthy) {
timing = next;
}
return storage_healthy;
}
bool saveAIBaseMoveDelay(uint16_t delay_ms)
{
if (!valid_move(delay_ms)) {
return false;
}
ai_timing_record_t next = timing;
next.move_ms = delay_ms;
return save_timing(next);
}
bool saveAIRestartDelaySeconds(uint8_t seconds)
{
if (seconds < AI_RESTART_DELAY_MIN_SECONDS || seconds > AI_RESTART_DELAY_MAX_SECONDS) {
return false;
}
ai_timing_record_t next = timing;
next.restart_seconds = seconds;
return save_timing(next);
}
uint16_t aiSpeedDelay(uint8_t index)
{
if (index >= AI_SPEED_COUNT) {
index = AI_SPEED_DEFAULT_INDEX;
}
return timing.move_ms / (1U << index);
}
uint32_t aiRestartDelay(void) { return (uint32_t)timing.restart_seconds * 1000U; }
void cycleAISpeed(uint8_t *index)
{
if (index != NULL) {
*index = (*index + 1) % AI_SPEED_COUNT;
}
}
const char *aiSpeedShortText(uint8_t index)
{
static const char *labels[] = {"X1", "X2", "X4", "X8"};
return labels[index < AI_SPEED_COUNT ? index : AI_SPEED_DEFAULT_INDEX];
}
const char *aiSpeedText(uint8_t index)
{
static const char *labels[] = {"AI SPEED X1", "AI SPEED X2", "AI SPEED X4", "AI SPEED X8"};
return labels[index < AI_SPEED_COUNT ? index : AI_SPEED_DEFAULT_INDEX];
}