#include "chess.h" #include #include /* this should tidy up when the game is finished, but for now it helps * me to debug allegro_404_char = ' '; */ #define SCREEN_WIDTH 360 #define SCREEN_HEIGHT 440 int errno; int bgcolour, hlcolour, black, white, text; const char *icons = " prnbqk"; volatile bool close_button_pressed = false; int cmd_setcolour(const char *buf); static void close_button(void); static void ask_to_close(void); static void text_in_box(BITMAP *bmp, const FONT *f, const char *s, int x1, int *x2, int y1, int *y2, int colour, int bg); static int strcolour(const char *buf); char *iconfiles[TYPE_TOTAL_TYPES] = { /* automatically append -$TEAM.tga */ NULL, /* TYPE_NONE */ "assets/pawn", /* TYPE_PAWN */ "assets/rook", /* TYPE_ROOK */ "assets/knight", /* TYPE_KNIGHT */ "assets/bishop", /* TYPE_BISHOP */ "assets/queen", /* TYPE_QUEEN */ "assets/king" /* TYPE_KING */ }; piece_t *highlighted = NULL; /* draw text breaking at spaces from x1 to x2 * note that the text can go down as far as y2 + text_height(font) because * it insists on completing lines * when this function returns, x2 and y2 are set to the position of the last * character */ static void text_in_box(BITMAP *bmp, const FONT *f, const char *s, int x1, int *x2, int y1, int *y2, int colour, int bg) { char *line, *alloc, swap; int i = 0, j = 0, linenum, textheight; size_t len; alloc = line = malloc(strlen(s) + 1); strcpy(line, s); textheight = text_height(font); len = strlen(line); while(i < len) { swap = line[i]; line[i] = '\0'; if(text_length(font, line) > *x2 - x1) { line[i] = swap; break; } line[i++] = swap; } for(linenum = 0; *line && y1 + linenum * text_height(font) <= *y2; linenum++) { if(i < len) { for(j = i; j > 0; j--) if(line[j] == ' ') break; } else { textout_ex(screen, font, line, x1, y1 + linenum * textheight, colour, bg); /* set the return vars */ *x2 = x1 + text_length(font, line); *y2 = y1 + linenum * textheight; break; } if(j == 0) { /* I'm sure there's a better way of doing this... */ swap = line[i]; line[i] = '\0'; textout_ex(screen, font, line, x1, y1 + linenum * textheight, colour, bg); line[i] = swap; line += i; len -= i; } else { line[j] = '\0'; textout_ex(screen, font, line, x1, y1 + linenum * textheight, colour, bg); line += j + 1; len -= j + 1; } } free(alloc); } static void close_button(void) { close_button_pressed = true; } static void ask_to_close(void) { if(!close_button_pressed) return; if(playing) { if(alert("Are you sure you want to", "forfeit the game?", NULL, "Resign", "Cancel", '\n', 0) == 1) exit(3 - nextMove); else close_button_pressed = false; } else exit(conclusion); } static int strcolour(const char *buf) { int i, rgb[3]; char arg[4]; for(i = 0; i < 3; i++) { cmd_argv(buf, i, arg, sizeof arg); rgb[i] = atoi(arg); if(rgb[i] > 255) rgb[i] = 255; } return makecol(rgb[0], rgb[1], rgb[2]); } int cmd_setcolour(const char *buf) { char *args; args = strchr(buf, ' '); if(args && cmd_argc(args) >= 3) { /* FIXME: lookup table? */ if(strncmp(buf, "bgcolour", 8) == 0) bgcolour = strcolour(args + 1); else if(strncmp(buf, "hlcolour", 8) == 0) hlcolour = strcolour(args + 1); else if(strncmp(buf, "white", 5) == 0) white = strcolour(args + 1); else if(strncmp(buf, "black", 5) == 0) black = strcolour(args + 1); else if(strncmp(buf, "text", 4) == 0) text = strcolour(args + 1); else /* should never happen */ { char cmd[16]; cmd_argv(buf, 0, cmd, sizeof cmd); snprintf(out, sizeof out, "Unrecognised colour name %s", cmd); } } else if(args) { char cmd[16]; cmd_argv(buf, 0, cmd, sizeof cmd); snprintf(out, sizeof out, "Not enough arguments to %s", cmd); } return 1; } void input(char *buf, size_t len) { /* len - 1 characters and a terminating 0 */ int i = 0, x, x2, y2; char c; bool clicked = false; highlighted = NULL; *buf = '\0'; if(inputstream != stdin) { /* input from a file */ if(feof(inputstream)) inputstream = stdin; else { ask_to_close(); while(1) { fgets(buf, len, inputstream); if(strncmp(buf, "//", 2)) break; } if(strchr(buf, '\n')) *strchr(buf, '\n') = '\0'; show_mouse(NULL); x2 = SCREEN_WIDTH - 30; y2 = SCREEN_HEIGHT; text_in_box(screen, font, buf, 30, &x2, SCREEN_HEIGHT - 30 - text_height(font), &y2, text, -1); show_mouse(screen); return; } } rectfill(screen, 30 + text_length(font, buf), SCREEN_HEIGHT - 30 - text_height(font), 25 + text_length(font, "x") * (strlen(buf) + 1), SCREEN_HEIGHT - 30, makecol(127, 127, 127)); while(1) { ask_to_close(); if(keypressed() && !(key_shifts & KB_COMMAND_FLAG)) { x = readkey(); c = x & 0xff; if(!c || x >> 8 == KEY_ENTER) /* if they press return... */ return; /* then do so :P */ if(((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || strchr(" -_./\'\"", c)) && i < len - 1) { buf[i++] = c; buf[i] = '\0'; } else if(x >> 8 == KEY_BACKSPACE) { if(i > 0) buf[--i] = '\0'; } /* TODO: else if(x >> 8 == KEY_LEFT) */ show_mouse(NULL); x2 = SCREEN_WIDTH - 30; y2 = SCREEN_HEIGHT; rectfill(screen, 30, SCREEN_HEIGHT - 30 - text_height(font), SCREEN_WIDTH, y2, bgcolour); text_in_box(screen, font, buf, 30, &x2, SCREEN_HEIGHT - 30 - text_height(font), &y2, text, -1); rectfill(screen, x2, y2, x2 + 3, y2 + text_height(font), makecol(127, 127, 127)); show_mouse(screen); } if(mouse_b & 1) { int xpos, ypos, x, y; xpos = mouse_pos >> 16; ypos = mouse_pos & 0x0000ffff; if(xpos >= 20 && xpos <= 340 && ypos >= 20 && ypos <= 340) { x = (xpos - 20) / 40; y = (ypos - 20) / 40; if(!clicked) { output(); int j, hx, hy; clicked = true; if(highlighted == pieces + board[y][x]) { /* clear the highlight */ highlighted = NULL; output(); } else if(team(board[y][x]) == nextMove) { highlighted = pieces + board[y][x]; hx = 40 * highlighted->file + 20; hy = 40 * highlighted->rank + 20; show_mouse(NULL); for(j = 0; j < 3; j++) rect(screen, hx + j, hy + j, hx + 40 - j, hy + 40 - j, hlcolour); show_mouse(screen); } else if(highlighted) { pieceType_t htype; square_t hsq; hsq = highlighted - pieces; htype = type(hsq); if(htype == TYPE_PAWN) snprintf(buf, len, "%c%c%c", highlighted->file + 'a', x + 'a', '8' - y); else if(htype == TYPE_KING && abs(pieces[hsq].file - x) == 2) { if(pieces[hsq].file > x) strncpy(buf, "0-0-0", len); else strncpy(buf, "0-0", len); return; } else { snprintf(buf, len, "%c%c%c%c%c", toupper(icons[htype]), pieces[hsq].rank + 'a', '8' - pieces[hsq].file, x + 'a', '8' - y); } return; } } } else { /* clear the highlight */ highlighted = NULL; output(); } } if(!(mouse_b & 1)) clicked = false; } } void output_init(void) { if(install_allegro(SYSTEM_AUTODETECT, &errno, atexit) != 0) { perror("install_allegro()"); exit(ERROR); } if(install_timer() < 0) { perror("install_timer()"); exit(ERROR); } if(install_keyboard() < 0) { perror("install_keyboard()"); exit(ERROR); } if(install_mouse() < 0) { perror("install_mouse()"); exit(ERROR); } if(set_gfx_mode(GFX_AUTODETECT_WINDOWED, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0) != 0) { if(set_gfx_mode(GFX_SAFE, SCREEN_WIDTH, SCREEN_HEIGHT, 0, 0) != 0) { set_gfx_mode(GFX_TEXT, 0, 0, 0, 0); allegro_message("Unable to set a graphic mode\n%s\n", allegro_error); return; } } set_close_button_callback(close_button); set_window_title("chessmachine"); bgcolour = makecol(255, 255, 127); hlcolour = makecol(255, 0, 0); black = makecol(0, 0, 0); white = makecol(255, 255, 255); text = makecol(0, 0, 0); addCommand("bgcolour", cmd_setcolour, CMD_LOGGED | CMD_INSTANT); addCommand("hlcolour", cmd_setcolour, CMD_LOGGED | CMD_INSTANT); addCommand("black", cmd_setcolour, CMD_LOGGED | CMD_INSTANT); addCommand("white", cmd_setcolour, CMD_LOGGED | CMD_INSTANT); addCommand("text", cmd_setcolour, CMD_LOGGED | CMD_INSTANT); show_mouse(screen); } void output(void) { int i, x, y, xpos, ypos, x2, y2, textheight; char filename[64]; BITMAP *tga; square_t current; acquire_screen(); show_mouse(NULL); clear_to_color(screen, bgcolour); textheight = text_height(font); for(i = 0; i < 64; i++) { x = (i % 8); y = (i / 8); xpos = x * 40 + 20; ypos = y * 40 + 20; if(!x) textprintf_centre_ex(screen, font, 10, ypos + 20 - textheight / 2, text, -1, "%c", '8' - y); if(!y) textprintf_centre_ex(screen, font, xpos + 20, 350 - textheight / 2, text, -1, "%c", x + 'a'); if((x % 2) ^ (y % 2)) rectfill(screen, xpos, ypos, xpos + 40, ypos + 40, black); else rectfill(screen, xpos, ypos, xpos + 40, ypos + 40, white); current = board[y][x]; snprintf(filename, sizeof(filename), "%s-%s.tga", iconfiles[type(current)], (team(current) == TEAM_WHITE) ? "white" : "black"); tga = load_tga(filename, NULL); if(!tga) textprintf_centre_ex(screen, font, xpos + 20, ypos + 20 - textheight / 2, makecol(255, 0, 0), -1, "%c", icons[type(current)]); else { int maskc, pinkc, w, h; /* FIXME: this is a bit of a hack */ pinkc = getpixel(tga, 0, 0); maskc = bitmap_mask_color(tga); for(h = 0; h < 40; h++) for(w = 0; w < 40; w++) if(getpixel(tga, w, h) == pinkc) putpixel(tga, w, h, maskc); masked_blit(tga, screen, 0, 0, xpos, ypos, 40, 40); destroy_bitmap(tga); } } x2 = SCREEN_WIDTH - 30; y2 = SCREEN_HEIGHT; if(text_length(font, out) > SCREEN_WIDTH - 60) text_in_box(screen, font, out, 30, &x2, 360, &y2, text, -1); else textout_ex(screen, font, out, 30, 360, text, -1); show_mouse(screen); release_screen(); return; }