1 | /* ncurses-minesweeper Copyright (c) 2021 Joshua 'joshuas3' Stockin |
2 | * <https://joshstock.in> |
3 | * <https://git.joshstock.in/ncurses-minesweeper> |
4 | * |
5 | * This software is licensed and distributed under the terms of the MIT License. |
6 | * See the MIT License in the LICENSE file of this project's root folder. |
7 | * |
8 | * This comment block and its contents, including this disclaimer, MUST be |
9 | * preserved in all copies or distributions of this software's source. |
10 | */ |
11 |
|
12 | #include <ncurses.h> |
13 |
|
14 | #include "../game/game.h" |
15 | #include "../game/reset.h" |
16 | #include "../state.h" |
17 | #include "../time.h" |
18 | #include "../strings.h" |
19 | #include "pages.h" |
20 | #include "text.h" |
21 |
|
22 | static int elapsed = 0; |
23 | void render_topbar(int top, int left, int right, game_board *board) { |
24 | if (board->status == Waiting) { |
25 | elapsed = 0; |
26 | } else if (board->status == Playing) { |
27 | elapsed = 1 + (time_us() - board->time) / 1000000; |
28 | } |
29 | attron(A_BOLD); |
30 | if (elapsed < 999) |
31 | mvprintw(top, right - 4, "%03d", elapsed); |
32 | else |
33 | mvaddstr(top, right - 4, "999"); |
34 | mvprintw(top, left, "%03d", board->mines_left); |
35 | attroff(A_BOLD); |
36 | int center = (int)(COLS / 2 - 1); |
37 | switch (board->status) { |
38 | case Waiting: |
39 | case Playing: |
40 | mvaddstr(top, center, "._."); |
41 | break; |
42 | case Done: |
43 | mvaddstr(top, center, "^-^"); |
44 | break; |
45 | case Kaboom: |
46 | mvaddstr(top, center, "x_x"); |
47 | break; |
48 | } |
49 | } |
50 |
|
51 | int draw_game(game_state *state, int ch) { |
52 | game_board *board = state->board; |
53 | int board_top = centery() - board->height/2 - 1; |
54 | if (board_top < 0) board_top = 0; |
55 | int bound_left = (int)(COLS / 2) - board->width; |
56 | if (bound_left < 0) bound_left = 0; |
57 | int bound_right = bound_left + board->width * 2; |
58 | render_topbar(board_top, bound_left, bound_right, board); |
59 |
|
60 | // handle input |
61 | switch (ch) { |
62 | case -1: { |
63 | return 0; |
64 | } |
65 | case KEY_RESIZE: { |
66 | clear(); |
67 | break; |
68 | } |
69 | case 27: { |
70 | clear(); |
71 | reset_board(state->board); |
72 | state->page = Title; |
73 | state->page_selection = 0; |
74 | return draw_title_screen(state, 0); |
75 | } |
76 | case '?': { |
77 | clear(); |
78 | state->page = Help; |
79 | state->last_page = Game; |
80 | return draw_help_screen(state, 0); |
81 | } |
82 | } |
83 |
|
84 | game(state, ch); // pass input to game controller |
85 |
|
86 | // draw board |
87 | attron(A_BOLD); |
88 | for (int cell = 0; cell < board->width * board->height; cell++) { |
89 | int x = bound_left + cell % board->width * 2; |
90 | int y = board_top + 1 + cell / board->width; |
91 | if (board->current_cell == cell) attron(A_STANDOUT); // highlight selected cell |
92 | game_board_cell *this_cell = &board->cells[cell]; |
93 | if (!this_cell->flagged) { |
94 | if (!this_cell->opened) { // unopened unflagged, grey territory |
95 | attroff(A_BOLD); |
96 | mvaddch(y, x, '~'); |
97 | attron(A_BOLD); |
98 | } else { // opened but unflagged |
99 | if (this_cell->is_bomb) { // bomb opened |
100 | attron(COLOR_PAIR(5)); |
101 | mvaddch(y, x, 'X'); |
102 | attroff(COLOR_PAIR(5)); |
103 | } else if (this_cell->surrounding_bomb_count) { // surrounding bomb-count label |
104 | int count = this_cell->surrounding_bomb_count; |
105 | attron(COLOR_PAIR(count)); |
106 | mvaddch(y, x, '0' + count); |
107 | attroff(COLOR_PAIR(count)); |
108 | } else { // no surrounding bombs, open area |
109 | mvaddch(y, x, ' '); |
110 | } |
111 | } |
112 | } else { // flagged cell |
113 | attron(A_STANDOUT); |
114 | if (board->status != Kaboom) |
115 | mvaddch(y, x, 'X'); |
116 | else { |
117 | if (!board->cells[cell].is_bomb) { // highlight false positives when done |
118 | attron(COLOR_PAIR(5)); |
119 | mvaddch(y, x, 'X'); |
120 | attroff(COLOR_PAIR(5)); |
121 | } else |
122 | mvaddch(y, x, 'X'); |
123 | } |
124 | attroff(A_STANDOUT); |
125 | } |
126 | if (board->current_cell == cell) attroff(A_STANDOUT); // un-highlight selected cell |
127 | } |
128 | attroff(A_BOLD); |
129 |
|
130 | // write help note at bottom |
131 | mvprintw(LINES - 1, centerx(game_help_note), "%s", game_help_note); |
132 |
|
133 | return 0; |
134 | } |
135 |
|