|
Crossfire Client, Trunk
R18666
|
00001 const char * const rcsid_gtk2_create_char_c = 00002 "$Id: create_char.c 12988 2010-04-27 04:04:46Z kbulgrien $"; 00003 /* 00004 Crossfire client, a client program for the crossfire program. 00005 00006 Copyright (C) 2010,2011 Mark Wedel & Crossfire Development Team 00007 00008 This program is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 2 of the License, or 00011 (at your option) any later version. 00012 00013 This program is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with this program; if not, write to the Free Software 00020 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 00021 00022 The author can be reached via e-mail to crossfire@metalforge.org 00023 */ 00024 00030 #ifdef HAVE_CONFIG_H 00031 # include <config.h> 00032 #endif 00033 00034 #include <gtk/gtk.h> 00035 #include <glade/glade.h> 00036 #include <ctype.h> 00037 00038 #include "client.h" 00039 00040 #include "image.h" 00041 00042 #include "main.h" 00043 #include "gtk2proto.h" 00044 #include "metaserver.h" 00045 00046 /* This corresponds to the number of opt_.. fields in the 00047 * create_character_window. In theory, the vbox could be resized 00048 * (or add a sub box), and adjust accordingly, 00049 * but it is unlikely that number of optional choices is going 00050 * to rapidly grow, and making it static makes some things much 00051 * easier. 00052 * Instead of having two different sets of fields named different, 00053 * we just have one set and split it in half, for race and 00054 * class. This is done so that boxes don't need to be moved 00055 * around - imagine cas where one race has options and 00056 * another doesn't, but the currently selected class does - 00057 * as player chooses different races, that race choice will 00058 * come and go, but we want the class box to remain and to keep 00059 * its same value. 00060 */ 00061 #define NUM_OPT_FIELDS 6 00062 #define RACE_OPT_START 0 00063 #define CLASS_OPT_START NUM_OPT_FIELDS/2 00064 #define RACE_OPT_END CLASS_OPT_START - 1 00065 #define CLASS_OPT_ENG NUM_OPT_FIELDS - 1 00066 00067 00068 /* These are in the create_character_window */ 00069 static GtkWidget *spinbutton_cc[NUM_NEW_CHAR_STATS], *label_rs[NUM_NEW_CHAR_STATS], 00070 *label_cs[NUM_NEW_CHAR_STATS], *label_tot[NUM_NEW_CHAR_STATS], 00071 *label_cc_unspent, *textview_rs_desc, *label_cc_desc, *label_cc_status_update, 00072 *button_cc_cancel, *button_cc_done, *create_character_window, *combobox_rs, 00073 *combobox_cs, *textview_cs_desc, *entry_new_character_name, *button_choose_starting_map, 00074 *opt_label[NUM_OPT_FIELDS], *opt_combobox[NUM_OPT_FIELDS]; 00075 00076 static GtkTextMark *text_mark_cs, *text_mark_rs; 00077 00078 /* These are in the choose starting map window */ 00079 static GtkWidget *choose_starting_map_window, 00080 *button_csm_done, *button_csm_cancel, *combobox_starting_map; 00081 00082 GtkTextBuffer *textbuf_starting_map; 00083 00084 static int has_init=0, negative_stat=0; 00085 00086 #define STARTING_MAP_PANE 0 00087 Info_Pane create_char_pane[1]; 00088 00089 #define WINDOW_NONE 0 00090 #define WINDOW_CREATE_CHARACTER 1 00091 #define WINDOW_CHOOSE_MAP 2 00092 00106 static void show_window(int window) 00107 { 00108 switch (window) { 00109 00110 case WINDOW_NONE: 00111 gtk_widget_hide(create_character_window); 00112 gtk_widget_hide(choose_starting_map_window); 00113 break; 00114 00115 case WINDOW_CREATE_CHARACTER: 00116 gtk_widget_show(create_character_window); 00117 gtk_widget_hide(choose_starting_map_window); 00118 break; 00119 00120 case WINDOW_CHOOSE_MAP: 00121 gtk_widget_hide(create_character_window); 00122 gtk_widget_show(choose_starting_map_window); 00123 break; 00124 } 00125 } 00126 00127 00137 static void create_character_set_sensitive(int sensitive) 00138 { 00139 int i; 00140 00141 gtk_widget_set_sensitive(button_cc_done, sensitive); 00142 gtk_widget_set_sensitive(button_choose_starting_map, sensitive); 00143 gtk_widget_set_sensitive(entry_new_character_name, sensitive); 00144 gtk_widget_set_sensitive(combobox_rs, sensitive); 00145 gtk_widget_set_sensitive(combobox_cs, sensitive); 00146 /* Note we do not change status of cancel button - let 00147 * the player cancel out of the window if they want - 00148 * no harm in doing so. 00149 */ 00150 00151 for (i=0; i<NUM_NEW_CHAR_STATS; i++) 00152 gtk_widget_set_sensitive(spinbutton_cc[i], sensitive); 00153 00154 /* If we do not have any starting maps, no reason to show 00155 * that button to the player. 00156 */ 00157 if (starting_map_number) 00158 gtk_widget_show(button_choose_starting_map); 00159 else 00160 gtk_widget_hide(button_choose_starting_map); 00161 } 00162 00169 void create_character_window_show() 00170 { 00171 int reset_needed = 0; 00172 00173 /* If we don't have race/class/stat_point values, get them now. 00174 * those values are reset if we switch between servers, so there 00175 * should never be any danger of them being wrong. 00176 * In theory, if one of these is true, all of them should be true 00177 * because it shouldn't be possible to get in a case where we have 00178 * gotten race info but not class. 00179 */ 00180 if (!races) { 00181 cs_print_string(csocket.fd, "requestinfo race_list"); 00182 reset_needed = 1; 00183 } 00184 if (!classes) { 00185 cs_print_string(csocket.fd, "requestinfo class_list"); 00186 reset_needed = 1; 00187 } 00188 if (!stat_points) { 00189 cs_print_string(csocket.fd, "requestinfo newcharinfo"); 00190 reset_needed = 1; 00191 } 00192 /* In this case, we are getting copies of some of the data 00193 * from the server - we need to discard any data we currently 00194 * have then (mainly, clear out things like the pulldown list 00195 * for classes 00196 */ 00197 if (reset_needed) { 00198 gtk_label_set_text(GTK_LABEL(label_cc_status_update), 00199 "Getting race & class information from the server"); 00200 create_character_set_sensitive(FALSE); 00201 } 00202 00203 /* This will be set true once we get all the data */ 00204 gtk_widget_show(create_character_window); 00205 } 00206 00212 void create_character_window_hide() 00213 { 00214 show_window(WINDOW_NONE); 00215 } 00216 00223 static void update_all_stats() 00224 { 00225 int i, stat_points_used=0, statval, tmp; 00226 const gchar *tval; 00227 char buf[MAX_BUF]; 00228 00229 negative_stat = 0; 00230 for (i=0; i<NUM_NEW_CHAR_STATS; i++) { 00231 00232 tmp = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i])); 00233 stat_points_used += tmp; 00234 statval = tmp; 00235 00236 /* We presume the label value is correct here - it should 00237 * be - this is easier than tracking down the corresponding 00238 * race/class structure and getting the value there. 00239 */ 00240 tval = gtk_label_get_text(GTK_LABEL(label_cs[i])); 00241 statval += atoi(tval); 00242 00243 tval = gtk_label_get_text(GTK_LABEL(label_rs[i])); 00244 statval += atoi(tval); 00245 00246 /* Might it be good to draw negative stats in red? Rather 00247 * than hardcode that, it should be a style 00248 */ 00249 if (statval < 0) negative_stat = 1; 00250 00251 sprintf(buf, "%d", statval); 00252 gtk_label_set_text(GTK_LABEL(label_tot[i]), buf); 00253 } 00254 00255 tmp = stat_points - stat_points_used; 00256 sprintf(buf,"%d", tmp); 00257 gtk_label_set_text(GTK_LABEL(label_cc_unspent), buf); 00258 00259 /* Display some warning messages - we could try and display all the 00260 * different warnings at once, but one at a time should be good enough. 00261 * perhaps the done button should be inactivated if there are errors. 00262 */ 00263 if (tmp < 0) { 00264 gtk_label_set_text(GTK_LABEL(label_cc_status_update), 00265 "You have used more than your allotted total attribute points"); 00266 } else if (negative_stat) { 00267 gtk_label_set_text(GTK_LABEL(label_cc_status_update), 00268 "Negative attributes are not allowed - adjust your selections before finishing"); 00269 00270 } else { 00271 gtk_label_set_text(GTK_LABEL(label_cc_status_update), "Waiting for player selections"); 00272 } 00273 00274 00275 } 00276 00277 static void send_create_player_to_server() 00278 { 00279 const gchar *char_name; 00280 int i, on_choice, tmp; 00281 SockList sl; 00282 char buf[MAX_BUF]; 00283 uint8 sockbuf[MAX_BUF]; 00284 00285 char_name = gtk_entry_get_text(GTK_ENTRY(entry_new_character_name)); 00286 00287 SockList_Init(&sl, sockbuf); 00288 SockList_AddString(&sl, "createplayer "); 00289 SockList_AddChar(&sl, strlen(char_name)); 00290 SockList_AddString(&sl, char_name); 00291 SockList_AddChar(&sl, strlen(account_password)); 00292 00293 SockList_AddString(&sl, account_password); 00294 00295 /* The client should never be popping up the new client creation 00296 * window unless the server supports loginmethod >= 2, so 00297 * we do not have any check here for that, but these 00298 * attributes are only valid for loginmethod >= 2 00299 */ 00300 i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_rs)); 00301 snprintf(buf, MAX_BUF, "race %s", races[i].arch_name); 00302 SockList_AddChar(&sl, strlen(buf)+1); 00303 SockList_AddString(&sl, buf); 00304 SockList_AddChar(&sl, 0); 00305 00306 /* From a practical standpoint, the server should never send 00307 * race/class choices unless it also supports the receipt of 00308 * those. So no special checks are needed here. 00309 */ 00310 for (on_choice = 0; on_choice < races[i].num_rc_choice; on_choice++) { 00311 int j; 00312 00313 j = gtk_combo_box_get_active(GTK_COMBO_BOX(opt_combobox[on_choice + RACE_OPT_START])); 00314 00315 snprintf(buf, MAX_BUF, "choice %s %s", races[i].rc_choice[on_choice].choice_name, 00316 races[i].rc_choice[on_choice].value_arch[j]); 00317 00318 SockList_AddChar(&sl, strlen(buf)+1); 00319 SockList_AddString(&sl, buf); 00320 SockList_AddChar(&sl, 0); 00321 } 00322 00323 00324 i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_cs)); 00325 snprintf(buf, MAX_BUF, "class %s", classes[i].arch_name); 00326 SockList_AddChar(&sl, strlen(buf)+1); 00327 SockList_AddString(&sl, buf); 00328 SockList_AddChar(&sl, 0); 00329 00330 for (on_choice = 0; on_choice < classes[i].num_rc_choice; on_choice++) { 00331 int j; 00332 00333 j = gtk_combo_box_get_active(GTK_COMBO_BOX(opt_combobox[on_choice + CLASS_OPT_START])); 00334 00335 snprintf(buf, MAX_BUF, "choice %s %s", classes[i].rc_choice[on_choice].choice_name, 00336 classes[i].rc_choice[on_choice].value_arch[j]); 00337 00338 SockList_AddChar(&sl, strlen(buf)+1); 00339 SockList_AddString(&sl, buf); 00340 SockList_AddChar(&sl, 0); 00341 } 00342 00343 /* Its possible that the server does not provide a choice of 00344 * starting maps - if that is the case, then we will never 00345 * display the starting map window. So check for that here. 00346 */ 00347 if (starting_map_number) { 00348 i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_starting_map)); 00349 if (i != -1) { 00350 snprintf(buf, MAX_BUF, "starting_map %s", starting_map_info[i].arch_name); 00351 SockList_AddChar(&sl, strlen(buf)+1); 00352 SockList_AddString(&sl, buf); 00353 SockList_AddChar(&sl, 0); 00354 } 00355 } 00356 00357 for (i=0; i<NUM_NEW_CHAR_STATS; i++) { 00358 tmp = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i])); 00359 snprintf(buf, MAX_BUF, "%s %d", stat_mapping[i].widget_suffix, tmp); 00360 SockList_AddChar(&sl, strlen(buf)+1); 00361 SockList_AddString(&sl, buf); 00362 SockList_AddChar(&sl, 0); 00363 } 00364 00365 SockList_Send(&sl, csocket.fd); 00366 00367 } 00368 00369 00377 void 00378 on_button_cc_cancel(GtkButton *button, gpointer user_data) 00379 { 00380 show_window(WINDOW_NONE); 00381 choose_char_window_show(); 00382 } 00383 00384 00392 void 00393 on_button_choose_starting_map(GtkButton *button, gpointer user_data) 00394 { 00395 show_window(WINDOW_CHOOSE_MAP); 00396 } 00397 00398 00409 static int character_data_ok() 00410 { 00411 const gchar *char_name; 00412 int i, stat_points_used=0, tmp[NUM_NEW_CHAR_STATS], negative_stat=0; 00413 SockList sl; 00414 char buf[MAX_BUF]; 00415 uint8 sockbuf[MAX_BUF]; 00416 00417 char_name = gtk_entry_get_text(GTK_ENTRY(entry_new_character_name)); 00418 00419 if (!char_name || char_name[0] == 0) { 00420 gtk_label_set_text(GTK_LABEL(label_cc_status_update), 00421 "You must enter a character name"); 00422 show_window(WINDOW_CREATE_CHARACTER); 00423 return FALSE; 00424 } 00425 00426 /* We get the stat values here - we also total up how many 00427 * points are used. If everything checks out, we will 00428 * need these stat values later. 00429 */ 00430 for (i=0; i<NUM_NEW_CHAR_STATS; i++) { 00431 tmp[i] = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spinbutton_cc[i])); 00432 stat_points_used += tmp[i]; 00433 } 00434 00435 if (stat_points_used > stat_points) { 00436 gtk_label_set_text(GTK_LABEL(label_cc_status_update), 00437 "You have used more than your allotted total attribute points"); 00438 show_window(WINDOW_CREATE_CHARACTER); 00439 return FALSE; 00440 } 00441 /* negative_stat is a global to this file. update_all_stats() 00442 * sets it/clears it - rather than doing that work again, just 00443 * re-use that value. 00444 */ 00445 if (negative_stat) { 00446 gtk_label_set_text(GTK_LABEL(label_cc_status_update), 00447 "Negative attributes are not allowed - adjust your selections before finishing"); 00448 show_window(WINDOW_CREATE_CHARACTER); 00449 return FALSE; 00450 } 00451 00452 /* No message is normally displayed for this - the player is 00453 * always going to get this case when starting out, but if 00454 * they hit done, we want to warn them that they have points 00455 * left to spend, since at present time there is no way to spend 00456 * these points later. 00457 */ 00458 if (stat_points_used < stat_points) { 00459 GtkWidget *dialog; 00460 int result; 00461 00462 dialog = 00463 gtk_message_dialog_new(GTK_WINDOW(create_character_window), 00464 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_QUESTION, 00465 GTK_BUTTONS_YES_NO, 00466 "%s\n%s\n%s", 00467 "You have not spent all your attribute points.", 00468 "You will be unable to spend these later.", 00469 "Create character anyways?"); 00470 result = gtk_dialog_run(GTK_DIALOG(dialog)); 00471 gtk_widget_destroy(dialog); 00472 if (result == GTK_RESPONSE_NO) { 00473 show_window(WINDOW_CREATE_CHARACTER); 00474 return FALSE; 00475 } 00476 /* Otherwise, fall through below */ 00477 } 00478 00479 /* Check to see starting map - note that start_map_number could 00480 * be zero, which means that the server does not have a choice, 00481 * and thus we don't have to get anything from the player. 00482 * Is throwing a dialog box up here perhaps overkill? 00483 */ 00484 i = gtk_combo_box_get_active(GTK_COMBO_BOX(combobox_starting_map)); 00485 if (starting_map_number && i == -1) { 00486 GtkWidget *dialog; 00487 int result; 00488 00489 show_window(WINDOW_CHOOSE_MAP); 00490 dialog = 00491 gtk_message_dialog_new(GTK_WINDOW(choose_starting_map_window), 00492 GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_WARNING, 00493 GTK_BUTTONS_OK, 00494 "You must choose a starting map before you can start playing"); 00495 result = gtk_dialog_run(GTK_DIALOG(dialog)); 00496 gtk_widget_destroy(dialog); 00497 return FALSE; 00498 } 00499 /* Everything checks out OK */ 00500 return TRUE; 00501 } 00502 00512 void 00513 on_button_cc_done(GtkButton *button, gpointer user_data) 00514 { 00515 if (character_data_ok()) { 00516 /* If we get here, everything checks out - now we have to 00517 * send the data to the server. 00518 */ 00519 gtk_label_set_text(GTK_LABEL(label_cc_status_update), 00520 "Sending new character information to server"); 00521 show_window(WINDOW_CREATE_CHARACTER); 00522 send_create_player_to_server(); 00523 } 00524 } 00525 00530 void 00531 on_spinbutton_cc (GtkSpinButton *spinbutton, gpointer user_data) { 00532 00533 update_all_stats(); 00534 } 00535 00548 void 00549 on_combobox_rcs_changed(GtkComboBox *box, gpointer user_data) 00550 { 00551 int active_entry, i, opt_start, opt_end; 00552 GtkWidget **label_stat; 00553 Race_Class_Info *rc; 00554 char buf[256]; 00555 00556 active_entry = gtk_combo_box_get_active(box); 00557 00558 /* I don't think this can ever happen - if we get here, 00559 * something should be active. 00560 */ 00561 if (active_entry == -1) 00562 return; 00563 00564 /* since we are using a list store, and we are not re-arranging the order, 00565 * the entry number should match our array number. 00566 */ 00567 if (box == GTK_COMBO_BOX(combobox_cs)) { 00568 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_cs_desc)), 00569 classes[active_entry].description, 00570 strlen(classes[active_entry].description)); 00571 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview_cs_desc), 00572 text_mark_cs, 0.0, TRUE, 0.0, 0.0); 00573 00574 rc = &classes[active_entry]; 00575 label_stat = label_cs; 00576 opt_start = CLASS_OPT_START; 00577 00578 } else if (box == GTK_COMBO_BOX(combobox_rs)) { 00579 gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_rs_desc)), 00580 races[active_entry].description, 00581 strlen(races[active_entry].description)); 00582 gtk_text_view_scroll_to_mark(GTK_TEXT_VIEW(textview_rs_desc), 00583 text_mark_rs, 0.0, TRUE, 0.0, 0.0); 00584 rc = &races[active_entry]; 00585 label_stat = label_rs; 00586 opt_start = RACE_OPT_START; 00587 } else { 00588 LOG(LOG_ERROR, "gtk-v2/src/create_char.c:on_combobox_rcs_changed", 00589 "Passed in combobox does not match any combobox"); 00590 return; 00591 } 00592 00593 for (i=0; i < rc->num_rc_choice; i++) { 00594 int j; 00595 GtkTreeModel *store; 00596 GtkTreeIter iter; 00597 00598 if (i == (NUM_OPT_FIELDS/2)) { 00599 LOG(LOG_ERROR, "gtk-v2/src/create_char.c:on_combobox_rcs_changed", 00600 "Number of racial option exceeds allocated amount (%d > %d)", 00601 i, NUM_OPT_FIELDS/2); 00602 break; 00603 } 00604 /* Set up the races combobox */ 00605 store = gtk_combo_box_get_model(GTK_COMBO_BOX(opt_combobox[i + opt_start])); 00606 gtk_list_store_clear(GTK_LIST_STORE(store)); 00607 00608 for (j=0; j<rc->rc_choice[i].num_values; j++) { 00609 gtk_list_store_append(GTK_LIST_STORE(store), &iter); 00610 gtk_list_store_set(GTK_LIST_STORE(store), &iter, 0, rc->rc_choice[i].value_desc[j], -1); 00611 } 00612 gtk_combo_box_set_active(GTK_COMBO_BOX(opt_combobox[i+opt_start]), 0); 00613 00614 gtk_label_set(GTK_LABEL(opt_label[i+opt_start]), rc->rc_choice[i].choice_desc); 00615 gtk_widget_show(opt_label[i+opt_start]); 00616 gtk_widget_show(opt_combobox[i+opt_start]); 00617 /* No signals are connected - the value of the combo 00618 * box will be when we send the data to the server. 00619 */ 00620 } 00621 00622 /* Hide any unused fields */ 00623 for ( ; i < (NUM_OPT_FIELDS/2); i++) { 00624 gtk_widget_hide(opt_label[i + opt_start]); 00625 gtk_widget_hide(opt_combobox[i + opt_start]); 00626 } 00627 00628 00629 /* label_stat now points at the array of stats to update, and rc points 00630 * at either the race or class to get values from. 00631 */ 00632 for (i=0; i < NUM_NEW_CHAR_STATS; i++) { 00633 sprintf(buf, "%+d", rc->stat_adj[stat_mapping[i].rc_offset]); 00634 gtk_label_set_text(GTK_LABEL(label_stat[i]), buf); 00635 } 00636 update_all_stats(); 00637 } 00638 00646 void new_char_window_update_info() 00647 { 00648 char buf[256]; 00649 GtkListStore *store; 00650 GtkTreeIter iter; 00651 GtkCellRenderer *renderer; 00652 int i; 00653 00654 /* We could do the update as we get the data, but it shouldn't take 00655 * too long to get all the data, and simpler to just do one update 00656 */ 00657 if (!stat_points || num_races != used_races || num_classes != used_classes) 00658 return; 00659 00660 gtk_label_set_text(GTK_LABEL(label_cc_status_update), "Waiting for player selections"); 00661 00662 sprintf(buf,"%d", stat_points); 00663 gtk_label_set_text(GTK_LABEL(label_cc_unspent), buf); 00664 00665 /* Set up the races combobox */ 00666 store = gtk_list_store_new(1, G_TYPE_STRING); 00667 00668 for (i=0; i<num_races; i++) { 00669 gtk_list_store_append(store, &iter); 00670 gtk_list_store_set(store, &iter, 0, races[i].public_name, -1); 00671 } 00672 00673 gtk_combo_box_set_model(GTK_COMBO_BOX(combobox_rs), GTK_TREE_MODEL(store)); 00674 gtk_cell_layout_clear(GTK_CELL_LAYOUT(combobox_rs)); 00675 00676 renderer = gtk_cell_renderer_text_new(); 00677 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox_rs), renderer, FALSE); 00678 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox_rs), renderer, 00679 "text", 0, NULL); 00680 00681 g_signal_connect ((gpointer) combobox_rs, "changed", 00682 G_CALLBACK (on_combobox_rcs_changed), NULL); 00683 00684 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_rs), 0); 00685 /* Set up the classes combobox */ 00686 store = gtk_list_store_new(1, G_TYPE_STRING); 00687 00688 for (i=0; i<num_classes; i++) { 00689 gtk_list_store_append(store, &iter); 00690 gtk_list_store_set(store, &iter, 0, classes[i].public_name, -1); 00691 00692 } 00693 00694 gtk_combo_box_set_model(GTK_COMBO_BOX(combobox_cs), GTK_TREE_MODEL(store)); 00695 gtk_cell_layout_clear(GTK_CELL_LAYOUT(combobox_cs)); 00696 00697 renderer = gtk_cell_renderer_text_new(); 00698 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox_cs), renderer, FALSE); 00699 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox_cs), renderer, 00700 "text", 0, NULL); 00701 g_signal_connect ((gpointer) combobox_cs, "changed", 00702 G_CALLBACK (on_combobox_rcs_changed), NULL); 00703 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_cs), 0); 00704 00705 /* Reset to minimum/maximum values for the spinbutton. 00706 */ 00707 for (i=0; i<NUM_NEW_CHAR_STATS; i++) { 00708 /* Reset any stat values - just makes more sense, but also 00709 * possible that starting value set in the glade file may 00710 * be outside of this range. 00711 */ 00712 gtk_spin_button_set_value(GTK_SPIN_BUTTON(spinbutton_cc[i]), stat_min); 00713 gtk_spin_button_set_range(GTK_SPIN_BUTTON(spinbutton_cc[i]), stat_min, 00714 stat_maximum); 00715 } 00716 00717 create_character_set_sensitive(TRUE); 00718 } 00719 00720 /****************************************************************************** 00721 * This section is related to the starting map window. 00722 *****************************************************************************/ 00723 00732 void 00733 on_button_csm_cancel(GtkButton *button, gpointer user_data) 00734 { 00735 show_window(WINDOW_CREATE_CHARACTER); 00736 } 00737 00738 00739 void 00740 on_combobox_starting_map_changed(GtkComboBox *box, gpointer user_data) 00741 { 00742 int active_entry, i; 00743 GtkWidget **label_stat; 00744 Race_Class_Info *rc; 00745 char buf[256]; 00746 00747 active_entry = gtk_combo_box_get_active(box); 00748 00749 /* I don't think this can ever happen - if we get here, 00750 * something should be active. 00751 */ 00752 if (active_entry == -1) 00753 return; 00754 00755 /* since we are using a list store, and we are not re-arranging the order, 00756 * the entry number should match our array number. 00757 */ 00758 gtk_text_buffer_set_text(textbuf_starting_map, "", 0); 00759 add_marked_text_to_pane(&create_char_pane[STARTING_MAP_PANE], 00760 starting_map_info[active_entry].description, 0, 0, 0); 00761 00762 } 00767 void starting_map_update_info() 00768 { 00769 char buf[256]; 00770 GtkListStore *store; 00771 GtkTreeIter iter; 00772 GtkCellRenderer *renderer; 00773 int i; 00774 00775 /* Set up the races combobox */ 00776 store = gtk_list_store_new(2, G_TYPE_STRING, G_TYPE_STRING); 00777 00778 for (i=0; i<=starting_map_number; i++) { 00779 gtk_list_store_append(store, &iter); 00780 gtk_list_store_set(store, &iter, 0, starting_map_info[i].public_name, -1); 00781 gtk_list_store_set(store, &iter, 1, starting_map_info[i].arch_name, -1); 00782 } 00783 00784 gtk_combo_box_set_model(GTK_COMBO_BOX(combobox_starting_map), GTK_TREE_MODEL(store)); 00785 gtk_cell_layout_clear(GTK_CELL_LAYOUT(combobox_starting_map)); 00786 00787 renderer = gtk_cell_renderer_text_new(); 00788 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(combobox_starting_map), renderer, FALSE); 00789 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(combobox_starting_map), renderer, 00790 "text", 0, NULL); 00791 00792 g_signal_connect ((gpointer) combobox_starting_map, "changed", 00793 G_CALLBACK (on_combobox_starting_map_changed), NULL); 00794 00795 gtk_combo_box_set_active(GTK_COMBO_BOX(combobox_starting_map), -1); 00796 00797 /* If we get called, we presume we have data to show, so activate button */ 00798 gtk_widget_show(button_choose_starting_map); 00799 00800 } 00801 00802 00806 void init_create_character_window() 00807 { 00808 GladeXML *xml_tree; 00809 char tmpbuf[80]; 00810 int i; 00811 GtkTextIter iter; 00812 GtkCellRenderer *renderer; 00813 00814 if (has_init) return; 00815 has_init=1; 00816 00817 create_character_window = glade_xml_get_widget(dialog_xml, "create_character_window"); 00818 gtk_window_set_transient_for(GTK_WINDOW(create_character_window), GTK_WINDOW(window_root)); 00819 00820 xml_tree = glade_get_widget_tree(GTK_WIDGET(create_character_window)); 00821 00822 button_cc_done = glade_xml_get_widget(dialog_xml,"button_cc_done"); 00823 button_cc_cancel = glade_xml_get_widget(dialog_xml,"button_cc_cancel"); 00824 button_choose_starting_map = glade_xml_get_widget(dialog_xml,"button_choose_starting_map"); 00825 label_cc_status_update = glade_xml_get_widget(dialog_xml,"label_cc_status_update"); 00826 label_cc_desc = glade_xml_get_widget(dialog_xml,"label_cc_desc"); 00827 label_cc_unspent = glade_xml_get_widget(dialog_xml,"label_cc_unspent"); 00828 combobox_rs = glade_xml_get_widget(dialog_xml,"combobox_rs"); 00829 combobox_cs = glade_xml_get_widget(dialog_xml,"combobox_cs"); 00830 entry_new_character_name = glade_xml_get_widget(dialog_xml,"cc_entry_new_character_name"); 00831 00832 textview_rs_desc = glade_xml_get_widget(dialog_xml,"textview_rs_desc"); 00833 text_mark_rs = gtk_text_mark_new("rs_start", TRUE); 00834 gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_rs_desc)), 00835 &iter); 00836 gtk_text_buffer_add_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_rs_desc)), 00837 text_mark_rs, &iter); 00838 00839 textview_cs_desc = glade_xml_get_widget(dialog_xml,"textview_cs_desc"); 00840 text_mark_cs = gtk_text_mark_new("cs_start", TRUE); 00841 gtk_text_buffer_get_start_iter(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_cs_desc)), 00842 &iter); 00843 gtk_text_buffer_add_mark(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textview_cs_desc)), 00844 text_mark_cs, &iter); 00845 00846 for (i=0; i<NUM_NEW_CHAR_STATS; i++) { 00847 snprintf(tmpbuf, 80, "spinbutton_cc_%s", stat_mapping[i].widget_suffix); 00848 spinbutton_cc[i] = glade_xml_get_widget(dialog_xml, tmpbuf); 00849 00850 g_signal_connect ((gpointer) spinbutton_cc[i], "value-changed", 00851 G_CALLBACK (on_spinbutton_cc), (void*)i); 00852 00853 snprintf(tmpbuf, 80, "label_rs_%s", stat_mapping[i].widget_suffix); 00854 label_rs[i] = glade_xml_get_widget(dialog_xml, tmpbuf); 00855 00856 snprintf(tmpbuf, 80, "label_cs_%s", stat_mapping[i].widget_suffix); 00857 label_cs[i] = glade_xml_get_widget(dialog_xml, tmpbuf); 00858 00859 snprintf(tmpbuf, 80, "label_tot_%s", stat_mapping[i].widget_suffix); 00860 label_tot[i] = glade_xml_get_widget(dialog_xml, tmpbuf); 00861 } 00862 00863 /* Note that in the glade file, the numbering starts at 1 */ 00864 for (i=0; i < NUM_OPT_FIELDS; i++ ) { 00865 GtkListStore *store; 00866 00867 snprintf(tmpbuf, 80, "opt_label%d", i+1); 00868 opt_label[i] = glade_xml_get_widget(dialog_xml, tmpbuf); 00869 00870 snprintf(tmpbuf, 80, "opt_combobox%d", i+1); 00871 opt_combobox[i] = glade_xml_get_widget(dialog_xml, tmpbuf); 00872 00873 gtk_cell_layout_clear(GTK_CELL_LAYOUT(opt_combobox[i])); 00874 renderer = gtk_cell_renderer_text_new(); 00875 gtk_cell_layout_pack_start(GTK_CELL_LAYOUT(opt_combobox[i]), renderer, FALSE); 00876 gtk_cell_layout_set_attributes(GTK_CELL_LAYOUT(opt_combobox[i]), renderer, 00877 "text", 0, NULL); 00878 store = gtk_list_store_new(1, G_TYPE_STRING); 00879 gtk_combo_box_set_model(GTK_COMBO_BOX(opt_combobox[i]), GTK_TREE_MODEL(store)); 00880 00881 } 00882 00883 g_signal_connect ((gpointer) button_cc_done, "clicked", 00884 G_CALLBACK (on_button_cc_done), NULL); 00885 g_signal_connect ((gpointer) button_cc_cancel, "clicked", 00886 G_CALLBACK (on_button_cc_cancel), NULL); 00887 g_signal_connect ((gpointer) button_choose_starting_map, "clicked", 00888 G_CALLBACK (on_button_choose_starting_map), NULL); 00889 00890 /* For starting map window */ 00891 choose_starting_map_window = glade_xml_get_widget(dialog_xml, "choose_starting_map_window"); 00892 00893 gtk_window_set_transient_for(GTK_WINDOW(choose_starting_map_window), GTK_WINDOW(window_root)); 00894 xml_tree = glade_get_widget_tree(GTK_WIDGET(create_character_window)); 00895 00896 create_char_pane[STARTING_MAP_PANE].textview = glade_xml_get_widget(dialog_xml,"textview_starting_map"); 00897 textbuf_starting_map = gtk_text_view_get_buffer( 00898 GTK_TEXT_VIEW(create_char_pane[STARTING_MAP_PANE].textview)); 00899 add_tags_to_textbuffer(&create_char_pane[STARTING_MAP_PANE], textbuf_starting_map); 00900 add_style_to_textbuffer(&create_char_pane[STARTING_MAP_PANE], NULL); 00901 00902 gtk_text_buffer_get_end_iter(create_char_pane[STARTING_MAP_PANE].textbuffer, &iter); 00903 create_char_pane[STARTING_MAP_PANE].textmark = gtk_text_buffer_create_mark( 00904 create_char_pane[STARTING_MAP_PANE].textbuffer, NULL, &iter, FALSE); 00905 00906 button_csm_done = glade_xml_get_widget(dialog_xml,"button_csm_done"); 00907 button_csm_cancel = glade_xml_get_widget(dialog_xml,"button_csm_cancel"); 00908 combobox_starting_map = glade_xml_get_widget(dialog_xml,"combobox_starting_map"); 00909 00910 g_signal_connect ((gpointer) button_csm_done, "clicked", 00911 G_CALLBACK (on_button_cc_done), NULL); 00912 g_signal_connect ((gpointer) button_csm_cancel, "clicked", 00913 G_CALLBACK (on_button_csm_cancel), NULL); 00914 00915 } 00916
1.7.6.1