Crossfire Client, Trunk  R20693
create_char.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2013 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, see the
9  * 'LICENSE' and 'COPYING' files.
10  *
11  * The authors can be reached via e-mail to crossfire-devel@real-time.com
12  */
13 
19 #include "client.h"
20 
21 #include <gtk/gtk.h>
22 
23 #include "image.h"
24 #include "main.h"
25 #include "metaserver.h"
26 #include "gtk2proto.h"
27 
28 /* This corresponds to the number of opt_.. fields in the
29  * create_character_window. In theory, the vbox could be resized
30  * (or add a sub box), and adjust accordingly,
31  * but it is unlikely that number of optional choices is going
32  * to rapidly grow, and making it static makes some things much
33  * easier.
34  * Instead of having two different sets of fields named different,
35  * we just have one set and split it in half, for race and
36  * class. This is done so that boxes don't need to be moved
37  * around - imagine cas where one race has options and
38  * another doesn't, but the currently selected class does -
39  * as player chooses different races, that race choice will
40  * come and go, but we want the class box to remain and to keep
41  * its same value.
42  */
43 #define NUM_OPT_FIELDS 6
44 #define RACE_OPT_START 0
45 #define CLASS_OPT_START NUM_OPT_FIELDS/2
46 #define RACE_OPT_END CLASS_OPT_START - 1
47 #define CLASS_OPT_ENG NUM_OPT_FIELDS - 1
48 
49 
50 /* These are in the create_character_window */
57 
58 static GtkTextMark *text_mark_cs, *text_mark_rs;
59 
60 /* These are in the choose starting map window */
61 static GtkWidget *choose_starting_map_window,
63 
64 GtkTextBuffer *textbuf_starting_map;
65 
66 static int has_init=0, negative_stat=0;
67 
68 #define STARTING_MAP_PANE 0
70 
71 #define WINDOW_NONE 0
72 #define WINDOW_CREATE_CHARACTER 1
73 #define WINDOW_CHOOSE_MAP 2
74 
88 static void show_window(int window)
89 {
90  switch (window) {
91 
92  case WINDOW_NONE:
93  gtk_widget_hide(create_character_window);
94  gtk_widget_hide(choose_starting_map_window);
95  break;
96 
98  gtk_widget_show(create_character_window);
99  gtk_widget_hide(choose_starting_map_window);
100  break;
101 
102  case WINDOW_CHOOSE_MAP:
103  gtk_widget_hide(create_character_window);
104  gtk_widget_show(choose_starting_map_window);
105  break;
106  }
107 }
108 
109 
119 static void create_character_set_sensitive(int sensitive)
120 {
121  int i;
122 
123  gtk_widget_set_sensitive(button_cc_done, sensitive);
124  gtk_widget_set_sensitive(button_choose_starting_map, sensitive);
125  gtk_widget_set_sensitive(entry_new_character_name, sensitive);
126  gtk_widget_set_sensitive(combobox_rs, sensitive);
127  gtk_widget_set_sensitive(combobox_cs, sensitive);
128  /* Note we do not change status of cancel button - let
129  * the player cancel out of the window if they want -
130  * no harm in doing so.
131  */
132 
133  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
134  gtk_widget_set_sensitive(spinbutton_cc[i], sensitive);
135  }
136 
137  /* If we do not have any starting maps, no reason to show
138  * that button to the player.
139  */
140  if (starting_map_number) {
141  gtk_widget_show(button_choose_starting_map);
142  } else {
143  gtk_widget_hide(button_choose_starting_map);
144  }
145 }
146 
154 {
155  int reset_needed = 0;
156 
157  /* If we don't have race/class/stat_point values, get them now.
158  * those values are reset if we switch between servers, so there
159  * should never be any danger of them being wrong.
160  * In theory, if one of these is true, all of them should be true
161  * because it shouldn't be possible to get in a case where we have
162  * gotten race info but not class.
163  */
164  if (!races) {
165  cs_print_string(csocket.fd, "requestinfo race_list");
166  reset_needed = 1;
167  }
168  if (!classes) {
169  cs_print_string(csocket.fd, "requestinfo class_list");
170  reset_needed = 1;
171  }
172  if (!stat_points) {
173  cs_print_string(csocket.fd, "requestinfo newcharinfo");
174  reset_needed = 1;
175  }
176  /* In this case, we are getting copies of some of the data
177  * from the server - we need to discard any data we currently
178  * have then (mainly, clear out things like the pulldown list
179  * for classes
180  */
181  if (reset_needed) {
182  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
183  "Getting race & class information from the server");
185  }
186 
187  /* This will be set true once we get all the data */
188  gtk_widget_show(create_character_window);
189 }
190 
197 {
199 }
200 
207 static void update_all_stats()
208 {
209  int i, stat_points_used=0, statval, tmp;
210  const gchar *tval;
211  char buf[MAX_BUF];
212 
213  negative_stat = 0;
214  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
215 
216  tmp = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i]));
217  stat_points_used += tmp;
218  statval = tmp;
219 
220  /* We presume the label value is correct here - it should
221  * be - this is easier than tracking down the corresponding
222  * race/class structure and getting the value there.
223  */
224  tval = gtk_label_get_text(GTK_LABEL(label_cs[i]));
225  statval += atoi(tval);
226 
227  tval = gtk_label_get_text(GTK_LABEL(label_rs[i]));
228  statval += atoi(tval);
229 
230  /* Might it be good to draw nonpositive stats in red? Rather
231  * than hardcode that, it should be a style
232  * Used to only check for negative stats, but zero is not allowed either.
233  */
234  if (statval < 1) {
235  negative_stat = 1;
236  }
237 
238  snprintf(buf, sizeof(buf), "%d", statval);
239  gtk_label_set_text(GTK_LABEL(label_tot[i]), buf);
240  }
241 
242  tmp = stat_points - stat_points_used;
243  snprintf(buf, sizeof(buf), "%d", tmp);
244  gtk_label_set_text(GTK_LABEL(label_cc_unspent), buf);
245 
246  /* Display some warning messages - we could try and display all the
247  * different warnings at once, but one at a time should be good enough.
248  * perhaps the done button should be inactivated if there are errors.
249  */
250  if (tmp < 0) {
251  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
252  "You have used more than your allotted total attribute points");
253  } else if (negative_stat) {
254  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
255  "Attributes less than 1 are not allowed - adjust your selections before finishing");
256 
257  } else {
258  gtk_label_set_text(GTK_LABEL(label_cc_status_update), "Waiting for player selections");
259  }
260 
261 
262 }
263 
265 {
266  const gchar *char_name;
267  int i, on_choice, tmp;
268  SockList sl;
269  char buf[MAX_BUF];
270  guint8 sockbuf[MAX_BUF];
271 
272  char_name = gtk_entry_get_text(GTK_ENTRY(entry_new_character_name));
273 
274  SockList_Init(&sl, sockbuf);
275  SockList_AddString(&sl, "createplayer ");
276  SockList_AddChar(&sl, strlen(char_name));
277  SockList_AddString(&sl, char_name);
278  SockList_AddChar(&sl, strlen(account_password));
279 
281 
282  /* The client should never be popping up the new client creation
283  * window unless the server supports loginmethod >= 2, so
284  * we do not have any check here for that, but these
285  * attributes are only valid for loginmethod >= 2
286  */
287  i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_rs));
288  snprintf(buf, MAX_BUF, "race %s", races[i].arch_name);
289  SockList_AddChar(&sl, strlen(buf)+1);
290  SockList_AddString(&sl, buf);
291  SockList_AddChar(&sl, 0);
292 
293  /* From a practical standpoint, the server should never send
294  * race/class choices unless it also supports the receipt of
295  * those. So no special checks are needed here.
296  */
297  for (on_choice = 0; on_choice < races[i].num_rc_choice; on_choice++) {
298  int j;
299 
300  j = gtk_combo_box_get_active(GTK_COMBO_BOX(opt_combobox[on_choice + RACE_OPT_START]));
301 
302  snprintf(buf, MAX_BUF, "choice %s %s", races[i].rc_choice[on_choice].choice_name,
303  races[i].rc_choice[on_choice].value_arch[j]);
304 
305  SockList_AddChar(&sl, strlen(buf)+1);
306  SockList_AddString(&sl, buf);
307  SockList_AddChar(&sl, 0);
308  }
309 
310 
311  i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_cs));
312  snprintf(buf, MAX_BUF, "class %s", classes[i].arch_name);
313  SockList_AddChar(&sl, strlen(buf)+1);
314  SockList_AddString(&sl, buf);
315  SockList_AddChar(&sl, 0);
316 
317  for (on_choice = 0; on_choice < classes[i].num_rc_choice; on_choice++) {
318  int j;
319 
320  j = gtk_combo_box_get_active(GTK_COMBO_BOX(opt_combobox[on_choice + CLASS_OPT_START]));
321 
322  snprintf(buf, MAX_BUF, "choice %s %s", classes[i].rc_choice[on_choice].choice_name,
323  classes[i].rc_choice[on_choice].value_arch[j]);
324 
325  SockList_AddChar(&sl, strlen(buf)+1);
326  SockList_AddString(&sl, buf);
327  SockList_AddChar(&sl, 0);
328  }
329 
330  /* Its possible that the server does not provide a choice of
331  * starting maps - if that is the case, then we will never
332  * display the starting map window. So check for that here.
333  */
334  if (starting_map_number) {
335  i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_starting_map));
336  if (i != -1) {
337  snprintf(buf, MAX_BUF, "starting_map %s", starting_map_info[i].arch_name);
338  SockList_AddChar(&sl, strlen(buf)+1);
339  SockList_AddString(&sl, buf);
340  SockList_AddChar(&sl, 0);
341  }
342  }
343 
344  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
345  tmp = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i]));
346  snprintf(buf, MAX_BUF, "%s %d", stat_mapping[i].widget_suffix, tmp);
347  SockList_AddChar(&sl, strlen(buf)+1);
348  SockList_AddString(&sl, buf);
349  SockList_AddChar(&sl, 0);
350  }
351 
352  SockList_Send(&sl, csocket.fd);
353 
354  keybindings_init(char_name);
355 }
356 
357 
365 void
366 on_button_cc_cancel(GtkButton *button, gpointer user_data)
367 {
370 }
371 
372 
380 void
381 on_button_choose_starting_map(GtkButton *button, gpointer user_data)
382 {
384 }
385 
386 
397 static int character_data_ok()
398 {
399  const gchar *char_name;
400  int i, stat_points_used=0, tmp[NUM_NEW_CHAR_STATS], negative_stat=0;
401 
402  char_name = gtk_entry_get_text(GTK_ENTRY(entry_new_character_name));
403 
404  if (!char_name || char_name[0] == 0) {
405  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
406  "You must enter a character name");
408  return FALSE;
409  }
410 
411  /* We get the stat values here - we also total up how many
412  * points are used. If everything checks out, we will
413  * need these stat values later.
414  */
415  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
416  tmp[i] = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i]));
417  stat_points_used += tmp[i];
418  }
419 
420  if (stat_points_used > stat_points) {
421  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
422  "You have used more than your allotted total attribute points");
424  return FALSE;
425  }
426  /* negative_stat is a global to this file. update_all_stats()
427  * sets it/clears it - rather than doing that work again, just
428  * re-use that value.
429  */
430  if (negative_stat) {
431  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
432  "Attributes less than 1 are not allowed - adjust your selections before finishing");
434  return FALSE;
435  }
436 
437  /* No message is normally displayed for this - the player is
438  * always going to get this case when starting out, but if
439  * they hit done, we want to warn them that they have points
440  * left to spend, since at present time there is no way to spend
441  * these points later.
442  */
443  if (stat_points_used < stat_points) {
444  GtkWidget *dialog;
445  int result;
446 
447  dialog =
448  gtk_message_dialog_new(GTK_WINDOW(create_character_window),
449  GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
450  GTK_BUTTONS_YES_NO,
451  "%s\n%s\n%s",
452  "You have not spent all your attribute points.",
453  "You will be unable to spend these later.",
454  "Create character anyways?");
455  result = gtk_dialog_run(GTK_DIALOG(dialog));
456  gtk_widget_destroy(dialog);
457  if (result == GTK_RESPONSE_NO) {
459  return FALSE;
460  }
461  /* Otherwise, fall through below */
462  }
463 
464  /* Check to see starting map - note that start_map_number could
465  * be zero, which means that the server does not have a choice,
466  * and thus we don't have to get anything from the player.
467  * Is throwing a dialog box up here perhaps overkill?
468  */
469  i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_starting_map));
470  if (starting_map_number && i == -1) {
471  GtkWidget *dialog;
472 
474  dialog =
475  gtk_message_dialog_new(GTK_WINDOW(choose_starting_map_window),
476  GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING,
477  GTK_BUTTONS_OK,
478  "You must choose a starting map before you can start playing");
479  gtk_dialog_run(GTK_DIALOG(dialog));
480  gtk_widget_destroy(dialog);
481  return FALSE;
482  }
483  /* Everything checks out OK */
484  return TRUE;
485 }
486 
496 void
497 on_button_cc_done(GtkButton *button, gpointer user_data)
498 {
499  if (character_data_ok()) {
500  /* If we get here, everything checks out - now we have to
501  * send the data to the server.
502  */
503  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
504  "Sending new character information to server");
507  }
508 }
509 
514 void
515 on_spinbutton_cc (GtkSpinButton *spinbutton, gpointer user_data)
516 {
517 
519 }
520 
533 void
534 on_combobox_rcs_changed(GtkComboBox *box, gpointer user_data)
535 {
536  int active_entry, i, opt_start;
537  GtkWidget **label_stat;
538  Race_Class_Info *rc;
539  char buf[256];
540 
541  active_entry = gtk_combo_box_get_active(box);
542 
543  /* I don't think this can ever happen - if we get here,
544  * something should be active.
545  */
546  if (active_entry == -1) {
547  return;
548  }
549 
550  /* since we are using a list store, and we are not re-arranging the order,
551  * the entry number should match our array number.
552  */
553  if (box == GTK_COMBO_BOX(combobox_cs)) {
554  gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_cs_desc)),
555  classes[active_entry].description,
556  strlen(classes[active_entry].description));
557  gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview_cs_desc),
558  text_mark_cs, 0.0, TRUE, 0.0, 0.0);
559 
560  rc = &classes[active_entry];
561  label_stat = label_cs;
562  opt_start = CLASS_OPT_START;
563 
564  } else if (box == GTK_COMBO_BOX(combobox_rs)) {
565  gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_rs_desc)),
566  races[active_entry].description,
567  strlen(races[active_entry].description));
568  gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview_rs_desc),
569  text_mark_rs, 0.0, TRUE, 0.0, 0.0);
570  rc = &races[active_entry];
571  label_stat = label_rs;
572  opt_start = RACE_OPT_START;
573  } else {
574  LOG(LOG_ERROR, "gtk-v2/src/create_char.c:on_combobox_rcs_changed",
575  "Passed in combobox does not match any combobox");
576  return;
577  }
578 
579  for (i=0; i < rc->num_rc_choice; i++) {
580  int j;
581  GtkTreeModel *store;
582  GtkTreeIter iter;
583 
584  if (i == (NUM_OPT_FIELDS/2)) {
585  LOG(LOG_ERROR, "gtk-v2/src/create_char.c:on_combobox_rcs_changed",
586  "Number of racial option exceeds allocated amount (%d > %d)",
587  i, NUM_OPT_FIELDS/2);
588  break;
589  }
590  /* Set up the races combobox */
591  store = gtk_combo_box_get_model(GTK_COMBO_BOX(opt_combobox[i + opt_start]));
592  gtk_list_store_clear(GTK_LIST_STORE(store));
593 
594  for (j=0; j<rc->rc_choice[i].num_values; j++) {
595  gtk_list_store_append(GTK_LIST_STORE(store), &iter);
596  gtk_list_store_set(GTK_LIST_STORE(store), &iter, 0, rc->rc_choice[i].value_desc[j], -1);
597  }
598  gtk_combo_box_set_active(GTK_COMBO_BOX(opt_combobox[i+opt_start]), 0);
599 
600  gtk_label_set_text(GTK_LABEL(opt_label[i + opt_start]),
601  rc->rc_choice[i].choice_desc);
602  gtk_widget_show(opt_label[i+opt_start]);
603  gtk_widget_show(opt_combobox[i+opt_start]);
604  /* No signals are connected - the value of the combo
605  * box will be when we send the data to the server.
606  */
607  }
608 
609  /* Hide any unused fields */
610  for ( ; i < (NUM_OPT_FIELDS/2); i++) {
611  gtk_widget_hide(opt_label[i + opt_start]);
612  gtk_widget_hide(opt_combobox[i + opt_start]);
613  }
614 
615 
616  /* label_stat now points at the array of stats to update, and rc points
617  * at either the race or class to get values from.
618  */
619  for (i=0; i < NUM_NEW_CHAR_STATS; i++) {
620  snprintf(buf, sizeof(buf), "%+d", rc->stat_adj[stat_mapping[i].rc_offset]);
621  gtk_label_set_text(GTK_LABEL(label_stat[i]), buf);
622  }
624 }
625 
634 {
635  char buf[256];
636  GtkListStore *store;
637  GtkTreeIter iter;
638  GtkCellRenderer *renderer;
639  int i;
640 
641  /* We could do the update as we get the data, but it shouldn't take
642  * too long to get all the data, and simpler to just do one update
643  */
645  return;
646  }
647 
648  gtk_label_set_text(GTK_LABEL(label_cc_status_update), "Waiting for player selections");
649 
650  snprintf(buf, sizeof(buf), "%d", stat_points);
651  gtk_label_set_text(GTK_LABEL(label_cc_unspent), buf);
652 
653  /* Set up the races combobox */
654  store = gtk_list_store_new(1, G_TYPE_STRING);
655 
656  for (i=0; i<num_races; i++) {
657  gtk_list_store_append(store, &iter);
658  gtk_list_store_set(store, &iter, 0, races[i].public_name, -1);
659  }
660 
661  gtk_combo_box_set_model(GTK_COMBO_BOX(combobox_rs), GTK_TREE_MODEL(store));
662  gtk_cell_layout_clear(GTK_CELL_LAYOUT(combobox_rs));
663 
664  renderer = gtk_cell_renderer_text_new();
665  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox_rs), renderer, FALSE);
666  gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox_rs), renderer,
667  "text", 0, NULL);
668 
669  g_signal_connect ((gpointer) combobox_rs, "changed",
670  G_CALLBACK (on_combobox_rcs_changed), NULL);
671 
672  gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_rs), 0);
673  /* Set up the classes combobox */
674  store = gtk_list_store_new(1, G_TYPE_STRING);
675 
676  for (i=0; i<num_classes; i++) {
677  gtk_list_store_append(store, &iter);
678  gtk_list_store_set(store, &iter, 0, classes[i].public_name, -1);
679 
680  }
681 
682  gtk_combo_box_set_model(GTK_COMBO_BOX(combobox_cs), GTK_TREE_MODEL(store));
683  gtk_cell_layout_clear(GTK_CELL_LAYOUT(combobox_cs));
684 
685  renderer = gtk_cell_renderer_text_new();
686  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox_cs), renderer, FALSE);
687  gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox_cs), renderer,
688  "text", 0, NULL);
689  g_signal_connect ((gpointer) combobox_cs, "changed",
690  G_CALLBACK (on_combobox_rcs_changed), NULL);
691  gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_cs), 0);
692 
693  /* Reset to minimum/maximum values for the spinbutton.
694  */
695  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
696  /* Reset any stat values - just makes more sense, but also
697  * possible that starting value set in the layout file may
698  * be outside of this range.
699  */
700  gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_cc[i]), stat_min);
701  gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinbutton_cc[i]), stat_min,
702  stat_maximum);
703  }
704 
706 }
707 
708 /******************************************************************************
709  * This section is related to the starting map window.
710  *****************************************************************************/
711 
720 void
721 on_button_csm_cancel(GtkButton *button, gpointer user_data)
722 {
724 }
725 
726 
727 void
728 on_combobox_starting_map_changed(GtkComboBox *box, gpointer user_data)
729 {
730  int active_entry;
731 
732  active_entry = gtk_combo_box_get_active(box);
733 
734  /* I don't think this can ever happen - if we get here,
735  * something should be active.
736  */
737  if (active_entry == -1) {
738  return;
739  }
740 
741  /* since we are using a list store, and we are not re-arranging the order,
742  * the entry number should match our array number.
743  */
744  gtk_text_buffer_set_text(textbuf_starting_map, "", 0);
745  add_marked_text_to_pane(&create_char_pane[STARTING_MAP_PANE],
746  starting_map_info[active_entry].description, 0, 0, 0);
747 
748 }
754 {
755  GtkListStore *store;
756  GtkTreeIter iter;
757  GtkCellRenderer *renderer;
758  int i;
759 
760  /* Set up the races combobox */
761  store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING);
762 
763  for (i=0; i<=starting_map_number; i++) {
764  gtk_list_store_append(store, &iter);
765  gtk_list_store_set(store, &iter, 0, starting_map_info[i].public_name, -1);
766  gtk_list_store_set(store, &iter, 1, starting_map_info[i].arch_name, -1);
767  }
768 
769  gtk_combo_box_set_model(GTK_COMBO_BOX(combobox_starting_map), GTK_TREE_MODEL(store));
770  gtk_cell_layout_clear(GTK_CELL_LAYOUT(combobox_starting_map));
771 
772  renderer = gtk_cell_renderer_text_new();
773  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox_starting_map), renderer, FALSE);
774  gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox_starting_map), renderer,
775  "text", 0, NULL);
776 
777  g_signal_connect ((gpointer) combobox_starting_map, "changed",
778  G_CALLBACK (on_combobox_starting_map_changed), NULL);
779 
780  gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_starting_map), -1);
781 
782  /* If we get called, we presume we have data to show, so activate button */
783  gtk_widget_show(button_choose_starting_map);
784 
785 }
786 
787 
792  char tmpbuf[80];
793  int i;
794  GtkTextIter iter;
795  GtkCellRenderer *renderer;
796 
797  if (has_init) {
798  return;
799  }
800  has_init=1;
801 
802  create_character_window = GTK_WIDGET(gtk_builder_get_object(dialog_xml, "create_character_window"));
803  gtk_window_set_transient_for(GTK_WINDOW(create_character_window), GTK_WINDOW(window_root));
804 
805 
806  button_cc_done = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_cc_done"));
807  button_cc_cancel = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_cc_cancel"));
808  button_choose_starting_map = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_choose_starting_map"));
809  label_cc_status_update = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"label_cc_status_update"));
810  label_cc_desc = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"label_cc_desc"));
811  label_cc_unspent = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"label_cc_unspent"));
812  combobox_rs = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"combobox_rs"));
813  combobox_cs = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"combobox_cs"));
814  entry_new_character_name = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"cc_entry_new_character_name"));
815 
816  textview_rs_desc = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"textview_rs_desc"));
817  text_mark_rs = gtk_text_mark_new("rs_start", TRUE);
818  gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_rs_desc)),
819  &iter);
820  gtk_text_buffer_add_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_rs_desc)),
821  text_mark_rs, &iter);
822 
823  textview_cs_desc = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"textview_cs_desc"));
824  text_mark_cs = gtk_text_mark_new("cs_start", TRUE);
825  gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_cs_desc)),
826  &iter);
827  gtk_text_buffer_add_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_cs_desc)),
828  text_mark_cs, &iter);
829 
830  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
831  snprintf(tmpbuf, 80, "spinbutton_cc_%s", stat_mapping[i].widget_suffix);
832  spinbutton_cc[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
833 
834  g_signal_connect ((gpointer) spinbutton_cc[i], "value-changed",
835  G_CALLBACK (on_spinbutton_cc), NULL);
836 
837  snprintf(tmpbuf, 80, "label_rs_%s", stat_mapping[i].widget_suffix);
838  label_rs[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
839 
840  snprintf(tmpbuf, 80, "label_cs_%s", stat_mapping[i].widget_suffix);
841  label_cs[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
842 
843  snprintf(tmpbuf, 80, "label_tot_%s", stat_mapping[i].widget_suffix);
844  label_tot[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
845  }
846 
847  /* Note that in the layout file, the numbering starts at 1 */
848  for (i=0; i < NUM_OPT_FIELDS; i++ ) {
849  GtkListStore *store;
850 
851  snprintf(tmpbuf, 80, "opt_label%d", i+1);
852  opt_label[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
853 
854  snprintf(tmpbuf, 80, "opt_combobox%d", i+1);
855  opt_combobox[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
856 
857  gtk_cell_layout_clear(GTK_CELL_LAYOUT(opt_combobox[i]));
858  renderer = gtk_cell_renderer_text_new();
859  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(opt_combobox[i]), renderer, FALSE);
860  gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(opt_combobox[i]), renderer,
861  "text", 0, NULL);
862  store = gtk_list_store_new(1, G_TYPE_STRING);
863  gtk_combo_box_set_model(GTK_COMBO_BOX(opt_combobox[i]), GTK_TREE_MODEL(store));
864 
865  }
866 
867  g_signal_connect ((gpointer) button_cc_done, "clicked",
868  G_CALLBACK (on_button_cc_done), NULL);
869  g_signal_connect ((gpointer) button_cc_cancel, "clicked",
870  G_CALLBACK (on_button_cc_cancel), NULL);
871  g_signal_connect ((gpointer) button_choose_starting_map, "clicked",
872  G_CALLBACK (on_button_choose_starting_map), NULL);
873 
874  /* For starting map window */
875  choose_starting_map_window = GTK_WIDGET(gtk_builder_get_object(dialog_xml, "choose_starting_map_window"));
876 
877  gtk_window_set_transient_for(GTK_WINDOW(choose_starting_map_window), GTK_WINDOW(window_root));
878 
879  create_char_pane[STARTING_MAP_PANE].textview = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"textview_starting_map"));
880  textbuf_starting_map = gtk_text_view_get_buffer(
881  GTK_TEXT_VIEW(create_char_pane[STARTING_MAP_PANE].textview));
883  add_style_to_textbuffer(&create_char_pane[STARTING_MAP_PANE], NULL);
884 
885  gtk_text_buffer_get_end_iter(create_char_pane[STARTING_MAP_PANE].textbuffer, &iter);
886  create_char_pane[STARTING_MAP_PANE].textmark = gtk_text_buffer_create_mark(
887  create_char_pane[STARTING_MAP_PANE].textbuffer, NULL, &iter, FALSE);
888 
889  button_csm_done = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_csm_done"));
890  button_csm_cancel = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_csm_cancel"));
891  combobox_starting_map = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"combobox_starting_map"));
892 
893  g_signal_connect ((gpointer) button_csm_done, "clicked",
894  G_CALLBACK (on_button_cc_done), NULL);
895  g_signal_connect ((gpointer) button_csm_cancel, "clicked",
896  G_CALLBACK (on_button_csm_cancel), NULL);
897 
898 }
#define STARTING_MAP_PANE
Definition: create_char.c:68
GtkWidget * textview
Definition: info.h:57
void init_create_character_window()
Definition: create_char.c:791
GSocketConnection * fd
Definition: client.h:120
int used_classes
Definition: commands.c:91
char * choice_desc
Definition: client.h:596
void choose_char_window_show()
Definition: account.c:457
static GtkWidget * opt_label[NUM_OPT_FIELDS]
Definition: create_char.c:51
int num_values
Definition: client.h:597
int stat_points
Definition: commands.c:93
static GtkWidget * button_csm_done
Definition: create_char.c:61
static GtkTextMark * text_mark_cs
Definition: create_char.c:58
static void create_character_set_sensitive(int sensitive)
Definition: create_char.c:119
Race_Class_Info * races
Definition: commands.c:98
void starting_map_update_info()
Definition: create_char.c:753
void add_marked_text_to_pane(Info_Pane *pane, const char *message, int type, int subtype, int orig_color)
Definition: info.c:819
static GtkWidget * label_tot[NUM_NEW_CHAR_STATS]
Definition: create_char.c:51
int num_classes
Definition: commands.c:90
static GtkWidget * label_cs[NUM_NEW_CHAR_STATS]
Definition: create_char.c:51
void add_tags_to_textbuffer(Info_Pane *pane, GtkTextBuffer *textbuf)
Definition: info.c:372
static void send_create_player_to_server()
Definition: create_char.c:264
static GtkWidget * label_rs[NUM_NEW_CHAR_STATS]
Definition: create_char.c:51
ClientSocket csocket
Definition: client.c:69
#define NUM_NEW_CHAR_STATS
Definition: client.h:569
#define WINDOW_CHOOSE_MAP
Definition: create_char.c:73
char ** value_desc
Definition: client.h:599
char account_password[256]
Definition: account.c:64
static GtkWidget * label_cc_unspent
Definition: create_char.c:51
void on_button_csm_cancel(GtkButton *button, gpointer user_data)
Definition: create_char.c:721
static int has_init
Definition: create_char.c:66
static GtkWidget * label_cc_desc
Definition: create_char.c:51
static GtkWidget * choose_starting_map_window
Definition: create_char.c:61
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:109
void on_button_cc_done(GtkButton *button, gpointer user_data)
Definition: create_char.c:497
static GtkWidget * create_character_window
Definition: create_char.c:51
int stat_maximum
Definition: commands.c:95
GtkWidget * window_root
Definition: main.c:87
static int negative_stat
Definition: create_char.c:66
int num_rc_choice
Definition: client.h:607
static GtkWidget * textview_cs_desc
Definition: create_char.c:51
static GtkWidget * textview_rs_desc
Definition: create_char.c:51
guint8 rc_offset
Definition: client.h:580
static GtkWidget * entry_new_character_name
Definition: create_char.c:51
static GtkWidget * button_choose_starting_map
Definition: create_char.c:51
int SockList_Send(SockList *sl, GSocketConnection *c)
Definition: newsocket.c:112
static GtkWidget * button_csm_cancel
Definition: create_char.c:61
#define WINDOW_NONE
Definition: create_char.c:71
Starting_Map_Info * starting_map_info
Definition: commands.c:99
void on_combobox_starting_map_changed(GtkComboBox *box, gpointer user_data)
Definition: create_char.c:728
void on_button_cc_cancel(GtkButton *button, gpointer user_data)
Definition: create_char.c:366
int stat_min
Definition: commands.c:94
void add_style_to_textbuffer(Info_Pane *pane, GtkStyle *base_style)
Definition: info.c:426
#define WINDOW_CREATE_CHARACTER
Definition: create_char.c:72
void SockList_AddString(SockList *sl, const char *str)
Definition: newsocket.c:98
#define MAX_BUF
Definition: client.h:40
int starting_map_number
Definition: commands.c:96
GtkTextMark * textmark
Definition: info.h:60
static void show_window(int window)
Definition: create_char.c:88
static GtkWidget * label_cc_status_update
Definition: create_char.c:51
static GtkWidget * combobox_cs
Definition: create_char.c:51
int num_races
Definition: commands.c:87
struct RC_Choice * rc_choice
Definition: client.h:608
static int character_data_ok()
Definition: create_char.c:397
void on_combobox_rcs_changed(GtkComboBox *box, gpointer user_data)
Definition: create_char.c:534
struct Stat_Mapping stat_mapping[NUM_NEW_CHAR_STATS]
Definition: commands.c:118
void create_character_window_show()
Definition: create_char.c:153
Warning that something definitely didn&#39;t work.
Definition: client.h:444
static GtkWidget * combobox_rs
Definition: create_char.c:51
void SockList_AddChar(SockList *sl, char c)
Definition: newsocket.c:43
Definition: info.h:55
GtkTextBuffer * textbuf_starting_map
Definition: create_char.c:64
void new_char_window_update_info()
Definition: create_char.c:633
static GtkTextMark * text_mark_rs
Definition: create_char.c:58
#define NUM_OPT_FIELDS
Definition: create_char.c:43
#define CLASS_OPT_START
Definition: create_char.c:45
void on_spinbutton_cc(GtkSpinButton *spinbutton, gpointer user_data)
Definition: create_char.c:515
static GtkWidget * opt_combobox[NUM_OPT_FIELDS]
Definition: create_char.c:51
void create_character_window_hide()
Definition: create_char.c:196
gint8 stat_adj[NUM_NEW_CHAR_STATS]
Definition: client.h:606
#define RACE_OPT_START
Definition: create_char.c:44
int used_races
Definition: commands.c:88
static GtkWidget * spinbutton_cc[NUM_NEW_CHAR_STATS]
Definition: create_char.c:51
void SockList_Init(SockList *sl, guint8 *buf)
Definition: newsocket.c:32
void on_button_choose_starting_map(GtkButton *button, gpointer user_data)
Definition: create_char.c:381
static void update_all_stats()
Definition: create_char.c:207
static GtkWidget * button_cc_done
Definition: create_char.c:51
static GtkWidget * combobox_starting_map
Definition: create_char.c:61
static GtkWidget * button_cc_cancel
Definition: create_char.c:51
int cs_print_string(GSocketConnection *fd, const char *str,...)
Definition: newsocket.c:245
GtkBuilder * dialog_xml
Definition: main.c:86
Info_Pane create_char_pane[1]
Definition: create_char.c:69
Race_Class_Info * classes
Definition: commands.c:98
void keybindings_init(const char *character_name)
Definition: keys.c:534