Crossfire Client, Trunk
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_choose_starting_map, sensitive);
124  gtk_widget_set_sensitive(entry_new_character_name, sensitive);
125  gtk_widget_set_sensitive(combobox_rs, sensitive);
126  gtk_widget_set_sensitive(combobox_cs, sensitive);
127  /* Note we do not change status of cancel button - let
128  * the player cancel out of the window if they want -
129  * no harm in doing so.
130  */
131 
132  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
133  gtk_widget_set_sensitive(spinbutton_cc[i], sensitive);
134  }
135 
136  /* If we do not have any starting maps, no reason to show
137  * that button to the player.
138  */
139  if (starting_map_number) {
140  gtk_widget_show(button_choose_starting_map);
141  } else {
142  gtk_widget_hide(button_choose_starting_map);
143  }
144 }
145 
153 {
154  int reset_needed = 0;
155 
156  /* If we don't have race/class/stat_point values, get them now.
157  * those values are reset if we switch between servers, so there
158  * should never be any danger of them being wrong.
159  * In theory, if one of these is true, all of them should be true
160  * because it shouldn't be possible to get in a case where we have
161  * gotten race info but not class.
162  */
163  if (!races) {
164  cs_print_string(csocket.fd, "requestinfo race_list");
165  reset_needed = 1;
166  }
167  if (!classes) {
168  cs_print_string(csocket.fd, "requestinfo class_list");
169  reset_needed = 1;
170  }
171  if (!stat_points) {
172  cs_print_string(csocket.fd, "requestinfo newcharinfo");
173  reset_needed = 1;
174  }
175  /* In this case, we are getting copies of some of the data
176  * from the server - we need to discard any data we currently
177  * have then (mainly, clear out things like the pulldown list
178  * for classes
179  */
180  if (reset_needed) {
181  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
182  "Getting race & class information from the server");
184  }
185 
186  /* This will be set true once we get all the data */
187  gtk_widget_show(create_character_window);
188 }
189 
196 {
198 }
199 
206 static void update_all_stats()
207 {
208  int i, stat_points_used=0, statval, tmp;
209  const gchar *tval;
210  char buf[MAX_BUF];
211 
212  negative_stat = 0;
213  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
214 
215  tmp = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i]));
216  stat_points_used += tmp;
217  statval = tmp;
218 
219  /* We presume the label value is correct here - it should
220  * be - this is easier than tracking down the corresponding
221  * race/class structure and getting the value there.
222  */
223  tval = gtk_label_get_text(GTK_LABEL(label_cs[i]));
224  statval += atoi(tval);
225 
226  tval = gtk_label_get_text(GTK_LABEL(label_rs[i]));
227  statval += atoi(tval);
228 
229  /* Might it be good to draw nonpositive stats in red? Rather
230  * than hardcode that, it should be a style
231  * Used to only check for negative stats, but zero is not allowed either.
232  */
233  if (statval < 1) {
234  negative_stat = 1;
235  }
236 
237  snprintf(buf, sizeof(buf), "%d", statval);
238  gtk_label_set_text(GTK_LABEL(label_tot[i]), buf);
239  }
240 
241  tmp = stat_points - stat_points_used;
242  snprintf(buf, sizeof(buf), "%d", tmp);
243  gtk_label_set_text(GTK_LABEL(label_cc_unspent), buf);
244 
245  /* Display some warning messages - we could try and display all the
246  * different warnings at once, but one at a time should be good enough.
247  * perhaps the done button should be inactivated if there are errors.
248  */
249  if (tmp < 0) {
250  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
251  "You have used more than your allotted total attribute points");
252  } else if (negative_stat) {
253  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
254  "Attributes less than 1 are not allowed - adjust your selections before finishing");
255 
256  } else {
257  gtk_label_set_text(GTK_LABEL(label_cc_status_update), "Waiting for player selections");
258  }
259 
260 
261 }
262 
264 {
265  const gchar *char_name;
266  int i, on_choice, tmp;
267  SockList sl;
268  char buf[MAX_BUF];
269  guint8 sockbuf[MAX_BUF];
270 
271  char_name = gtk_entry_get_text(GTK_ENTRY(entry_new_character_name));
272 
273  SockList_Init(&sl, sockbuf);
274  SockList_AddString(&sl, "createplayer ");
275  SockList_AddChar(&sl, strlen(char_name));
276  SockList_AddString(&sl, char_name);
277  SockList_AddChar(&sl, strlen(account_password));
278 
280 
281  /* The client should never be popping up the new client creation
282  * window unless the server supports loginmethod >= 2, so
283  * we do not have any check here for that, but these
284  * attributes are only valid for loginmethod >= 2
285  */
286  i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_rs));
287  snprintf(buf, MAX_BUF, "race %s", races[i].arch_name);
288  SockList_AddChar(&sl, strlen(buf)+1);
289  SockList_AddString(&sl, buf);
290  SockList_AddChar(&sl, 0);
291 
292  /* From a practical standpoint, the server should never send
293  * race/class choices unless it also supports the receipt of
294  * those. So no special checks are needed here.
295  */
296  for (on_choice = 0; on_choice < races[i].num_rc_choice; on_choice++) {
297  int j;
298 
299  j = gtk_combo_box_get_active(GTK_COMBO_BOX(opt_combobox[on_choice + RACE_OPT_START]));
300 
301  snprintf(buf, MAX_BUF, "choice %s %s", races[i].rc_choice[on_choice].choice_name,
302  races[i].rc_choice[on_choice].value_arch[j]);
303 
304  SockList_AddChar(&sl, strlen(buf)+1);
305  SockList_AddString(&sl, buf);
306  SockList_AddChar(&sl, 0);
307  }
308 
309 
310  i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_cs));
311  snprintf(buf, MAX_BUF, "class %s", classes[i].arch_name);
312  SockList_AddChar(&sl, strlen(buf)+1);
313  SockList_AddString(&sl, buf);
314  SockList_AddChar(&sl, 0);
315 
316  for (on_choice = 0; on_choice < classes[i].num_rc_choice; on_choice++) {
317  int j;
318 
319  j = gtk_combo_box_get_active(GTK_COMBO_BOX(opt_combobox[on_choice + CLASS_OPT_START]));
320 
321  snprintf(buf, MAX_BUF, "choice %s %s", classes[i].rc_choice[on_choice].choice_name,
322  classes[i].rc_choice[on_choice].value_arch[j]);
323 
324  SockList_AddChar(&sl, strlen(buf)+1);
325  SockList_AddString(&sl, buf);
326  SockList_AddChar(&sl, 0);
327  }
328 
329  /* Its possible that the server does not provide a choice of
330  * starting maps - if that is the case, then we will never
331  * display the starting map window. So check for that here.
332  */
333  if (starting_map_number) {
334  i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_starting_map));
335  if (i != -1) {
336  snprintf(buf, MAX_BUF, "starting_map %s", starting_map_info[i].arch_name);
337  SockList_AddChar(&sl, strlen(buf)+1);
338  SockList_AddString(&sl, buf);
339  SockList_AddChar(&sl, 0);
340  }
341  }
342 
343  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
344  tmp = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i]));
345  snprintf(buf, MAX_BUF, "%s %d", stat_mapping[i].widget_suffix, tmp);
346  SockList_AddChar(&sl, strlen(buf)+1);
347  SockList_AddString(&sl, buf);
348  SockList_AddChar(&sl, 0);
349  }
350 
351  SockList_Send(&sl, csocket.fd);
352 
353  keybindings_init(char_name);
354 }
355 
356 
364 void
365 on_button_cc_cancel(GtkButton *button, gpointer user_data)
366 {
369 }
370 
371 
379 void
380 on_button_choose_starting_map(GtkButton *button, gpointer user_data)
381 {
383 }
384 
385 
396 static int character_data_ok()
397 {
398  const gchar *char_name;
399  int i, stat_points_used=0, tmp[NUM_NEW_CHAR_STATS], negative_stat=0;
400 
401  char_name = gtk_entry_get_text(GTK_ENTRY(entry_new_character_name));
402 
403  if (!char_name || char_name[0] == 0) {
404  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
405  "You must enter a character name");
407  return FALSE;
408  }
409 
410  /* We get the stat values here - we also total up how many
411  * points are used. If everything checks out, we will
412  * need these stat values later.
413  */
414  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
415  tmp[i] = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i]));
416  stat_points_used += tmp[i];
417  }
418 
419  if (stat_points_used > stat_points) {
420  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
421  "You have used more than your allotted total attribute points");
423  return FALSE;
424  }
425  /* negative_stat is a global to this file. update_all_stats()
426  * sets it/clears it - rather than doing that work again, just
427  * re-use that value.
428  */
429  if (negative_stat) {
430  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
431  "Attributes less than 1 are not allowed - adjust your selections before finishing");
433  return FALSE;
434  }
435 
436  /* No message is normally displayed for this - the player is
437  * always going to get this case when starting out, but if
438  * they hit done, we want to warn them that they have points
439  * left to spend, since at present time there is no way to spend
440  * these points later.
441  */
442  if (stat_points_used < stat_points) {
443  GtkWidget *dialog;
444  int result;
445 
446  dialog =
447  gtk_message_dialog_new(GTK_WINDOW(create_character_window),
448  GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION,
449  GTK_BUTTONS_YES_NO,
450  "%s\n%s\n%s",
451  "You have not spent all your attribute points.",
452  "You will be unable to spend these later.",
453  "Create character anyways?");
454  result = gtk_dialog_run(GTK_DIALOG(dialog));
455  gtk_widget_destroy(dialog);
456  if (result == GTK_RESPONSE_NO) {
458  return FALSE;
459  }
460  /* Otherwise, fall through below */
461  }
462 
463  /* Check to see starting map - note that start_map_number could
464  * be zero, which means that the server does not have a choice,
465  * and thus we don't have to get anything from the player.
466  * Is throwing a dialog box up here perhaps overkill?
467  */
468  i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_starting_map));
469  if (starting_map_number && i == -1) {
470  GtkWidget *dialog;
471 
473  dialog =
474  gtk_message_dialog_new(GTK_WINDOW(choose_starting_map_window),
475  GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING,
476  GTK_BUTTONS_OK,
477  "You must choose a starting map before you can start playing");
478  gtk_dialog_run(GTK_DIALOG(dialog));
479  gtk_widget_destroy(dialog);
480  return FALSE;
481  }
482  /* Everything checks out OK */
483  return TRUE;
484 }
485 
495 void
496 on_button_cc_done(GtkButton *button, gpointer user_data)
497 {
498  if (character_data_ok()) {
499  /* If we get here, everything checks out - now we have to
500  * send the data to the server.
501  */
502  gtk_label_set_text(GTK_LABEL(label_cc_status_update),
503  "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);
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(connect_window));
804 
805 
806  button_cc_cancel = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_cc_cancel"));
807  button_choose_starting_map = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_choose_starting_map"));
808  label_cc_status_update = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"label_cc_status_update"));
809  label_cc_desc = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"label_cc_desc"));
810  label_cc_unspent = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"label_cc_unspent"));
811  combobox_rs = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"combobox_rs"));
812  combobox_cs = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"combobox_cs"));
813  entry_new_character_name = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"cc_entry_new_character_name"));
814 
815  textview_rs_desc = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"textview_rs_desc"));
816  text_mark_rs = gtk_text_mark_new("rs_start", TRUE);
817  gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_rs_desc)),
818  &iter);
819  gtk_text_buffer_add_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_rs_desc)),
820  text_mark_rs, &iter);
821 
822  textview_cs_desc = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"textview_cs_desc"));
823  text_mark_cs = gtk_text_mark_new("cs_start", TRUE);
824  gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_cs_desc)),
825  &iter);
826  gtk_text_buffer_add_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_cs_desc)),
827  text_mark_cs, &iter);
828 
829  for (i=0; i<NUM_NEW_CHAR_STATS; i++) {
830  snprintf(tmpbuf, 80, "spinbutton_cc_%s", stat_mapping[i].widget_suffix);
831  spinbutton_cc[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
832 
833  g_signal_connect ((gpointer) spinbutton_cc[i], "value-changed",
834  G_CALLBACK (on_spinbutton_cc), NULL);
835 
836  snprintf(tmpbuf, 80, "label_rs_%s", stat_mapping[i].widget_suffix);
837  label_rs[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
838 
839  snprintf(tmpbuf, 80, "label_cs_%s", stat_mapping[i].widget_suffix);
840  label_cs[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
841 
842  snprintf(tmpbuf, 80, "label_tot_%s", stat_mapping[i].widget_suffix);
843  label_tot[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
844  }
845 
846  /* Note that in the layout file, the numbering starts at 1 */
847  for (i=0; i < NUM_OPT_FIELDS; i++ ) {
848  GtkListStore *store;
849 
850  snprintf(tmpbuf, 80, "opt_label%d", i+1);
851  opt_label[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
852 
853  snprintf(tmpbuf, 80, "opt_combobox%d", i+1);
854  opt_combobox[i] = GTK_WIDGET(gtk_builder_get_object(dialog_xml, tmpbuf));
855 
856  gtk_cell_layout_clear(GTK_CELL_LAYOUT(opt_combobox[i]));
857  renderer = gtk_cell_renderer_text_new();
858  gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(opt_combobox[i]), renderer, FALSE);
859  gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(opt_combobox[i]), renderer,
860  "text", 0, NULL);
861  store = gtk_list_store_new(1, G_TYPE_STRING);
862  gtk_combo_box_set_model(GTK_COMBO_BOX(opt_combobox[i]), GTK_TREE_MODEL(store));
863 
864  }
865 
866  g_signal_connect ((gpointer) button_cc_cancel, "clicked",
867  G_CALLBACK (on_button_cc_cancel), NULL);
868  g_signal_connect ((gpointer) button_choose_starting_map, "clicked",
869  G_CALLBACK (on_button_choose_starting_map), NULL);
870 
871  /* For starting map window */
872  choose_starting_map_window = GTK_WIDGET(gtk_builder_get_object(dialog_xml, "choose_starting_map_window"));
873 
874  gtk_window_set_transient_for(GTK_WINDOW(choose_starting_map_window), GTK_WINDOW(window_root));
875 
876  create_char_pane[STARTING_MAP_PANE].textview = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"textview_starting_map"));
877  textbuf_starting_map = gtk_text_view_get_buffer(
878  GTK_TEXT_VIEW(create_char_pane[STARTING_MAP_PANE].textview));
881 
882  gtk_text_buffer_get_end_iter(create_char_pane[STARTING_MAP_PANE].textbuffer, &iter);
883  create_char_pane[STARTING_MAP_PANE].textmark = gtk_text_buffer_create_mark(
884  create_char_pane[STARTING_MAP_PANE].textbuffer, NULL, &iter, FALSE);
885 
886  button_csm_done = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_csm_done"));
887  button_csm_cancel = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"button_csm_cancel"));
888  combobox_starting_map = GTK_WIDGET(gtk_builder_get_object(dialog_xml,"combobox_starting_map"));
889 
890  g_signal_connect ((gpointer) button_csm_done, "clicked",
891  G_CALLBACK (on_button_cc_done), NULL);
892  g_signal_connect ((gpointer) button_csm_cancel, "clicked",
893  G_CALLBACK (on_button_csm_cancel), NULL);
894 
895 }
show_window
static void show_window(int window)
Definition: create_char.c:88
on_combobox_rcs_changed
void on_combobox_rcs_changed(GtkComboBox *box, gpointer user_data)
Definition: create_char.c:534
on_button_cc_done
void on_button_cc_done(GtkButton *button, gpointer user_data)
Definition: create_char.c:496
create_character_window
static GtkWidget * create_character_window
Definition: create_char.c:54
choose_char_window_show
void choose_char_window_show()
Definition: account.c:436
WINDOW_NONE
#define WINDOW_NONE
Definition: create_char.c:71
on_combobox_starting_map_changed
void on_combobox_starting_map_changed(GtkComboBox *box, gpointer user_data)
Definition: create_char.c:728
num_classes
int num_classes
Definition: client.h:547
character_data_ok
static int character_data_ok()
Definition: create_char.c:396
metaserver.h
SockList_Init
void SockList_Init(SockList *sl, guint8 *buf)
Definition: newsocket.c:32
Info_Pane::textview
GtkWidget * textview
Definition: info.h:57
button_choose_starting_map
static GtkWidget * button_choose_starting_map
Definition: create_char.c:55
races
Race_Class_Info * races
Definition: commands.c:98
keybindings_init
void keybindings_init(const char *character_name)
Definition: keys.c:532
used_classes
int used_classes
Definition: client.h:547
ClientSocket::fd
GSocketConnection * fd
Definition: client.h:124
RACE_OPT_START
#define RACE_OPT_START
Definition: create_char.c:44
used_races
int used_races
Definition: client.h:547
RC_Choice::value_desc
char ** value_desc
Definition: client.h:590
CLASS_OPT_START
#define CLASS_OPT_START
Definition: create_char.c:45
text_mark_rs
static GtkTextMark * text_mark_rs
Definition: create_char.c:58
RC_Choice::choice_desc
char * choice_desc
Definition: client.h:587
NUM_OPT_FIELDS
#define NUM_OPT_FIELDS
Definition: create_char.c:43
SockList_Send
int SockList_Send(SockList *sl, GSocketConnection *c)
Definition: newsocket.c:112
Stat_Mapping::rc_offset
guint8 rc_offset
Definition: client.h:571
create_character_window_hide
void create_character_window_hide()
Definition: create_char.c:195
button_cc_cancel
static GtkWidget * button_cc_cancel
Definition: create_char.c:54
SockList_AddChar
void SockList_AddChar(SockList *sl, char c)
Definition: newsocket.c:43
RC_Choice::num_values
int num_values
Definition: client.h:588
account_password
char account_password[256]
Definition: account.c:58
create_character_window_show
void create_character_window_show()
Definition: create_char.c:152
combobox_cs
static GtkWidget * combobox_cs
Definition: create_char.c:55
new_char_window_update_info
void new_char_window_update_info()
Definition: create_char.c:633
spinbutton_cc
static GtkWidget * spinbutton_cc[NUM_NEW_CHAR_STATS]
Definition: create_char.c:51
on_spinbutton_cc
void on_spinbutton_cc(GtkSpinButton *spinbutton, gpointer user_data)
Definition: create_char.c:515
combobox_rs
static GtkWidget * combobox_rs
Definition: create_char.c:54
textbuf_starting_map
GtkTextBuffer * textbuf_starting_map
Definition: create_char.c:64
on_button_choose_starting_map
void on_button_choose_starting_map(GtkButton *button, gpointer user_data)
Definition: create_char.c:380
update_all_stats
static void update_all_stats()
Definition: create_char.c:206
starting_map_info
Starting_Map_Info * starting_map_info
Definition: commands.c:99
NUM_NEW_CHAR_STATS
#define NUM_NEW_CHAR_STATS
Definition: client.h:560
stat_min
int stat_min
Definition: client.h:548
combobox_starting_map
static GtkWidget * combobox_starting_map
Definition: create_char.c:62
opt_combobox
static GtkWidget * opt_combobox[NUM_OPT_FIELDS]
Definition: create_char.c:56
MAX_BUF
#define MAX_BUF
Definition: client.h:40
Race_Class_Info::rc_choice
struct RC_Choice * rc_choice
Definition: client.h:599
SockList_AddString
void SockList_AddString(SockList *sl, const char *str)
Definition: newsocket.c:98
STARTING_MAP_PANE
#define STARTING_MAP_PANE
Definition: create_char.c:68
gtk2proto.h
text_mark_cs
static GtkTextMark * text_mark_cs
Definition: create_char.c:58
Info_Pane::textmark
GtkTextMark * textmark
Definition: info.h:60
stat_maximum
int stat_maximum
Definition: client.h:548
LOG
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:111
cs_print_string
int cs_print_string(GSocketConnection *fd, const char *str,...)
Definition: newsocket.c:252
Race_Class_Info::num_rc_choice
int num_rc_choice
Definition: client.h:598
create_char_pane
Info_Pane create_char_pane[1]
Definition: create_char.c:69
starting_map_number
int starting_map_number
Definition: commands.c:96
csocket
ClientSocket csocket
Definition: client.c:70
Race_Class_Info::stat_adj
gint8 stat_adj[NUM_NEW_CHAR_STATS]
Definition: client.h:597
image.h
button_csm_done
static GtkWidget * button_csm_done
Definition: create_char.c:62
Race_Class_Info
Definition: client.h:593
add_tags_to_textbuffer
void add_tags_to_textbuffer(Info_Pane *pane, GtkTextBuffer *textbuf)
Definition: info.c:355
stat_mapping
struct Stat_Mapping stat_mapping[NUM_NEW_CHAR_STATS]
Definition: commands.c:118
label_cs
static GtkWidget * label_cs[NUM_NEW_CHAR_STATS]
Definition: create_char.c:52
send_create_player_to_server
static void send_create_player_to_server()
Definition: create_char.c:263
Info_Pane
Definition: info.h:55
add_style_to_textbuffer
void add_style_to_textbuffer(Info_Pane *pane, GtkStyle *base_style)
Definition: info.c:409
dialog_xml
GtkBuilder * dialog_xml
Definition: main.c:102
label_rs
static GtkWidget * label_rs[NUM_NEW_CHAR_STATS]
Definition: create_char.c:51
has_init
static int has_init
Definition: create_char.c:66
init_create_character_window
void init_create_character_window()
Definition: create_char.c:791
LOG_ERROR
@ LOG_ERROR
Warning that something definitely didn't work.
Definition: client.h:436
WINDOW_CHOOSE_MAP
#define WINDOW_CHOOSE_MAP
Definition: create_char.c:73
main.h
add_marked_text_to_pane
void add_marked_text_to_pane(Info_Pane *pane, const char *message, int type, int subtype, int orig_color)
Definition: info.c:802
on_button_csm_cancel
void on_button_csm_cancel(GtkButton *button, gpointer user_data)
Definition: create_char.c:721
opt_label
static GtkWidget * opt_label[NUM_OPT_FIELDS]
Definition: create_char.c:56
create_character_set_sensitive
static void create_character_set_sensitive(int sensitive)
Definition: create_char.c:119
textview_rs_desc
static GtkWidget * textview_rs_desc
Definition: create_char.c:53
starting_map_update_info
void starting_map_update_info()
Definition: create_char.c:753
show_main_client
void show_main_client(void)
Definition: main.c:466
label_tot
static GtkWidget * label_tot[NUM_NEW_CHAR_STATS]
Definition: create_char.c:52
num_races
int num_races
Definition: commands.c:87
stat_points
int stat_points
Definition: commands.c:93
on_button_cc_cancel
void on_button_cc_cancel(GtkButton *button, gpointer user_data)
Definition: create_char.c:365
label_cc_desc
static GtkWidget * label_cc_desc
Definition: create_char.c:53
textview_cs_desc
static GtkWidget * textview_cs_desc
Definition: create_char.c:55
window_root
GtkWidget * window_root
Definition: main.c:103
WINDOW_CREATE_CHARACTER
#define WINDOW_CREATE_CHARACTER
Definition: create_char.c:72
label_cc_status_update
static GtkWidget * label_cc_status_update
Definition: create_char.c:53
entry_new_character_name
static GtkWidget * entry_new_character_name
Definition: create_char.c:55
label_cc_unspent
static GtkWidget * label_cc_unspent
Definition: create_char.c:53
button_csm_cancel
static GtkWidget * button_csm_cancel
Definition: create_char.c:62
connect_window
GtkWidget * connect_window
Definition: main.c:103
SockList
Definition: newclient.h:651
client.h
negative_stat
static int negative_stat
Definition: create_char.c:66
classes
Race_Class_Info * classes
Definition: client.h:608
choose_starting_map_window
static GtkWidget * choose_starting_map_window
Definition: create_char.c:61