#include <genesis.h>
#include <resources.h>
#include <string.h>
#include "megapong.h"

#define SCREEN_WIDTH   320
#define SCREEN_HEIGHT  224
#define LEFT_EDGE      0
#define RIGHT_EDGE     320
#define TOP_EDGE       0
#define BOTTOM_EDGE    224
#define Chosby_base    0

// ========= SETTINGS ENUMS ========= //
typedef enum { DIFF_SLOW, DIFF_NORMAL, DIFF_FAST, DIFF_HYPER } Difficulty;
typedef enum { P_SMALL, P_NORMAL } PadSize;
typedef enum { BALL_CLASSIC, BALL_NEMO, BALL_SONIC, BALL_CHOSBY } BallType;
typedef enum { CTRL_STD, CTRL_INV, CTRL_PADDLE } ControlType;
typedef enum { WIN_10, WIN_25, WIN_50, WIN_NONE } WinLimit;

// ========= GLOBAL SETTINGS ========= //
typedef struct {
    Difficulty difficulty;
    PadSize paddleSize;
    BallType ballType;
    ControlType p1Control;
    ControlType p2Control;
    WinLimit winLimit;
} PongSettings;

static PongSettings settings = {
    DIFF_NORMAL,
    P_NORMAL,
    BALL_CLASSIC,
    CTRL_STD,
    CTRL_STD,
    WIN_10
};

// ========= MAIN STATES ========= //
typedef enum {
    STATE_MENU,
    STATE_OPTIONS,
    STATE_PLAY,
    STATE_EXIT
} PongState;

// ========= GAMEPLAY SUB-STATES ========= //
typedef enum {
    SUB_INTERMISSION, 
    SUB_COUNTDOWN,    
    SUB_PLAY          
} PongSubState;

// ========= GAME VARIABLES ========= //
static PongSubState subState;
static bool game_over_screen;
static int countdown_timer; 

// Scores
static int score;
static int score2;
static char str_score[4];
static char str_score2[4];
static char label_score[9]  = "P1 SCORE";
static char label_score2[9] = "P2 SCORE";
static char msg_start[22]   = "PRESS START TO BEGIN!";

// Sprites
static Sprite* ball;
static Sprite* player;
static Sprite* player2;

// Physics Variables
static int ball_pos_x, ball_pos_y;
static int ball_vel_x, ball_vel_y;

// Exact Dimensions (Set in playMegapong)
static int ball_width; 
static int ball_height;
static int player_width = 8; // Fixed paddle width
static int player_height;

static int base_speed = 2;   
static int paddle_speed = 3; 

static int player_pos_x, player_pos_y;
static int player_vel_y;
static int player_h_coll; // Same as player_height

static int player2_pos_x, player2_pos_y;
static int player2_vel_y;

// Scrolling text
static char scroll_buffer[100]; 
static int scroll_offset;

// ========= FUNCTION DECLARATIONS ========= //
static void updateScoreDisplay();
static void updateScoreDisplay2();
static void myJoyHandler(u16 joy, u16 changed, u16 state);
static void positionPlayer();
static void moveBall();
static void showText(char* s);
static void startGame();
static void resetBall(int winner);
static void checkWinCondition(); 
static void updateScrollingText(const char* targetText); 
static void centerPaddles(); 
static int sign(int x) { return (x > 0) - (x < 0); }

// State Functions
static PongState megapong_menu();
static PongState megapong_options();
static PongState playMegapong(); 

// ========================================= //
//          ENTRY POINT
// ========================================= //
void runMegapong()
{
    PongState currentState = STATE_MENU;

    while(currentState != STATE_EXIT)
    {
        switch(currentState)
        {
            case STATE_MENU:
                currentState = megapong_menu();
                break;
            case STATE_OPTIONS:
                currentState = megapong_options();
                break;
            case STATE_PLAY:
                currentState = playMegapong();
                break;
            case STATE_EXIT:
                break;
        }
    }

    SPR_reset();
    VDP_resetScreen();
}

// ========================================= //
//          MENU LOGIC
// ========================================= //
static PongState megapong_menu()
{
    VDP_resetScreen();
    
    // --- SPRITE SETUP FOR TITLE ---
    SPR_init();
    
    // Load palette for the logo (PAL1 as in megasplash)
    PAL_setPalette(PAL1, pongImg.palette->data, DMA);
    
    // Add the sprite centered horizontally
    // Screen 320, Sprite 152. (320 - 152) / 2 = 84
    SPR_addSprite(&pongImg, 84, 32, TILE_ATTR(PAL1, TRUE, FALSE, FALSE));

    VDP_setTextPlane(BG_A);
    // Removed old text calls for title

    int selection = 0;
    int old_selection = -1; 

    while(JOY_readJoypad(JOY_1) & (BUTTON_START | BUTTON_A | BUTTON_C | BUTTON_B))
    {
        SPR_update(); // Keep sprite rendered
        SYS_doVBlankProcess();
    }

    u16 last_state = 0; 

    while(1)
    {
        u16 current_state = JOY_readJoypad(JOY_1);
        u16 pressed = current_state & ~last_state;
        last_state = current_state;

        if (pressed & BUTTON_UP) {
            if (selection > 0) selection--;
        }
        if (pressed & BUTTON_DOWN) {
            if (selection < 1) selection++;
        }

        if (pressed & (BUTTON_START | BUTTON_A)) {
            SPR_reset(); // Cleanup before leaving
            if (selection == 0) return STATE_PLAY;
            if (selection == 1) return STATE_OPTIONS;
        }

        if (pressed & BUTTON_B) {
            SPR_reset(); // Cleanup before leaving
            return STATE_EXIT;
        }

        if (selection != old_selection)
        {
            VDP_clearText(14, 10, 20);
            VDP_clearText(14, 12, 20);
            VDP_drawText("  EXIT      ", 14, 14);
            VDP_drawText(selection == 0 ? "> START GAME" : "  START GAME", 14, 10);
            VDP_drawText(selection == 1 ? "> OPTIONS"    : "  OPTIONS   ", 14, 12);
            old_selection = selection;
        }
        
        SPR_update(); // Keep sprite rendered
        SYS_doVBlankProcess();
    }
}

// ========================================= //
//          OPTIONS MENU LOGIC
// ========================================= //
static PongState megapong_options()
{
    VDP_resetScreen();
    VDP_drawText("MEGAPONG OPTIONS", 12, 2);
    VDP_drawText("----------------", 12, 3);
    VDP_drawText("PRESS B TO RETURN", 12, 22);

    int opt_sel = 0;
    bool dirty = TRUE;

    scroll_offset = 0;
    memset(scroll_buffer, 0, sizeof(scroll_buffer));

    while(JOY_readJoypad(JOY_1) & (BUTTON_START | BUTTON_A | BUTTON_C | BUTTON_B)) { SYS_doVBlankProcess(); }

    u16 last_state = 0;

    while(1)
    {
        u16 current_state = JOY_readJoypad(JOY_1);
        u16 pressed = current_state & ~last_state;
        last_state = current_state;

        if (pressed & BUTTON_UP) {
            if (opt_sel > 0) { opt_sel--; dirty = TRUE; }
        }
        if (pressed & BUTTON_DOWN) {
            if (opt_sel < 5) { opt_sel++; dirty = TRUE; }
        }

        if (pressed & BUTTON_B) return STATE_MENU;

        if (pressed & (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_A))
        {
            int dir = (pressed & BUTTON_LEFT) ? -1 : 1;
            dirty = TRUE;

            switch(opt_sel)
            {
                case 0: settings.difficulty = (settings.difficulty + dir + 4) % 4; break;
                case 1: settings.paddleSize = (settings.paddleSize + 1) % 2; break;
                case 2: settings.ballType = (settings.ballType + dir + 4) % 4; break;
                case 3: settings.p1Control = (settings.p1Control + dir + 3) % 3; break;
                case 4: settings.p2Control = (settings.p2Control + dir + 3) % 3; break;
                case 5: settings.winLimit  = (settings.winLimit + dir + 4) % 4; break;
            }
        }

        if (dirty)
        {
            VDP_clearText(20, 5, 12);
            for(int r=5; r<18; r++) VDP_clearText(20, r, 12);

            VDP_drawText(opt_sel == 0 ? "> DIFFICULTY: " : "  DIFFICULTY: ", 4, 6);
            const char* s_diff[] = {"SLOW", "NORMAL", "FAST", "HYPER"};
            VDP_drawText(s_diff[settings.difficulty], 20, 6);

            VDP_drawText(opt_sel == 1 ? "> PADDLE SIZE: " : "  PADDLE SIZE: ", 4, 8);
            VDP_drawText(settings.paddleSize == P_SMALL ? "SMALL " : "NORMAL", 20, 8);

            VDP_drawText(opt_sel == 2 ? "> BALL TYPE: " : "  BALL TYPE: ", 4, 10);
            const char* s_ball[] = {"CLASSIC", "NEMO", "SONIC", "CHOSBY"};
            VDP_drawText(s_ball[settings.ballType], 20, 10);

            VDP_drawText(opt_sel == 3 ? "> P1 CONTROLS: " : "  P1 CONTROLS: ", 4, 12);
            const char* s_ctrl[] = {"STANDARD", "INVERTED", "PADDLE"};
            VDP_drawText(s_ctrl[settings.p1Control], 20, 12);

            VDP_drawText(opt_sel == 4 ? "> P2 CONTROLS: " : "  P2 CONTROLS: ", 4, 14);
            VDP_drawText(s_ctrl[settings.p2Control], 20, 14);

            VDP_drawText(opt_sel == 5 ? "> WIN LIMIT: " : "  WIN LIMIT: ", 4, 16);
            const char* s_win[] = {"10", "25", "50", "NONE"};
            VDP_drawText(s_win[settings.winLimit], 20, 16);

            dirty = FALSE;
        }

        const char* flavor = "";
        switch(opt_sel) {
            case 0:
                if(settings.difficulty == DIFF_SLOW) flavor = "SLOW: CHUGS LIKE A 16-BIT POTATO.";
                else if(settings.difficulty == DIFF_NORMAL) flavor = "NORMAL: STANDARD SPEED FOR CASUAL PLAY.";
                else if(settings.difficulty == DIFF_FAST) flavor = "FAST: NOW THINGS ARE GETTING INTENSE!";
                else flavor = "HYPER: BLAST PROCESSING SPEED! <3 !!!";
                break;
            case 1:
                if(settings.paddleSize == P_SMALL) flavor = "SMALL: ENJOY THE DIFFICULTY OF SMALLER SIZE.";
                else flavor = "NORMAL: STANDARD SIZE MOST ARE COMFORTABLE WITH.";
                break;
            case 2:
                if(settings.ballType == BALL_CLASSIC) flavor = "CLASSIC: FOR THE TRADITIONALIST.";
                else if(settings.ballType == BALL_NEMO) flavor = "NEMO: A SLUMBER LAND SPECTACLE.";
                else if(settings.ballType == BALL_SONIC) flavor = "SONIC: MEGAPONG NEEDS OUR SEGA MEGA-MASCOT.";
                else flavor = "CHOSBY: Q-LUDES TO CALM 90S 'TUDE! PUDDIN' POP!";
                break;
            case 3:
            case 4:
                flavor = "SET CONTROLS FOR PLAYER.";
                break;
            case 5:
                if(settings.winLimit == WIN_NONE) flavor = "UNLIMITED: PLAY UNTIL YOUR THUMBS FALL OFF!";
                else flavor = "SET THE SCORE LIMIT TO WIN THE MATCH.";
                break;
        }
        updateScrollingText(flavor);
        SYS_doVBlankProcess();
    }
}

// ========================================= //
//         GAMEPLAY LOGIC
// ========================================= //
static PongState playMegapong()
{
    game_over_screen = FALSE;
    score = 0;
    score2 = 0;
    scroll_offset = 0;

    subState = SUB_INTERMISSION;

    VDP_resetScreen();
    VDP_setTextPlane(BG_A);
    VDP_drawText(label_score, 1, 1);
    VDP_drawText(label_score2, 28, 1);

    VDP_clearText(14, 1, 12); 
    switch(settings.ballType) {
        case BALL_CLASSIC: VDP_drawText("MEGAPONG", 16, 1); break;
        case BALL_NEMO:    VDP_drawText("NEMOPONG", 16, 1); break;
        case BALL_SONIC:   VDP_drawText("SONICPONG", 15, 1); break; 
        case BALL_CHOSBY:  VDP_drawText("CHOSPONG", 16, 1); break;
    }

    updateScoreDisplay();
    updateScoreDisplay2();

    switch(settings.difficulty) {
        case DIFF_SLOW:   base_speed = 1; break;
        case DIFF_NORMAL: base_speed = 2; break;
        case DIFF_FAST:   base_speed = 4; break;
        case DIFF_HYPER:  base_speed = 6; break;
    }
    
    paddle_speed = base_speed + 2;
    
    // --- SET EXACT DIMENSIONS ---
    player_height = (settings.paddleSize == P_SMALL) ? 16 : 32;
    player_h_coll = player_height;
    player_width = 8; // All paddles are 8px wide

    // --- SET BALL DIMENSIONS ---
    if(settings.ballType == BALL_CHOSBY) {
        // Chosby is now 64x64
        ball_width = 64;
        ball_height = 64;
    } 
    else if(settings.ballType == BALL_SONIC || settings.ballType == BALL_NEMO) {
        // Sonic and Nemo are 32x32
        ball_width = 32;
        ball_height = 32;
    }
    else {
        // BALL_CLASSIC
        ball_width = 8;
        ball_height = 8;
    }

    VDP_loadTileSet(bgtile.tileset, 1, DMA);
    VDP_fillTileMapRect(BG_B, TILE_ATTR_FULL(PAL1, 0, FALSE, FALSE, 1), 0, 0, 40, 30);
    
    PAL_setPalette(PAL1, megapong_pal.data, DMA); 
    PAL_setPalette(PAL2, chosby.palette->data, DMA); 

    SPR_init();

    player_pos_x = 32;
    player_pos_y = 96;
    player2_pos_x = 288;
    player2_pos_y = 96;
    
    player_vel_y = 0;
    player2_vel_y = 0;

    resetBall(0);

    switch(settings.ballType) {
        case BALL_CLASSIC:
            ball = SPR_addSprite(&imgball, ball_pos_x, ball_pos_y, TILE_ATTR(PAL2,0,FALSE,FALSE));
            PAL_setPalette(PAL2, imgball.palette->data, DMA);
            break;
        case BALL_NEMO:
            ball = SPR_addSprite(&nemo_sprite, ball_pos_x, ball_pos_y, TILE_ATTR(PAL2,0,FALSE,FALSE));
            SPR_setAnim(ball, 7); 
            PAL_setPalette(PAL2, nemo_sprite.palette->data, DMA);
            break;
        case BALL_SONIC:
            ball = SPR_addSprite(&sonic, ball_pos_x, ball_pos_y, TILE_ATTR(PAL2,0,FALSE,FALSE));
            PAL_setPalette(PAL2, sonic.palette->data, DMA);
            break;
        case BALL_CHOSBY:
            ball = SPR_addSprite(&chosby, ball_pos_x, ball_pos_y, TILE_ATTR(PAL2,0,FALSE,FALSE));
            PAL_setPalette(PAL2, chosby.palette->data, DMA);
            break;
    }

    const SpriteDefinition* paddleDef = (settings.paddleSize == P_SMALL) ? &vpaddle_small : &vpaddle;

    player  = SPR_addSprite(paddleDef, player_pos_x, player_pos_y, TILE_ATTR(PAL1,0,FALSE,FALSE));
    player2 = SPR_addSprite(paddleDef, player2_pos_x, player2_pos_y, TILE_ATTR(PAL1,0,FALSE,TRUE));

    JOY_setEventHandler(myJoyHandler);

    bool intermission_drawn = FALSE; 

    while(1)
    {
        if (game_over_screen)
        {
            SYS_doVBlankProcess();
            if (JOY_readJoypad(JOY_1) & BUTTON_START) startGame(); 
            else if (JOY_readJoypad(JOY_1) & BUTTON_B) {
                SPR_end(); 
                JOY_setEventHandler(NULL); 
                return STATE_MENU;
            }
            continue; 
        }

        switch (subState)
        {
            case SUB_INTERMISSION:
                if (!intermission_drawn) {
                    char roundMsg[20];
                    sprintf(roundMsg, "ROUND %d", score + score2 + 1);
                    VDP_drawText(roundMsg, 20 - strlen(roundMsg)/2, 10);
                    VDP_drawText("PRESS A: BEGIN NEXT ROUND", 7, 13);
                    VDP_drawText("PRESS B: EXIT", 13, 15);
                    intermission_drawn = TRUE;
                    
                    centerPaddles(); 
                }

                u16 pressed = JOY_readJoypad(JOY_1);
                
                if (pressed & BUTTON_A) {
                    subState = SUB_COUNTDOWN;
                    countdown_timer = 180; 
                    VDP_clearTextArea(0, 10, 40, 6); 
                }
                else if (pressed & BUTTON_B) {
                    SPR_end(); 
                    JOY_setEventHandler(NULL); 
                    return STATE_MENU;
                }
                
                positionPlayer(); 
                break;

            case SUB_COUNTDOWN:
                centerPaddles(); 
                positionPlayer(); 

                countdown_timer--;
                
                if (countdown_timer > 120) VDP_drawText("3", 20, 12);
                else if (countdown_timer > 60) VDP_drawText("2", 20, 12);
                else if (countdown_timer > 0)  VDP_drawText("1", 20, 12);
                
                if (countdown_timer <= 0) {
                    VDP_clearText(20, 12, 1); 
                    subState = SUB_PLAY;
                    intermission_drawn = FALSE; 
                }
                break;

            case SUB_PLAY:
                moveBall();
                positionPlayer();
                break;
        }

        SPR_update();
        SYS_doVBlankProcess();
    }
}

// ========================================= //
// HELPER FUNCTIONS
// ========================================= //

static void centerPaddles()
{
    // Center Y
    int target_y = (224 - player_height) / 2;
    
    player_pos_y = target_y;
    player2_pos_y = target_y;
    
    player_vel_y = 0;
    player2_vel_y = 0;
}

static void resetBall(int winner)
{
    ball_pos_x = 160;
    ball_pos_y = SCREEN_HEIGHT / 2 - ball_height / 2;
    
    if (winner == 0) {
        ball_vel_x = (random() % 2 == 0) ? base_speed : -base_speed;
    } else if (winner == 1) {
        ball_vel_x = base_speed; 
    } else {
        ball_vel_x = -base_speed;  
    }
    ball_vel_y = (random() % 2 == 0) ? base_speed : -base_speed;
}

static void updateScoreDisplay(){
    sprintf(str_score,"%d",score);
    VDP_clearText(1,2,3);
    VDP_drawText(str_score,1,2);
}

static void updateScoreDisplay2(){
    sprintf(str_score2,"%d", score2);
    VDP_clearText(30,2,3);
    VDP_drawText(str_score2, 30, 2);
}

static void startGame(){
    score = 0;
    score2 = 0;
    game_over_screen = FALSE; 
    updateScoreDisplay();
    updateScoreDisplay2();
    
    resetBall(0);
    
    VDP_clearTextArea(0,10,40,10); 
    
    subState = SUB_INTERMISSION;
}

static void checkWinCondition()
{
    int limit = 9999;
    switch(settings.winLimit) {
        case WIN_10: limit = 10; break;
        case WIN_25: limit = 25; break;
        case WIN_50: limit = 50; break;
        case WIN_NONE: return; 
    }

    if (score >= limit || score2 >= limit)
    {
        game_over_screen = TRUE; 
        
        char winMsg[30];
        if (score >= limit) sprintf(winMsg, "PLAYER 1 WINS!");
        else                sprintf(winMsg, "PLAYER 2 WINS!");

        VDP_clearTextArea(0, 10, 40, 10);
        VDP_drawText(winMsg, 20 - strlen(winMsg)/2, 12);
        
        char finalScore[30];
        sprintf(finalScore, "%d  -  %d", score, score2);
        VDP_drawText(finalScore, 20 - strlen(finalScore)/2, 14);

        VDP_drawText("START: REPLAY   B: EXIT", 8, 18);
    }
}

static void updateScrollingText(const char* targetText)
{
    if (targetText != NULL)
    {
        static const char* lastTextPtr = NULL;
        if (targetText != lastTextPtr)
        {
             strcpy(scroll_buffer, "                ");
             strcat(scroll_buffer, targetText);
             strcat(scroll_buffer, "                ");
             scroll_offset = 0;
             lastTextPtr = targetText;
        }
    }

    char display_text[41];
    int len = strlen(scroll_buffer);
    if(len == 0) return;

    for (int i = 0; i < 40; i++)
        display_text[i] = scroll_buffer[(scroll_offset + i) % len];

    display_text[40] = '\0';
    VDP_clearTextLine(26);
    VDP_drawText(display_text, 0, 26);

    static int frame_counter = 0;
    frame_counter++;
    if (frame_counter >= 5){
        scroll_offset = (scroll_offset + 1) % len;
        frame_counter = 0;
    }
}

static void myJoyHandler(u16 joy, u16 changed, u16 state)
{
    if (game_over_screen) return; 
    
    // === INPUT LOCK ===
    if (subState != SUB_PLAY) return;

    // === PLAYER 1 LOGIC ===
    if (joy == JOY_1)
    {
        int p1_move = 0;
        if (settings.p1Control == CTRL_STD) 
        {
            if (state & BUTTON_UP) p1_move = -paddle_speed;
            if (state & BUTTON_DOWN) p1_move = paddle_speed;
        }
        else if (settings.p1Control == CTRL_INV)
        {
            if (state & BUTTON_UP) p1_move = paddle_speed;
            if (state & BUTTON_DOWN) p1_move = -paddle_speed;
        }
        else if (settings.p1Control == CTRL_PADDLE)
        {
            if (state & BUTTON_LEFT) p1_move = -paddle_speed;
            if (state & BUTTON_RIGHT) p1_move = paddle_speed;
        }
        player_vel_y = p1_move;
    }

    // === PLAYER 2 LOGIC ===
    if (joy == JOY_2)
    {
        int p2_move = 0;
        if (settings.p2Control == CTRL_STD) 
        {
            if (state & BUTTON_UP) p2_move = -paddle_speed;
            if (state & BUTTON_DOWN) p2_move = paddle_speed;
        }
        else if (settings.p2Control == CTRL_INV)
        {
            if (state & BUTTON_UP) p2_move = paddle_speed;
            if (state & BUTTON_DOWN) p2_move = -paddle_speed;
        }
        else if (settings.p2Control == CTRL_PADDLE)
        {
            if (state & BUTTON_LEFT) p2_move = paddle_speed; 
            if (state & BUTTON_RIGHT) p2_move = -paddle_speed; 
        }
        player2_vel_y = p2_move;
    }
}

static void positionPlayer(){
    player_pos_y += player_vel_y;
    if(player_pos_y < TOP_EDGE) player_pos_y = TOP_EDGE;
    if(player_pos_y + player_height > BOTTOM_EDGE)
        player_pos_y = BOTTOM_EDGE - player_height;

    player2_pos_y += player2_vel_y;
    if(player2_pos_y < TOP_EDGE) player2_pos_y = TOP_EDGE;
    if(player2_pos_y + player_height > BOTTOM_EDGE)
        player2_pos_y = BOTTOM_EDGE - player_height;

    SPR_setPosition(player, player_pos_x, player_pos_y);
    SPR_setPosition(player2, player2_pos_x, player2_pos_y);
}

// ==========================================================
// FIXED PHYSICS ENGINE (EXACT SPRITE BOUNDARIES)
// ==========================================================
static void moveBall(){
    
    // Position Update
    ball_pos_x += ball_vel_x;
    ball_pos_y += ball_vel_y;

    // --- COLLISION CHECKS (PURE AABB) ---
    // NO OFFSETS. Just "Ball Rect vs Paddle Rect".
    
    // Check P1 (Left)
    // ball_left < p1_right AND ball_right > p1_left AND Y overlap
    if (ball_pos_x < player_pos_x + player_width &&
        ball_pos_x + ball_width > player_pos_x &&
        ball_pos_y < player_pos_y + player_height &&
        ball_pos_y + ball_height >= player_pos_y)
    {
        // Hit P1
        ball_pos_x = player_pos_x + player_width; // Snap to right edge
        ball_vel_x = -ball_vel_x;
        
        // English
        if (score % 5 == 0 && abs(ball_vel_x) < 8) {
             ball_vel_x += sign(ball_vel_x);
        }
    }

    // Check P2 (Right)
    if (ball_pos_x < player2_pos_x + player_width &&
        ball_pos_x + ball_width > player2_pos_x &&
        ball_pos_y < player2_pos_y + player_height &&
        ball_pos_y + ball_height >= player2_pos_y)
    {
        // Hit P2
        ball_pos_x = player2_pos_x - ball_width; // Snap to left edge
        ball_vel_x = -ball_vel_x;
    }

    // --- 3. WALL BOUNCES ---
    if (ball_pos_y < TOP_EDGE) {
        ball_pos_y = TOP_EDGE;
        ball_vel_y = abs(ball_vel_y);
    }
    else if (ball_pos_y + ball_height > BOTTOM_EDGE) {
        ball_pos_y = BOTTOM_EDGE - ball_height;
        ball_vel_y = -abs(ball_vel_y);
    }

    // --- 4. SCORING ---
    // Using center point to determine score
    int center_x = ball_pos_x + (ball_width / 2);
    bool scored = FALSE;

    if (center_x < LEFT_EDGE) {
        score2++;
        updateScoreDisplay2();
        resetBall(2);
        scored = TRUE;
    }
    else if (center_x > RIGHT_EDGE) {
        score++;
        updateScoreDisplay();
        resetBall(1);
        scored = TRUE;
    }

    if (scored) {
        checkWinCondition();
        if (!game_over_screen) subState = SUB_INTERMISSION;
    }

    SPR_setPosition(ball, ball_pos_x, ball_pos_y);
    
    if (settings.ballType == BALL_CHOSBY) {
        SPR_setAnim(ball, Chosby_base);
    }
}