X-Git-Url: https://git.cworth.org/git?a=blobdiff_plain;f=src%2Fgrrobot.c;h=1a8d66579e103777d0462c5bf5a1d4984fffb40a;hb=85953690f1a640d11af15017628df86ab6f03e56;hp=b7433ca583f06aa20dbeeff3e4aee6706c284895;hpb=a9073cef8cae5bddd59d7c6aff5decca20801e42;p=grrobot diff --git a/src/grrobot.c b/src/grrobot.c index b7433ca..1a8d665 100644 --- a/src/grrobot.c +++ b/src/grrobot.c @@ -30,9 +30,12 @@ #include #include +#include + #include #include "grr_board_view.h" +#include "grr_util.h" #include "args.h" typedef struct grr_game { @@ -41,12 +44,24 @@ typedef struct grr_game { GtkWidget *window; GtkWidget *board_view; + GtkWidget *command_entry; + GtkTextBuffer *message_buffer; GtkWidget *message_view; - GtkWidget *command_entry; - GtkTextIter message_iter; + int msg_id; + int last_move_msg_id; + rr_robot_t last_move_robot; } grr_game_t; +static int +grr_game_printf (grr_game_t *game, const char *fmt, ...); + +static int +grr_game_vprintf (grr_game_t *game, const char *fmt, va_list ap); + +static int +grr_game_print (grr_game_t *game, const char *msg); + static int grr_game_start_gui (grr_game_t *game); @@ -83,6 +98,9 @@ main (int argc, char **argv) } game.board = rr_board_create (16, 16); + game.msg_id = 0; + game.last_move_msg_id = 0; + game.last_move_robot = RR_ROBOT_NONE; source = grr_game_notices_source_new (&game); g_source_set_priority (source, GDK_PRIORITY_EVENTS); @@ -165,63 +183,108 @@ grr_game_read_notices (grr_game_t *game) { rr_board_t *board = game->board; rr_status_t status; - char **notice_s; rr_notice_t *notice; - int i; while (rr_client_notice_pending (game->client)) { - status = rr_client_next_notice (game->client, ¬ice_s); + status = rr_client_next_notice (game->client, ¬ice); if (status) { - fprintf (stderr, "Error during rr_client_notice: %s\n", + fprintf (stderr, "Error during rr_client_next_notice: %s\n", rr_status_str (status)); gtk_exit (1); return; } - for (i=0; notice_s[i]; i++) { - gtk_text_buffer_insert_at_cursor (game->message_buffer, notice_s[i], -1); - gtk_text_buffer_insert_at_cursor (game->message_buffer, " ", -1); - } - gtk_text_buffer_insert_at_cursor (game->message_buffer, "\n", -1); - gtk_text_buffer_get_iter_at_offset (game->message_buffer, - &game->message_iter, - -1); - gtk_text_view_scroll_to_iter (GTK_TEXT_VIEW (game->message_view), - &game->message_iter, - 0.0, FALSE, 0.0, 0.0); - - notice = rr_client_parse_notice (game->client, notice_s); - if (notice == NULL) { - int i; - fprintf (stderr, "Failed to parse notice: "); - for (i=0; notice_s[i]; i++) - fprintf (stderr, " %s", notice_s[i]); - fprintf (stderr, "\n"); - return; - } switch (notice->type) { case RR_NOTICE_USER: + grr_game_printf (game, + "\nGLOBAL: %s has connected.", notice->u.string); + break; case RR_NOTICE_QUIT: + grr_game_printf (game, + "\nGLOBAL: %s has disconnected.", notice->u.string); + break; case RR_NOTICE_GAME: + grr_game_printf (game, + "\nGLOBAL: New game available: %s.", notice->u.string); + break; case RR_NOTICE_DISPOSE: + grr_game_printf (game, + "\nGLOBAL: Game %s has been disposed.", notice->u.string); + break; case RR_NOTICE_MESSAGE: + grr_game_printf (game, "\n%s> %s", + notice->u.message.username, + notice->u.message.text); + break; case RR_NOTICE_GAMESTATE: + grr_game_printf (game, "\nGame state changed to: %s.", + rr_gamestate_str (notice->u.gamestate)); + break; case RR_NOTICE_JOIN: + grr_game_printf (game, "\nUser %s has joined the game.", + notice->u.string); + break; case RR_NOTICE_WATCH: + grr_game_printf (game, "\nUser %s has started watching the game.", + notice->u.string); + break; case RR_NOTICE_PART: + grr_game_printf (game, "\nUser %s has left the game.", + notice->u.string); + break; case RR_NOTICE_BID: + grr_game_printf (game, "\nUser %s bids %d.", + notice->u.bid.username, + notice->u.bid.number); + break; case RR_NOTICE_REVOKE: - case RR_NOTICE_TIMER: + grr_game_printf (game, "\nUser %s revokes previous bid.", + notice->u.string); + break; case RR_NOTICE_ABANDON: + grr_game_printf (game, "\nUser %s is willing to abandon this turn.", + notice->u.string); + break; case RR_NOTICE_NOBID: - case RR_NOTICE_ACTIVE: + grr_game_printf (game, "\nUser %s sees no point in bidding further this round", + notice->u.string); + break; case RR_NOTICE_MOVE: + if (game->msg_id == game->last_move_msg_id + && game->last_move_robot == notice->u.move.robot) { + game->last_move_msg_id = grr_game_printf (game, " %s", + rr_direction_str (notice->u.move.direction)); + } else { + game->last_move_msg_id = grr_game_printf (game, "\nMove #%d: %s %s", + notice->u.move.count, + rr_robot_str (notice->u.move.robot), + rr_direction_str (notice->u.move.direction)); + game->last_move_robot = notice->u.move.robot; + } + break; case RR_NOTICE_UNDO: + grr_game_print (game, "\nUNDO"); + break; case RR_NOTICE_RESET: + grr_game_print (game, "\nRESET"); + break; case RR_NOTICE_SCORE: + grr_game_printf (game, "\nScore for %s: %d.", + notice->u.bid.username, + notice->u.bid.number); + break; case RR_NOTICE_ACTIVATE: - /* XXX: Need to actually handle many of these. */ - fprintf (stderr, "Warning: Ignoring notice of type %d\n", notice->type); + grr_game_printf (game, "\nYour turn.", + notice->u.number); + break; + case RR_NOTICE_ACTIVE: + grr_game_printf (game, "\nUser %s now active to demonstrate solution in %d moves.", + notice->u.bid.username, + notice->u.bid.number); + break; + case RR_NOTICE_TIMER: + grr_game_printf (game, "\nTime remaining: %d seconds.", + notice->u.number); break; case RR_NOTICE_POSITION: rr_board_position (board, notice->u.position.robot, @@ -229,6 +292,7 @@ grr_game_read_notices (grr_game_t *game) gtk_widget_queue_draw (GTK_WIDGET (game->window)); break; case RR_NOTICE_TURN: + grr_game_print (game, "\nNew round!"); rr_board_set_goal_target (board, notice->u.target); gtk_widget_queue_draw (GTK_WIDGET (game->window)); break; @@ -250,20 +314,13 @@ grr_game_entry_callback (GtkWidget *widget, status = rr_client_request (game->client, entry_text, &response); if (status) { - gtk_text_buffer_insert_at_cursor (game->message_buffer, - "ERROR: ", -1); - gtk_text_buffer_insert_at_cursor (game->message_buffer, - rr_status_str (status), -1); - gtk_text_buffer_insert_at_cursor (game->message_buffer, - "\n", -1); + grr_game_printf (game, "\nERROR: %s.", rr_status_str (status)); } else { - for (i=0; response[i]; i++) { - gtk_text_buffer_insert_at_cursor (game->message_buffer, - response[i], -1); - gtk_text_buffer_insert_at_cursor (game->message_buffer, - " ", -1); + if (response[0]) { + grr_game_print (game, "\n"); + for (i=0; response[i]; i++) + grr_game_printf (game, "%s ", response[i]); } - gtk_text_buffer_insert_at_cursor (game->message_buffer, "\n", -1); } gtk_entry_set_text (GTK_ENTRY (game->command_entry), ""); @@ -274,6 +331,60 @@ grr_game_entry_callback (GtkWidget *widget, } +static int +grr_game_printf (grr_game_t *game, const char *fmt, ...) +{ + int msg_id; + + va_list ap; + + va_start (ap, fmt); + msg_id = grr_game_vprintf (game, fmt, ap); + va_end (ap); + + return msg_id; +} + +static int +grr_game_vprintf (grr_game_t *game, const char *fmt, va_list ap) +{ + char *msg; + int msg_id; + + grr_sprintf_alloc_va (&msg, fmt, ap); + if (msg == NULL) + return 0; + + msg_id = grr_game_print (game, msg); + + free (msg); + + return msg_id; +} + +static int +grr_game_print (grr_game_t *game, const char *msg) +{ + GtkTextIter iter; + GtkTextMark *mark; + + /* There might be a lighter way to do this, but this seems to + work. */ + + gtk_text_buffer_get_end_iter (game->message_buffer, &iter); + + mark = gtk_text_buffer_get_mark (game->message_buffer, "end"); + + gtk_text_buffer_move_mark (game->message_buffer, mark, &iter); + + gtk_text_buffer_insert (game->message_buffer, &iter, msg, -1); + + gtk_text_view_scroll_to_mark (GTK_TEXT_VIEW (game->message_view), + mark, 0.0, TRUE, 0.0, 1.0); + + return ++game->msg_id; +} + static int grr_game_start_gui (grr_game_t *game) { @@ -298,9 +409,14 @@ grr_game_start_gui (grr_game_t *game) vbox = gtk_vbox_new (FALSE, 1); gtk_container_add (GTK_CONTAINER (window), vbox); { + GtkTextIter iter; game->board_view = grr_board_view_new (game->board); grr_board_view_set_client (GRR_BOARD_VIEW (game->board_view), game->client); game->message_buffer = gtk_text_buffer_new (NULL); + gtk_text_buffer_get_iter_at_offset (game->message_buffer, + &iter, -1); + gtk_text_buffer_create_mark (game->message_buffer, + "end", &iter, FALSE); game->message_view = gtk_text_view_new_with_buffer (game->message_buffer); game->command_entry = gtk_entry_new ();