317 lines
6.4 KiB
C
317 lines
6.4 KiB
C
#include "main.h"
|
|
#include "graphics.h"
|
|
#include "audio.h"
|
|
|
|
#include <stdlib.h>
|
|
#include <time.h>
|
|
|
|
SDL_Rect player;
|
|
int pause = 0;
|
|
|
|
int main(void)
|
|
{
|
|
srand(time(NULL));
|
|
|
|
if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_TIMER|SDL_INIT_AUDIO) < 0)
|
|
{
|
|
fprintf(stderr,
|
|
"Couldn't initialize SDL: %s\n", SDL_GetError());
|
|
exit(1);
|
|
return 1;
|
|
}
|
|
|
|
init_video();
|
|
init_audio();
|
|
|
|
player.w = 1;
|
|
player.h = 1;
|
|
|
|
tick();
|
|
|
|
video_destroy();
|
|
audio_destroy();
|
|
|
|
SDL_Quit();
|
|
|
|
return 0;
|
|
}
|
|
|
|
void tick()
|
|
{
|
|
int close_requested = 0;
|
|
|
|
SDL_Event event;
|
|
|
|
int r_mouse = 0;
|
|
int l_mouse = 0;
|
|
|
|
srand(time(NULL));
|
|
|
|
int player_bombs = NUM_OF_BOMBS;
|
|
int player_unclicked = GRID_X * GRID_Y;
|
|
|
|
populate();
|
|
|
|
/* Check the board and give all blocks their proper values */
|
|
for (int i = 0; i < GRID_Y; i++) for (int j = 0; j < GRID_X; j++)
|
|
{
|
|
int bombs_block = check_adjacent(i, j); /* Store value to not check twice */
|
|
if (bombs_block > 0 && bombs_block < 9) {
|
|
grid.state[i][j] = bombs_block + 5; /* In the DEFINE macros the numerical blocks start at 6 */
|
|
} else if (bombs_block == 9) {
|
|
grid.state[i][j] = EXPLOSION;
|
|
}
|
|
}
|
|
|
|
|
|
while(!close_requested)
|
|
{
|
|
while (SDL_PollEvent(&event))
|
|
{
|
|
switch(event.type)
|
|
{
|
|
case SDL_QUIT:
|
|
{
|
|
close_requested = 1;
|
|
break;
|
|
}
|
|
case SDL_MOUSEBUTTONDOWN:
|
|
if (event.button.button == SDL_BUTTON_RIGHT) r_mouse = 1;
|
|
if (event.button.button == SDL_BUTTON_LEFT) l_mouse = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!pause)
|
|
{
|
|
if (player_bombs == 0) {
|
|
for (int i = 0; i < GRID_Y; i++) for (int j = 0; j < GRID_X; j++)
|
|
if (grid.show[i][j] == SHOW_FLAG && grid.state[i][j] == EXPLOSION) player_bombs++;
|
|
if (player_bombs == NUM_OF_BOMBS)
|
|
game_over(WON);
|
|
}
|
|
|
|
/* This is probably inneficient, a last minute add because I forgot this is also a win condition of minesweeper */
|
|
player_unclicked = GRID_X * GRID_Y;
|
|
for (int i = 0; i < GRID_Y; i++) for (int j = 0; j < GRID_X; j++)
|
|
{
|
|
if (grid.show[i][j] == SHOW_TRUE) player_unclicked--;
|
|
}
|
|
|
|
if (player_unclicked == NUM_OF_BOMBS) game_over(WON);
|
|
|
|
if (player_bombs == 1) {
|
|
joe.state = SWEAT;
|
|
}
|
|
else if (joe.state == SWEAT) {
|
|
joe.state = IDLE;
|
|
}
|
|
|
|
int mouse_x, mouse_y;
|
|
SDL_GetMouseState(&mouse_x, &mouse_y);
|
|
|
|
/* Update position */
|
|
player.x = mouse_x;
|
|
player.y = mouse_y;
|
|
|
|
for (int i = 0; i < GRID_Y; i++) for (int j = 0; j < GRID_X; j++)
|
|
{
|
|
if (check_collision(&player, &grid.block[i][j])) {
|
|
if (r_mouse == 1) {
|
|
r_mouse = 0; /* Reset the mouse the moment a single collision happened to ensure only a single block is clicked */
|
|
if (!grid.show[i][j] && player_bombs != 0) {
|
|
play_audio(SHOW_FLAG);
|
|
grid.show[i][j] = SHOW_FLAG;
|
|
player_bombs--;
|
|
break;
|
|
}
|
|
if (grid.show[i][j] == SHOW_FLAG) {
|
|
play_audio(SHOW_FLAG);
|
|
grid.show[i][j] = DONT_SHOW;
|
|
player_bombs++;
|
|
break;
|
|
}
|
|
break; /* No need to keep checking since the mouse is reset */
|
|
}
|
|
if (l_mouse == 1) {
|
|
l_mouse = 0;
|
|
reveal(i, j);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
video_loop();
|
|
SDL_Delay(1000/60);
|
|
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
void game_over(int winstate)
|
|
{
|
|
for (int i = 0; i < GRID_Y; i++) for (int j = 0; j < GRID_X; j++) {
|
|
grid.show[i][j] = SHOW_TRUE;
|
|
if (grid.state[i][j] == UNCLICKED) grid.state[i][j] = EMPTY;
|
|
|
|
}
|
|
|
|
if (winstate == LOST) {
|
|
joe.state = ANGER;
|
|
/* play_audio(LOST); the explosion sound is enough and avoids conflict with explosion sound */
|
|
}
|
|
if (winstate == WON) {
|
|
joe.state = HAPPY;
|
|
play_audio(WON);
|
|
}
|
|
|
|
pause = 1;
|
|
}
|
|
|
|
int check_adjacent(int i, int j) /* Got too used to dealing with i and j with the for loops I guess */
|
|
{
|
|
int bombs = 0; /* This value stores the amount of bombs around a block not the amount of bombs on the whole grid */
|
|
|
|
/* check middle */
|
|
if (grid.bomb[i][j]) return 9; /* Since there can never be more than 8 bombs, this is a safe value to use */
|
|
|
|
/* check upper left */
|
|
if (i - 1 >= 0 && j - 1 >= 0) {
|
|
if (grid.bomb[i - 1][j - 1]) bombs++;
|
|
}
|
|
|
|
/* check upper middle */
|
|
if (i - 1 >= 0) {
|
|
if (grid.bomb[i - 1][j]) bombs++;
|
|
}
|
|
|
|
/* check upper right */
|
|
if (i - 1 >= 0 && j + 1 < GRID_X ) {
|
|
if (grid.bomb[i - 1][j + 1]) bombs++;
|
|
}
|
|
|
|
/* check middle left */
|
|
if (j - 1 >= 0) {
|
|
if (grid.bomb[i][j - 1]) bombs++;
|
|
}
|
|
|
|
/* check middle right */
|
|
if (j + 1 < GRID_X ) {
|
|
if (grid.bomb[i][j + 1]) bombs++;
|
|
}
|
|
|
|
/* check lower left */
|
|
if (i + 1 < GRID_Y && j - 1 >= 0) {
|
|
if (grid.bomb[i + 1][j - 1]) bombs++;
|
|
}
|
|
|
|
/* check lower middle */
|
|
if (i + 1 < GRID_Y) {
|
|
if (grid.bomb[i + 1][j]) bombs++;
|
|
}
|
|
|
|
/* check lower right */
|
|
if (i + 1 < GRID_Y && j + 1 < GRID_X) {
|
|
if (grid.bomb[i + 1][j + 1]) bombs++;
|
|
}
|
|
|
|
return bombs;
|
|
}
|
|
|
|
void reveal(int i, int j)
|
|
{
|
|
if (!grid.show[i][j]) {
|
|
grid.show[i][j] = SHOW_TRUE;
|
|
if (grid.state[i][j] == EXPLOSION) {
|
|
play_audio(EXPLOSION);
|
|
game_over(LOST);
|
|
} else {
|
|
play_audio(UNCLICKED);
|
|
}
|
|
if (grid.state[i][j] == UNCLICKED) {
|
|
grid.state[i][j] = EMPTY;
|
|
}
|
|
}
|
|
|
|
if (grid.state[i][j] == EMPTY) {
|
|
/* check upper middle */
|
|
if (i - 1 >= 0) {
|
|
if (grid.state[i - 1][j] == UNCLICKED)
|
|
{
|
|
grid.state[i - 1][j] = EMPTY;
|
|
grid.show[i - 1][j] = SHOW_TRUE;
|
|
reveal(i - 1, j);
|
|
} else {
|
|
grid.show[i - 1][j] = SHOW_TRUE;
|
|
}
|
|
}
|
|
|
|
/* check middle left */
|
|
if (j - 1 >= 0) {
|
|
if (grid.state[i][j - 1] == UNCLICKED)
|
|
{
|
|
grid.state[i][j - 1] = EMPTY;
|
|
grid.show[i][j - 1] = SHOW_TRUE;
|
|
reveal(i, j - 1);
|
|
} else {
|
|
grid.show[i][j - 1] = SHOW_TRUE;
|
|
}
|
|
}
|
|
|
|
/* check middle right */
|
|
if (j + 1 < GRID_X ) {
|
|
if (grid.state[i][j + 1] == UNCLICKED)
|
|
{
|
|
grid.state[i][j + 1] = EMPTY;
|
|
grid.show[i][j + 1] = SHOW_TRUE;
|
|
reveal(i, j + 1);
|
|
} else {
|
|
grid.show[i][j + 1] = SHOW_TRUE;
|
|
}
|
|
}
|
|
|
|
/* check lower middle */
|
|
if (i + 1 < GRID_Y) {
|
|
if (grid.state[i + 1][j] == UNCLICKED)
|
|
{
|
|
grid.state[i + 1][j] = EMPTY;
|
|
grid.show[i + 1][j] = SHOW_TRUE;
|
|
reveal(i + 1, j);
|
|
} else {
|
|
grid.show[i + 1][j] = SHOW_TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
/* Populate grid with bombs */
|
|
void populate()
|
|
{
|
|
for (int i = 0; i < NUM_OF_BOMBS; i++) {
|
|
int rand_x = rand() % GRID_X;
|
|
int rand_y = rand() % GRID_Y;
|
|
|
|
if (!grid.bomb[rand_y][rand_x]) {
|
|
grid.bomb[rand_y][rand_x] = 1;
|
|
} else {
|
|
--i;
|
|
}
|
|
}
|
|
}
|
|
|
|
int check_collision(SDL_Rect * obj1, SDL_Rect * obj2)
|
|
{
|
|
if (obj1->x < obj2->x + obj2->w && obj1->x + obj1->w > obj2->x) {
|
|
if ( obj1->y < obj2->y + obj2->h && obj1->y + obj1->h > obj2->y) {
|
|
/* collision happened */
|
|
return 1;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|