]> git.cworth.org Git - grrobot/blobdiff - src/grrobot.c
Added support for RR_NOTICE_GAMEOVER.
[grrobot] / src / grrobot.c
index 95f4363a64bcdac8d3a1a733ee6dca65bc11ddea..98f14f2582fad574e77c4317ed16a6fd2a13318b 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);
 
@@ -55,7 +70,7 @@ grr_game_read_notices (grr_game_t *game);
 
 static GSource *
 grr_game_notices_source_new (grr_game_t *game);
-    
+
 int 
 main (int argc, char **argv)
 {
@@ -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,62 +183,128 @@ 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);
        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_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;
+       case RR_NOTICE_GAMEOVER:
+       {
+           char *diagram;
+           grr_game_printf (game, "\nGame over. New game will begin now.");
+           /* XXX: Can drop this when the BOARD NOTICE is added in the server */
+           rr_client_show (game->client, &diagram);
+           rr_board_parse (board, diagram);
+           free (diagram);
+           gtk_widget_queue_draw (GTK_WIDGET (game->window));
+       }
+       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_POSITION:
-           rr_board_position (board, notice->u.position.robot,
-                              notice->u.position.x, notice->u.position.y);
-           gtk_widget_queue_draw (GTK_WIDGET (game->window));
+       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_TURN:
-           rr_board_set_goal_target (board, notice->u.target);
+       case RR_NOTICE_TIMER:
+           grr_game_printf (game, "\nTime remaining: %d seconds.",
+                            notice->u.number);
+           break;
+       case RR_NOTICE_POSITION:
+           rr_board_position_robot (board, notice->u.position.robot,
+                                    notice->u.position.x, notice->u.position.y);
            gtk_widget_queue_draw (GTK_WIDGET (game->window));
            break;
        }
@@ -241,20 +325,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), "");
@@ -265,6 +342,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)
 {
@@ -286,51 +417,58 @@ grr_game_start_gui (grr_game_t *game)
                      G_CALLBACK (exit), NULL);
     gtk_container_set_border_width (GTK_CONTAINER (window), 0);
 
-    vpaned = gtk_vpaned_new ();
-    gtk_container_set_border_width (GTK_CONTAINER (vpaned), 5);
-    gtk_container_add (GTK_CONTAINER (window), vpaned);
+    vbox = gtk_vbox_new (FALSE, 1);
+    gtk_container_add (GTK_CONTAINER (window), vbox);
     {
-       board_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
-       gtk_paned_pack1 (GTK_PANED (vpaned), board_frame, TRUE, TRUE);
+       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 ();
+
+       vpaned = gtk_vpaned_new ();
+       gtk_container_set_border_width (GTK_CONTAINER (vpaned), 0);
+       gtk_box_pack_start (GTK_BOX (vbox), vpaned,
+                           TRUE, TRUE, 0);
        {
-           game->board_view = grr_board_view_new (game->board);
-           grr_board_view_set_client (GRR_BOARD_VIEW (game->board_view),
-                                      game->client);
-
-           gtk_container_add (GTK_CONTAINER (board_frame), game->board_view);
-           gtk_widget_show (game->board_view);
-       }
-       gtk_widget_show (board_frame);
+           board_frame = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1.0, FALSE);
+           gtk_paned_pack1 (GTK_PANED (vpaned), board_frame, TRUE, TRUE);
+           {
+               gtk_container_add (GTK_CONTAINER (board_frame), game->board_view);
+               gtk_widget_show (game->board_view);
+           }
+           gtk_widget_show (board_frame);
 
-       vbox = gtk_vbox_new (FALSE, 1);
-       gtk_paned_pack2 (GTK_PANED (vpaned), vbox, FALSE, TRUE);
-       {
            sw = gtk_scrolled_window_new (NULL, NULL);
            gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (sw),
                                            GTK_POLICY_NEVER,
                                            GTK_POLICY_AUTOMATIC);
-           gtk_container_add (GTK_CONTAINER (vbox), sw);
+           gtk_paned_pack2 (GTK_PANED (vpaned), sw, FALSE, TRUE);
+           {
+               message_view = game->message_view;
+               gtk_text_view_set_editable (GTK_TEXT_VIEW (message_view), FALSE);
+               gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (message_view), FALSE);
+               gtk_container_add (GTK_CONTAINER (sw), message_view);
+               gtk_widget_show (message_view);
+           }
            gtk_widget_show (sw);
-
-           game->message_buffer = gtk_text_buffer_new (NULL);
-           game->message_view = gtk_text_view_new_with_buffer (game->message_buffer);
-           message_view = game->message_view;
-           gtk_text_view_set_editable (GTK_TEXT_VIEW (message_view), FALSE);
-           gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (message_view), FALSE);
-           gtk_container_add (GTK_CONTAINER (sw), message_view);
-           gtk_widget_show (message_view);
-
-           game->command_entry = gtk_entry_new ();
-           command_entry = game->command_entry;
-           gtk_container_add (GTK_CONTAINER (vbox), command_entry);
-           gtk_widget_show (command_entry);
-           g_signal_connect (G_OBJECT (command_entry), "activate",
-                             G_CALLBACK (grr_game_entry_callback),
-                             (gpointer) game);
        }
-       gtk_widget_show (vbox);
+       gtk_widget_show (vpaned);
+
+       command_entry = game->command_entry;
+       gtk_box_pack_end (GTK_BOX (vbox), command_entry,
+                         FALSE, FALSE, 0);
+       gtk_widget_show (command_entry);
+       g_signal_connect (G_OBJECT (command_entry), "activate",
+                         G_CALLBACK (grr_game_entry_callback),
+                         (gpointer) game);
     }
-    gtk_widget_show (vpaned);
+    gtk_widget_show (vbox);
 
     gtk_widget_show (window);