Maze Chase

Source: src/maze_chase.c · 344 lines · 18 functions.

Screen captures

Views of this part running on the Mini Arcade.

Maze Chase game screen on the Mini Arcade
Maze Chase showing the player and ghosts in the maze.
Maze Chase at a later game state on the Mini Arcade
A second Maze Chase state from the running game.

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

absoluteValue() · source line 59
static int absoluteValue(int value)
  1. Exit this functionreturn value < 0 ? -value : value;
Read original function source
static int absoluteValue(int value) { return value < 0 ? -value : value; }
wallAt() · source line 61
static bool wallAt(int column, int row)
  1. Exit this functionreturn row < 0 || row >= MAZE_ROWS || column < 0 || column >= MAZE_COLUMNS || maze_layout[row][column] == '#';
Read original function source
static bool wallAt(int column, int row)
{
    return row < 0 || row >= MAZE_ROWS || column < 0 || column >= MAZE_COLUMNS ||
        maze_layout[row][column] == '#';
}
oppositeDirection() · source line 67
static direction_t oppositeDirection(direction_t direction)
  1. Decisiondirection == DIRECTION_UP
    True
    1. Exit this functionreturn DIRECTION_DOWN;
    False

    Continue after this decision.

  2. Decisiondirection == DIRECTION_DOWN
    True
    1. Exit this functionreturn DIRECTION_UP;
    False

    Continue after this decision.

  3. Decisiondirection == DIRECTION_LEFT
    True
    1. Exit this functionreturn DIRECTION_RIGHT;
    False

    Continue after this decision.

  4. Exit this functionreturn direction == DIRECTION_RIGHT ? DIRECTION_LEFT : DIRECTION_NONE;
Read original function source
static direction_t oppositeDirection(direction_t direction)
{
    if (direction == DIRECTION_UP) return DIRECTION_DOWN;
    if (direction == DIRECTION_DOWN) return DIRECTION_UP;
    if (direction == DIRECTION_LEFT) return DIRECTION_RIGHT;
    return direction == DIRECTION_RIGHT ? DIRECTION_LEFT : DIRECTION_NONE;
}
directionOffset() · source line 75
static void directionOffset(direction_t direction, int *column, int *row)
  1. Execute*column = 0;
  2. Execute*row = 0;
  3. Decisiondirection == DIRECTION_UP
    True
    1. Execute*row = -1;
    False
    1. Decisiondirection == DIRECTION_DOWN
      True
      1. Execute*row = 1;
      False
      1. Decisiondirection == DIRECTION_LEFT
        True
        1. Execute*column = -1;
        False
        1. Decisiondirection == DIRECTION_RIGHT
          True
          1. Execute*column = 1;
          False

          Continue after this decision.

Read original function source
static void directionOffset(direction_t direction, int *column, int *row)
{
    *column = 0;
    *row = 0;
    if (direction == DIRECTION_UP) *row = -1;
    else if (direction == DIRECTION_DOWN) *row = 1;
    else if (direction == DIRECTION_LEFT) *column = -1;
    else if (direction == DIRECTION_RIGHT) *column = 1;
}
nextTile() · source line 85
static bool nextTile(const maze_actor_t *actor, direction_t direction, int *column, int *row)

Calls into this documentation:

  1. Executeint dx, dy;
  2. ExecutedirectionOffset(direction, &dx, &dy);
  3. Execute*column = actor->column + dx;
  4. Execute*row = actor->row + dy;
  5. Decision*row == TUNNEL_ROW && *column < 0
    True
    1. Execute*column = MAZE_COLUMNS - 1;
    False

    Continue after this decision.

  6. Decision*row == TUNNEL_ROW && *column >= MAZE_COLUMNS
    True
    1. Execute*column = 0;
    False

    Continue after this decision.

  7. Exit this functionreturn !wallAt(*column, *row);
Read original function source
static bool nextTile(const maze_actor_t *actor, direction_t direction, int *column, int *row)
{
    int dx, dy;
    directionOffset(direction, &dx, &dy);
    *column = actor->column + dx;
    *row = actor->row + dy;
    if (*row == TUNNEL_ROW && *column < 0) *column = MAZE_COLUMNS - 1;
    if (*row == TUNNEL_ROW && *column >= MAZE_COLUMNS) *column = 0;
    return !wallAt(*column, *row);
}
resetActors() · source line 96
static void resetActors(void)
  1. Executeplayer = (maze_actor_t){1, 7, DIRECTION_RIGHT};
  2. Executeconst maze_actor_t starts[GHOST_COUNT] = { {4, 1, DIRECTION_LEFT}, {5, 1, DIRECTION_RIGHT}, {6, 1, DIRECTION_LEFT}, {7, 1, DIRECTION_RIGHT} };
  3. FOR loopunsigned i = 0; i < GHOST_COUNT; ++i

    Repeat body while the loop condition permits; then continue below.

    1. Executeghosts[i] = starts[i];
Read original function source
static void resetActors(void)
{
    player = (maze_actor_t){1, 7, DIRECTION_RIGHT};
    const maze_actor_t starts[GHOST_COUNT] = {
        {4, 1, DIRECTION_LEFT}, {5, 1, DIRECTION_RIGHT},
        {6, 1, DIRECTION_LEFT}, {7, 1, DIRECTION_RIGHT}
    };
    for (unsigned i = 0; i < GHOST_COUNT; ++i) ghosts[i] = starts[i];
}
resetMaze() · source line 106
static void resetMaze(void)

Calls into this documentation:

  1. Executepellets_left = 0U;
  2. FOR loopint row = 0; row < MAZE_ROWS; ++row

    Repeat body while the loop condition permits; then continue below.

      1. FOR loopint column = 0; column < MAZE_COLUMNS; ++column

        Repeat body while the loop condition permits; then continue below.

          1. Executepellets[row][column] = wallAt(column, row) ? 0U : 1U;
          2. Decisionpellets[row][column] != 0U
            True
            1. Execute++pellets_left;
            False

            Continue after this decision.

  3. Executepellets[1][1] = 2U;
  4. Executepellets[1][MAZE_COLUMNS - 2] = 2U;
  5. Executepellets[7][MAZE_COLUMNS - 2] = 2U;
  6. Executepellets[5][1] = 2U;
  7. FOR loopunsigned i = 0; i < GHOST_COUNT; ++i

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst int row = ghosts[i].row;
      2. Executeconst int column = ghosts[i].column;
      3. Decisionpellets[row][column] != 0U
        True
        1. Execute--pellets_left;
        False

        Continue after this decision.

      4. Executepellets[row][column] = 0U;
  8. Decisionpellets[player.row][player.column] != 0U
    True
    1. Execute--pellets_left;
    False

    Continue after this decision.

  9. Executepellets[player.row][player.column] = 0U;
Read original function source
static void resetMaze(void)
{
    pellets_left = 0U;
    for (int row = 0; row < MAZE_ROWS; ++row) {
        for (int column = 0; column < MAZE_COLUMNS; ++column) {
            pellets[row][column] = wallAt(column, row) ? 0U : 1U;
            if (pellets[row][column] != 0U) ++pellets_left;
        }
    }
    pellets[1][1] = 2U;
    pellets[1][MAZE_COLUMNS - 2] = 2U;
    pellets[7][MAZE_COLUMNS - 2] = 2U;
    pellets[5][1] = 2U;
    for (unsigned i = 0; i < GHOST_COUNT; ++i) {
        const int row = ghosts[i].row;
        const int column = ghosts[i].column;
        if (pellets[row][column] != 0U) --pellets_left;
        pellets[row][column] = 0U;
    }
    if (pellets[player.row][player.column] != 0U) --pellets_left;
    pellets[player.row][player.column] = 0U;
}
beginRound() · source line 129
static void beginRound(uint32_t now_ms)

Calls into this documentation:

  1. ExecuteresetActors();
  2. ExecuteresetMaze();
  3. Executefrightened_until = 0U;
  4. Executeghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
  5. Executeplayer_last_step = now_ms;
  6. Executeghost_last_step = now_ms;
  7. Executestate = MAZE_PLAYING;
Read original function source
static void beginRound(uint32_t now_ms)
{
    resetActors();
    resetMaze();
    frightened_until = 0U;
    ghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
    player_last_step = now_ms;
    ghost_last_step = now_ms;
    state = MAZE_PLAYING;
}
loseLife() · source line 140
static void loseLife(uint32_t now_ms)

Calls into this documentation:

  1. ExecuteaudioPlay(AUDIO_SFX_PLAYER_EXPLOSION);
  2. Decisionlives != 0U
    True
    1. Execute--lives;
    False

    Continue after this decision.

  3. Executestate_started = now_ms;
  4. Executestate = lives == 0U ? MAZE_FINISHED : MAZE_LIFE_LOST;
Read original function source
static void loseLife(uint32_t now_ms)
{
    audioPlay(AUDIO_SFX_PLAYER_EXPLOSION);
    if (lives != 0U) --lives;
    state_started = now_ms;
    state = lives == 0U ? MAZE_FINISHED : MAZE_LIFE_LOST;
}
collectPellet() · source line 148
static void collectPellet(uint32_t now_ms)

Calls into this documentation:

  1. Executeuint8_t *pellet = &pellets[player.row][player.column];
  2. Decision*pellet == 0U
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  3. Executeconst bool power_pellet = *pellet == 2U;
  4. Executescore += power_pellet ? 50U : 10U;
  5. ExecuteaudioPlay(power_pellet ? AUDIO_SFX_POWER_UP : AUDIO_SFX_MAZE_PELLET);
  6. Decisionpower_pellet
    True
    1. Executefrightened_until = now_ms + POWER_MS;
    False

    Continue after this decision.

  7. Execute*pellet = 0U;
  8. Decisionpellets_left != 0U
    True
    1. Execute--pellets_left;
    False

    Continue after this decision.

  9. Decisionpellets_left == 0U
    True
      1. ExecuteaudioPlay(AUDIO_SFX_WAVE_CLEAR);
      2. Execute++round_number;
      3. ExecuteresetMaze();
      4. ExecuteresetActors();
      5. Executeghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
    False

    Continue after this decision.

Read original function source
static void collectPellet(uint32_t now_ms)
{
    uint8_t *pellet = &pellets[player.row][player.column];
    if (*pellet == 0U) return;
    const bool power_pellet = *pellet == 2U;
    score += power_pellet ? 50U : 10U;
    audioPlay(power_pellet ? AUDIO_SFX_POWER_UP : AUDIO_SFX_MAZE_PELLET);
    if (power_pellet) frightened_until = now_ms + POWER_MS;
    *pellet = 0U;
    if (pellets_left != 0U) --pellets_left;
    if (pellets_left == 0U) {
        audioPlay(AUDIO_SFX_WAVE_CLEAR);
        ++round_number;
        resetMaze();
        resetActors();
        ghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
    }
}
movePlayer() · source line 167
static void movePlayer(direction_t requested, uint32_t now_ms)

Calls into this documentation:

  1. Executeint column, row;
  2. Decisionrequested != DIRECTION_NONE && nextTile(&player, requested, &column, &row)
    True
    1. Executeplayer.direction = requested;
    False

    Continue after this decision.

  3. Decision!nextTile(&player, player.direction, &column, &row)
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  4. Executeplayer.column = column;
  5. Executeplayer.row = row;
  6. ExecutecollectPellet(now_ms);
Read original function source
static void movePlayer(direction_t requested, uint32_t now_ms)
{
    int column, row;
    if (requested != DIRECTION_NONE && nextTile(&player, requested, &column, &row)) player.direction = requested;
    if (!nextTile(&player, player.direction, &column, &row)) return;
    player.column = column;
    player.row = row;
    collectPellet(now_ms);
}
moveGhost() · source line 177
static void moveGhost(unsigned index, uint32_t now_ms)

Calls into this documentation:

  1. Executemaze_actor_t *ghost = &ghosts[index];
  2. Executedirection_t selected = DIRECTION_NONE;
  3. Executeint best_distance = 0x7fffffff;
  4. Executeconst bool frightened = (int32_t)(frightened_until - now_ms) > 0;
  5. Executeconst direction_t choices[] = {DIRECTION_UP, DIRECTION_LEFT, DIRECTION_DOWN, DIRECTION_RIGHT};
  6. FOR loopunsigned i = 0; i < sizeof(choices) / sizeof(choices[0]); ++i

    Repeat body while the loop condition permits; then continue below.

      1. Executeint column, row;
      2. Decision!nextTile(ghost, choices[i], &column, &row)
        True
        1. Next loop iterationcontinue;
        False

        Continue after this decision.

      3. Decisionchoices[i] == oppositeDirection(ghost->direction) && selected != DIRECTION_NONE
        True
        1. Next loop iterationcontinue;
        False

        Continue after this decision.

      4. Executeconst int distance = absoluteValue(column - player.column) + absoluteValue(row - player.row);
      5. Executeconst int target_distance = frightened ? -distance : distance + (int)((index * 3U + i) % 4U);
      6. Decisiontarget_distance < best_distance
        True
          1. Executebest_distance = target_distance;
          2. Executeselected = choices[i];
        False

        Continue after this decision.

  7. Executeint column, row;
  8. Decisionselected != DIRECTION_NONE && nextTile(ghost, selected, &column, &row)
    True
      1. Executeghost->direction = selected;
      2. Executeghost->column = column;
      3. Executeghost->row = row;
    False

    Continue after this decision.

Read original function source
static void moveGhost(unsigned index, uint32_t now_ms)
{
    maze_actor_t *ghost = &ghosts[index];
    direction_t selected = DIRECTION_NONE;
    int best_distance = 0x7fffffff;
    const bool frightened = (int32_t)(frightened_until - now_ms) > 0;
    const direction_t choices[] = {DIRECTION_UP, DIRECTION_LEFT, DIRECTION_DOWN, DIRECTION_RIGHT};
    for (unsigned i = 0; i < sizeof(choices) / sizeof(choices[0]); ++i) {
        int column, row;
        if (!nextTile(ghost, choices[i], &column, &row)) continue;
        if (choices[i] == oppositeDirection(ghost->direction) && selected != DIRECTION_NONE) continue;
        const int distance = absoluteValue(column - player.column) + absoluteValue(row - player.row);
        const int target_distance = frightened ? -distance : distance + (int)((index * 3U + i) % 4U);
        if (target_distance < best_distance) {
            best_distance = target_distance;
            selected = choices[i];
        }
    }
    int column, row;
    if (selected != DIRECTION_NONE && nextTile(ghost, selected, &column, &row)) {
        ghost->direction = selected;
        ghost->column = column;
        ghost->row = row;
    }
}
checkGhostHits() · source line 203
static void checkGhostHits(uint32_t now_ms)

Calls into this documentation:

  1. FOR loopunsigned i = 0; i < GHOST_COUNT; ++i

    Repeat body while the loop condition permits; then continue below.

      1. Decisionghosts[i].column != player.column || ghosts[i].row != player.row
        True
        1. Next loop iterationcontinue;
        False

        Continue after this decision.

      2. Decision(int32_t)(frightened_until - now_ms) > 0
        True
          1. Executescore += 200U;
          2. Executeghosts[i] = (maze_actor_t){5, 1, DIRECTION_LEFT};
          3. ExecuteaudioPlay(AUDIO_SFX_HIT);
        False
          1. ExecuteloseLife(now_ms);
      3. Exit this functionreturn;
Read original function source
static void checkGhostHits(uint32_t now_ms)
{
    for (unsigned i = 0; i < GHOST_COUNT; ++i) {
        if (ghosts[i].column != player.column || ghosts[i].row != player.row) continue;
        if ((int32_t)(frightened_until - now_ms) > 0) {
            score += 200U;
            ghosts[i] = (maze_actor_t){5, 1, DIRECTION_LEFT};
            audioPlay(AUDIO_SFX_HIT);
        } else {
            loseLife(now_ms);
        }
        return;
    }
}
startMazeChase() · source line 218
void startMazeChase(uint32_t now_ms)
  1. Executescore = 0U;
  2. Executeround_number = 1U;
  3. Executelives = 3U;
  4. Executecontrols_ready = false;
  5. Executerunning = true;
  6. Executestate = MAZE_READY;
  7. Executestate_started = now_ms;
Read original function source
void startMazeChase(uint32_t now_ms)
{
    score = 0U;
    round_number = 1U;
    lives = 3U;
    controls_ready = false;
    running = true;
    state = MAZE_READY;
    state_started = now_ms;
}
stopMazeChase() · source line 229
void stopMazeChase(void)

Calls into this documentation:

  1. ExecutecancelHighScoreEntry();
  2. Executerunning = false;
Read original function source
void stopMazeChase(void)
{
    cancelHighScoreEntry();
    running = false;
}
mazeChaseAction() · source line 235
void mazeChaseAction(bool action, uint32_t now_ms)

Calls into this documentation:

  1. Decision!running || !action
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Decisionstate == MAZE_READY
    True
      1. ExecutebeginRound(now_ms);
      2. ExecuteaudioPlay(AUDIO_SFX_GAME_START);
    False

    Continue after this decision.

Read original function source
void mazeChaseAction(bool action, uint32_t now_ms)
{
    if (!running || !action) return;
    if (state == MAZE_READY) {
        beginRound(now_ms);
        audioPlay(AUDIO_SFX_GAME_START);
    }
}
updateMazeChase() · source line 244
void updateMazeChase(int x_offset, int y_offset, bool joystick_valid, bool left, bool right,
                     uint32_t now_ms)

Calls into this documentation:

  1. Decision!running
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Decisionstate == MAZE_SCORES
    True
      1. DecisionupdateHighScoreEntry(x_offset, y_offset, joystick_valid, now_ms)
        True
        1. Executestate = MAZE_READY;
        False

        Continue after this decision.

      2. Exit this functionreturn;
    False

    Continue after this decision.

  3. Decisionstate == MAZE_FINISHED
    True
      1. Decisionnow_ms - state_started >= LIFE_LOST_MS
        True
          1. ExecutestartHighScoreEntry(HIGH_SCORE_MAZE_CHASE, score, now_ms);
          2. Executestate = MAZE_SCORES;
        False

        Continue after this decision.

      2. Exit this functionreturn;
    False

    Continue after this decision.

  4. Decisionstate == MAZE_LIFE_LOST
    True
      1. Decisionnow_ms - state_started >= LIFE_LOST_MS
        True
          1. ExecuteresetActors();
          2. Executeplayer_last_step = now_ms;
          3. Executeghost_last_step = now_ms;
          4. Executeghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
          5. Executestate = MAZE_PLAYING;
        False

        Continue after this decision.

      2. Exit this functionreturn;
    False

    Continue after this decision.

  5. Decisionstate != MAZE_PLAYING
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  6. Decision!joystick_valid
    True
    1. Executecontrols_ready = false;
    False
    1. DecisionabsoluteValue(x_offset) < 350 && absoluteValue(y_offset) < 350
      True
      1. Executecontrols_ready = true;
      False

      Continue after this decision.

  7. Executedirection_t requested = DIRECTION_NONE;
  8. Decisionleft != right
    True
    1. Executerequested = left ? DIRECTION_LEFT : DIRECTION_RIGHT;
    False
    1. Decisionjoystick_valid && controls_ready && absoluteValue(x_offset) > 500
      True
      1. Executerequested = x_offset < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
      False
      1. Decisionjoystick_valid && controls_ready && absoluteValue(y_offset) > 500
        True
        1. Executerequested = y_offset > 0 ? DIRECTION_UP : DIRECTION_DOWN;
        False

        Continue after this decision.

  9. WHILE loopnow_ms - player_last_step >= PLAYER_STEP_MS && state == MAZE_PLAYING

    Repeat body while the loop condition permits; then continue below.

      1. Executeplayer_last_step += PLAYER_STEP_MS;
      2. ExecutemovePlayer(requested, now_ms);
      3. ExecutecheckGhostHits(now_ms);
  10. Decision(int32_t)(now_ms - ghosts_release_at) < 0
    True
      1. Executeghost_last_step = now_ms;
      2. Exit this functionreturn;
    False

    Continue after this decision.

  11. Executeconst uint32_t ghost_step = GHOST_STEP_MS > round_number * 5U ? GHOST_STEP_MS - round_number * 5U : 90U;
  12. WHILE loopnow_ms - ghost_last_step >= ghost_step && state == MAZE_PLAYING

    Repeat body while the loop condition permits; then continue below.

      1. Executeghost_last_step += ghost_step;
      2. FOR loopunsigned i = 0; i < GHOST_COUNT && state == MAZE_PLAYING; ++i

        Repeat body while the loop condition permits; then continue below.

          1. ExecutemoveGhost(i, now_ms);
          2. ExecutecheckGhostHits(now_ms);
Read original function source
void updateMazeChase(int x_offset, int y_offset, bool joystick_valid, bool left, bool right,
                     uint32_t now_ms)
{
    if (!running) return;
    if (state == MAZE_SCORES) {
        if (updateHighScoreEntry(x_offset, y_offset, joystick_valid, now_ms)) state = MAZE_READY;
        return;
    }
    if (state == MAZE_FINISHED) {
        if (now_ms - state_started >= LIFE_LOST_MS) {
            startHighScoreEntry(HIGH_SCORE_MAZE_CHASE, score, now_ms);
            state = MAZE_SCORES;
        }
        return;
    }
    if (state == MAZE_LIFE_LOST) {
        if (now_ms - state_started >= LIFE_LOST_MS) {
            resetActors();
            player_last_step = now_ms;
            ghost_last_step = now_ms;
            ghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
            state = MAZE_PLAYING;
        }
        return;
    }
    if (state != MAZE_PLAYING) return;
    if (!joystick_valid) controls_ready = false;
    else if (absoluteValue(x_offset) < 350 && absoluteValue(y_offset) < 350) controls_ready = true;
    direction_t requested = DIRECTION_NONE;
    if (left != right) requested = left ? DIRECTION_LEFT : DIRECTION_RIGHT;
    else if (joystick_valid && controls_ready && absoluteValue(x_offset) > 500) requested = x_offset < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
    else if (joystick_valid && controls_ready && absoluteValue(y_offset) > 500) requested = y_offset > 0 ? DIRECTION_UP : DIRECTION_DOWN;
    while (now_ms - player_last_step >= PLAYER_STEP_MS && state == MAZE_PLAYING) {
        player_last_step += PLAYER_STEP_MS;
        movePlayer(requested, now_ms);
        checkGhostHits(now_ms);
    }
    if ((int32_t)(now_ms - ghosts_release_at) < 0) {
        // Keep the movement clock current during the release delay: the chasers
        // begin with one normal step, rather than catching up two seconds at once.
        ghost_last_step = now_ms;
        return;
    }
    const uint32_t ghost_step = GHOST_STEP_MS > round_number * 5U ? GHOST_STEP_MS - round_number * 5U : 90U;
    while (now_ms - ghost_last_step >= ghost_step && state == MAZE_PLAYING) {
        ghost_last_step += ghost_step;
        for (unsigned i = 0; i < GHOST_COUNT && state == MAZE_PLAYING; ++i) {
            moveGhost(i, now_ms);
            checkGhostHits(now_ms);
        }
    }
}
drawMazeChase() · source line 297
void drawMazeChase(uint16_t *frame)

Calls into this documentation:

  1. Decision!running || frame == NULL
    True
    1. Exit this functionreturn;
    False

    Continue after this decision.

  2. Decisionstate == MAZE_SCORES
    True
      1. ExecutedrawHighScoreEntry(frame);
      2. Exit this functionreturn;
    False

    Continue after this decision.

  3. Executeclear(frame, COLOR_BLACK);
  4. Decisionstate == MAZE_READY
    True
      1. Executedraw_text_centred(frame, LCD_WIDTH / 2, 20, "MAZE CHASE", 2, COLOR_YELLOW);
      2. Executedraw_text_centred(frame, LCD_WIDTH / 2, 55, "CLEAR THE MAZE", 1, COLOR_CYAN);
      3. Executedraw_text_centred(frame, LCD_WIDTH / 2, 73, "AVOID THE CHASERS", 1, COLOR_MAGENTA);
      4. Executedraw_text_centred(frame, LCD_WIDTH / 2, 110, "D/B OR STICK MOVE", 1, COLOR_LIGHTGRAY);
      5. Executedraw_text_centred(frame, LCD_WIDTH / 2, 145, "A/K START", 2, COLOR_YELLOW);
      6. Exit this functionreturn;
    False

    Continue after this decision.

  5. Executechar text[28];
  6. Executesnprintf(text, sizeof(text), "SCORE %u", (unsigned)score);
  7. Executedraw_text(frame, 3, 0, text, 1, COLOR_WHITE);
  8. Executesnprintf(text, sizeof(text), "LIVES %u", (unsigned)lives);
  9. Executedraw_text_centred(frame, LCD_WIDTH / 2, 0, text, 1, COLOR_CYAN);
  10. Executesnprintf(text, sizeof(text), "ROUND %u", (unsigned)round_number);
  11. Executedraw_text(frame, 255, 0, text, 1, COLOR_YELLOW);
  12. FOR loopint row = 0; row < MAZE_ROWS; ++row

    Repeat body while the loop condition permits; then continue below.

    1. FOR loopint column = 0; column < MAZE_COLUMNS; ++column

      Repeat body while the loop condition permits; then continue below.

        1. Executeconst int x = MAZE_X + column * TILE_SIZE;
        2. Executeconst int y = MAZE_Y + row * TILE_SIZE;
        3. DecisionwallAt(column, row)
          True
          1. Executefill_rect(frame, x, y, TILE_SIZE, TILE_SIZE, RGB565(0, 30, 190));
          False
          1. Decisionpellets[row][column] == 2U
            True
            1. Executefill_circle(frame, x + TILE_CENTRE, y + TILE_CENTRE, 6, COLOR_WHITE);
            False
            1. Decisionpellets[row][column] == 1U
              True
              1. Executefill_circle(frame, x + TILE_CENTRE, y + TILE_CENTRE, 2, COLOR_YELLOW);
              False

              Continue after this decision.

  13. Executeconst int player_x = MAZE_X + player.column * TILE_SIZE + TILE_CENTRE;
  14. Executeconst int player_y = MAZE_Y + player.row * TILE_SIZE + TILE_CENTRE;
  15. Executefill_circle(frame, player_x, player_y, 8, COLOR_YELLOW);
  16. Decisionplayer.direction == DIRECTION_RIGHT
    True
    1. Executefill_rect(frame, player_x + 4, player_y - 4, 5, 9, COLOR_BLACK);
    False
    1. Decisionplayer.direction == DIRECTION_LEFT
      True
      1. Executefill_rect(frame, player_x - 8, player_y - 4, 5, 9, COLOR_BLACK);
      False
      1. Decisionplayer.direction == DIRECTION_UP
        True
        1. Executefill_rect(frame, player_x - 4, player_y - 8, 9, 5, COLOR_BLACK);
        False
        1. Decisionplayer.direction == DIRECTION_DOWN
          True
          1. Executefill_rect(frame, player_x - 4, player_y + 4, 9, 5, COLOR_BLACK);
          False

          Continue after this decision.

  17. Executeconst bool frightened = (int32_t)(frightened_until - player_last_step) > 0;
  18. FOR loopunsigned i = 0; i < GHOST_COUNT; ++i

    Repeat body while the loop condition permits; then continue below.

      1. Executeconst int x = MAZE_X + ghosts[i].column * TILE_SIZE + TILE_CENTRE;
      2. Executeconst int y = MAZE_Y + ghosts[i].row * TILE_SIZE + TILE_CENTRE;
      3. Executeconst uint16_t colour = frightened ? COLOR_DARKBLUE : ghost_colours[i];
      4. Executefill_circle(frame, x, y - 2, 8, colour);
      5. Executefill_rect(frame, x - 8, y - 2, 17, 10, colour);
      6. Executefill_rect(frame, x - 4, y, 2, 4, COLOR_WHITE);
      7. Executefill_rect(frame, x + 4, y, 2, 4, COLOR_WHITE);
  19. Decisionstate == MAZE_LIFE_LOST
    True
    1. Executedraw_text_centred(frame, LCD_WIDTH / 2, 83, "LIFE LOST", 2, COLOR_RED);
    False
    1. Decisionstate == MAZE_FINISHED
      True
      1. Executedraw_text_centred(frame, LCD_WIDTH / 2, 83, "GAME OVER", 2, COLOR_RED);
      False

      Continue after this decision.

Read original function source
void drawMazeChase(uint16_t *frame)
{
    if (!running || frame == NULL) return;
    if (state == MAZE_SCORES) { drawHighScoreEntry(frame); return; }
    clear(frame, COLOR_BLACK);
    if (state == MAZE_READY) {
        draw_text_centred(frame, LCD_WIDTH / 2, 20, "MAZE CHASE", 2, COLOR_YELLOW);
        draw_text_centred(frame, LCD_WIDTH / 2, 55, "CLEAR THE MAZE", 1, COLOR_CYAN);
        draw_text_centred(frame, LCD_WIDTH / 2, 73, "AVOID THE CHASERS", 1, COLOR_MAGENTA);
        draw_text_centred(frame, LCD_WIDTH / 2, 110, "D/B OR STICK MOVE", 1, COLOR_LIGHTGRAY);
        draw_text_centred(frame, LCD_WIDTH / 2, 145, "A/K START", 2, COLOR_YELLOW);
        return;
    }
    char text[28];
    snprintf(text, sizeof(text), "SCORE %u", (unsigned)score);
    draw_text(frame, 3, 0, text, 1, COLOR_WHITE);
    snprintf(text, sizeof(text), "LIVES %u", (unsigned)lives);
    draw_text_centred(frame, LCD_WIDTH / 2, 0, text, 1, COLOR_CYAN);
    snprintf(text, sizeof(text), "ROUND %u", (unsigned)round_number);
    draw_text(frame, 255, 0, text, 1, COLOR_YELLOW);
    for (int row = 0; row < MAZE_ROWS; ++row) for (int column = 0; column < MAZE_COLUMNS; ++column) {
        const int x = MAZE_X + column * TILE_SIZE;
        const int y = MAZE_Y + row * TILE_SIZE;
        if (wallAt(column, row)) fill_rect(frame, x, y, TILE_SIZE, TILE_SIZE, RGB565(0, 30, 190));
        else if (pellets[row][column] == 2U) fill_circle(frame, x + TILE_CENTRE, y + TILE_CENTRE, 6, COLOR_WHITE);
        else if (pellets[row][column] == 1U) fill_circle(frame, x + TILE_CENTRE, y + TILE_CENTRE, 2, COLOR_YELLOW);
    }
    const int player_x = MAZE_X + player.column * TILE_SIZE + TILE_CENTRE;
    const int player_y = MAZE_Y + player.row * TILE_SIZE + TILE_CENTRE;
    fill_circle(frame, player_x, player_y, 8, COLOR_YELLOW);
    if (player.direction == DIRECTION_RIGHT) fill_rect(frame, player_x + 4, player_y - 4, 5, 9, COLOR_BLACK);
    else if (player.direction == DIRECTION_LEFT) fill_rect(frame, player_x - 8, player_y - 4, 5, 9, COLOR_BLACK);
    else if (player.direction == DIRECTION_UP) fill_rect(frame, player_x - 4, player_y - 8, 9, 5, COLOR_BLACK);
    else if (player.direction == DIRECTION_DOWN) fill_rect(frame, player_x - 4, player_y + 4, 9, 5, COLOR_BLACK);
    const bool frightened = (int32_t)(frightened_until - player_last_step) > 0;
    for (unsigned i = 0; i < GHOST_COUNT; ++i) {
        const int x = MAZE_X + ghosts[i].column * TILE_SIZE + TILE_CENTRE;
        const int y = MAZE_Y + ghosts[i].row * TILE_SIZE + TILE_CENTRE;
        const uint16_t colour = frightened ? COLOR_DARKBLUE : ghost_colours[i];
        fill_circle(frame, x, y - 2, 8, colour);
        fill_rect(frame, x - 8, y - 2, 17, 10, colour);
        fill_rect(frame, x - 4, y, 2, 4, COLOR_WHITE);
        fill_rect(frame, x + 4, y, 2, 4, COLOR_WHITE);
    }
    if (state == MAZE_LIFE_LOST) draw_text_centred(frame, LCD_WIDTH / 2, 83, "LIFE LOST", 2, COLOR_RED);
    else if (state == MAZE_FINISHED) draw_text_centred(frame, LCD_WIDTH / 2, 83, "GAME OVER", 2, COLOR_RED);
}
Complete original file, including constants and data
/* Coded By JD(2026) */
#error "Reference listing only — not provided as build-ready source."
#include "maze_chase.h"

#include "audio.h"
#include "game_graphics.h"
#include "PET2001_font.h"
#include "high_scores.h"

#include <stdio.h>

#define MAZE_COLUMNS 11
#define MAZE_ROWS 9
#define TILE_SIZE 18
#define MAZE_X ((LCD_WIDTH - MAZE_COLUMNS * TILE_SIZE) / 2)
#define MAZE_Y 8
#define TUNNEL_ROW 4
#define TILE_CENTRE (TILE_SIZE / 2)
#define PLAYER_STEP_MS 105U
#define GHOST_STEP_MS 145U
#define GHOST_RELEASE_DELAY_MS 2000U
#define POWER_MS 6000U
#define LIFE_LOST_MS 900U
#define GHOST_COUNT 4U

typedef enum { DIRECTION_NONE, DIRECTION_UP, DIRECTION_DOWN, DIRECTION_LEFT, DIRECTION_RIGHT } direction_t;
typedef enum { MAZE_READY, MAZE_PLAYING, MAZE_LIFE_LOST, MAZE_FINISHED, MAZE_SCORES } maze_state_t;
typedef struct { int column; int row; direction_t direction; } maze_actor_t;

static uint8_t pellets[MAZE_ROWS][MAZE_COLUMNS];
static maze_actor_t player;
static maze_actor_t ghosts[GHOST_COUNT];
static maze_state_t state;
static uint32_t score;
static uint32_t round_number;
static uint32_t state_started;
static uint32_t player_last_step;
static uint32_t ghost_last_step;
static uint32_t frightened_until;
static uint32_t ghosts_release_at;
static uint8_t lives;
static uint16_t pellets_left;
static bool controls_ready;
static bool running;

static const uint16_t ghost_colours[GHOST_COUNT] = { COLOR_RED, COLOR_MAGENTA, COLOR_CYAN, COLOR_YELLOW };

// Each '.' is one traversable maze unit.  The corridors form connected loops and
// crossings, giving the player several escape choices without dead ends.
static const char maze_layout[MAZE_ROWS][MAZE_COLUMNS + 1] = {
    "###########",
    "#.........#",
    "#.###.###.#",
    "#.........#",
    "...........",
    "#.........#",
    "#.###.###.#",
    "#.........#",
    "###########",
};

static int absoluteValue(int value) { return value < 0 ? -value : value; }

static bool wallAt(int column, int row)
{
    return row < 0 || row >= MAZE_ROWS || column < 0 || column >= MAZE_COLUMNS ||
        maze_layout[row][column] == '#';
}

static direction_t oppositeDirection(direction_t direction)
{
    if (direction == DIRECTION_UP) return DIRECTION_DOWN;
    if (direction == DIRECTION_DOWN) return DIRECTION_UP;
    if (direction == DIRECTION_LEFT) return DIRECTION_RIGHT;
    return direction == DIRECTION_RIGHT ? DIRECTION_LEFT : DIRECTION_NONE;
}

static void directionOffset(direction_t direction, int *column, int *row)
{
    *column = 0;
    *row = 0;
    if (direction == DIRECTION_UP) *row = -1;
    else if (direction == DIRECTION_DOWN) *row = 1;
    else if (direction == DIRECTION_LEFT) *column = -1;
    else if (direction == DIRECTION_RIGHT) *column = 1;
}

static bool nextTile(const maze_actor_t *actor, direction_t direction, int *column, int *row)
{
    int dx, dy;
    directionOffset(direction, &dx, &dy);
    *column = actor->column + dx;
    *row = actor->row + dy;
    if (*row == TUNNEL_ROW && *column < 0) *column = MAZE_COLUMNS - 1;
    if (*row == TUNNEL_ROW && *column >= MAZE_COLUMNS) *column = 0;
    return !wallAt(*column, *row);
}

static void resetActors(void)
{
    player = (maze_actor_t){1, 7, DIRECTION_RIGHT};
    const maze_actor_t starts[GHOST_COUNT] = {
        {4, 1, DIRECTION_LEFT}, {5, 1, DIRECTION_RIGHT},
        {6, 1, DIRECTION_LEFT}, {7, 1, DIRECTION_RIGHT}
    };
    for (unsigned i = 0; i < GHOST_COUNT; ++i) ghosts[i] = starts[i];
}

static void resetMaze(void)
{
    pellets_left = 0U;
    for (int row = 0; row < MAZE_ROWS; ++row) {
        for (int column = 0; column < MAZE_COLUMNS; ++column) {
            pellets[row][column] = wallAt(column, row) ? 0U : 1U;
            if (pellets[row][column] != 0U) ++pellets_left;
        }
    }
    pellets[1][1] = 2U;
    pellets[1][MAZE_COLUMNS - 2] = 2U;
    pellets[7][MAZE_COLUMNS - 2] = 2U;
    pellets[5][1] = 2U;
    for (unsigned i = 0; i < GHOST_COUNT; ++i) {
        const int row = ghosts[i].row;
        const int column = ghosts[i].column;
        if (pellets[row][column] != 0U) --pellets_left;
        pellets[row][column] = 0U;
    }
    if (pellets[player.row][player.column] != 0U) --pellets_left;
    pellets[player.row][player.column] = 0U;
}

static void beginRound(uint32_t now_ms)
{
    resetActors();
    resetMaze();
    frightened_until = 0U;
    ghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
    player_last_step = now_ms;
    ghost_last_step = now_ms;
    state = MAZE_PLAYING;
}

static void loseLife(uint32_t now_ms)
{
    audioPlay(AUDIO_SFX_PLAYER_EXPLOSION);
    if (lives != 0U) --lives;
    state_started = now_ms;
    state = lives == 0U ? MAZE_FINISHED : MAZE_LIFE_LOST;
}

static void collectPellet(uint32_t now_ms)
{
    uint8_t *pellet = &pellets[player.row][player.column];
    if (*pellet == 0U) return;
    const bool power_pellet = *pellet == 2U;
    score += power_pellet ? 50U : 10U;
    audioPlay(power_pellet ? AUDIO_SFX_POWER_UP : AUDIO_SFX_MAZE_PELLET);
    if (power_pellet) frightened_until = now_ms + POWER_MS;
    *pellet = 0U;
    if (pellets_left != 0U) --pellets_left;
    if (pellets_left == 0U) {
        audioPlay(AUDIO_SFX_WAVE_CLEAR);
        ++round_number;
        resetMaze();
        resetActors();
        ghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
    }
}

static void movePlayer(direction_t requested, uint32_t now_ms)
{
    int column, row;
    if (requested != DIRECTION_NONE && nextTile(&player, requested, &column, &row)) player.direction = requested;
    if (!nextTile(&player, player.direction, &column, &row)) return;
    player.column = column;
    player.row = row;
    collectPellet(now_ms);
}

static void moveGhost(unsigned index, uint32_t now_ms)
{
    maze_actor_t *ghost = &ghosts[index];
    direction_t selected = DIRECTION_NONE;
    int best_distance = 0x7fffffff;
    const bool frightened = (int32_t)(frightened_until - now_ms) > 0;
    const direction_t choices[] = {DIRECTION_UP, DIRECTION_LEFT, DIRECTION_DOWN, DIRECTION_RIGHT};
    for (unsigned i = 0; i < sizeof(choices) / sizeof(choices[0]); ++i) {
        int column, row;
        if (!nextTile(ghost, choices[i], &column, &row)) continue;
        if (choices[i] == oppositeDirection(ghost->direction) && selected != DIRECTION_NONE) continue;
        const int distance = absoluteValue(column - player.column) + absoluteValue(row - player.row);
        const int target_distance = frightened ? -distance : distance + (int)((index * 3U + i) % 4U);
        if (target_distance < best_distance) {
            best_distance = target_distance;
            selected = choices[i];
        }
    }
    int column, row;
    if (selected != DIRECTION_NONE && nextTile(ghost, selected, &column, &row)) {
        ghost->direction = selected;
        ghost->column = column;
        ghost->row = row;
    }
}

static void checkGhostHits(uint32_t now_ms)
{
    for (unsigned i = 0; i < GHOST_COUNT; ++i) {
        if (ghosts[i].column != player.column || ghosts[i].row != player.row) continue;
        if ((int32_t)(frightened_until - now_ms) > 0) {
            score += 200U;
            ghosts[i] = (maze_actor_t){5, 1, DIRECTION_LEFT};
            audioPlay(AUDIO_SFX_HIT);
        } else {
            loseLife(now_ms);
        }
        return;
    }
}

void startMazeChase(uint32_t now_ms)
{
    score = 0U;
    round_number = 1U;
    lives = 3U;
    controls_ready = false;
    running = true;
    state = MAZE_READY;
    state_started = now_ms;
}

void stopMazeChase(void)
{
    cancelHighScoreEntry();
    running = false;
}

void mazeChaseAction(bool action, uint32_t now_ms)
{
    if (!running || !action) return;
    if (state == MAZE_READY) {
        beginRound(now_ms);
        audioPlay(AUDIO_SFX_GAME_START);
    }
}

void updateMazeChase(int x_offset, int y_offset, bool joystick_valid, bool left, bool right,
                     uint32_t now_ms)
{
    if (!running) return;
    if (state == MAZE_SCORES) {
        if (updateHighScoreEntry(x_offset, y_offset, joystick_valid, now_ms)) state = MAZE_READY;
        return;
    }
    if (state == MAZE_FINISHED) {
        if (now_ms - state_started >= LIFE_LOST_MS) {
            startHighScoreEntry(HIGH_SCORE_MAZE_CHASE, score, now_ms);
            state = MAZE_SCORES;
        }
        return;
    }
    if (state == MAZE_LIFE_LOST) {
        if (now_ms - state_started >= LIFE_LOST_MS) {
            resetActors();
            player_last_step = now_ms;
            ghost_last_step = now_ms;
            ghosts_release_at = now_ms + GHOST_RELEASE_DELAY_MS;
            state = MAZE_PLAYING;
        }
        return;
    }
    if (state != MAZE_PLAYING) return;
    if (!joystick_valid) controls_ready = false;
    else if (absoluteValue(x_offset) < 350 && absoluteValue(y_offset) < 350) controls_ready = true;
    direction_t requested = DIRECTION_NONE;
    if (left != right) requested = left ? DIRECTION_LEFT : DIRECTION_RIGHT;
    else if (joystick_valid && controls_ready && absoluteValue(x_offset) > 500) requested = x_offset < 0 ? DIRECTION_LEFT : DIRECTION_RIGHT;
    else if (joystick_valid && controls_ready && absoluteValue(y_offset) > 500) requested = y_offset > 0 ? DIRECTION_UP : DIRECTION_DOWN;
    while (now_ms - player_last_step >= PLAYER_STEP_MS && state == MAZE_PLAYING) {
        player_last_step += PLAYER_STEP_MS;
        movePlayer(requested, now_ms);
        checkGhostHits(now_ms);
    }
    if ((int32_t)(now_ms - ghosts_release_at) < 0) {
        // Keep the movement clock current during the release delay: the chasers
        // begin with one normal step, rather than catching up two seconds at once.
        ghost_last_step = now_ms;
        return;
    }
    const uint32_t ghost_step = GHOST_STEP_MS > round_number * 5U ? GHOST_STEP_MS - round_number * 5U : 90U;
    while (now_ms - ghost_last_step >= ghost_step && state == MAZE_PLAYING) {
        ghost_last_step += ghost_step;
        for (unsigned i = 0; i < GHOST_COUNT && state == MAZE_PLAYING; ++i) {
            moveGhost(i, now_ms);
            checkGhostHits(now_ms);
        }
    }
}

void drawMazeChase(uint16_t *frame)
{
    if (!running || frame == NULL) return;
    if (state == MAZE_SCORES) { drawHighScoreEntry(frame); return; }
    clear(frame, COLOR_BLACK);
    if (state == MAZE_READY) {
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 20, "MAZE CHASE", COLOR_YELLOW, 2);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 55, "CLEAR THE MAZE", COLOR_CYAN, 1);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 73, "AVOID THE CHASERS", COLOR_MAGENTA, 1);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 110, "D/B OR STICK MOVE", COLOR_LIGHTGRAY, 1);
        drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 145, "A/K START", COLOR_YELLOW, 2);
        return;
    }
    char text[28];
    snprintf(text, sizeof(text), "SCORE %u", (unsigned)score);
    drawPet2001TextTransparent(frame, 3, 0, text, COLOR_WHITE, 1);
    snprintf(text, sizeof(text), "LIVES %u", (unsigned)lives);
    drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 0, text, COLOR_CYAN, 1);
    snprintf(text, sizeof(text), "ROUND %u", (unsigned)round_number);
    drawPet2001TextTransparent(frame, 255, 0, text, COLOR_YELLOW, 1);
    for (int row = 0; row < MAZE_ROWS; ++row) for (int column = 0; column < MAZE_COLUMNS; ++column) {
        const int x = MAZE_X + column * TILE_SIZE;
        const int y = MAZE_Y + row * TILE_SIZE;
        if (wallAt(column, row)) fill_rect(frame, x, y, TILE_SIZE, TILE_SIZE, RGB565(0, 30, 190));
        else if (pellets[row][column] == 2U) fill_circle(frame, x + TILE_CENTRE, y + TILE_CENTRE, 6, COLOR_WHITE);
        else if (pellets[row][column] == 1U) fill_circle(frame, x + TILE_CENTRE, y + TILE_CENTRE, 2, COLOR_YELLOW);
    }
    const int player_x = MAZE_X + player.column * TILE_SIZE + TILE_CENTRE;
    const int player_y = MAZE_Y + player.row * TILE_SIZE + TILE_CENTRE;
    fill_circle(frame, player_x, player_y, 8, COLOR_YELLOW);
    if (player.direction == DIRECTION_RIGHT) fill_rect(frame, player_x + 4, player_y - 4, 5, 9, COLOR_BLACK);
    else if (player.direction == DIRECTION_LEFT) fill_rect(frame, player_x - 8, player_y - 4, 5, 9, COLOR_BLACK);
    else if (player.direction == DIRECTION_UP) fill_rect(frame, player_x - 4, player_y - 8, 9, 5, COLOR_BLACK);
    else if (player.direction == DIRECTION_DOWN) fill_rect(frame, player_x - 4, player_y + 4, 9, 5, COLOR_BLACK);
    const bool frightened = (int32_t)(frightened_until - player_last_step) > 0;
    for (unsigned i = 0; i < GHOST_COUNT; ++i) {
        const int x = MAZE_X + ghosts[i].column * TILE_SIZE + TILE_CENTRE;
        const int y = MAZE_Y + ghosts[i].row * TILE_SIZE + TILE_CENTRE;
        const uint16_t colour = frightened ? COLOR_DARKBLUE : ghost_colours[i];
        fill_circle(frame, x, y - 2, 8, colour);
        fill_rect(frame, x - 8, y - 2, 17, 10, colour);
        fill_rect(frame, x - 4, y, 2, 4, COLOR_WHITE);
        fill_rect(frame, x + 4, y, 2, 4, COLOR_WHITE);
    }
    if (state == MAZE_LIFE_LOST) drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 83, "LIFE LOST", COLOR_RED, 2);
    else if (state == MAZE_FINISHED) drawPet2001TextCentredTransparent(frame, LCD_WIDTH / 2, 83, "GAME OVER", COLOR_RED, 2);
}