Logo Search packages:      
Sourcecode: papaya version File versions  Download package

TurfProtocol.cpp

#include <sys/types.h>
#include <stdlib.h>
#include <string.h>
#ifndef WIN32
#include <sys/utsname.h>
#else
#include <windows.h>
#endif

#include "Win32PluginAPI.cpp"
#include "TurfProtocol.h"

#define MAJOR "1"
#define MINOR "1"

extern EntityHandler * entities;
extern BaseWindow * mainWindow;

static TurfProtocol * turf = NULL;

extern "C" G_MODULE_EXPORT void plugin_init(plugin_address_table_t * pat) {

  plugin_address_table_init(pat);
  
  turf = new TurfProtocol();
  
  // Register the plugin here so that the 'turf' variable is set,
  // else copyover breaks when setting the menu item selectedness.
  register_plugin(turf, VERSION);
  plugin_handler_add_output_filter(get_plugin_handler(), turf);
  
  // Keepalive extensions for Turfish muds
  //    turf_old_keepalive = keepalive_send;
  //    keepalive_send = &TurfProtocol::keepalive_send;
}

extern "C" G_MODULE_EXPORT void plugin_cleanup(void) {
  delete turf;
  turf = NULL;
}

extern "C" G_MODULE_EXPORT char * plugin_query_name() {
  return "TurfProtocol";
}

extern "C" G_MODULE_EXPORT char * plugin_query_description() {
  return _("Adds TurfProtocol support to Papaya.  This is necessary for some plugins.  It requires a TurfProtocol aware MUD.");
}

extern "C" G_MODULE_EXPORT char * plugin_query_major() {
  return MAJOR;
}

extern "C" G_MODULE_EXPORT char * plugin_query_minor() {
  return MINOR;
}

void c4_get_players(GtkButton *, gpointer, gint) {
  turf->getPlayers();
}

/**
 * This function is provided with a character array of length 1024 bytes.
 *
 * The character array is filled with information in the form:
 * <client name> <client version> (<OS> <OS Version> <Architecture>)
 */

void ident(char * id) {
#ifdef WIN32
  OSVERSIONINFOA osInfo;
  SYSTEM_INFO sysInfo;
  char version[128];
  char arbitrary[1024];
  
  osInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
  GetVersionExA(&osInfo);
  GetSystemInfo(&sysInfo);
  
  switch (osInfo.dwPlatformId) {
  case VER_PLATFORM_WIN32_WINDOWS:
    if (osInfo.dwMinorVersion == 0) {
      sprintf(version, "95");
    } else {
      sprintf(version, "98");
    }
    break;
  case VER_PLATFORM_WIN32_NT:
    if (osInfo.dwMajorVersion >= 5) {
            if (osInfo.dwMinorVersion == 0) {
                  sprintf(version, "2000");
            } else {
                  sprintf(version, "XP");
            }
    } else {
      sprintf(version, "NT %d.%d", osInfo.dwMajorVersion, osInfo.dwMinorVersion);
    }
    break;
  case VER_PLATFORM_WIN32s:
    sprintf(version, "3.11(!)");
    break;
  default:
    sprintf(version, "???");
    break;
  }
  
  if (strlen(osInfo.szCSDVersion) > 1)
    sprintf(arbitrary, ", %s", osInfo.szCSDVersion);
  else      
    arbitrary[0] = '\0';
  
  sprintf(id, "Papaya %s (Windows %s%s)", VERSION, version, arbitrary);
  
#else
  struct utsname system;
  
  sprintf(id, "%s %s", PACKAGE, VERSION);

  // Don't know if uname(2) is supported on Win32

  if (uname(&system) == -1) {
    // Unable to figure out system name.
    sprintf(id, "%s %s", PACKAGE, VERSION);
  } else {
    sprintf(id, "%s %s (%s %s %s)", PACKAGE, VERSION, system.sysname, system.release, system.machine);
  }
#endif
}


void on_c4_list_select_row_gtk2(GtkTreeView * treeview, void * arg, GtkTreeViewColumn * column, gpointer d) {

  struct c4_data * data = (struct c4_data *)d;

  GtkTreeSelection * selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(data->player_list_view));
  GtkTreeIter iter;
  GtkTreeModel * model;

  if (gtk_tree_selection_get_selected(selection, &model, &iter)) {
    gchar * name;
    gtk_tree_model_get(model, &iter, 0, &name, -1);
    
    turf->challengePlayer(data, name);
    g_free(name);
  }

  gtk_widget_hide(data->player_list_window);
  gtk_widget_destroy(data->player_list_window);
  data->player_list_window = NULL;
  data->player_list_view = NULL;
  g_object_unref(data->player_list_store);
  data->player_list_store = NULL;
}
 
int TurfProtocol_Identity_Callback(regex_t * regexp, Connection * conn, char * in, char * stripped_in, void * data) {

  char id[1024];
  char buf[2048];

  if (!conn)
    return 0;

  ident(id);
  // Register conn as a TurfProtocol user

  sprintf(buf, "c15 a%s\n", id);
  socket_write(connection_get_socket(conn), buf, strlen(buf));
  turf->canUse(conn);
  return 1;
}

int TurfProtocol_Connect_Callback(regex_t * regexp, Connection * conn, char * in, char * stripped_in, void * data) {
  char buf[16384];

  if (!conn)
    return 0;

  sprintf(buf, "ClientConnect\n");
  socket_write(connection_get_socket(conn), buf, strlen(buf));

  return 1;
}

static int TurfDataCmp(struct turf_data * t1, struct turf_data * t2) {
  return (t1 < t2);
}

static int C4DataCmp(struct c4_data * t1, struct c4_data * t2) {
  return (t1 < t2);
}

struct turf_data * TurfProtocol::find_turf_data(Connection * conn) {
  for (TurfDataList::iterator i = turfData.begin(); i != turfData.end(); i++) {
    if ((*i)->connection == conn)
      return (*i);
  }
  return NULL;
}

struct c4_data * TurfProtocol::find_c4_data(Connection * conn) {
  for (C4DataList::iterator i = c4Data.begin(); i != c4Data.end(); i++) {
    if ((*i)->connection == conn)
      return (*i);
  }
  return NULL;
}

void TurfProtocol::remove_c4_data(struct c4_data * data) {

  C4DataList::iterator i = std::lower_bound(c4Data.begin(),
                                            c4Data.end(),
                                            data,
                                            C4DataCmp);
 
  if (i == c4Data.end() || (*i) != data)
    return;
 
  c4Data.erase(i);
}

void TurfProtocol::delete_turf_data(Connection * conn) {

  TurfDataList::iterator i_next;
  for (TurfDataList::iterator i = turfData.begin(); i != turfData.end(); i = i_next) {
    i_next = i;
    i_next++;

    if ((*i)->connection == conn) {
      remove_turf_data((*i));
      free((*i));
      return;
    }
  }
}

void TurfProtocol::remove_turf_data(struct turf_data * data) {
  TurfDataList::iterator i = std::lower_bound(turfData.begin(),
                                            turfData.end(),
                                            data,
                                            TurfDataCmp);
 
  if (i == turfData.end() || (*i) != data)
    return;
 
  turfData.erase(i);
}


void TurfProtocol::getPlayers() {
  Connection * conn = main_window_get_current_connection(get_main_window());
  if (!conn)
    return;

  struct turf_data * data = find_turf_data(conn);
  if (!data) {
    message_new(_("Connect Four"), _("Connect Four can only be played on Turf Protocol enabled MUDs."), true);
    return;
  }

  if (data->supported) {
    char buf[1024];

    sprintf(buf, "c15 ba\n");
    socket_write(connection_get_socket(conn), buf, strlen(buf));
  }
  else
    message_new(_("Connect Four"), _("Connect Four can only be played on Turf Protocol enabled MUDs."), true);
}

#define TURF_MENU "/Plugins/Turf"
#define C4_MENU TURF_MENU "/Play Connect Four"

TurfProtocol::TurfProtocol() {

  version = 1.0;
  name = strdup("Turf protocol support");

  first_cb = NULL;
  id = 0;

  identify_trigger = system_trigger_entity_new("Welcome to Turf.  Have a pleasant stay.", NULL, (SystemTriggerCallbackFunction) TurfProtocol_Identity_Callback, NULL);
  identify_trigger2 = system_trigger_entity_new("You have reconnected.", NULL, (SystemTriggerCallbackFunction)TurfProtocol_Identity_Callback, NULL);
  client_connect = system_trigger_entity_new(".*A Mud/Talker based around the code of Merc and Envy,", NULL, (SystemTriggerCallbackFunction)TurfProtocol_Connect_Callback, NULL);

  EntityHandler * entities = get_entity_handler();

  entity_handler_add_entity(entities, "TurfProtocol", identify_trigger);
  entity_handler_add_entity(entities, "TurfProtocol", identify_trigger2);
  entity_handler_add_entity(entities, "TurfProtocol", client_connect);

  // Add a menu item for the connect four game.
  GtkItemFactory * factory = main_window_get_item_factory(get_main_window());
  
  GtkItemFactoryEntry turf_entry = { TURF_MENU, NULL, NULL, 0, "<Branch>" };
  GtkItemFactoryEntry connect_four_entry = { C4_MENU, "<control>4", (GtkItemFactoryCallback)c4_get_players, 0 };

  gtk_item_factory_create_item(factory, &turf_entry, NULL, 2);
  gtk_item_factory_create_item(factory, &connect_four_entry, NULL, 2);

  gtk_widget_set_sensitive(gtk_item_factory_get_item(factory, C4_MENU), false);  
}

void TurfProtocol::pageSwitched() {

      GtkItemFactory * factory = main_window_get_item_factory(get_main_window());
      if (!factory) {
            return;
      }

      GtkWidget * menu_item = gtk_item_factory_get_item(factory, C4_MENU);
      if (!menu_item) {
            return;
      }

      Connection * conn = main_window_get_current_connection(get_main_window());
      if (!conn) {
            gtk_widget_set_sensitive(menu_item, false);
            return;
      }

      struct turf_data * data = find_turf_data(conn);
      if (data && data->supported)
        gtk_widget_set_sensitive(menu_item, true);
      else
        gtk_widget_set_sensitive(menu_item, false);
}

/**
 * I don't think this is ever called as it's the TurfProtocolWrapper that
 * gets auto-destructed.
 */

TurfProtocol::~TurfProtocol() {

  // Destroy all data stored in TurfDataList
  // Destroy all data stored in C4DataList

  struct TurfProtocolCallback * tmp, * tmp_next;
  
  // Destroy any callbacks waiting to be processed.
  for (tmp = first_cb; tmp; tmp = tmp_next) {
    tmp_next = tmp->next;
    if (tmp->command)
      free(tmp->command);
    if (tmp->data)
      free(tmp->data);
    free(tmp);
  }

  EntityHandler * entities = get_entity_handler();
  entity_handler_remove_entity(entities, identify_trigger);
  entity_handler_remove_entity(entities, identify_trigger2);
  entity_handler_remove_entity(entities, client_connect);

//  delete(identify_trigger);
//  delete(identify_trigger2);
//  delete(client_connect);

  free(name);
  name = NULL;

  unregister_plugin(this);
}

void TurfProtocol::addCommand(Connection * c, char * command, CallbackPtr callback, void * d) {

  // Can this connection support TurfProtocol?

  struct turf_data * data = find_turf_data(c);
  if (!data) {
    printf("TurfProtocol::addCommand called for connection that doesn't support TurfProtocol.\n");
    return;
  }

  if (!data->supported)
    return; // Either this connection doesn't support TP, or it is disabled.

  struct TurfProtocolCallback * cb = (struct TurfProtocolCallback *)malloc(sizeof(struct TurfProtocolCallback));
  char dat[16384];

  memset(cb, 0, sizeof(struct TurfProtocolCallback));

  // Initialise the structure.
  cb->next = NULL;
  cb->conn = c;
  cb->command = strdup(command);
  cb->callback = callback;
  cb->data = d;
  cb->id = id++;

  // Append to the end of the list to preserve FIFO ordering.
  
  if (!first_cb) {
    first_cb = cb;
  } else {
    struct TurfProtocolCallback * tmp_cb = first_cb;
    for (; tmp_cb->next; tmp_cb = tmp_cb->next);
    tmp_cb->next = cb;
  }

  // SEND the command.
  if (cb->command[strlen(cb->command) - 1] != '\n')
    sprintf(dat, "c15 h%d %s\n", cb->id, cb->command);
  else
    sprintf(dat, "c15 h%d %s", cb->id, cb->command);

  socket_write(connection_get_socket(cb->conn), dat, strlen(dat));
}

// Returns TRUE if the function handled the data (IE don't print it.)

bool TurfProtocol::isSupported(Connection * c) {
  struct turf_data * data = find_turf_data(c);
  if (!data)
    return false;
  
  return data->supported;
}

void TurfProtocol::output(Connection * conn, char * in) {

  struct TurfProtocolCallback * cb;
  char * start = in;
  char * pc;
  
  for (cb = first_cb; cb; cb = cb->next)
    if (cb->conn == conn)
      break;
  
  // Check to see if any c15 h's are currently reading.
  if (cb && cb->reading) {
    readTurfProtocol(conn, in);
    
    // Make sure that we don't prevent the prompt reaching the user.
    if (!strchr(in, '\001')) // MAGIC_PROMPT = \001
      in[0] = '\0';
    else {
      char * pc = strrchr(in, '\r');
      if (pc)
      memmove(in, pc + 1, strlen(pc + 1) + 1);
    }
    
    return;
  }
  
  while (start && *start != '\0') {
    pc = strchr(start, '\r');
    if (pc)
      *pc = '\0';
    
    if (cb && cb->reading) {
      readTurfProtocol(conn, start);
      
      if (pc)
      memmove(start, pc + 1, strlen(pc + 1) + 1);
      else
      *start = '\0';
      
      continue;
    }
    
    if (*start != '\x1f') {
      char * tmp = strchr(start, '\x1f');
      if (tmp)
      start = tmp;
    }
    
    if (*start == '\x1f') {
      switch (*(start + 1)) {
      
      case 'h': // c15 h protocol.
      if (cb) {
        cb->reading = TRUE;
        readTurfProtocol(conn, start);
      }
      break;
      
      case 'b': // A connect four sub-command.
      readConnectFour(conn, start);
      break;
      
      case 'c': // A message from a user.
      readMessage(conn, start);
      break;
      
      case 'd': // My name
      readName(conn, start);
      break;
      
      case 'e': // Site info
      readSiteInfo(conn, start);
      break;
      
      default:
      // printf("Unrecognised protocol line: %s\n", start);
      break;
      }
      
      if (pc)
      memmove(start, pc + 1, strlen(pc + 1) + 1); // + 1 to get the NUL
      else
      *start = '\0';
    } else {
      if (pc)
      start = pc + 1;
      else
      start = pc;
    }
  }
  
  return;
}

void TurfProtocol::readConnectFour(Connection * conn, char * in) {

  switch (*(in + 2)) {
  case 'a': // People list pending.
    createPlayerList(conn);
    break;

  case 'b': // Willing to play C4
    addPlayer(conn, in + 3);
    break;

  case 'c': // Starting game
    createBoard(conn);
    break;

  case 'd': // Challenge from user
    receiveChallenge(conn, in);
    break;

  case 'f': // Piece to be placed
    placePiece(conn, in+3);
    break;

  case 'g': // C4 message
    displayMessage(conn, in + 3);
    break;

  case 'h': // Draw line and game end
    placeLine(conn, in + 3);
    break;

  default:
    printf("Unrecognised C4 command '%c'\n", *(in + 2));
    break;
  }

}

void TurfProtocol::readSiteInfo(Connection * conn, char * in) {
  printf("SITEINFO: %s\n", in + 2);
}

void TurfProtocol::readMessage(Connection * conn, char * in) {

  // Pass the message to the Python Plugin (if loaded) and see
  // if it'll handle it.

  plugin_handler_client_message(get_plugin_handler(), conn, in + 2);
  printf("MESSAGE: %s\n", in + 2);
}

void TurfProtocol::readName(Connection * conn, char * in) {
  printf("I think my name is %s\n", in + 2);
}

void TurfProtocol::readTurfProtocol(Connection * conn, char * in) {
  struct TurfProtocolCallback * cb;

  for (cb = first_cb; cb; cb = cb->next) {
    if (cb->conn == conn) {

      if (cb->reading) {
      // \x1fh indicates the end of the string.  Anything before the
      // terminator should be appended to the data.

      char * pc = strstr(in, "\x1fh");
      if (pc && (*(pc + 2) == '\0' || *(pc + 2) == '\r')) { // End of c15 command.
        if (pc != in) { // There was stuff before the \x1fh
          cb->callback(conn, in, cb->data);
        }
        cb->callback(conn, (char *)NULL, cb->data);
        remove(cb);
        return;
      } else { // We are in the middle of the string.
        cb->callback(conn, in, cb->data);
        return;
      }

      }
    }
  }

  return;
}

void TurfProtocol::receiveCommand(char * cmd) {

  printf("Incoming command:\n\t");
  
  for (int i = 0; i < (int)strlen(cmd); i++)
    printf("%d ", cmd[i]);

  printf("\n");
}

// Cannot reference cb after exit from this function.

void TurfProtocol::remove(struct TurfProtocolCallback * cb) {

  struct TurfProtocolCallback * tmp = first_cb;

  if (cb == first_cb) {
    first_cb = cb->next;
    if (cb->command)
      free(cb->command);
    // In Win32 we can't free memory allocated by another DLL.  Free it in the plugin instead.
    //if (cb->data)
    //  free(cb->data);
    free(cb);
    return;
  }

  for (tmp = first_cb; tmp; tmp = tmp->next) {
    if (tmp->next == cb) {
      tmp->next = cb->next;
      if (cb->command)
      free(cb->command);
      // We don't free this here, the plugin MUST do this when line given to it is NULL.
        // This is because in Win32 we can't free memory allocated by another DLL.
     // if (cb->data)
       //   free(cb->data);
      free(cb);
      return;
    }
  }
}

void TurfProtocol::canUse(Connection * c) {
  struct turf_data * data = find_turf_data(c);
  
  if (!data) {
    data = (struct turf_data *)malloc(sizeof(struct turf_data));
    memset(data, 0, sizeof(struct turf_data));
    data->connection = c;

    TurfDataList::iterator i = std::lower_bound(turfData.begin(),
                                    turfData.end(),
                                    data,
                                    TurfDataCmp);
    turfData.insert(i, data);
  }

  data->supported = true;
  pageSwitched();
}

void TurfProtocol::onEvent(Event * e, Connection * c) {

  if (event_get_type(e) == EvDisconnect) {
    delete_turf_data(c);
    return;
  }

  if (event_get_type(e) == EvConnect) {
    struct turf_data * data = find_turf_data(c);
    if (!data) {
      data = (struct turf_data *)malloc(sizeof(struct turf_data));
      memset(data, 0, sizeof(struct turf_data));
      data->connection = c;
      TurfDataList::iterator i = std::lower_bound(turfData.begin(),
                                      turfData.end(),
                                      data,
                                      TurfDataCmp);
      turfData.insert(i, data);
    }
    
    data->supported = false; // We don't know that this is a supporting connection.
    return;
  }

}

char * TurfProtocol::getDescription() {
  return _("Adds TurfProtocol(c15) support to Papaya.");
}

struct c4_data * TurfProtocol::createPlayerList(Connection * conn) {

  struct c4_data * data = find_c4_data(conn);
  if (!data) {
    data = (struct c4_data *)malloc(sizeof(struct c4_data));
    init_c4_data(data);
    data->connection = conn;
    C4DataList::iterator i = std::lower_bound(c4Data.begin(),
                                    c4Data.end(),
                                    data,
                                    C4DataCmp);
    c4Data.insert(i, data);
  }

  if (data->player_list_view) {
    gtk_widget_hide(data->player_list_view);
    gtk_widget_destroy(data->player_list_view);
  }

  create_c4_player_list(data);
  gtk_widget_show(data->player_list_window);

  return data;
}

void TurfProtocol::addPlayer(Connection * conn, char * name) {
  
  struct c4_data * data = find_c4_data(conn);
  if (!data)
    data = createPlayerList(conn);

  if (!data->player_list_view)
    return;

  GtkTreeIter iter;
  gtk_list_store_append(data->player_list_store,
                  &iter);
  gtk_list_store_set(data->player_list_store,
                 &iter, 0, name, -1);

  return;
}

void TurfProtocol::challengePlayer(struct c4_data * data, char * name) {

  char cmd[1024];
  sprintf(cmd, "c15 bb%s\n", name);

  socket_write(connection_get_socket(data->connection), cmd, strlen(cmd));
}

void create_c4_player_list (struct c4_data * data)
{
  GtkWidget *vbox1;
  GtkWidget *vbox2;
  GtkWidget *label;
  GtkWidget *scrolledwindow1;
  GtkWidget *label2;
  GtkWidget *hbuttonbox1;
  GtkWidget *challenge_button;
  GtkWidget *cancel_button;

  data->player_list_window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title (GTK_WINDOW (data->player_list_window), _("Connect Four Player List"));

  vbox1 = gtk_vbox_new (FALSE, 0);
  gtk_widget_ref (vbox1);

  gtk_widget_show (vbox1);
  gtk_container_add (GTK_CONTAINER (data->player_list_window), vbox1);

  vbox2 = gtk_vbox_new (FALSE, 0);
  gtk_widget_ref (vbox2);

  gtk_widget_show (vbox2);
  gtk_box_pack_start (GTK_BOX (vbox1), vbox2, TRUE, TRUE, 0);

  label = gtk_label_new (_("Please select a player to challenge to a game of connect four:"));
  gtk_widget_ref (label);

  gtk_widget_show (label);
  gtk_box_pack_start (GTK_BOX (vbox2), label, FALSE, FALSE, 4);
  gtk_misc_set_alignment (GTK_MISC (label), 0.07, 0.5);

  scrolledwindow1 = gtk_scrolled_window_new (NULL, NULL);
  gtk_widget_ref (scrolledwindow1);

  gtk_widget_show (scrolledwindow1);
  gtk_box_pack_start (GTK_BOX (vbox2), scrolledwindow1, TRUE, TRUE, 0);

  GtkTreeViewColumn * column;
  GtkCellRenderer * cell_renderer;

  data->player_list_store = gtk_list_store_new(1, G_TYPE_STRING);
  data->player_list_view = gtk_tree_view_new_with_model(GTK_TREE_MODEL(data->player_list_store));
  g_signal_connect_data(data->player_list_view, "row-activated",
                  G_CALLBACK(on_c4_list_select_row_gtk2), NULL, NULL,
                  (GConnectFlags)0);

  cell_renderer = gtk_cell_renderer_text_new();
  column = gtk_tree_view_column_new_with_attributes(_("Player"),
                                        cell_renderer,
                                        "text", 0,
                                        NULL);

  gtk_tree_view_append_column(GTK_TREE_VIEW(data->player_list_view), column);
  gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(data->player_list_view), false);
  gtk_widget_show(data->player_list_view);

  gtk_list_store_clear(data->player_list_store);
  gtk_container_add(GTK_CONTAINER(scrolledwindow1), data->player_list_view);

  label2 = gtk_label_new ("label2");
  gtk_widget_ref (label2);
  gtk_widget_show (label2);

  hbuttonbox1 = gtk_hbutton_box_new ();
  gtk_widget_ref (hbuttonbox1);
  gtk_widget_show (hbuttonbox1);
  gtk_box_pack_start (GTK_BOX (vbox1), hbuttonbox1, FALSE, TRUE, 0);
  gtk_button_box_set_layout (GTK_BUTTON_BOX (hbuttonbox1), GTK_BUTTONBOX_SPREAD);

  challenge_button = gtk_button_new_with_label (_("Challenge"));
  gtk_widget_ref (challenge_button);
  gtk_widget_show (challenge_button);
  gtk_container_add (GTK_CONTAINER (hbuttonbox1), challenge_button);
  GTK_WIDGET_SET_FLAGS (challenge_button, GTK_CAN_DEFAULT);

  cancel_button = gtk_button_new_with_label (_("Cancel"));
  gtk_widget_ref (cancel_button);

  gtk_widget_show (cancel_button);
  gtk_container_add (GTK_CONTAINER (hbuttonbox1), cancel_button);
  GTK_WIDGET_SET_FLAGS (cancel_button, GTK_CAN_DEFAULT);

  g_signal_connect_data (G_OBJECT (challenge_button), "clicked",
                   G_CALLBACK (on_c4_challenge_button_clicked),
                   (gpointer)data,
                   NULL, (GConnectFlags) 0);
  g_signal_connect_data (GTK_OBJECT (cancel_button), "clicked",
                   GTK_SIGNAL_FUNC (on_c4_cancel_button_clicked),
                   (gpointer)data,
                   NULL, (GConnectFlags) 0);
  return;
  //  return data->player_list_window;
}



void on_c4_challenge_button_clicked(GtkButton * button, gpointer d) {
  on_c4_list_select_row_gtk2(NULL, NULL, NULL, d);
}

void on_c4_cancel_button_clicked(GtkButton *, gpointer d) {

  struct c4_data * data = (struct c4_data *)d;

  if (data->player_list_window) {
    gtk_widget_hide(data->player_list_window);
    gtk_widget_destroy(data->player_list_window);
    data->player_list_window = NULL;
    data->player_list_view = NULL;
    g_object_unref(data->player_list_store);
    data->player_list_store = NULL;
  }
  
}

void TurfProtocol::createBoard(Connection * conn) {

  struct c4_data * data = find_c4_data(conn);
  if (!data) {
    data = (struct c4_data *)malloc(sizeof(struct c4_data));
    data->connection = conn;
    C4DataList::iterator i = std::lower_bound(c4Data.begin(),
                                              c4Data.end(),
                                              data,
                                              C4DataCmp);
    c4Data.insert(i, data);
  }
  init_c4_data(data);

  if (data->board_window) {
    gtk_widget_hide(data->board_window);
    gtk_widget_destroy(data->board_window);

    data->board_window = NULL;
    data->board = NULL;
  }

  create_c4_board(data);
}

void TurfProtocol::create_c4_board(struct c4_data * data) {

  GtkWidget * vbox;

  data->board_window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
  gtk_window_set_title(GTK_WINDOW(data->board_window), _("Connect Four Playing Area"));

  vbox = gtk_vbox_new(FALSE, 0);
  gtk_widget_ref(vbox);
  gtk_widget_show(vbox);
  gtk_container_add(GTK_CONTAINER(data->board_window), vbox);

  data->board = gtk_drawing_area_new();
  gtk_widget_ref(data->board);
  gtk_widget_set_events(data->board, GDK_BUTTON_PRESS_MASK);
  g_signal_connect_data(data->board, "event",
                  GTK_SIGNAL_FUNC(c4_board_clicked),
                  data,
                  NULL,
                  (GConnectFlags)0);
  g_signal_connect_data(data->board, "expose_event",
                  GTK_SIGNAL_FUNC(c4_expose_event),
                  data,
                  NULL,
                  (GConnectFlags)0);

  gtk_widget_set_size_request(GTK_WIDGET(data->board), 200, 240);
  
  gtk_widget_show(data->board);
  gtk_box_pack_start(GTK_BOX(vbox), data->board, TRUE, TRUE, 0);

  data->board_status = gtk_entry_new();
  gtk_widget_ref(data->board_status);

  gtk_editable_set_editable(GTK_EDITABLE(data->board_status), FALSE);
  gtk_widget_show(data->board_status);

  gtk_box_pack_start(GTK_BOX(vbox), data->board_status, FALSE, FALSE, 0);

  //  gtk_container_add(GTK_CONTAINER(data->board_window), vbox);

  gtk_widget_show(data->board_window);

  exposeEvent(data->board, NULL, data);

}

void c4_board_clicked(GtkWidget * area, GdkEvent * event, gpointer d) {
  turf->boardClicked(area, event, d);
}


void TurfProtocol::boardClicked(GtkWidget * area, GdkEvent * event, gpointer d) {
  struct c4_data * data = (struct c4_data *)d;

  if (event->type == GDK_BUTTON_PRESS) {
    
    if (data->gameover) {
      gtk_widget_destroy(data->board_window);
      data->board_window = NULL;
      data->board = NULL;
      data->board_status = NULL;
      data->gameover = 0;
      
      return;
    }
    
    
    int x, y;
    int c;
    int window_width = data->board->allocation.width;
    int hgaps = C4_WIDTH + 1;
    int piece_width = (window_width - (C4_GAP * hgaps))/C4_WIDTH;
    
    gtk_widget_get_pointer(data->board, &x, &y);
    
    c = C4_GAP;
    
    for (int i = 0; i < C4_WIDTH; i++) {
      int minx = (i + 1)*C4_GAP + i*piece_width;
      int maxx = minx + piece_width;
      
      if (x >= minx && x <= maxx) {
      char buf[1024];
      // column i has been clicked.
      sprintf(buf, "c15 bf%d\n", i);
      socket_write(connection_get_socket(data->connection), buf, strlen(buf));
      }
      
    }
    
    return;
  }
}

void c4_expose_event(GtkWidget * widget, GdkEventExpose * event, gpointer d) {
  turf->exposeEvent(widget, event, d);
}

void TurfProtocol::exposeEvent(GtkWidget * widget, GdkEventExpose * expose, gpointer d) {
  struct c4_data * data = (struct c4_data *)d;

  GdkColor red = {0, 0xffff, 0x0000, 0x0000};
  GdkColor yellow = {0, 0x0000, 0xffff, 0xffff};
  GdkColor black = {0, 0x0000, 0x0000, 0x0000};

  GdkGC * gc = gdk_gc_new(widget->window);
  if (!gc)
    return;
  gdk_gc_copy(gc, widget->style->white_gc);

  int window_width = data->board->allocation.width;
  int window_height = data->board->allocation.height;

  //  int window_width = 320;
  //  int window_height = 200;

  int hgaps = C4_WIDTH + 1;
  int vgaps = C4_HEIGHT + 1;

  int x = C4_GAP;
  int y = C4_GAP;

  int itx;
  int ity;

  int piece_width = (window_width - (C4_GAP * hgaps))/C4_WIDTH;
  int piece_height = (window_height - (C4_GAP * vgaps))/C4_HEIGHT;

  gdk_color_alloc(gdk_colormap_get_system(), &red);
  gdk_color_alloc(gdk_colormap_get_system(), &yellow);
  gdk_color_alloc(gdk_colormap_get_system(), &black);

  for (itx = 0; itx < C4_WIDTH; itx++) {
    for (ity = 0; ity < C4_HEIGHT; ity++) {
      // Draw the circle

      if (data->pieces[itx][ity] == 1) {
        /* Alternative colour. */
      gdk_gc_set_foreground(gc, &red);
      } else {
        if (data->pieces[itx][ity] == 2) {
        gdk_gc_set_foreground(gc, &yellow);
        } else {
        gdk_gc_set_foreground(gc, &black);
        }
      }

      gdk_draw_arc(data->board->window, 
               gc,
                   TRUE,
                   x, y,
                   piece_width, piece_height,
                   0, 360 * 64);
      y += piece_height + C4_GAP;
    }
    y = C4_GAP;
    x += piece_width + C4_GAP;
  }

  if (data->a >= 0) {

    int x1, y1, x2, y2;


    x1 = C4_GAP + piece_width/2 + ((data->a) * (piece_width + C4_GAP));
    x2 = C4_GAP + piece_width/2 + ((data->c) * (piece_width + C4_GAP));

    y1 = C4_GAP + piece_height/2 + ((C4_HEIGHT - data->b - 1) * (piece_height + C4_GAP) );
    y2 = C4_GAP + piece_height/2 + ((C4_HEIGHT - data->d - 1) * (piece_height + C4_GAP) );

    gdk_draw_line(data->board->window, data->board->style->fg_gc[0],
                  x1, y1,
                  x2, y2);
  }
}

void TurfProtocol::init_c4_data(struct c4_data * data) {
  memset(data, 0, sizeof(struct c4_data));

  data->a = data->b = data->c = data->d = -1;

}

void TurfProtocol::placeLine(Connection * conn, char * line) {

  struct c4_data * data = find_c4_data(conn);
  if (!data)
    return;

  data->gameover = 1;

  char arg[2];
  arg[1] = '\0';


  arg[0] = *line;
  data->a = atoi(arg);

  arg[0] = *(line+1);
  data->b = atoi(arg);

  arg[0] = *(line+2);
  data->c = atoi(arg);

  arg[0] = *(line+3);
  data->d = atoi(arg);

  exposeEvent(data->board, NULL, data);
}

void TurfProtocol::placePiece(Connection * conn, char * line) {

  int x, y, c;

  struct c4_data * data = find_c4_data(conn);
  if (!data)
    return;

  char arg[2];
 
  arg[1] = '\0';

  arg[0] = *line;
  x = atoi(arg);
  
  arg[0] = *(line+1);
  y = atoi(arg);

  arg[0] = *(line+2);
  c = atoi(arg);

  data->pieces[x][C4_HEIGHT - 1 - y] = c;
  exposeEvent(data->board, NULL, data);

}

void TurfProtocol::displayMessage(Connection * conn, char * msg) {

  struct c4_data * data = find_c4_data(conn);
  if (!data || ! data->board_status)
    return;

  gtk_entry_set_text(GTK_ENTRY(data->board_status), msg);
}

void TurfProtocol::receiveChallenge(Connection * conn, char * line) {

  GtkWidget *label, *yes_button, *no_button;
  char buf2[1024];

  struct c4_data * data = find_c4_data(conn);
  if (!data) {
    data = (struct c4_data *)malloc(sizeof(struct c4_data));
    init_c4_data(data);
    data->connection = conn;

    C4DataList::iterator i = std::lower_bound(c4Data.begin(),
                                              c4Data.end(),
                                              data,
                                              C4DataCmp);
    c4Data.insert(i, data);
  }


  if (data->current_request)
    free(data->current_request);

  data->current_request = strdup(line+3);

  sprintf(buf2, _("Connect four request from %s.  Do you want to play?"), line+3);

  /* Create the widgets */
  
  data->dialog = gtk_dialog_new();
  label = gtk_label_new (buf2);
  yes_button = gtk_button_new_with_label(_("Yes"));
  no_button = gtk_button_new_with_label(_("No"));

  g_signal_connect_data(yes_button, "clicked",
                  GTK_SIGNAL_FUNC(c4_ok_clicked), data,
                  NULL, (GConnectFlags)0);

  g_signal_connect_data(no_button, "clicked",
                  GTK_SIGNAL_FUNC(c4_cancel_clicked), data,
                  NULL, (GConnectFlags)0);

  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(data->dialog)->action_area),
                     yes_button);
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(data->dialog)->action_area),
                     no_button);
  
  /* Add the label, and show everything we've added to the dialog. */
  
  gtk_container_add (GTK_CONTAINER (GTK_DIALOG(data->dialog)->vbox),
                     label);

  gtk_widget_show_all (data->dialog);
}

void c4_cancel_clicked(GtkWidget * button, gpointer d) {
  turf->cancelClicked(button, d);
}

void TurfProtocol::cancelClicked(GtkWidget * button, gpointer d) {
  struct c4_data * data = (struct c4_data *)d;

  gtk_widget_hide(data->dialog);
  gtk_widget_destroy(data->dialog);
  data->dialog = NULL;
  return;
}

void c4_ok_clicked(GtkWidget * button, gpointer d) {
  turf->okClicked(button, d);
}

void TurfProtocol::okClicked(GtkWidget * button, gpointer d) {
  struct c4_data * data = (struct c4_data *)d;

  gtk_widget_hide(data->dialog);
  gtk_widget_destroy(data->dialog);
  data->dialog = NULL;
  
  char cmd[1024];
  sprintf(cmd, "c15 bc%s\n", data->current_request); 
  socket_write(connection_get_socket(data->connection), cmd, strlen(cmd));
  return;
}

// Turfish MUDs use the Turf protocol to mask their keepalives
void TurfProtocol::keepalive_send(Connection * c) {
//#ifndef WIN32
//  if (turf->tList->findEntry(c))
//    turf->addCommand(c, "randomunlikelycommand", keepalive_callback, NULL);
//  else
//    turf_old_keepalive(c);
//#endif
}

void keepalive_callback(Connection * c, char * in, void * data) {
  return;
}

extern "C" G_MODULE_EXPORT void turf_protocol_get_turf(void ** ptr) {
  *ptr = turf;
}

extern "C" G_MODULE_EXPORT void turf_add_command(void * connection, char * cmd, void * callback, gpointer data) {
      turf->addCommand((Connection *)connection, cmd, (CallbackPtr) callback, data);
}

extern "C" G_MODULE_EXPORT unsigned char turf_is_supported(void * connection) {
      return turf->isSupported((Connection *)connection);
}

Generated by  Doxygen 1.6.0   Back to index