From 4edaf3fb9853b3eb140196ac5e4d6ed3a34eb4ba Mon Sep 17 00:00:00 2001 From: Solomon Peachy Date: Wed, 6 Feb 2019 13:16:58 -0500 Subject: FS#7912: Voice enable the chessbox plugin Original patch by Mario Lang Heavily updated by Igor Poretsky Change-Id: Iaa0c32a79a464860ff294096825ae788f35cf312 --- apps/plugins/chessbox/chessbox.c | 159 +++++++++++++++++++++++++++++------ apps/plugins/chessbox/chessbox_pgn.c | 54 ++++++++++-- apps/plugins/chessbox/gnuchess.c | 4 + 3 files changed, 182 insertions(+), 35 deletions(-) (limited to 'apps/plugins') diff --git a/apps/plugins/chessbox/chessbox.c b/apps/plugins/chessbox/chessbox.c index c7cd94c7e1..52a1f2789b 100644 --- a/apps/plugins/chessbox/chessbox.c +++ b/apps/plugins/chessbox/chessbox.c @@ -78,16 +78,16 @@ extern const fb_data chessbox_pieces[]; short plugin_mode; /* level+1's string */ -const char *level_string[] = { "Level 1: 60 moves / 5 min" , - "Level 2: 60 moves / 15 min" , - "Level 3: 60 moves / 30 min" , - "Level 4: 40 moves / 30 min" , - "Level 5: 40 moves / 60 min" , - "Level 6: 40 moves / 120 min" , - "Level 7: 40 moves / 240 min" , - "Level 8: 1 move / 15 min" , - "Level 9: 1 move / 60 min" , - "Level 10: 1 move / 600 min" }; +const char *level_string[] = { ID2P(LANG_CHESSBOX_LEVEL_1) , + ID2P(LANG_CHESSBOX_LEVEL_2) , + ID2P(LANG_CHESSBOX_LEVEL_3) , + ID2P(LANG_CHESSBOX_LEVEL_4) , + ID2P(LANG_CHESSBOX_LEVEL_5) , + ID2P(LANG_CHESSBOX_LEVEL_6) , + ID2P(LANG_CHESSBOX_LEVEL_7) , + ID2P(LANG_CHESSBOX_LEVEL_8) , + ID2P(LANG_CHESSBOX_LEVEL_9) , + ID2P(LANG_CHESSBOX_LEVEL_10) }; /* "While thinking" command */ int wt_command = COMMAND_NOP; @@ -175,8 +175,35 @@ static void cb_drawboard (void) { rb->lcd_update(); } +static short oldx, oldy = 0; +void cb_talk(short x, short y) +{ + if (x != oldx || y != oldy) { + short c, r; + short l, piece, p_color; + + rb->talk_shutup(); + cr2xy(x, y, &c, &r); + l = locn[r][c]; + piece = board[l]; + p_color = color[l]; + if (piece != no_piece) { + rb->talk_id (VOICE_WHITE + p_color, true); + if (piece >= pawn && piece <= king) { + rb->talk_id (VOICE_PAWN + piece - 1, true); + } + } + rb->talk_id (VOICE_CHAR_A + c, true); + rb->talk_id (VOICE_ONE + r, true); + oldx = x; + oldy = y; + } +} + /* ---- Switch mark on board ---- */ static void cb_switch ( short x , short y ) { + if (rb->global_settings->talk_menu) + cb_talk(x, y); rb->lcd_set_drawmode ( DRMODE_COMPLEMENT ); rb->lcd_drawrect ( XOFS + x*TILE_WIDTH + 1 , YOFS + ( 7 - y )*TILE_HEIGHT +1 , @@ -380,7 +407,7 @@ static void cb_saveposition ( void ) { #ifdef CHESSBOX_SAVE_FILE_DBG cb_saveposition_dbg(); #endif - rb->splash ( 0 , "Saving position" ); + rb->splash ( 0 , ID2P(LANG_CHESSBOX_SAVING_POSITION) ); fd = rb->open(SAVE_FILE, O_WRONLY|O_CREAT, 0666); @@ -434,7 +461,7 @@ static void cb_restoreposition ( void ) { unsigned short m; if ( (fd = rb->open(SAVE_FILE, O_RDONLY)) >= 0 ) { - rb->splash ( 0 , "Loading position" ); + rb->splash ( 0 , ID2P(LANG_CHESSBOX_LOADING_POSITION) ); rb->read(fd, &(computer), sizeof(computer)); rb->read(fd, &(opponent), sizeof(opponent)); rb->read(fd, &(Game50), sizeof(Game50)); @@ -503,8 +530,10 @@ static int cb_menu_viewer(void) int result = 0; bool menu_quit = false; - MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"Restart Game", - "Select Other Game", "Quit"); + MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL, + ID2P(LANG_CHESSBOX_MENU_RESTART_GAME), + ID2P(LANG_CHESSBOX_MENU_SELECT_OTHER_GAME), + ID2P(LANG_MENU_QUIT)); while(!menu_quit) { @@ -572,7 +601,7 @@ static void cb_start_viewer(char* filename){ first_game = pgn_list_games(filename); if (first_game == NULL){ - rb->splash ( HZ*2 , "No games found !" ); + rb->splash ( HZ*2 , ID2P(LANG_CHESSBOX_NO_GAMES) ); return; } @@ -602,7 +631,7 @@ static void cb_start_viewer(char* filename){ if (curr_ply->prev_node != NULL){ curr_ply = curr_ply->prev_node; } else { - rb->splash ( HZ*2 , "At the begining of the game" ); + rb->splash ( HZ*2 , ID2P(LANG_CHESSBOX_GAME_BEGINNING) ); break; } board[locn[curr_ply->row_from][curr_ply->column_from]] @@ -648,9 +677,39 @@ static void cb_start_viewer(char* filename){ case COMMAND_NEXT: /* apply the current move */ if (curr_ply->player == neutral){ - rb->splash ( HZ*2 , "At the end of the game" ); + rb->splash ( HZ*2 , ID2P(LANG_CHESSBOX_GAME_END) ); break; } + if (rb->global_settings->talk_menu) { + rb->talk_id (VOICE_WHITE + curr_ply->player, false); + if (curr_ply->castle){ + rb->talk_id (VOICE_CHESSBOX_CASTLE, true); + if (curr_ply->column_to == 6){ + rb->talk_id (VOICE_CHESSBOX_KINGSIDE, true); + } else { + rb->talk_id (VOICE_CHESSBOX_QUEENSIDE, true); + } + } else { + rb->talk_id (VOICE_PAWN + + board[locn[curr_ply->row_from] + [curr_ply->column_from]] + - 1, true); + rb->talk_id (VOICE_CHAR_A + curr_ply->column_from, + true); + rb->talk_id (VOICE_ONE + curr_ply->row_from, true); + if (board[locn[curr_ply->row_to] + [curr_ply->column_to]] != no_piece) { + rb->talk_id (VOICE_CHESSBOX_CAPTURES, true); + rb->talk_id (VOICE_PAWN + + board[locn[curr_ply->row_to] + [curr_ply->column_to]] + - 1, true); + } + rb->talk_id (VOICE_CHAR_A + curr_ply->column_to, + true); + rb->talk_id (VOICE_ONE + curr_ply->row_to, true); + } + } board[locn[curr_ply->row_to][curr_ply->column_to]] = board[locn[curr_ply->row_from][curr_ply->column_from]]; color[locn[curr_ply->row_to][curr_ply->column_to]] @@ -677,6 +736,10 @@ static void cb_start_viewer(char* filename){ color[locn[curr_ply->row_from][curr_ply->column_to]] = neutral; } if (curr_ply->promotion){ + if (rb->global_settings->talk_menu) + rb->talk_id (VOICE_PAWN + + curr_ply->promotion_piece - 1, + true); board[locn[curr_ply->row_to][curr_ply->column_to]] = curr_ply->promotion_piece; color[locn[curr_ply->row_to][curr_ply->column_to]] @@ -701,7 +764,7 @@ static void cb_start_viewer(char* filename){ } } while (!exit_game && !exit_viewer); } else { - rb->splash ( HZ*2 , "Error parsing game !"); + rb->splash ( HZ*2 , ID2P(LANG_CHESSBOX_PGN_PARSE_ERROR)); } } while (!exit_viewer); } @@ -713,12 +776,15 @@ static int cb_menu(void) int result = 0; bool menu_quit = false; - MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL,"New Game","Resume Game", - "Save Game", "Restore Game", + MENUITEM_STRINGLIST(menu,"Chessbox Menu",NULL, + ID2P(LANG_CHESSBOX_MENU_NEW_GAME), + ID2P(LANG_CHESSBOX_MENU_RESUME_GAME), + ID2P(LANG_CHESSBOX_MENU_SAVE_GAME), + ID2P(LANG_CHESSBOX_MENU_RESTORE_GAME), #ifdef HAVE_PLAYBACK_CONTROL - "Playback Control", + ID2P(LANG_PLAYBACK_CONTROL), #endif - "Quit"); + ID2P(LANG_MENU_QUIT)); while(!menu_quit) { @@ -813,6 +879,10 @@ static struct cb_command cb_getcommand (void) { } if ( marked && ( marked_x == x ) && ( marked_y == y ) ) { from_marked = true ; + if (rb->global_settings->talk_menu) { + cb_talk(x, y); + rb->talk_id(VOICE_MARKED, true); + } } else { from_marked = false ; cb_switch ( x , y ); @@ -831,6 +901,10 @@ static struct cb_command cb_getcommand (void) { } if ( marked && ( marked_x == x ) && ( marked_y == y ) ) { from_marked = true ; + if (rb->global_settings->talk_menu) { + cb_talk(x, y); + rb->talk_id(VOICE_MARKED, true); + } } else { from_marked = false ; cb_switch ( x , y ); @@ -849,6 +923,10 @@ static struct cb_command cb_getcommand (void) { } if ( marked && ( marked_x == x ) && ( marked_y == y ) ) { from_marked = true ; + if (rb->global_settings->talk_menu) { + cb_talk(x, y); + rb->talk_id(VOICE_MARKED, true); + } } else { from_marked = false ; cb_switch ( x , y ); @@ -867,6 +945,10 @@ static struct cb_command cb_getcommand (void) { } if ( marked && ( marked_x == x ) && ( marked_y == y ) ) { from_marked = true ; + if (rb->global_settings->talk_menu) { + cb_talk(x, y); + rb->talk_id(VOICE_MARKED, true); + } } else { from_marked = false ; cb_switch ( x , y ); @@ -885,11 +967,15 @@ static struct cb_command cb_getcommand (void) { from_marked = true ; marked_x = x; marked_y = y; + if (rb->global_settings->talk_menu) + rb->talk_id(VOICE_MARKED, false); } } else { if ( ( marked_x == x ) && ( marked_y == y ) ) { marked = false; from_marked = false; + if (rb->global_settings->talk_menu) + rb->talk_id(VOICE_UNMARKED, false); } else { xy2cr ( marked_x , marked_y , &c , &r ); result.mv_s[0] = 'a' + c; @@ -912,6 +998,23 @@ static struct cb_command cb_getcommand (void) { } +/* Talk a move */ +static void talk_move(char *move_buffer) +{ + if (rb->global_settings->talk_menu) { + rb->talk_id (VOICE_PAWN + + board[locn[move_buffer[3]-'1'][move_buffer[2]-'a']] - 1, + false); + rb->talk_id(VOICE_CHAR_A + move_buffer[0] - 'a', true); + rb->talk_id(VOICE_ONE + move_buffer[1] - '1', true); + rb->talk_id(VOICE_CHAR_A + move_buffer[2] - 'a', true); + rb->talk_id(VOICE_ONE + move_buffer[3] - '1', true); + if (move_buffer[4] == '+' && !mate) { + rb->talk_id(VOICE_CHESSBOX_CHECK, true); + } + } +} + /* ---- game main loop ---- */ static void cb_play_game(void) { struct cb_command command; @@ -939,7 +1042,8 @@ static void cb_play_game(void) { while (!exit) { if ( mate ) { - rb->splash ( HZ*3 , "Checkmate!" ); + rb->talk_force_enqueue_next(); + rb->splash ( HZ*3 , ID2P(LANG_CHESSBOX_CHECKMATE) ); rb->button_get(true); pgn_store_game(game); GNUChess_Initialize(); @@ -950,7 +1054,7 @@ static void cb_play_game(void) { switch (command.type) { case COMMAND_MOVE: if ( ! VerifyMove (opponent, command.mv_s , 0 , &command.mv, move_buffer ) ) { - rb->splash ( HZ/2 , "Illegal move!" ); + rb->splash ( HZ/2 , ID2P(LANG_CHESSBOX_ILLEGAL_MOVE) ); cb_drawboard(); } else { cb_drawboard(); @@ -958,7 +1062,8 @@ static void cb_play_game(void) { /* Add the ply to the PGN history (in algebraic notation) */ pgn_append_ply(game, opponent, move_buffer, mate); - rb->splash ( 0 , "Thinking..." ); + talk_move(move_buffer); + rb->splash ( 0 , ID2P(LANG_CHESSBOX_THINKING) ); #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost ( true ); #endif @@ -971,6 +1076,7 @@ static void cb_play_game(void) { */ if (move_buffer[0] != '\0'){ pgn_append_ply(game, computer, move_buffer, mate); + talk_move(move_buffer); } else { pgn_set_result(game, mate); } @@ -1016,7 +1122,7 @@ static void cb_play_game(void) { opponent = white; computer = black; } - rb->splash ( 0 , "Thinking..." ); + rb->splash ( 0 , ID2P(LANG_CHESSBOX_THINKING) ); ElapsedTime(1); #ifdef HAVE_ADJUSTABLE_CPU_FREQ rb->cpu_boost ( true ); @@ -1031,6 +1137,7 @@ static void cb_play_game(void) { */ if (move_buffer[0] != '\0'){ pgn_append_ply(game, computer, move_buffer, mate); + talk_move(move_buffer); } else { pgn_set_result(game, mate); } diff --git a/apps/plugins/chessbox/chessbox_pgn.c b/apps/plugins/chessbox/chessbox_pgn.c index 4e16834f5c..39a24d6fa1 100644 --- a/apps/plugins/chessbox/chessbox_pgn.c +++ b/apps/plugins/chessbox/chessbox_pgn.c @@ -539,14 +539,21 @@ static void coords_to_pgn(struct pgn_ply_node* ply){ } } -static const char* get_game_text(int selected_item, void *data, - char *buffer, size_t buffer_len){ +static struct pgn_game_node *get_game_info(int selected_item, void *data){ int i; struct pgn_game_node *temp_node = (struct pgn_game_node *)data; for (i=0;inext_node; } + + return temp_node; +} + +static const char* get_game_text(int selected_item, void *data, + char *buffer, size_t buffer_len){ + struct pgn_game_node *temp_node = get_game_info(selected_item, data); + if (temp_node == NULL){ return NULL; } @@ -556,6 +563,35 @@ static const char* get_game_text(int selected_item, void *data, return buffer; } +static void say_player(const char *name, bool enqueue) { + if (!rb->strcasecmp(name, "player")) + rb->talk_id(VOICE_PLAYER, enqueue); + else if (!rb->strcasecmp(name, "gnuchess")) + rb->talk_id(VOICE_GNUCHESS, enqueue); + else + rb->talk_spell(name, enqueue); +} + +static int speak_game_selection(int selected_item, void *data){ + struct pgn_game_node *temp_node = get_game_info(selected_item, data); + + if (temp_node != NULL){ + say_player(temp_node->white_player, false); + say_player(temp_node->black_player, true); + if (temp_node->game_date[0] != '?') { + char buf[12]; + rb->strcpy(buf, temp_node->game_date); + buf[4] = 0; + buf[7] = 0; + rb->talk_id(LANG_MONTH_JANUARY + rb->atoi(&(buf[5])) - 1, true); + rb->talk_number(rb->atoi(&(buf[8])), true); + rb->talk_number(rb->atoi(buf), true); + } + } + + return 0; +} + static void write_pgn_token(int fhandler, char *buffer, size_t *line_length){ if (*line_length + rb->strlen(buffer) + 1 > 80){ rb->fdprintf(fhandler,"\n"); @@ -636,14 +672,18 @@ struct pgn_game_node* pgn_show_game_list(struct pgn_game_node* first_game){ rb->gui_synclist_init(&games_list, &get_game_text, first_game, false, 1, NULL); - rb->gui_synclist_set_title(&games_list, "Games", NOICON); + rb->gui_synclist_set_title(&games_list, rb->str(LANG_CHESSBOX_GAMES), NOICON); rb->gui_synclist_set_icon_callback(&games_list, NULL); + if (rb->global_settings->talk_menu) + rb->gui_synclist_set_voice_callback(&games_list, speak_game_selection); rb->gui_synclist_set_nb_items(&games_list, i); rb->gui_synclist_limit_scroll(&games_list, true); rb->gui_synclist_select_item(&games_list, 0); + rb->gui_synclist_draw(&games_list); + rb->gui_synclist_speak_item(&games_list); + while (true) { - rb->gui_synclist_draw(&games_list); curr_selection = rb->gui_synclist_get_sel_pos(&games_list); button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK); if (rb->gui_synclist_do_button(&games_list,&button,LIST_WRAP_OFF)){ @@ -651,11 +691,7 @@ struct pgn_game_node* pgn_show_game_list(struct pgn_game_node* first_game){ } switch (button) { case ACTION_STD_OK: - temp_node = first_game; - for (i=0;inext_node; - } - return temp_node; + return get_game_info(curr_selection, first_game); break; case ACTION_STD_CANCEL: return NULL; diff --git a/apps/plugins/chessbox/gnuchess.c b/apps/plugins/chessbox/gnuchess.c index 4b21cd785c..ff9bb99b91 100644 --- a/apps/plugins/chessbox/gnuchess.c +++ b/apps/plugins/chessbox/gnuchess.c @@ -1117,6 +1117,10 @@ static short i,alpha,beta,score,tempb,tempc,tempsf,tempst,xside,rpt; for (index=0;index<5;index++){ move_buffer[index] = mvstr1[index]; } + if (SqAtakd(PieceList[(side==white)?black:white][0],side)){ + move_buffer[4] = '+'; + move_buffer[5] = '\0'; + } if (score == -9999 || score == 9998) mate = true; if (mate) hint = 0; -- cgit v1.2.3