]> git.cworth.org Git - grrobot/blobdiff - src/grrobot.c
Fixed messages and scrolling
[grrobot] / src / grrobot.c
index b7433ca583f06aa20dbeeff3e4aee6706c284895..1a8d66579e103777d0462c5bf5a1d4984fffb40a 100644 (file)
 
 #include <stdio.h>
 #include <stdlib.h>
+#include <string.h>
+
 #include <gtk/gtk.h>
 
 #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, &notice_s);
+       status = rr_client_next_notice (game->client, &notice);
        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 ();