Subversion Repositories Code-Repo

Rev

Rev 278 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include "defines.h"
#include "CONTROLLERS.h"
#include "TRON.h"
#include "TIMER4.h"

static TRON_DATA *tron_data_p;

void Tron_Init(TRON_DATA *data) {
    tron_data_p = data;

    // Set players 1-4 colors
    tron_data_p->Color_Head_R[0] = 0xFF;
    tron_data_p->Color_Head_G[0] = 0x00;
    tron_data_p->Color_Head_B[0] = 0x00;
    tron_data_p->Color_Body_R[0] = 0x20;
    tron_data_p->Color_Body_G[0] = 0x00;
    tron_data_p->Color_Body_B[0] = 0x00;

    tron_data_p->Color_Head_R[1] = 0x00;
    tron_data_p->Color_Head_G[1] = 0x00;
    tron_data_p->Color_Head_B[1] = 0xFF;
    tron_data_p->Color_Body_R[1] = 0x00;
    tron_data_p->Color_Body_G[1] = 0x00;
    tron_data_p->Color_Body_B[1] = 0x20;

    tron_data_p->Color_Head_R[2] = 0x00;
    tron_data_p->Color_Head_G[2] = 0xFF;
    tron_data_p->Color_Head_B[2] = 0x00;
    tron_data_p->Color_Body_R[2] = 0x00;
    tron_data_p->Color_Body_G[2] = 0x20;
    tron_data_p->Color_Body_B[2] = 0x00;

    tron_data_p->Color_Head_R[3] = 0xFF;
    tron_data_p->Color_Head_G[3] = 0x60;
    tron_data_p->Color_Head_B[3] = 0x00;
    tron_data_p->Color_Body_R[3] = 0x20;
    tron_data_p->Color_Body_G[3] = 0x10;
    tron_data_p->Color_Body_B[3] = 0x00;

//    // Set starting points for players
    tron_data_p->body[0][0] = (TRON_POINT){0,0,7};
    tron_data_p->body[1][0] = (TRON_POINT){7,7,7};
    tron_data_p->body[2][0] = (TRON_POINT){0,7,7};
    tron_data_p->body[3][0] = (TRON_POINT){7,0,7};

    tron_data_p->delay = TRON_DELAY;

    Cube_Clear();
    Cube_Overlay_Clear();

    // Determine the number of players (connected controllers)
    tron_data_p->players = Controller_Get_Connected();
    while (tron_data_p->players < 2) {
        Delay_MS(100);
        Controller_Poll_Connected();
        tron_data_p->players = Controller_Get_Connected();
    }
    if (tron_data_p->players > TRON_MAX_PLAYERS)
        tron_data_p->players = TRON_MAX_PLAYERS;
    tron_data_p->players_alive = tron_data_p->players;

    // Draw each player's light trail
    uint8_t i;
    for (i = 0; i < tron_data_p->players; i++) {
        tron_data_p->length[i] = 1;
        tron_data_p->dead[i] = 0;
        // Draw the head
        Cube_Set_Pixel(tron_data_p->body[i][tron_data_p->length[i] - 1].z,
                tron_data_p->body[i][tron_data_p->length[i] - 1].x,
                tron_data_p->body[i][tron_data_p->length[i] - 1].y,
                tron_data_p->Color_Head_R[i], tron_data_p->Color_Head_G[i],
                tron_data_p->Color_Head_B[i]);
    }

    // Set starting direction for players
    Tron_Update_Direction(0, (CTRL_BTN_STATUS) (uint8_t) 0x08);
    Tron_Update_Direction(1, (CTRL_BTN_STATUS) (uint8_t) 0x10);
    Tron_Update_Direction(2, (CTRL_BTN_STATUS) (uint8_t) 0x04);
    Tron_Update_Direction(3, (CTRL_BTN_STATUS) (uint8_t) 0x20);
}

void Tron_Main(void) {
    // Main function, loops and delays while updating the frame every x milliseconds
    uint8_t i;
    for (i = 0; i < tron_data_p->players; i++) {
        Controller_Set_Active(i);
    }
    Delay_MS(20);
    // Light up the player indicators
    switch (tron_data_p->players) {
        case 4:
            Controller_Set_Left_Leds(3, 0x02);
        case 3:
            Controller_Set_Left_Leds(2, 0x04);
        case 2:
        default:
            Controller_Set_Left_Leds(1, 0x08);
            Controller_Set_Left_Leds(0, 0x01);
            break;
    }
    TIMER4_Start();
    Delay_MS(3000);
    while (1) {
        Tron_Update_Frame();
        Delay_MS(tron_data_p->delay);
    }
}

void Tron_Update_Direction(uint8_t controller, CTRL_BTN_STATUS value) {
    // Determine the next direction for the trails based off the last button press
    if (controller < tron_data_p->players) {
        // Save the current button value
        tron_data_p->last_direction[controller] = value.w;

        // Grab the location of the head
        TRON_POINT next_pos = tron_data_p->body[controller][tron_data_p->length[controller] - 1];

        // Determine which next point to move to
        if (value.BTN_L_N || value.BTN_L_E) {   // Up
            next_pos.z = (next_pos.z == CUBE_LAYER_COUNT - 1) ? 0 : next_pos.z + 1;
        } else if (value.BTN_L_S || value.BTN_L_W) {    // Down
            next_pos.z = (next_pos.z == 0) ? CUBE_LAYER_COUNT - 1 : next_pos.z - 1;
        } else if (value.BTN_R_N) { // Forward
            next_pos.x = (next_pos.x == CUBE_ROW_COUNT - 1) ? 0 : next_pos.x + 1;
        } else if (value.BTN_R_W) { // Left
            next_pos.y = (next_pos.y == CUBE_COLUMN_COUNT - 1) ? 0 : next_pos.y + 1;
        } else if (value.BTN_R_S) { // Backwards
            next_pos.x = (next_pos.x == 0) ? CUBE_ROW_COUNT - 1 : next_pos.x - 1;
//        } else if (value.BTN_R_E) { // Right
        } else { // Right
            next_pos.y = (next_pos.y== 0) ? CUBE_COLUMN_COUNT - 1 : next_pos.y - 1;
        }
        
        // Save the next point to move to
        tron_data_p->direction[controller] = next_pos;
    }
}

void Tron_Update_Frame(void) {
    uint8_t player, player2;

    // Change the current head color to the body color
    for (player = 0; player < tron_data_p->players; player++) {
        if (tron_data_p->dead[player] == 0) {
            Cube_Set_Pixel(tron_data_p->body[player][tron_data_p->length[player] - 1].z,
                    tron_data_p->body[player][tron_data_p->length[player] - 1].x,
                    tron_data_p->body[player][tron_data_p->length[player] - 1].y,
                    tron_data_p->Color_Body_R[player],
                    tron_data_p->Color_Body_G[player],
                    tron_data_p->Color_Body_B[player]);
        }
    }

    // Check if there is a head-on collision between any of the players
    for (player = 0; player < tron_data_p->players; player++) {
        if (tron_data_p->dead[player] == 0) {
            for (player2 = 0; player2 < tron_data_p->players; player2++) {
                if (player2 == player) continue;
                if (tron_data_p->dead[player2] == 0) {
                    if (tron_data_p->direction[player].x == tron_data_p->direction[player2].x &&
                            tron_data_p->direction[player].y == tron_data_p->direction[player2].y &&
                            tron_data_p->direction[player].z == tron_data_p->direction[player2].z) {
                        // Indicate the collision point
                        Cube_Set_Pixel(tron_data_p->direction[player].z, tron_data_p->direction[player].x,
                                tron_data_p->direction[player].y, TRON_COLLISION);
                        // Mark the players as dead
                        tron_data_p->dead[player] = 1;
                        tron_data_p->dead[player2] = 1;
                        tron_data_p->players_alive -= 2;
                    }
                }
            }
        }
    }

    // Check if the location that we are moving to is overlapping either trails
    uint8_t index;
    for (player = 0; player < tron_data_p->players; player++) {
        // Check if the player in question is dead
        if (tron_data_p->dead[player] == 0) {
            // See if the player's next point hits anyone elses trail
            for (player2 = 0; player2 < tron_data_p->players; player2++) {
                for (index = 0; index < tron_data_p->length[player2]; index++) {
                    if (tron_data_p->direction[player].x == tron_data_p->body[player2][index].x &&
                            tron_data_p->direction[player].y == tron_data_p->body[player2][index].y &&
                            tron_data_p->direction[player].z == tron_data_p->body[player2][index].z) {
                        // Indicate the collision point
                        Cube_Set_Pixel(tron_data_p->direction[player].z, tron_data_p->direction[player].x,
                                tron_data_p->direction[player].y, TRON_COLLISION);
                        // Mark the player as dead
                        tron_data_p->dead[player] = 1;
                        tron_data_p->players_alive -= 1;
                    }
                }
            }
        }
    }

    // Save the new head location of each trail
    for (player = 0; player < tron_data_p->players; player++) {
        // If player is still alive, extend its body in the next direction
        if (tron_data_p->dead[player] == 0) {
            tron_data_p->length[player]++;
            tron_data_p->body[player][tron_data_p->length[player] - 1] = tron_data_p->direction[player];
        }
    }

    // Update the head to its corresponding color
    for (player = 0; player < tron_data_p->players; player++) {
        // If player is still alive, recolor its body to indicate its new head
        if (tron_data_p->dead[player] == 0) {
            // Set the color of the new head
            Cube_Set_Pixel(tron_data_p->body[player][tron_data_p->length[player] - 1].z,
                    tron_data_p->body[player][tron_data_p->length[player] - 1].x,
                    tron_data_p->body[player][tron_data_p->length[player] - 1].y,
                    tron_data_p->Color_Head_R[player],
                    tron_data_p->Color_Head_G[player],
                    tron_data_p->Color_Head_B[player]);
        }
    }

    // End the game if there is one player left alive
    if (tron_data_p->players_alive == 1) {
        Delay_MS(5000);
        // Determine which player is still alive and flash his color
        for (player = 0; player < tron_data_p->players; player++) {
            if (tron_data_p->dead[player] == 0) {
                Animation_Cube_In_Out(200, tron_data_p->Color_Head_R[player],
                        tron_data_p->Color_Head_G[player], tron_data_p->Color_Head_B[player]);
            }
        }
        Reset_Board(BOARD_MODE_IDLE);
    } else if (tron_data_p->players_alive == 0) {
        // If no players are alive flash neutral color
        Delay_MS(5000);
        Animation_Cube_In_Out(200, TRON_COLLISION_2);
        Reset_Board(BOARD_MODE_IDLE);
    }

    // Determine the next direction to move to for each player
    for (player = 0; player < tron_data_p->players; player++) {
        if (tron_data_p->dead[player] == 0) {
            Tron_Update_Direction(player, (CTRL_BTN_STATUS)tron_data_p->last_direction[player]);
        }
    }

    // Decrease the delay between frame updates by 5ms
    tron_data_p->delay -= 5;
}