Blackjack
Source: src/blackjack.c · 300 lines · 19 functions.
Screen captures
Views of this part running on the Mini Arcade.

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
cardValue() · source line 47
static uint8_t cardValue(card_t card)
- Exit this function
return card.rank == 1U ? 11U : card.rank >= 10U ? 10U : card.rank;
Read original function source
static uint8_t cardValue(card_t card)
{
return card.rank == 1U ? 11U : card.rank >= 10U ? 10U : card.rank;
}handValue() · source line 52
static uint8_t handValue(const hand_t *hand, uint8_t visible_count)
Calls into this documentation:
- Decision
visible_count == 0U || visible_count > hand->countTrue- Execute
visible_count = hand->count;
FalseContinue after this decision.
- Execute
uint8_t total = 0U, aces = 0U; - FOR loop
uint8_t index = 0U; index < visible_count; ++indexRepeat body while the loop condition permits; then continue below.
- Execute
total += cardValue(hand->cards[index]); - Decision
hand->cards[index].rank == 1UTrue- Execute
++aces;
FalseContinue after this decision.
- WHILE loop
total > 21U && aces > 0URepeat body while the loop condition permits; then continue below.
- Execute
total -= 10U; - Execute
--aces;
- Exit this function
return total;
Read original function source
static uint8_t handValue(const hand_t *hand, uint8_t visible_count)
{
if (visible_count == 0U || visible_count > hand->count) visible_count = hand->count;
uint8_t total = 0U, aces = 0U;
for (uint8_t index = 0U; index < visible_count; ++index) {
total += cardValue(hand->cards[index]);
if (hand->cards[index].rank == 1U) ++aces;
}
while (total > 21U && aces > 0U) { total -= 10U; --aces; }
return total;
}usableAce() · source line 64
static bool usableAce(const hand_t *hand)
Calls into this documentation:
- Execute
uint8_t total = 0U, aces = 0U; - FOR loop
uint8_t index = 0U; index < hand->count; ++indexRepeat body while the loop condition permits; then continue below.
- Execute
total += cardValue(hand->cards[index]); - Decision
hand->cards[index].rank == 1UTrue- Execute
++aces;
FalseContinue after this decision.
- WHILE loop
total > 21U && aces > 0URepeat body while the loop condition permits; then continue below.
- Execute
total -= 10U; - Execute
--aces;
- Exit this function
return aces > 0U;
Read original function source
static bool usableAce(const hand_t *hand)
{
uint8_t total = 0U, aces = 0U;
for (uint8_t index = 0U; index < hand->count; ++index) {
total += cardValue(hand->cards[index]);
if (hand->cards[index].rank == 1U) ++aces;
}
while (total > 21U && aces > 0U) { total -= 10U; --aces; }
return aces > 0U;
}naturalBlackjack() · source line 75
static bool naturalBlackjack(const hand_t *hand)
Calls into this documentation:
- Exit this function
return hand->count == 2U && handValue(hand, 0U) == 21U;
Read original function source
static bool naturalBlackjack(const hand_t *hand) { return hand->count == 2U && handValue(hand, 0U) == 21U; }autoShouldHit() · source line 77
static bool autoShouldHit(void)
Calls into this documentation:
- Execute
const uint8_t total = handValue(&player_hand, 0U); - Execute
const uint8_t dealer_card = cardValue(dealer_hand.cards[0]); - Decision
usableAce(&player_hand)True- Exit this function
return total <= 17U || (total == 18U && dealer_card >= 9U);
FalseContinue after this decision.
- Decision
total <= 11UTrue- Exit this function
return true;
FalseContinue after this decision.
- Decision
total == 12UTrue- Exit this function
return dealer_card < 4U || dealer_card > 6U;
FalseContinue after this decision.
- Exit this function
return total <= 16U && dealer_card >= 7U;
Read original function source
static bool autoShouldHit(void)
{
const uint8_t total = handValue(&player_hand, 0U);
const uint8_t dealer_card = cardValue(dealer_hand.cards[0]);
if (usableAce(&player_hand)) return total <= 17U || (total == 18U && dealer_card >= 9U);
if (total <= 11U) return true;
if (total == 12U) return dealer_card < 4U || dealer_card > 6U;
return total <= 16U && dealer_card >= 7U;
}initialiseDeck() · source line 87
static void initialiseDeck(void)
- Execute
static const char suits[] = { 'C', 'D', 'H', 'S' }; - Execute
uint8_t index = 0U; - FOR loop
uint8_t suit = 0U; suit < 4U; ++suitRepeat body while the loop condition permits; then continue below.
- FOR loop
uint8_t rank = 1U; rank <= 13U; ++rankRepeat body while the loop condition permits; then continue below.
- Execute
deck[index++] = (card_t){ rank, suits[suit] };
- FOR loop
int current = DECK_SIZE - 1; current > 0; --currentRepeat body while the loop condition permits; then continue below.
- Execute
const uint8_t selected = esp_random() % (uint32_t)(current + 1); - Execute
const card_t temporary = deck[current]; - Execute
deck[current] = deck[selected]; - Execute
deck[selected] = temporary;
- Execute
deck_position = 0U;
Read original function source
static void initialiseDeck(void)
{
static const char suits[] = { 'C', 'D', 'H', 'S' };
uint8_t index = 0U;
for (uint8_t suit = 0U; suit < 4U; ++suit)
for (uint8_t rank = 1U; rank <= 13U; ++rank) deck[index++] = (card_t){ rank, suits[suit] };
for (int current = DECK_SIZE - 1; current > 0; --current) {
const uint8_t selected = esp_random() % (uint32_t)(current + 1);
const card_t temporary = deck[current]; deck[current] = deck[selected]; deck[selected] = temporary;
}
deck_position = 0U;
}dealCard() · source line 100
static bool dealCard(hand_t *hand)
Calls into this documentation:
- Decision
hand->count >= MAX_HAND_CARDS || deck_position >= DECK_SIZETrue- Exit this function
return false;
FalseContinue after this decision.
- Execute
hand->cards[hand->count++] = deck[deck_position++]; - Execute
audioPlay(AUDIO_SFX_CARD_DEAL); - Exit this function
return true;
Read original function source
static bool dealCard(hand_t *hand)
{
if (hand->count >= MAX_HAND_CARDS || deck_position >= DECK_SIZE) return false;
hand->cards[hand->count++] = deck[deck_position++];
audioPlay(AUDIO_SFX_CARD_DEAL);
return true;
}loadScores() · source line 108
static void loadScores(void)
Calls into this documentation:
- Execute
bool found = false; - Execute
scores = (blackjack_scores_t){ .version = 1U }; - Decision
!game_storage_read(SCORE_NAMESPACE, SCORE_KEY, &scores, sizeof(scores), &found) || !found || scores.version != 1UTrue- Execute
scores = (blackjack_scores_t){ .version = 1U };
FalseContinue after this decision.
Read original function source
static void loadScores(void)
{
bool found = false;
scores = (blackjack_scores_t){ .version = 1U };
if (!game_storage_read(SCORE_NAMESPACE, SCORE_KEY, &scores, sizeof(scores), &found) ||
!found || scores.version != 1U) scores = (blackjack_scores_t){ .version = 1U };
}saveScores() · source line 116
static void saveScores(void)
Calls into this documentation:
- Execute
(void)game_storage_write(SCORE_NAMESPACE, SCORE_KEY, &scores, sizeof(scores));
Read original function source
static void saveScores(void) { (void)game_storage_write(SCORE_NAMESPACE, SCORE_KEY, &scores, sizeof(scores)); }finishGame() · source line 118
static void finishGame(blackjack_result_t result, const char *message, uint32_t now_ms)
Calls into this documentation:
- Execute
audioPlay(result == BJ_WIN ? AUDIO_SFX_WAVE_CLEAR : result == BJ_LOSS ? AUDIO_SFX_GAME_OVER : AUDIO_SFX_MENU_SELECT); - Execute
snprintf(result_text, sizeof(result_text), "%s", message); - Decision
!auto_modeTrue- Decision
result == BJ_WINTrue- Execute
++scores.wins; - Execute
++scores.streak; - Decision
scores.streak > scores.best_streakTrue- Execute
scores.best_streak = scores.streak;
FalseContinue after this decision.
False- Execute
scores.streak = 0U; - Decision
result == BJ_LOSSTrue- Execute
++scores.losses;
False- Execute
++scores.draws;
- Execute
saveScores();
FalseContinue after this decision.
- Decision
result == BJ_WINTrue- Decision
auto_modeTrue- Execute
addAIGold(BLACKJACK_WIN_GOLD);
False- Execute
addUserGoldWon(BLACKJACK_WIN_GOLD);
FalseContinue after this decision.
- Execute
state = BJ_FINISHED; - Execute
auto_restart_started = now_ms; - Execute
auto_seconds_shown = (uint8_t)((aiRestartDelay() + 999U) / 1000U); - Execute
redraw_needed = true;
Read original function source
static void finishGame(blackjack_result_t result, const char *message, uint32_t now_ms)
{
audioPlay(result == BJ_WIN ? AUDIO_SFX_WAVE_CLEAR : result == BJ_LOSS ? AUDIO_SFX_GAME_OVER : AUDIO_SFX_MENU_SELECT);
snprintf(result_text, sizeof(result_text), "%s", message);
if (!auto_mode) {
if (result == BJ_WIN) { ++scores.wins; ++scores.streak; if (scores.streak > scores.best_streak) scores.best_streak = scores.streak; }
else { scores.streak = 0U; if (result == BJ_LOSS) ++scores.losses; else ++scores.draws; }
saveScores();
}
if (result == BJ_WIN) {
if (auto_mode) addAIGold(BLACKJACK_WIN_GOLD); else addUserGoldWon(BLACKJACK_WIN_GOLD);
}
state = BJ_FINISHED;
auto_restart_started = now_ms;
auto_seconds_shown = (uint8_t)((aiRestartDelay() + 999U) / 1000U);
redraw_needed = true;
}startDealerTurn() · source line 136
static void startDealerTurn(uint32_t now_ms)
- Execute
state = BJ_DEALER; - Execute
state_started = now_ms; - Execute
redraw_needed = true;
Read original function source
static void startDealerTurn(uint32_t now_ms)
{
state = BJ_DEALER;
state_started = now_ms;
redraw_needed = true;
}beginGame() · source line 143
static void beginGame(uint32_t now_ms)
Calls into this documentation:
- Execute
player_hand = (hand_t){0}; - Execute
dealer_hand = (hand_t){0}; - Execute
selected_action = 0U; - Execute
result_text[0] = '\0'; - Execute
initialiseDeck(); - Execute
dealCard(&player_hand); - Execute
dealCard(&dealer_hand); - Execute
dealCard(&player_hand); - Execute
dealCard(&dealer_hand); - Decision
naturalBlackjack(&player_hand) && naturalBlackjack(&dealer_hand)True- Execute
finishGame(BJ_DRAW, "BOTH BLACKJACK - DRAW", now_ms);
False- Decision
naturalBlackjack(&player_hand)True- Execute
finishGame(BJ_WIN, "BLACKJACK - YOU WIN", now_ms);
False- Decision
naturalBlackjack(&dealer_hand)True- Execute
finishGame(BJ_LOSS, "DEALER BLACKJACK", now_ms);
False- Execute
state = BJ_PLAYER; - Execute
state_started = now_ms; - Execute
redraw_needed = true;
Read original function source
static void beginGame(uint32_t now_ms)
{
player_hand = (hand_t){0}; dealer_hand = (hand_t){0}; selected_action = 0U; result_text[0] = '\0';
initialiseDeck();
dealCard(&player_hand); dealCard(&dealer_hand); dealCard(&player_hand); dealCard(&dealer_hand);
if (naturalBlackjack(&player_hand) && naturalBlackjack(&dealer_hand)) finishGame(BJ_DRAW, "BOTH BLACKJACK - DRAW", now_ms);
else if (naturalBlackjack(&player_hand)) finishGame(BJ_WIN, "BLACKJACK - YOU WIN", now_ms);
else if (naturalBlackjack(&dealer_hand)) finishGame(BJ_LOSS, "DEALER BLACKJACK", now_ms);
else { state = BJ_PLAYER; state_started = now_ms; redraw_needed = true; }
}startBlackjack() · source line 154
void startBlackjack(uint32_t now_ms)
Calls into this documentation:
- Execute
loadScores(); - Execute
auto_mode = false; - Execute
ai_speed = AI_SPEED_DEFAULT_INDEX; - Execute
running = true; - Execute
modeSelectionReset(&mode_input); - Execute
state = BJ_SCORES; - Execute
state_started = now_ms; - Execute
redraw_needed = true;
Read original function source
void startBlackjack(uint32_t now_ms)
{
loadScores();
auto_mode = false; ai_speed = AI_SPEED_DEFAULT_INDEX; running = true;
modeSelectionReset(&mode_input);
state = BJ_SCORES; state_started = now_ms; redraw_needed = true;
}stopBlackjack() · source line 162
void stopBlackjack(void)
- Execute
running = false;
Read original function source
void stopBlackjack(void) { running = false; }blackjackAction() · source line 164
void blackjackAction(bool next, bool speed, bool select, uint32_t now_ms)
Calls into this documentation:
- Decision
!runningTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
state == BJ_MODETrue- Decision
nextTrue- Execute
beginGame(now_ms);
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
auto_modeTrue- Decision
speedTrue- Execute
cycleAISpeed(&ai_speed); - Execute
state_started = now_ms; - Execute
redraw_needed = true;
FalseContinue after this decision.
- Decision
selectTrue- Execute
auto_mode = false; - Execute
state = BJ_MODE; - Execute
modeSelectionReset(&mode_input); - Execute
redraw_needed = true;
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
state == BJ_PLAYERTrue- Decision
nextTrue- Execute
selected_action = selected_action == 0U ? 1U : 0U; - Execute
redraw_needed = true;
FalseContinue after this decision.
- Decision
select && selected_action == 1UTrue- Execute
startDealerTurn(now_ms);
False- Decision
select && dealCard(&player_hand)True- Execute
const uint8_t total = handValue(&player_hand, 0U); - Decision
total > 21UTrue- Execute
finishGame(BJ_LOSS, "BUST - DEALER WINS", now_ms);
False- Decision
total == 21UTrue- Execute
startDealerTurn(now_ms);
False- Execute
redraw_needed = true;
FalseContinue after this decision.
False- Decision
state == BJ_FINISHED && selectTrue- Execute
beginGame(now_ms);
FalseContinue after this decision.
Read original function source
void blackjackAction(bool next, bool speed, bool select, uint32_t now_ms)
{
if (!running) return;
if (state == BJ_MODE) {
if (next) beginGame(now_ms);
return;
}
if (auto_mode) {
if (speed) { cycleAISpeed(&ai_speed); state_started = now_ms; redraw_needed = true; }
if (select) { auto_mode = false; state = BJ_MODE; modeSelectionReset(&mode_input); redraw_needed = true; }
return;
}
if (state == BJ_PLAYER) {
if (next) { selected_action = selected_action == 0U ? 1U : 0U; redraw_needed = true; }
if (select && selected_action == 1U) startDealerTurn(now_ms);
else if (select && dealCard(&player_hand)) {
const uint8_t total = handValue(&player_hand, 0U);
if (total > 21U) finishGame(BJ_LOSS, "BUST - DEALER WINS", now_ms);
else if (total == 21U) startDealerTurn(now_ms);
else redraw_needed = true;
}
} else if (state == BJ_FINISHED && select) beginGame(now_ms);
}updateBlackjack() · source line 188
void updateBlackjack(int x_offset, int y_offset, bool joystick_valid, bool left, bool right,
uint32_t now_ms)Calls into this documentation:
- Decision
!runningTrue- Exit this function
return;
FalseContinue after this decision.
- Decision
state == BJ_SCORES && now_ms - state_started >= SHOW_SCORES_MSTrue- Execute
state = BJ_MODE; - Execute
redraw_needed = true; - Exit this function
return;
FalseContinue after this decision.
- Decision
state == BJ_MODETrue- Decision
modeSelectionNext(&mode_input, x_offset, y_offset, joystick_valid, left, right, now_ms)True- Execute
auto_mode = !auto_mode; - Execute
redraw_needed = true;
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
state == BJ_FINISHED && auto_modeTrue- Execute
const uint32_t elapsed = now_ms - auto_restart_started; - Execute
const uint32_t delay = aiRestartDelay(); - Decision
elapsed >= delayTrue- Execute
beginGame(now_ms); - Exit this function
return;
FalseContinue after this decision.
- Execute
const uint8_t seconds_left = (uint8_t)((delay - elapsed + 999U) / 1000U); - Decision
seconds_left != auto_seconds_shownTrue- Execute
auto_seconds_shown = seconds_left; - Execute
redraw_needed = true;
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
state == BJ_PLAYER && auto_mode && now_ms - state_started >= aiSpeedDelay(ai_speed)True- Decision
!autoShouldHit()True- Execute
startDealerTurn(now_ms);
False- Decision
dealCard(&player_hand)True- Execute
const uint8_t total = handValue(&player_hand, 0U); - Decision
total > 21UTrue- Execute
finishGame(BJ_LOSS, "BUST - DEALER WINS", now_ms);
False- Decision
total == 21UTrue- Execute
startDealerTurn(now_ms);
False- Execute
state_started = now_ms; - Execute
redraw_needed = true;
FalseContinue after this decision.
- Exit this function
return;
FalseContinue after this decision.
- Decision
state == BJ_DEALER && now_ms - state_started >= (auto_mode ? aiSpeedDelay(ai_speed) : DEALER_DELAY_MS)True- Decision
handValue(&dealer_hand, 0U) < 17UTrue- Execute
dealCard(&dealer_hand); - Execute
state_started = now_ms; - Execute
redraw_needed = true;
False- Execute
const uint8_t player_total = handValue(&player_hand, 0U), dealer_total = handValue(&dealer_hand, 0U); - Decision
dealer_total > 21U || player_total > dealer_totalTrue- Execute
finishGame(BJ_WIN, dealer_total > 21U ? "DEALER BUST - YOU WIN" : "YOU WIN", now_ms);
False- Decision
player_total < dealer_totalTrue- Execute
finishGame(BJ_LOSS, "DEALER WINS", now_ms);
False- Execute
finishGame(BJ_DRAW, "PUSH - DRAW", now_ms);
FalseContinue after this decision.
Read original function source
void updateBlackjack(int x_offset, int y_offset, bool joystick_valid, bool left, bool right,
uint32_t now_ms)
{
if (!running) return;
if (state == BJ_SCORES && now_ms - state_started >= SHOW_SCORES_MS) { state = BJ_MODE; redraw_needed = true; return; }
if (state == BJ_MODE) {
if (modeSelectionNext(&mode_input, x_offset, y_offset, joystick_valid, left, right, now_ms)) {
auto_mode = !auto_mode;
redraw_needed = true;
}
return;
}
if (state == BJ_FINISHED && auto_mode) {
const uint32_t elapsed = now_ms - auto_restart_started;
const uint32_t delay = aiRestartDelay();
if (elapsed >= delay) { beginGame(now_ms); return; }
const uint8_t seconds_left = (uint8_t)((delay - elapsed + 999U) / 1000U);
if (seconds_left != auto_seconds_shown) { auto_seconds_shown = seconds_left; redraw_needed = true; }
return;
}
if (state == BJ_PLAYER && auto_mode && now_ms - state_started >= aiSpeedDelay(ai_speed)) {
if (!autoShouldHit()) startDealerTurn(now_ms);
else if (dealCard(&player_hand)) {
const uint8_t total = handValue(&player_hand, 0U);
if (total > 21U) finishGame(BJ_LOSS, "BUST - DEALER WINS", now_ms);
else if (total == 21U) startDealerTurn(now_ms);
else { state_started = now_ms; redraw_needed = true; }
}
return;
}
if (state == BJ_DEALER && now_ms - state_started >= (auto_mode ? aiSpeedDelay(ai_speed) : DEALER_DELAY_MS)) {
if (handValue(&dealer_hand, 0U) < 17U) { dealCard(&dealer_hand); state_started = now_ms; redraw_needed = true; }
else {
const uint8_t player_total = handValue(&player_hand, 0U), dealer_total = handValue(&dealer_hand, 0U);
if (dealer_total > 21U || player_total > dealer_total) finishGame(BJ_WIN, dealer_total > 21U ? "DEALER BUST - YOU WIN" : "YOU WIN", now_ms);
else if (player_total < dealer_total) finishGame(BJ_LOSS, "DEALER WINS", now_ms);
else finishGame(BJ_DRAW, "PUSH - DRAW", now_ms);
}
}
}drawCard() · source line 229
static void drawCard(uint16_t *frame, const card_t *card, int x, int y)
Calls into this documentation:
- Execute
char path[32]; - Execute
const char *rank = card->rank == 1U ? "A" : card->rank == 11U ? "J" : card->rank == 12U ? "Q" : card->rank == 13U ? "K" : NULL; - Decision
rank != NULLTrue- Execute
snprintf(path, sizeof(path), "/spiffs/cards/%s%c.jpg", rank, card->suit);
False- Execute
snprintf(path, sizeof(path), "/spiffs/cards/%u%c.jpg", (unsigned)card->rank, card->suit);
- Decision
!imageDecodeJpegAt(path, frame, (unsigned)x, (unsigned)y)True- Execute
fill_rect(frame, x, y, 48, 64, COLOR_WHITE); - Execute
draw_rect(frame, x, y, 48, 64, COLOR_RED); - Execute
draw_text_centred(frame, x + 24, y + 25, path + 14, 1, COLOR_BLACK);
FalseContinue after this decision.
Read original function source
static void drawCard(uint16_t *frame, const card_t *card, int x, int y)
{
char path[32];
const char *rank = card->rank == 1U ? "A" : card->rank == 11U ? "J" : card->rank == 12U ? "Q" : card->rank == 13U ? "K" : NULL;
if (rank != NULL) snprintf(path, sizeof(path), "/spiffs/cards/%s%c.jpg", rank, card->suit);
else snprintf(path, sizeof(path), "/spiffs/cards/%u%c.jpg", (unsigned)card->rank, card->suit);
if (!imageDecodeJpegAt(path, frame, (unsigned)x, (unsigned)y)) {
fill_rect(frame, x, y, 48, 64, COLOR_WHITE); draw_rect(frame, x, y, 48, 64, COLOR_RED);
draw_text_centred(frame, x + 24, y + 25, path + 14, 1, COLOR_BLACK);
}
}drawHand() · source line 241
static void drawHand(uint16_t *frame, const hand_t *hand, int y, bool hide_second)
Calls into this documentation:
- Decision
hand->count == 0UTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
const int spacing = hand->count > 1U ? (266 - 48) / (hand->count - 1U) : 48; - FOR loop
uint8_t index = 0U; index < hand->count; ++indexRepeat body while the loop condition permits; then continue below.
- Execute
const int x = 54 + index * (spacing > 48 ? 48 : spacing); - Decision
hide_second && index == 1UTrue- Decision
!imageDecodeJpegAt("/spiffs/cards/Back.jpg", frame, (unsigned)x, (unsigned)y)True- Execute
fill_rect(frame, x, y, 48, 64, COLOR_BLUE); - Execute
draw_rect(frame, x, y, 48, 64, COLOR_WHITE);
FalseContinue after this decision.
False- Execute
drawCard(frame, &hand->cards[index], x, y);
Read original function source
static void drawHand(uint16_t *frame, const hand_t *hand, int y, bool hide_second)
{
if (hand->count == 0U) return;
const int spacing = hand->count > 1U ? (266 - 48) / (hand->count - 1U) : 48;
for (uint8_t index = 0U; index < hand->count; ++index) {
const int x = 54 + index * (spacing > 48 ? 48 : spacing);
if (hide_second && index == 1U) {
if (!imageDecodeJpegAt("/spiffs/cards/Back.jpg", frame, (unsigned)x, (unsigned)y)) {
fill_rect(frame, x, y, 48, 64, COLOR_BLUE); draw_rect(frame, x, y, 48, 64, COLOR_WHITE);
}
} else drawCard(frame, &hand->cards[index], x, y);
}
}drawBlackjack() · source line 255
void drawBlackjack(uint16_t *frame)
Calls into this documentation:
- Decision
!running || !redraw_neededTrue- Exit this function
return;
FalseContinue after this decision.
- Execute
redraw_needed = false; - Execute
clear(frame, COLOR_BLACK); - Execute
char text[40]; - Decision
state == BJ_SCORESTrue- Execute
draw_text_centred(frame, 160, 8, "BLACKJACK", 4, COLOR_CYAN); - Execute
draw_text_centred(frame, 160, 45, "GAME RECORD", 2, COLOR_LIGHTGRAY); - Execute
snprintf(text, sizeof(text), "WINS %u LOSSES %u", (unsigned)scores.wins, (unsigned)scores.losses); - Execute
draw_text_centred(frame, 160, 78, text, 2, COLOR_WHITE); - Execute
snprintf(text, sizeof(text), "DRAWS %u STREAK %u", (unsigned)scores.draws, (unsigned)scores.streak); - Execute
draw_text_centred(frame, 160, 105, text, 2, COLOR_WHITE); - Execute
snprintf(text, sizeof(text), "BEST STREAK %u", (unsigned)scores.best_streak); - Execute
draw_text_centred(frame, 160, 135, text, 2, COLOR_GOLD); - Exit this function
return;
FalseContinue after this decision.
- Decision
state == BJ_MODETrue- Execute
draw_text_centred(frame, 160, 8, "BLACKJACK", 4, COLOR_CYAN); - Execute
draw_text_centred(frame, 160, 52, "SELECT MODE", 2, COLOR_LIGHTGRAY); - Execute
draw_text_centred(frame, 100, 84, "PLAY", 2, auto_mode ? COLOR_LIGHTGRAY : COLOR_YELLOW); - Execute
draw_text_centred(frame, 220, 84, "AUTO", 2, auto_mode ? COLOR_YELLOW : COLOR_LIGHTGRAY); - Execute
draw_text_centred(frame, 160, 115, "WIN 10 GOLD", 2, COLOR_GOLD); - Execute
draw_text_centred(frame, 160, 145, "D/B/STICK CHANGE A/K START", 1, COLOR_LIGHTGRAY); - Exit this function
return;
FalseContinue after this decision.
- Execute
const bool reveal_dealer = state == BJ_DEALER || state == BJ_FINISHED; - Execute
drawHand(frame, &dealer_hand, 3, !reveal_dealer); - Execute
drawHand(frame, &player_hand, 86, false); - Execute
draw_text(frame, 2, 5, "DLR", 1, COLOR_CYAN); - Execute
snprintf(text, sizeof(text), reveal_dealer ? "%u" : "%u+?", (unsigned)handValue(&dealer_hand, reveal_dealer ? 0U : 1U)); - Execute
draw_text_centred(frame, 25, 24, text, 2, COLOR_WHITE); - Execute
draw_text(frame, 2, 88, "YOU", 1, COLOR_GREEN); - Execute
snprintf(text, sizeof(text), "%u", (unsigned)handValue(&player_hand, 0U)); - Execute
draw_text_centred(frame, 25, 107, text, 2, COLOR_WHITE); - Execute
drawGameGold(frame, 2, 134, 50, true); - Decision
state == BJ_PLAYERTrue- Execute
draw_text_centred(frame, 160, 70, auto_mode ? "AUTO TURN" : "YOUR TURN", 1, COLOR_WHITE); - Decision
auto_modeTrue- Execute
snprintf(text, sizeof(text), "E SPEED %s C STOP", aiSpeedShortText(ai_speed)); - Execute
draw_text_centred(frame, 160, 155, text, 1, COLOR_LIGHTGRAY);
False- Execute
draw_text_centred(frame, 80, 153, "HIT", 2, selected_action == 0U ? COLOR_YELLOW : COLOR_WHITE); - Execute
draw_text_centred(frame, 240, 153, "STAY", 2, selected_action == 1U ? COLOR_YELLOW : COLOR_WHITE);
False- Decision
state == BJ_DEALERTrue- Execute
draw_text_centred(frame, 160, 70, "DEALER TURN", 1, COLOR_WHITE); - Execute
draw_text_centred(frame, 160, 155, "PLEASE WAIT", 1, COLOR_LIGHTGRAY);
False- Execute
draw_text_centred(frame, 160, 70, result_text, 1, COLOR_YELLOW); - Decision
auto_modeTrue- Execute
snprintf(text, sizeof(text), "NEXT GAME %u E SPEED C STOP", (unsigned)auto_seconds_shown); - Execute
draw_text_centred(frame, 160, 155, text, 1, COLOR_LIGHTGRAY);
False- Execute
draw_text_centred(frame, 160, 155, "C NEW GAME", 1, COLOR_LIGHTGRAY);
Read original function source
void drawBlackjack(uint16_t *frame)
{
if (!running || !redraw_needed) return;
redraw_needed = false;
clear(frame, COLOR_BLACK);
char text[40];
if (state == BJ_SCORES) {
draw_text_centred(frame, 160, 8, "BLACKJACK", 4, COLOR_CYAN);
draw_text_centred(frame, 160, 45, "GAME RECORD", 2, COLOR_LIGHTGRAY);
snprintf(text, sizeof(text), "WINS %u LOSSES %u", (unsigned)scores.wins, (unsigned)scores.losses); draw_text_centred(frame, 160, 78, text, 2, COLOR_WHITE);
snprintf(text, sizeof(text), "DRAWS %u STREAK %u", (unsigned)scores.draws, (unsigned)scores.streak); draw_text_centred(frame, 160, 105, text, 2, COLOR_WHITE);
snprintf(text, sizeof(text), "BEST STREAK %u", (unsigned)scores.best_streak); draw_text_centred(frame, 160, 135, text, 2, COLOR_GOLD);
return;
}
if (state == BJ_MODE) {
draw_text_centred(frame, 160, 8, "BLACKJACK", 4, COLOR_CYAN);
draw_text_centred(frame, 160, 52, "SELECT MODE", 2, COLOR_LIGHTGRAY);
draw_text_centred(frame, 100, 84, "PLAY", 2, auto_mode ? COLOR_LIGHTGRAY : COLOR_YELLOW);
draw_text_centred(frame, 220, 84, "AUTO", 2, auto_mode ? COLOR_YELLOW : COLOR_LIGHTGRAY);
draw_text_centred(frame, 160, 115, "WIN 10 GOLD", 2, COLOR_GOLD);
draw_text_centred(frame, 160, 145, "D/B/STICK CHANGE A/K START", 1, COLOR_LIGHTGRAY);
return;
}
const bool reveal_dealer = state == BJ_DEALER || state == BJ_FINISHED;
drawHand(frame, &dealer_hand, 3, !reveal_dealer);
drawHand(frame, &player_hand, 86, false);
draw_text(frame, 2, 5, "DLR", 1, COLOR_CYAN);
snprintf(text, sizeof(text), reveal_dealer ? "%u" : "%u+?", (unsigned)handValue(&dealer_hand, reveal_dealer ? 0U : 1U)); draw_text_centred(frame, 25, 24, text, 2, COLOR_WHITE);
draw_text(frame, 2, 88, "YOU", 1, COLOR_GREEN); snprintf(text, sizeof(text), "%u", (unsigned)handValue(&player_hand, 0U)); draw_text_centred(frame, 25, 107, text, 2, COLOR_WHITE);
drawGameGold(frame, 2, 134, 50, true);
if (state == BJ_PLAYER) {
draw_text_centred(frame, 160, 70, auto_mode ? "AUTO TURN" : "YOUR TURN", 1, COLOR_WHITE);
if (auto_mode) { snprintf(text, sizeof(text), "E SPEED %s C STOP", aiSpeedShortText(ai_speed)); draw_text_centred(frame, 160, 155, text, 1, COLOR_LIGHTGRAY); }
else { draw_text_centred(frame, 80, 153, "HIT", 2, selected_action == 0U ? COLOR_YELLOW : COLOR_WHITE); draw_text_centred(frame, 240, 153, "STAY", 2, selected_action == 1U ? COLOR_YELLOW : COLOR_WHITE); }
} else if (state == BJ_DEALER) {
draw_text_centred(frame, 160, 70, "DEALER TURN", 1, COLOR_WHITE);
draw_text_centred(frame, 160, 155, "PLEASE WAIT", 1, COLOR_LIGHTGRAY);
} else {
draw_text_centred(frame, 160, 70, result_text, 1, COLOR_YELLOW);
if (auto_mode) {
snprintf(text, sizeof(text), "NEXT GAME %u E SPEED C STOP", (unsigned)auto_seconds_shown);
draw_text_centred(frame, 160, 155, text, 1, COLOR_LIGHTGRAY);
} else draw_text_centred(frame, 160, 155, "C NEW GAME", 1, COLOR_LIGHTGRAY);
}
}Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "blackjack.h"
#include "ai_speed.h"
#include "audio.h"
#include "game_graphics.h"
#include "game_storage.h"
#include "gold.h"
#include "image_decoder.h"
#include "mode_selection.h"
#include "PET2001_font.h"
#include "esp_system.h"
#include "esp_random.h"
#include <stdio.h>
#include <string.h>
#define DECK_SIZE 52U
#define MAX_HAND_CARDS 12U
#define SHOW_SCORES_MS 1000U
#define DEALER_DELAY_MS 850U
#define BLACKJACK_WIN_GOLD 10U
#define SCORE_NAMESPACE "arcade_results"
#define SCORE_KEY "blackjack"
typedef enum { BJ_SCORES, BJ_MODE, BJ_PLAYER, BJ_DEALER, BJ_FINISHED } blackjack_state_t;
typedef enum { BJ_WIN, BJ_LOSS, BJ_DRAW } blackjack_result_t;
typedef struct { uint8_t rank; char suit; } card_t;
typedef struct { card_t cards[MAX_HAND_CARDS]; uint8_t count; } hand_t;
typedef struct {
uint32_t version;
uint32_t wins;
uint32_t losses;
uint32_t draws;
uint32_t streak;
uint32_t best_streak;
} blackjack_scores_t;
static card_t deck[DECK_SIZE];
static hand_t player_hand, dealer_hand;
static blackjack_scores_t scores;
static blackjack_state_t state;
static uint8_t deck_position, selected_action, ai_speed, auto_seconds_shown;
static uint32_t state_started, auto_restart_started;
static bool running, auto_mode, redraw_needed;
static mode_selection_input_t mode_input;
static char result_text[32];
static uint8_t cardValue(card_t card)
{
return card.rank == 1U ? 11U : card.rank >= 10U ? 10U : card.rank;
}
static uint8_t handValue(const hand_t *hand, uint8_t visible_count)
{
if (visible_count == 0U || visible_count > hand->count) visible_count = hand->count;
uint8_t total = 0U, aces = 0U;
for (uint8_t index = 0U; index < visible_count; ++index) {
total += cardValue(hand->cards[index]);
if (hand->cards[index].rank == 1U) ++aces;
}
while (total > 21U && aces > 0U) { total -= 10U; --aces; }
return total;
}
static bool usableAce(const hand_t *hand)
{
uint8_t total = 0U, aces = 0U;
for (uint8_t index = 0U; index < hand->count; ++index) {
total += cardValue(hand->cards[index]);
if (hand->cards[index].rank == 1U) ++aces;
}
while (total > 21U && aces > 0U) { total -= 10U; --aces; }
return aces > 0U;
}
static bool naturalBlackjack(const hand_t *hand) { return hand->count == 2U && handValue(hand, 0U) == 21U; }
static bool autoShouldHit(void)
{
const uint8_t total = handValue(&player_hand, 0U);
const uint8_t dealer_card = cardValue(dealer_hand.cards[0]);
if (usableAce(&player_hand)) return total <= 17U || (total == 18U && dealer_card >= 9U);
if (total <= 11U) return true;
if (total == 12U) return dealer_card < 4U || dealer_card > 6U;
return total <= 16U && dealer_card >= 7U;
}
static void initialiseDeck(void)
{
static const char suits[] = { 'C', 'D', 'H', 'S' };
uint8_t index = 0U;
for (uint8_t suit = 0U; suit < 4U; ++suit)
for (uint8_t rank = 1U; rank <= 13U; ++rank) deck[index++] = (card_t){ rank, suits[suit] };
for (int current = DECK_SIZE - 1; current > 0; --current) {
const uint8_t selected = esp_random() % (uint32_t)(current + 1);
const card_t temporary = deck[current]; deck[current] = deck[selected]; deck[selected] = temporary;
}
deck_position = 0U;
}
static bool dealCard(hand_t *hand)
{
if (hand->count >= MAX_HAND_CARDS || deck_position >= DECK_SIZE) return false;
hand->cards[hand->count++] = deck[deck_position++];
audioPlay(AUDIO_SFX_CARD_DEAL);
return true;
}
static void loadScores(void)
{
bool found = false;
scores = (blackjack_scores_t){ .version = 1U };
if (!game_storage_read(SCORE_NAMESPACE, SCORE_KEY, &scores, sizeof(scores), &found) ||
!found || scores.version != 1U) scores = (blackjack_scores_t){ .version = 1U };
}
static void saveScores(void) { (void)game_storage_write(SCORE_NAMESPACE, SCORE_KEY, &scores, sizeof(scores)); }
static void finishGame(blackjack_result_t result, const char *message, uint32_t now_ms)
{
audioPlay(result == BJ_WIN ? AUDIO_SFX_WAVE_CLEAR : result == BJ_LOSS ? AUDIO_SFX_GAME_OVER : AUDIO_SFX_MENU_SELECT);
snprintf(result_text, sizeof(result_text), "%s", message);
if (!auto_mode) {
if (result == BJ_WIN) { ++scores.wins; ++scores.streak; if (scores.streak > scores.best_streak) scores.best_streak = scores.streak; }
else { scores.streak = 0U; if (result == BJ_LOSS) ++scores.losses; else ++scores.draws; }
saveScores();
}
if (result == BJ_WIN) {
if (auto_mode) addAIGold(BLACKJACK_WIN_GOLD); else addUserGoldWon(BLACKJACK_WIN_GOLD);
}
state = BJ_FINISHED;
auto_restart_started = now_ms;
auto_seconds_shown = (uint8_t)((aiRestartDelay() + 999U) / 1000U);
redraw_needed = true;
}
static void startDealerTurn(uint32_t now_ms)
{
state = BJ_DEALER;
state_started = now_ms;
redraw_needed = true;
}
static void beginGame(uint32_t now_ms)
{
player_hand = (hand_t){0}; dealer_hand = (hand_t){0}; selected_action = 0U; result_text[0] = '\0';
initialiseDeck();
dealCard(&player_hand); dealCard(&dealer_hand); dealCard(&player_hand); dealCard(&dealer_hand);
if (naturalBlackjack(&player_hand) && naturalBlackjack(&dealer_hand)) finishGame(BJ_DRAW, "BOTH BLACKJACK - DRAW", now_ms);
else if (naturalBlackjack(&player_hand)) finishGame(BJ_WIN, "BLACKJACK - YOU WIN", now_ms);
else if (naturalBlackjack(&dealer_hand)) finishGame(BJ_LOSS, "DEALER BLACKJACK", now_ms);
else { state = BJ_PLAYER; state_started = now_ms; redraw_needed = true; }
}
void startBlackjack(uint32_t now_ms)
{
loadScores();
auto_mode = false; ai_speed = AI_SPEED_DEFAULT_INDEX; running = true;
modeSelectionReset(&mode_input);
state = BJ_SCORES; state_started = now_ms; redraw_needed = true;
}
void stopBlackjack(void) { running = false; }
void blackjackAction(bool next, bool speed, bool select, uint32_t now_ms)
{
if (!running) return;
if (state == BJ_MODE) {
if (next) beginGame(now_ms);
return;
}
if (auto_mode) {
if (speed) { cycleAISpeed(&ai_speed); state_started = now_ms; redraw_needed = true; }
if (select) { auto_mode = false; state = BJ_MODE; modeSelectionReset(&mode_input); redraw_needed = true; }
return;
}
if (state == BJ_PLAYER) {
if (next) { selected_action = selected_action == 0U ? 1U : 0U; redraw_needed = true; }
if (select && selected_action == 1U) startDealerTurn(now_ms);
else if (select && dealCard(&player_hand)) {
const uint8_t total = handValue(&player_hand, 0U);
if (total > 21U) finishGame(BJ_LOSS, "BUST - DEALER WINS", now_ms);
else if (total == 21U) startDealerTurn(now_ms);
else redraw_needed = true;
}
} else if (state == BJ_FINISHED && select) beginGame(now_ms);
}
void updateBlackjack(int x_offset, int y_offset, bool joystick_valid, bool left, bool right,
uint32_t now_ms)
{
if (!running) return;
if (state == BJ_SCORES && now_ms - state_started >= SHOW_SCORES_MS) { state = BJ_MODE; redraw_needed = true; return; }
if (state == BJ_MODE) {
if (modeSelectionNext(&mode_input, x_offset, y_offset, joystick_valid, left, right, now_ms)) {
auto_mode = !auto_mode;
redraw_needed = true;
}
return;
}
if (state == BJ_FINISHED && auto_mode) {
const uint32_t elapsed = now_ms - auto_restart_started;
const uint32_t delay = aiRestartDelay();
if (elapsed >= delay) { beginGame(now_ms); return; }
const uint8_t seconds_left = (uint8_t)((delay - elapsed + 999U) / 1000U);
if (seconds_left != auto_seconds_shown) { auto_seconds_shown = seconds_left; redraw_needed = true; }
return;
}
if (state == BJ_PLAYER && auto_mode && now_ms - state_started >= aiSpeedDelay(ai_speed)) {
if (!autoShouldHit()) startDealerTurn(now_ms);
else if (dealCard(&player_hand)) {
const uint8_t total = handValue(&player_hand, 0U);
if (total > 21U) finishGame(BJ_LOSS, "BUST - DEALER WINS", now_ms);
else if (total == 21U) startDealerTurn(now_ms);
else { state_started = now_ms; redraw_needed = true; }
}
return;
}
if (state == BJ_DEALER && now_ms - state_started >= (auto_mode ? aiSpeedDelay(ai_speed) : DEALER_DELAY_MS)) {
if (handValue(&dealer_hand, 0U) < 17U) { dealCard(&dealer_hand); state_started = now_ms; redraw_needed = true; }
else {
const uint8_t player_total = handValue(&player_hand, 0U), dealer_total = handValue(&dealer_hand, 0U);
if (dealer_total > 21U || player_total > dealer_total) finishGame(BJ_WIN, dealer_total > 21U ? "DEALER BUST - YOU WIN" : "YOU WIN", now_ms);
else if (player_total < dealer_total) finishGame(BJ_LOSS, "DEALER WINS", now_ms);
else finishGame(BJ_DRAW, "PUSH - DRAW", now_ms);
}
}
}
static void drawCard(uint16_t *frame, const card_t *card, int x, int y)
{
char path[32];
const char *rank = card->rank == 1U ? "A" : card->rank == 11U ? "J" : card->rank == 12U ? "Q" : card->rank == 13U ? "K" : NULL;
if (rank != NULL) snprintf(path, sizeof(path), "/spiffs/cards/%s%c.jpg", rank, card->suit);
else snprintf(path, sizeof(path), "/spiffs/cards/%u%c.jpg", (unsigned)card->rank, card->suit);
if (!imageDecodeJpegAt(path, frame, (unsigned)x, (unsigned)y)) {
fill_rect(frame, x, y, 48, 64, COLOR_WHITE); draw_rect(frame, x, y, 48, 64, COLOR_RED);
drawPet2001TextCentredTransparent(frame, x + 24, y + 25, path + 14, COLOR_BLACK, 1);
}
}
static void drawHand(uint16_t *frame, const hand_t *hand, int y, bool hide_second)
{
if (hand->count == 0U) return;
const int spacing = hand->count > 1U ? (266 - 48) / (hand->count - 1U) : 48;
for (uint8_t index = 0U; index < hand->count; ++index) {
const int x = 54 + index * (spacing > 48 ? 48 : spacing);
if (hide_second && index == 1U) {
if (!imageDecodeJpegAt("/spiffs/cards/Back.jpg", frame, (unsigned)x, (unsigned)y)) {
fill_rect(frame, x, y, 48, 64, COLOR_BLUE); draw_rect(frame, x, y, 48, 64, COLOR_WHITE);
}
} else drawCard(frame, &hand->cards[index], x, y);
}
}
void drawBlackjack(uint16_t *frame)
{
if (!running || !redraw_needed) return;
redraw_needed = false;
clear(frame, COLOR_BLACK);
char text[40];
if (state == BJ_SCORES) {
drawPet2001TextCentredTransparent(frame, 160, 8, "BLACKJACK", COLOR_CYAN, 4);
drawPet2001TextCentredTransparent(frame, 160, 45, "GAME RECORD", COLOR_LIGHTGRAY, 2);
snprintf(text, sizeof(text), "WINS %u LOSSES %u", (unsigned)scores.wins, (unsigned)scores.losses); drawPet2001TextCentredTransparent(frame, 160, 78, text, COLOR_WHITE, 1);
snprintf(text, sizeof(text), "DRAWS %u STREAK %u", (unsigned)scores.draws, (unsigned)scores.streak); drawPet2001TextCentredTransparent(frame, 160, 105, text, COLOR_WHITE, 1);
snprintf(text, sizeof(text), "BEST STREAK %u", (unsigned)scores.best_streak); drawPet2001TextCentredTransparent(frame, 160, 135, text, COLOR_GOLD, 1);
return;
}
if (state == BJ_MODE) {
drawPet2001TextCentredTransparent(frame, 160, 8, "BLACKJACK", COLOR_CYAN, 4);
drawPet2001TextCentredTransparent(frame, 160, 52, "SELECT MODE", COLOR_LIGHTGRAY, 2);
drawPet2001TextCentredTransparent(frame, 100, 84, "PLAY", auto_mode ? COLOR_LIGHTGRAY : COLOR_YELLOW, 2);
drawPet2001TextCentredTransparent(frame, 220, 84, "AUTO", auto_mode ? COLOR_YELLOW : COLOR_LIGHTGRAY, 2);
drawPet2001TextCentredTransparent(frame, 160, 115, "WIN 10 GOLD", COLOR_GOLD, 2);
drawPet2001TextCentredTransparent(frame, 160, 145, "D/B/STICK CHANGE A/K START", COLOR_LIGHTGRAY, 1);
return;
}
const bool reveal_dealer = state == BJ_DEALER || state == BJ_FINISHED;
drawHand(frame, &dealer_hand, 3, !reveal_dealer);
drawHand(frame, &player_hand, 86, false);
drawPet2001TextTransparent(frame, 2, 5, "DLR", COLOR_CYAN, 1);
snprintf(text, sizeof(text), reveal_dealer ? "%u" : "%u+?", (unsigned)handValue(&dealer_hand, reveal_dealer ? 0U : 1U)); drawPet2001TextCentredTransparent(frame, 25, 24, text, COLOR_WHITE, 2);
drawPet2001TextTransparent(frame, 2, 88, "YOU", COLOR_GREEN, 1); snprintf(text, sizeof(text), "%u", (unsigned)handValue(&player_hand, 0U)); drawPet2001TextCentredTransparent(frame, 25, 107, text, COLOR_WHITE, 2);
drawGameGold(frame, 2, 134, 50, true);
if (state == BJ_PLAYER) {
drawPet2001TextCentredTransparent(frame, 160, 70, auto_mode ? "AUTO TURN" : "YOUR TURN", COLOR_WHITE, 1);
if (auto_mode) { snprintf(text, sizeof(text), "E SPEED %s C STOP", aiSpeedShortText(ai_speed)); drawPet2001TextCentredTransparent(frame, 160, 155, text, COLOR_LIGHTGRAY, 1); }
else { drawPet2001TextCentredTransparent(frame, 80, 153, "HIT", selected_action == 0U ? COLOR_YELLOW : COLOR_WHITE, 2); drawPet2001TextCentredTransparent(frame, 240, 153, "STAY", selected_action == 1U ? COLOR_YELLOW : COLOR_WHITE, 2); }
} else if (state == BJ_DEALER) {
drawPet2001TextCentredTransparent(frame, 160, 70, "DEALER TURN", COLOR_WHITE, 1);
drawPet2001TextCentredTransparent(frame, 160, 155, "PLEASE WAIT", COLOR_LIGHTGRAY, 1);
} else {
drawPet2001TextCentredTransparent(frame, 160, 70, result_text, COLOR_YELLOW, 1);
if (auto_mode) {
snprintf(text, sizeof(text), "NEXT GAME %u E SPEED C STOP", (unsigned)auto_seconds_shown);
drawPet2001TextCentredTransparent(frame, 160, 155, text, COLOR_LIGHTGRAY, 1);
} else drawPet2001TextCentredTransparent(frame, 160, 155, "C NEW GAME", COLOR_LIGHTGRAY, 1);
}
}