#include "display.h" #include "cardstack.h" // Definition of ncurses color pair identifiers #define CP_WHITE_ON_BLACK 1 #define CP_YELLOW_ON_BLACK 2 #define CP_BLUE_ON_BLACK 3 #define CP_MAGENTA_ON_BLACK 4 #define CP_RED_ON_BLACK 5 static bool colors = false; static WINDOW *w_table_cards; static WINDOW *w_stack_points; static WINDOW *w_current_state; static WINDOW *w_hand_cards; static void draw_card(WINDOW *w, const uint8_t row, const uint8_t col, const bool highlight, const card c) { unsigned color_pair = 0; if (highlight) wattron(w, A_BOLD); if (colors) { switch (card_get_points(c)) { case 7: color_pair = CP_MAGENTA_ON_BLACK; break; case 5: color_pair = CP_RED_ON_BLACK; break; case 3: color_pair = CP_YELLOW_ON_BLACK; break; case 2: color_pair = CP_BLUE_ON_BLACK; break; default: color_pair = CP_WHITE_ON_BLACK; } wattron(w, COLOR_PAIR(color_pair)); } mvwaddch(w, row, col, ACS_ULCORNER); // Upper left corner mvwhline(w, row, col+1, ACS_HLINE, 5); // Upper horizontal line mvwaddch(w, row, col+6, ACS_URCORNER); // Upper right corner mvwvline(w, row+1, col, ACS_VLINE, 3); // Left vertical line mvwvline(w, row+1, col+6, ACS_VLINE, 3); // Right vertical line mvwaddch(w, row+4, col, ACS_LLCORNER); // Lower left corner mvwhline(w, row+4, col+1, ACS_HLINE, 5); // Lower horizontal line mvwaddch(w, row+4, col+6, ACS_LRCORNER); // Lower right corner mvwprintw(w, row+1, col+1, " %3d ", c); // Card number, 3 digits wide, filled with spaces, if number has fewer digits // Clear the rest of the card first mvwprintw(w, row+2, col+1, " "); mvwprintw(w, row+3, col+1, " "); switch (card_get_points(c)) { case 7: // "** **" // " *** " mvwhline(w, row+2, col+1, ACS_DIAMOND, 2); mvwhline(w, row+2, col+4, ACS_DIAMOND, 2); mvwhline(w, row+3, col+2, ACS_DIAMOND, 3); break; case 5: // "* * *" // " * * " mvwaddch(w, row+2, col+1, ACS_DIAMOND); mvwaddch(w, row+2, col+3, ACS_DIAMOND); mvwaddch(w, row+2, col+5, ACS_DIAMOND); mvwaddch(w, row+3, col+2, ACS_DIAMOND); mvwaddch(w, row+3, col+4, ACS_DIAMOND); break; case 3: // " * * " // " * " mvwaddch(w, row+2, col+2, ACS_DIAMOND); mvwaddch(w, row+2, col+4, ACS_DIAMOND); mvwaddch(w, row+3, col+3, ACS_DIAMOND); break; case 2: // " * * " // " " mvwaddch(w, row+2, col+2, ACS_DIAMOND); mvwaddch(w, row+2, col+4, ACS_DIAMOND); break; default: // " * " // " " mvwaddch(w, row+2, col+3, ACS_DIAMOND); } if (colors) { wattroff(w, COLOR_PAIR(color_pair)); } if (highlight) wattroff(w, A_BOLD); } static void draw_cardstack(WINDOW *w, const uint8_t row, const uint8_t col, const bool highlight, const cardstack cs) { for (uint8_t i = 0; i < MAX_CARDSTACK_SIZE; i++) { if (cs[i] != 0) { draw_card(w, row, i*2, highlight, cs[i]); } } } void display_window_table_cards(const tablestacks ts, const bool highlight, const uint8_t highlighted_stack) { wattron(w_table_cards, A_BOLD); mvwprintw(w_table_cards, 0, 2, "Table Cards:"); wattroff(w_table_cards, A_BOLD); for (uint8_t i = 0; i < NUM_TABLESTACKS; i++) { if (highlight) { if (i == highlighted_stack) { draw_cardstack(w_table_cards, 1 + i*5, 0, true, ts[i]); continue; } } draw_cardstack(w_table_cards, 1 + i*5, 0, false, ts[i]); } wrefresh(w_table_cards); } void display_window_stack_points(const tablestacks ts) { wattron(w_stack_points, A_BOLD); mvwprintw(w_stack_points, 0, 0, "Pts:"); wattroff(w_stack_points, A_BOLD); for (uint8_t i = 0; i < NUM_TABLESTACKS; i++) { mvwprintw(w_stack_points, 3 + i*5, 1, "%2d", cardstack_get_points(ts[i])); } wrefresh(w_stack_points); } /** * Displays the current state window, showing all player names and their open cards and the client player's score. * @param[in] pnoc Array of (player name, open card) tuples. Array has to be sorted by open card, lowest open card first * @param[in] num_players The number of players to show a player name and open card for * @param[in] score The players score */ void display_window_current_state(const player_name_open_card_tuple pnoc[], const uint8_t num_players, const uint8_t active_player, const uint32_t score) { wattron(w_current_state, A_BOLD); mvwprintw(w_current_state, 0, 0, "Current state:"); mvwprintw(w_current_state, 0, 22, "Your Score: %3d", score); wattroff(w_current_state, A_BOLD); mvwprintw(w_current_state, 1, 1, "Player Card"); mvwprintw(w_current_state, 1, 22, "Player Card"); mvwvline(w_current_state, 1, 19, ACS_VLINE, 6); // Vertical line for (uint8_t i = 0; i < num_players; i++) { if (i == active_player) wattron(w_current_state, COLOR_PAIR(CP_YELLOW_ON_BLACK)); if (i < 5) { mvwprintw(w_current_state, 2+i, 1, "%-s", pnoc[i].player_name); mvwprintw(w_current_state, 2+i, 13, "%3d", pnoc[i].open_card); } else { mvwprintw(w_current_state, 2+(i-5), 22, "%-s", pnoc[i].player_name); mvwprintw(w_current_state, 2+(i-5), 34, "%3d", pnoc[i].open_card); } if (i == active_player) wattroff(w_current_state, COLOR_PAIR(CP_YELLOW_ON_BLACK)); } wrefresh(w_current_state); } /** * Displays the hand cards window. * @param[in] h The hand that will be displayed. h must not contain 0 */ void display_window_hand_cards(const hand h, const bool highlight, const uint8_t highlighted_card) { wattron(w_hand_cards, A_BOLD); mvwprintw(w_hand_cards, 0, 0, "Hand Cards:"); wattroff(w_hand_cards, A_BOLD); for (uint8_t i = 0; i < MAX_HAND_CARDS; i++) { if (highlight && i == highlighted_card) { if (i < 5) // Start with the first row of cards draw_card(w_hand_cards, 1, i*8, true, h[i]); else // And then draw the second row draw_card(w_hand_cards, 6, (i-5)*8, true, h[i]); continue; } if (i < 5) // Start with the first row of cards draw_card(w_hand_cards, 1, i*8, false, h[i]); else // And then draw the second row draw_card(w_hand_cards, 6, (i-5)*8, false, h[i]); } wrefresh(w_hand_cards); } void display_init(void) { initscr(); // Start curses mode if (TRUE == has_colors()) { colors = true; start_color(); init_pair(CP_WHITE_ON_BLACK, COLOR_WHITE, COLOR_BLACK); init_pair(CP_YELLOW_ON_BLACK, COLOR_YELLOW, COLOR_BLACK); init_pair(CP_BLUE_ON_BLACK, COLOR_BLUE, COLOR_BLACK); init_pair(CP_MAGENTA_ON_BLACK, COLOR_MAGENTA, COLOR_BLACK); init_pair(CP_RED_ON_BLACK, COLOR_RED, COLOR_BLACK); bkgd(COLOR_PAIR(0)); } raw(); // Line buffering disabled keypad(stdscr, true); // We get F1, F2 etc.. nodelay(stdscr, true); // Non-blocking input noecho(); // Don't echo() while we do getch curs_set(0); // Make the cursor invisible clear(); refresh(); // Window positions and sizes w_table_cards = newwin(21, 15, 0, 0); w_stack_points = newwin(19, 4, 0, 17); w_current_state = newwin(10, 38, 0, 24); w_hand_cards = newwin(11, 39, 10, 24); // Example data set for table cards window const tablestacks ts = {{1, 2, 3, 4, 101}, {6, 7, 53, 0, 0}, {11, 55, 0, 0, 0}, {17, 29, 36, 42, 0}}; // The stack points window uses ts, too, so there is no separate data set // Example data set for hand cards window const hand h = {12, 13, 22, 25, 27, 69, 77, 85, 100, 103}; // Example data set for current state window const player_name_open_card_tuple pnoc[10] = { {"$you", 10}, {"1234567890", 23}, {"baz", 38}, {"foo_bar", 14}, {"lolcat", 60}, {"blablub123", 15}, {"abcdefg", 103}, {"hello", 98}, {"hornoxe", 33}, {"1337nick", 74} }; const uint8_t num_players = 10; const uint32_t score = 10; // Draw user interface mvvline(0, 22, ACS_VLINE, 21); // Vertical line refresh(); display_window_table_cards(ts, true, 1); display_window_stack_points(ts); display_window_current_state(pnoc, num_players, 2, score); display_window_hand_cards(h, true, 8); sleep(4); } void display_fini(void) { delwin(w_table_cards); delwin(w_stack_points); delwin(w_current_state); delwin(w_hand_cards); endwin(); // End curses mode }