#include #include #include #include #include #include "raylib.h" // don't forget the / at the end of dir #ifdef RELEASE #define RESSOURCES_DIR "/home/cptbb/opt/dev/built/data/mineur/" #else #define RESSOURCES_DIR "/home/cptbb/dev/mineur/ressources/" #endif #define RECORD_FILE "/home/cptbb/.local/share/mineur_record" #define SCREEN_SHOT_NAME "minesweeper-screenshot.png" #define ARRAT(arr, type, x, y) ((arr) + (y)*(type) + (x)) #define min(a, b) ((a) < (b) ? (a) : (b)) #define max(a, b) ((a) > (b) ? (a) : (b)) typedef enum GameState { PLAYING, WIN, LOSE, RECORD, } GameState; GameState game_state = PLAYING; int game_cap = 16*30; char game[16][30] = {0}; char discover[16][30] = {0}; char zero[16][30] = {0}; // I confused myself with game type, mode and diff, but it all mean the same // TODO: refactor it typedef enum GameType { BEGINNER = 0, INTERMEDIATE, EXPERT, GAME_TYPE_NB, } GameType; GameType current_game_type = BEGINNER; char *current_game_name = "beginner"; Color current_game_color = GREEN; typedef struct Vec2i { int x; int y; } Vec2i; Vec2i game_size; int nb_bomb; int nb_bomb_pad = 9; char *nb_bomb_text; int screen_width = 500; int screen_height = 550; Rectangle menu; Rectangle grid = {0}; const Color text_color = BLACK; const Color hover_color = RED; float timer = 0.0f; char timer_text[10] = {0}; char timer_record[GAME_TYPE_NB][10] = {"9999", "9999", "9999"}; FILE *record_file_read; FILE *record_file_write; int need_to_fill = 1; #define INIT_TEXTURE(img, tex) \ Image img = {0}; \ Texture tex = {0} INIT_TEXTURE(tile_image_orig, tile_texture); INIT_TEXTURE(tile_hover_image_orig, tile_hover_texture); INIT_TEXTURE(mine_image_orig, mine_texture); INIT_TEXTURE(t1_image_orig, t1_texture); INIT_TEXTURE(t2_image_orig, t2_texture); INIT_TEXTURE(t3_image_orig, t3_texture); INIT_TEXTURE(t4_image_orig, t4_texture); INIT_TEXTURE(t5_image_orig, t5_texture); INIT_TEXTURE(t6_image_orig, t6_texture); INIT_TEXTURE(t7_image_orig, t7_texture); INIT_TEXTURE(t8_image_orig, t8_texture); Texture camera_texture; Texture lose_texture; Texture win_texture; Texture record_texture; Texture playing_texture; Texture fixed_tile_texture; Texture double_tile_texture; Texture triple_tile_texture; void screen_resize_handle(void) { screen_width = GetScreenWidth(); screen_height = GetScreenHeight(); menu.width = screen_width; float width = screen_width / game_size.x; float height = (screen_height - menu.height) / game_size.y; float cell_len = min(width, height); int grid_width = cell_len * game_size.x; int grid_height = cell_len * game_size.y; grid = (Rectangle){ (screen_width - grid_width) / 2, screen_height - grid_height, grid_width, grid_height }; #define RESIZE_TEXTURE(name, copy, orig) \ do { \ Image copy = ImageCopy(orig); \ ImageResize(&(copy), grid.width/game_size.x, grid.height/game_size.y);\ name = LoadTextureFromImage(copy); \ } while (0) RESIZE_TEXTURE(tile_texture, tile_copy, tile_image_orig); RESIZE_TEXTURE(tile_hover_texture, tile_hover_copy, tile_hover_image_orig); RESIZE_TEXTURE(mine_texture, mine_copy, mine_image_orig); RESIZE_TEXTURE(t1_texture, t1_copy, t1_image_orig); RESIZE_TEXTURE(t2_texture, t2_copy, t2_image_orig); RESIZE_TEXTURE(t3_texture, t3_copy, t3_image_orig); RESIZE_TEXTURE(t4_texture, t4_copy, t4_image_orig); RESIZE_TEXTURE(t5_texture, t5_copy, t5_image_orig); RESIZE_TEXTURE(t6_texture, t6_copy, t6_image_orig); RESIZE_TEXTURE(t7_texture, t7_copy, t7_image_orig); RESIZE_TEXTURE(t8_texture, t8_copy, t8_image_orig); } int count_bomb(int x, int y) { int count = 0; for (int i=-1; i<=1; i++) { if (x+i < 0 || x+i >= game_size.x) continue; for (int j=-1; j<=1; j++) { if (y+j < 0 || y+j > game_size.y) continue; if (i == 0 && j == 0) continue; if (game[y+j][x+i] == 'X') count++; } } return count; } void setup_game(void) { switch (current_game_type) { case BEGINNER: game_size.x = 9; game_size.y = 9; nb_bomb = 10; nb_bomb_text = "10"; nb_bomb_pad = 13; break; case INTERMEDIATE: game_size.x = 16; game_size.y = 16; nb_bomb = 40; nb_bomb_text = "40"; nb_bomb_pad = 9; break; case EXPERT: game_size.x = 30; game_size.y = 16; nb_bomb = 99; nb_bomb_text = "99"; nb_bomb_pad = 9; break; default: assert(0 && "game mode not supported"); } } void fill_game(int click_x, int click_y) { for (int i=0; i= game_size.x || y < 0 || y >= game_size.y) return; if (zero[y][x]) return; discover[y][x] = 1; zero[y][x] = 1; if (game[y][x] != '0') return; for (int j=-1; j<=1; j++) { if (y+j < 0 || y+j >= game_size.y) continue; for (int i=-1; i<=1; i++) { if (x+i < 0 || x+i >= game_size.x) continue; zero_click(x+i, y+j); } } } int collision(Vec2i coord, Texture text, int x, int y) { return x > coord.x && x < coord.x + text.width && y > coord.y && y < coord.y + text.height; } void reload_game(void) { setup_game(); game_state = PLAYING; memset(game, 0, game_cap); memset(discover, 0, game_cap); memset(zero, 0, game_cap); need_to_fill = 1; screen_resize_handle(); timer = 0.0f; memset(timer_text, 0, sizeof(timer_text)); } void switch_mode(GameType gt) { current_game_type = gt; switch (gt) { case BEGINNER: current_game_name = "beginner"; current_game_color = GREEN; break; case INTERMEDIATE: current_game_name = "intermediate"; current_game_color = ORANGE; break; case EXPERT: current_game_name = "expert"; current_game_color = RED; break; default: assert(0 && "game mode not supported"); } } int nb_len(char *string) { int i = 0; for (; string[i] >= 48 && string[i] <= 48+10; i++); return i+1; } void load_record(void) { for ( int i=0; iwidth/2, 0}; DrawTexture( *menu_smiley, smiley_coord.x, smiley_coord.y, WHITE); Vec2i camera_coord = { menu.width/2 - menu_smiley->width/2 - camera_texture.width -10, menu.height/2 - camera_texture.height/2, }; DrawTexture( camera_texture, camera_coord.x, camera_coord.y, WHITE ); DrawTexture( fixed_tile_texture, menu.width - fixed_tile_texture.width, 0, WHITE ); DrawText(nb_bomb_text, menu.width - fixed_tile_texture.width + nb_bomb_pad, 13, 30, text_color ); DrawTexture(triple_tile_texture, 0, 0, WHITE); DrawText("mode :", 13, 5, 20, text_color); DrawText(current_game_name, 13, 25, 20.0f, current_game_color); DrawRectangleRec(grid, (Color) { .r = 0xC6, .g = 0xC6, .b = 0xC6, .a = 255 }); int timer_pad = 10; int timer_mid = (screen_width * 3) / 4; DrawTexture( double_tile_texture, timer_mid - timer_pad - double_tile_texture.width, 0, WHITE ); DrawText( timer_text, timer_mid - timer_pad - double_tile_texture.width + 13, 10, 35.0f, text_color ); DrawTexture( double_tile_texture, timer_mid + timer_pad, 0, WHITE ); DrawText( timer_record[current_game_type], timer_mid + timer_pad + 13, 10, 35.0f, text_color ); for (int y=0; y