npcedit.cc

Go to the documentation of this file.
00001 
00007 /*
00008 Copyright (C) 2000-2001 The Exult Team
00009 
00010 This program is free software; you can redistribute it and/or
00011 modify it under the terms of the GNU General Public License
00012 as published by the Free Software Foundation; either version 2
00013 of the License, or (at your option) any later version.
00014 
00015 This program is distributed in the hope that it will be useful,
00016 but WITHOUT ANY WARRANTY; without even the implied warranty of
00017 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018 GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 */
00024 
00025 #ifdef HAVE_CONFIG_H
00026 #  include <config.h>
00027 #endif
00028 
00029 #include "studio.h"
00030 #include "u7drag.h"
00031 #include "servemsg.h"
00032 #include "objserial.h"
00033 #include "exult_constants.h"
00034 #include "utils.h"
00035 #include "shapefile.h"
00036 #include "shapedraw.h"
00037 
00038 #ifdef WIN32
00039 #include "windrag.h"
00040 #endif
00041 
00042 using std::cout;
00043 using std::endl;
00044 /*
00045  *  Open npc window.
00046  */
00047 
00048 C_EXPORT void on_open_npc_activate
00049   (
00050   GtkMenuItem     *menuitem,
00051         gpointer         user_data
00052   )
00053   {
00054   ExultStudio *studio = ExultStudio::get_instance();
00055   studio->open_npc_window();
00056   }
00057 
00058 /*
00059  *  Npc window's Apply button.
00060  */
00061 C_EXPORT void on_npc_apply_btn_clicked
00062   (
00063   GtkButton *btn,
00064   gpointer user_data
00065   )
00066   {
00067   ExultStudio::get_instance()->save_npc_window();
00068   }
00069 
00070 /*
00071  *  Npc window's Cancel button.
00072  */
00073 C_EXPORT void on_npc_cancel_btn_clicked
00074   (
00075   GtkButton *btn,
00076   gpointer user_data
00077   )
00078   {
00079   ExultStudio::get_instance()->close_npc_window();
00080   }
00081 
00082 /*
00083  *  Npc window's close button.
00084  */
00085 C_EXPORT gboolean on_npc_window_delete_event
00086   (
00087   GtkWidget *widget,
00088   GdkEvent *event,
00089   gpointer user_data
00090   )
00091   {
00092   ExultStudio::get_instance()->close_npc_window();
00093   return TRUE;
00094   }
00095 
00096 /*
00097  *  Draw shape in NPC shape area.
00098  */
00099 C_EXPORT gboolean on_npc_draw_expose_event
00100   (
00101   GtkWidget *widget,    // The view window.
00102   GdkEventExpose *event,
00103   gpointer data     // ->Shape_chooser.
00104   )
00105   {
00106   ExultStudio::get_instance()->show_npc_shape(
00107     event->area.x, event->area.y, event->area.width,
00108               event->area.height);
00109   return (TRUE);
00110   }
00111 
00112 /*
00113  *  Npc shape # lost focus, so update shape displayed.
00114  */
00115 C_EXPORT gboolean on_npc_shape_focus_out_event
00116   (
00117   GtkWidget *widget,
00118   GdkEventFocus *event,
00119   gpointer user_data
00120   )
00121   {
00122   ExultStudio::get_instance()->show_npc_shape();
00123   return FALSE;
00124   }
00125 
00126 /*
00127  *  Callback for when a shape is dropped on the NPC draw area.
00128  */
00129 
00130 static void Npc_shape_dropped
00131   (
00132   int file,     // U7_SHAPE_SHAPES.
00133   int shape,
00134   int frame,
00135   void *udata
00136   )
00137   {
00138   if (file == U7_SHAPE_SHAPES && shape >= 0 && shape < 1024)
00139     ((ExultStudio *) udata)->set_npc_shape(shape, frame);
00140   }
00141 
00142           // Schedule names.
00143 /*
00144  *  Draw face.
00145  */
00146 C_EXPORT gboolean on_npc_face_draw_expose_event
00147   (
00148   GtkWidget *widget,    // The view window.
00149   GdkEventExpose *event,
00150   gpointer data     // ->Shape_chooser.
00151   )
00152   {
00153   ExultStudio::get_instance()->show_npc_face(
00154     event->area.x, event->area.y, event->area.width,
00155               event->area.height);
00156   return (TRUE);
00157   }
00158 
00159 /*
00160  *  Callback for when a shape is dropped on the NPC face area.
00161  */
00162 
00163 static void Npc_face_dropped
00164   (
00165   int file,     // U7_SHAPE_FACES
00166   int shape,
00167   int frame,
00168   void *udata
00169   )
00170   {
00171   if (file == U7_SHAPE_FACES && shape >= 0 && shape < 1024)
00172     ((ExultStudio *) udata)->set_npc_face(shape, frame);
00173   }
00174 
00175           // Schedule names.
00176 static char *sched_names[32] = {
00177     "Combat", "Horiz. Pace", "Vert. Pace", "Talk", "Dance",
00178     "Eat", "Farm", "Tend Shop", "Miner", "Hound", "Stand",
00179     "Loiter", "Wander", "Blacksmith", "Sleep", "Wait", "Sit",
00180     "Graze", "Bake", "Sew", "Shy", "Lab Work", "Thief", "Waiter",
00181     "Special", "Kid Games", "Eat at Inn", "Duel", "Preach",
00182     "Patrol", "Desk Work", "Follow"};
00183 
00184 /*
00185  *  Set a line in the schedule page.
00186  */
00187 
00188 static void Set_schedule_line
00189   (
00190   GladeXML *app_xml,
00191   int time,     // 0-7.
00192   int type,     // Activity (0-31, or -1 for none).
00193   int tx, int ty, int tz = 0  // Location.
00194   )
00195   {
00196   char *lname = g_strdup_printf("npc_sched%d", time);
00197   GtkLabel *label = GTK_LABEL(glade_xml_get_widget(app_xml, lname));
00198   g_free(lname);
00199           // User data = schedule #.
00200   gtk_object_set_user_data(GTK_OBJECT(label), (gpointer) type);
00201   gtk_label_set_text(label, 
00202       type >= 0 && type < 32 ? sched_names[type] : "-----");
00203           // Set location.
00204   char *locname = g_strdup_printf("sched_loc%d", time);
00205   GtkBox *box = GTK_BOX(glade_xml_get_widget(app_xml, locname));
00206   g_free(locname);
00207   GList *list = g_list_first(box->children);
00208   GtkWidget *spin = ((GtkBoxChild *) list->data)->widget;
00209   gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), tx);
00210   list = g_list_next(list);
00211   spin = ((GtkBoxChild *) list->data)->widget;
00212   gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), ty);
00213   list = g_list_next(list);
00214   spin = ((GtkBoxChild *) list->data)->widget;
00215           // Current engine assumes tz==0.
00216   gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), 0);
00217   gtk_widget_set_sensitive(spin, FALSE);
00218   }
00219 
00220 /*
00221  *  Get info. from line in the schedule page.
00222  *
00223  *  Output: False if schedule isn't set.
00224  */
00225 
00226 static bool Get_schedule_line
00227   (
00228   GladeXML *app_xml,
00229   int time,     // 0-7.
00230   Serial_schedule& sched    // Filled in if 'true' returned.
00231   )
00232   {
00233   char *lname = g_strdup_printf("npc_sched%d", time);
00234   GtkLabel *label = GTK_LABEL(glade_xml_get_widget(app_xml, lname));
00235   g_free(lname);
00236           // User data = schedule #.
00237   sched.type = (int) gtk_object_get_user_data(GTK_OBJECT(label));
00238   if (sched.type < 0 || sched.type > 31)
00239     return false;
00240           // Get location.
00241   char *locname = g_strdup_printf("sched_loc%d", time);
00242   GtkBox *box = GTK_BOX(glade_xml_get_widget(app_xml, locname));
00243   g_free(locname);
00244   GList *list = g_list_first(box->children);
00245   GtkWidget *spin = ((GtkBoxChild *) list->data)->widget;
00246   sched.tx = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
00247   list = g_list_next(list);
00248   spin = ((GtkBoxChild *) list->data)->widget;
00249   sched.ty = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
00250 //  list = g_list_next(list);
00251 //  spin = ((GtkBoxChild *) list->data)->widget;
00252 //  sched.tz = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(spin));
00253   sched.time = time;
00254   return true;
00255   }
00256 
00257 /*
00258  *  Open the npc-editing window.
00259  */
00260 
00261 #ifdef WIN32
00262 
00263 static void Drop_dragged_shape(int shape, int frame, int x, int y, void *data)
00264 {
00265   cout << "Dropped a shape: " << shape << "," << frame << " " << data << endl;
00266 
00267   Npc_shape_dropped(U7_SHAPE_SHAPES, shape, frame, data);
00268 }
00269 
00270 static void Drop_dragged_face(int shape, int frame, int x, int y, void *data)
00271 {
00272   cout << "Dropped a face: " << shape << "," << frame << " " << data << endl;
00273 
00274   Npc_face_dropped(U7_SHAPE_FACES, shape, frame, data);
00275 }
00276 
00277 #endif
00278 
00279 void ExultStudio::open_npc_window
00280   (
00281   unsigned char *data,    // Serialized npc, or null.
00282   int datalen
00283   )
00284   {
00285   bool first_time = false;
00286   if (!npcwin)      // First time?
00287     {
00288     first_time = true;
00289     npcwin = glade_xml_get_widget( app_xml, "npc_window" );
00290 
00291     if (vgafile && palbuf)
00292       {
00293       npc_draw = new Shape_draw(vgafile->get_ifile(), palbuf,
00294           glade_xml_get_widget(app_xml, "npc_draw"));
00295       npc_draw->enable_drop(Npc_shape_dropped, this);
00296       }
00297     if (facefile && palbuf)
00298       {
00299       npc_face_draw = new Shape_draw(facefile->get_ifile(),
00300                 palbuf,
00301           glade_xml_get_widget(app_xml, "npc_face_draw"));
00302       npc_face_draw->enable_drop(Npc_face_dropped, this);
00303       }
00304     npc_ctx = gtk_statusbar_get_context_id(
00305       GTK_STATUSBAR(glade_xml_get_widget(
00306         app_xml, "npc_status")), "Npc Editor");
00307     for (int i = 0; i < 24/3; i++)  // Init. schedules' user_data.
00308       Set_schedule_line(app_xml, i, -1, 0, 0, 0);
00309 
00310     }
00311           // Init. npc address to null.
00312   gtk_object_set_user_data(GTK_OBJECT(npcwin), 0);
00313           // Make 'apply', 'cancel' sensitive.
00314   set_sensitive("npc_apply_btn", true);
00315   set_sensitive("npc_cancel_btn", true);
00316   remove_statusbar("npc_status", npc_ctx, npc_status_id);
00317   if (data)
00318     {
00319     if (!init_npc_window(data, datalen))
00320       return;
00321     }
00322   else    
00323     init_new_npc();
00324   gtk_widget_show(npcwin);
00325 #ifdef WIN32
00326   if (first_time || !npcdnd)
00327     Windnd::CreateStudioDropDest(npcdnd, npchwnd, Drop_dragged_shape, NULL, Drop_dragged_face, (void*) this);
00328 
00329 #endif
00330   }
00331 
00332 /*
00333  *  Close the npc-editing window.
00334  */
00335 
00336 void ExultStudio::close_npc_window
00337   (
00338   )
00339   {
00340   if (npcwin) {
00341     gtk_widget_hide(npcwin);
00342 #ifdef WIN32
00343     Windnd::DestroyStudioDropDest(npcdnd, npchwnd);
00344 #endif
00345   }
00346   }
00347 
00348 /*
00349  *  Get one of the NPC 'property' spin buttons from the table in the NPC
00350  *  dialog box.
00351  *
00352  *  Output: true if successful, with spin, pnum returned.
00353  */
00354 
00355 static bool Get_prop_spin
00356   (
00357   GList *list,      // Entry in table of properties.
00358   GtkSpinButton *& spin,    // Spin button returned.
00359   int& pnum     // Property number (0-11) returned.
00360   )
00361   {
00362   GtkTableChild *ent = (GtkTableChild *) list->data;
00363   GtkBin *frame = GTK_BIN(ent->widget);
00364   spin = GTK_SPIN_BUTTON(frame->child);
00365   assert (spin != 0);
00366   const char *name = glade_get_widget_name(GTK_WIDGET(spin));
00367           // Names: npc_prop_nn.
00368   if (strncmp(name, "npc_prop_", 9) != 0)
00369     return false;
00370   pnum = atoi(name + 9);
00371   return (pnum >= 0 && pnum < 12);
00372   }
00373 
00374 /*
00375  *  Get one of the NPC flag checkbox's from the table in the NPC
00376  *  dialog box.
00377  *
00378  *  Output: true if successful, with cbox, fnum returned.
00379  */
00380 
00381 static bool Get_flag_cbox
00382   (
00383   GList *list,      // Entry in table of flags.
00384   unsigned long *oflags,    // Object flags.
00385   unsigned long *siflags,   // Serpent Isle flags.
00386   unsigned long *type_flags,  // Type (movement) flags.
00387   GtkCheckButton *& cbox,   // Checkbox returned.
00388   unsigned long *& bits,    // ->one of 3 flags above.
00389   int& fnum     // Flag # (0-31) returned.
00390   )
00391   {
00392   GtkTableChild *ent = (GtkTableChild *) list->data;
00393   cbox = GTK_CHECK_BUTTON(ent->widget);
00394   assert (cbox != 0);
00395   const char *name = glade_get_widget_name(GTK_WIDGET(cbox));
00396           // Names: npc_flag_xx_nn, where
00397           //   xx = si, of, tf.
00398   if (strncmp(name, "npc_flag_", 9) != 0)
00399     return false;
00400           // Which flag.
00401   if (strncmp(name + 9, "si", 2) == 0)
00402     bits = siflags;
00403   else if (strncmp(name + 9, "of", 2) == 0)
00404     bits = oflags;
00405   else if (strncmp(name + 9, "tf", 2) == 0)
00406     bits = type_flags;
00407   else
00408     return false;
00409   fnum = atoi(name + 9 + 3);
00410   return (fnum >= 0 && fnum < 32);
00411   }
00412 
00413 /*
00414  *  Init. the npc editor for a new NPC.
00415  */
00416 
00417 void ExultStudio::init_new_npc
00418   (
00419   )
00420   {
00421   int npc_num = -1;   // Got to get what new NPC # will be.
00422   if (Send_data(server_socket, Exult_server::npc_info) == -1)
00423     cout << "Error sending data to server." << endl;
00424           // Should get immediate answer.
00425   unsigned char data[Exult_server::maxlength];
00426   Exult_server::Msg_type id;
00427   Exult_server::wait_for_response(server_socket, 100);
00428   int len = Exult_server::Receive_data(server_socket, 
00429         id, data, sizeof(data));
00430   unsigned char *ptr = &data[0];
00431   int npcs = Read2(ptr);
00432   int first_unused = Read2(ptr);
00433   npc_num = first_unused;
00434   set_entry("npc_num_entry", npc_num, true, false);
00435       // Usually, usecode = 0x400 + num.
00436   set_entry("npc_usecode_entry", 0x400 + npc_num, true,
00437         npc_num >=256 ? true : false);
00438       // Usually, face = npc_num.
00439   set_npc_face(npc_num, 0);
00440   set_entry("npc_name_entry", "");
00441   set_entry("npc_ident_entry", 0);
00442   set_entry("npc_shape", -1);
00443   set_entry("npc_frame", 0);
00444   set_optmenu("npc_attack_mode", 0);
00445   set_optmenu("npc_alignment", 0);
00446           // Clear flag buttons.
00447   GtkTable *ftable = GTK_TABLE(
00448       glade_xml_get_widget(app_xml, "npc_flags_table"));
00449           // Set flag checkboxes.
00450   for (GList *list = g_list_first(ftable->children); list; 
00451             list = g_list_next(list))
00452     {
00453     GtkTableChild *ent = (GtkTableChild *) list->data;
00454     GtkCheckButton *cbox = GTK_CHECK_BUTTON(ent->widget);
00455     gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbox), false);
00456     }
00457           // Set properties.
00458   GtkTable *ptable = GTK_TABLE(
00459       glade_xml_get_widget(app_xml, "npc_props_table"));
00460   for (GList *list = g_list_first(ptable->children); list; 
00461             list = g_list_next(list))
00462     {
00463     GtkSpinButton *spin;
00464     int pnum;
00465     if (Get_prop_spin(list, spin, pnum))
00466       gtk_spin_button_set_value(spin, 12);
00467     }
00468           // Clear schedules.
00469   for (int i = 0; i < 24/3; i++)
00470     Set_schedule_line(app_xml, i, -1, 0, 0, 0);
00471   }
00472 
00473 /*
00474  *  Init. the npc editor with data from Exult.
00475  *
00476  *  Output: 0 if error (reported).
00477  */
00478 
00479 int ExultStudio::init_npc_window
00480   (
00481   unsigned char *data,
00482   int datalen
00483   )
00484   {
00485   unsigned long addr;
00486   int tx, ty, tz;
00487   int shape, frame, face;
00488   std::string name;
00489   short npc_num, ident;
00490   int usecode;
00491   int properties[12];
00492   short attack_mode, alignment;
00493   unsigned long oflags;   // Object flags.
00494   unsigned long siflags;    // Extra flags for SI.
00495   unsigned long type_flags; // Movement flags.
00496   short num_schedules;
00497   Serial_schedule schedules[8];
00498   if (!Npc_actor_in(data, datalen, addr, tx, ty, tz, shape, frame, face,
00499     name, npc_num, ident, usecode, properties, 
00500       attack_mode, alignment,
00501       oflags, siflags, type_flags, num_schedules, schedules))
00502     {
00503     cout << "Error decoding npc" << endl;
00504     return 0;
00505     }
00506           // Store address with window.
00507   gtk_object_set_user_data(GTK_OBJECT(npcwin), (gpointer) addr);
00508           // Store name, ident, num.
00509   set_entry("npc_name_entry", name.c_str());
00510           // (Not allowed to change npc#.).
00511   set_entry("npc_num_entry", npc_num, true, false);
00512   set_entry("npc_ident_entry", ident);
00513           // Shape/frame.
00514   set_entry("npc_shape", shape);
00515   set_entry("npc_frame", frame);
00516   set_npc_face(face, 0);
00517           // Usecode #.
00518   set_entry("npc_usecode_entry", usecode, true,
00519           npc_num >= 256 ? true : false);
00520           // Combat:
00521   set_optmenu("npc_attack_mode", attack_mode);
00522   set_optmenu("npc_alignment", alignment);
00523           // Set flag buttons.
00524   GtkTable *ftable = GTK_TABLE(
00525       glade_xml_get_widget(app_xml, "npc_flags_table"));
00526           // Set flag checkboxes.
00527   for (GList *list = g_list_first(ftable->children); list; 
00528             list = g_list_next(list))
00529     {
00530     GtkCheckButton *cbox;
00531     unsigned long *bits;
00532     int fnum;
00533     if (Get_flag_cbox(list, &oflags, &siflags, &type_flags, cbox,
00534             bits, fnum))
00535       gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(cbox), 
00536           (*bits&(1<<fnum)) != 0);
00537     }
00538           // Set properties.
00539   GtkTable *ptable = GTK_TABLE(
00540       glade_xml_get_widget(app_xml, "npc_props_table"));
00541   for (GList *list = g_list_first(ptable->children); list; 
00542             list = g_list_next(list))
00543     {
00544     GtkSpinButton *spin;
00545     int pnum;
00546     if (Get_prop_spin(list, spin, pnum))
00547       gtk_spin_button_set_value(spin, properties[pnum]);
00548     }
00549           // Set schedules.
00550   for (int i = 0; i < 24/3; i++)  // First init. to empty.
00551     Set_schedule_line(app_xml, i, -1, 0, 0, 0);
00552   for (int i = 0; i < num_schedules; i++)
00553     {
00554     Serial_schedule& sched = schedules[i];
00555     int time = sched.time;  // 0-7.
00556     if (time < 0 || time > 7)
00557       continue; // Invalid.
00558     Set_schedule_line(app_xml,time,sched.type, sched.tx, sched.ty);
00559     }
00560   return 1;
00561   }
00562 
00563 /*
00564  *  Callback for when user clicked where NPC should be inserted.
00565  */
00566 
00567 static void Npc_response
00568   (
00569   Exult_server::Msg_type id,
00570   unsigned char *data,
00571   int datalen,
00572   void * /* client */
00573   )
00574   {
00575   ExultStudio *studio = ExultStudio::get_instance();
00576   if (id == Exult_server::user_responded)
00577     studio->close_npc_window();
00578   //+++++cancel??
00579   }
00580 
00581 /*
00582  *  Send updated NPC info. back to Exult.
00583  *
00584  *  Output: 0 if error (reported).
00585  */
00586 
00587 int ExultStudio::save_npc_window
00588   (
00589   )
00590   {
00591   cout << "In save_npc_window()" << endl;
00592   unsigned char data[Exult_server::maxlength];
00593           // Get npc (null if creating new).
00594   unsigned long addr = (unsigned long) gtk_object_get_user_data(
00595               GTK_OBJECT(npcwin));
00596   int tx = -1, ty = -1, tz = -1;  // +++++For now.
00597   std::string name(get_text_entry("npc_name_entry"));
00598   short npc_num = get_num_entry("npc_num_entry");
00599   short ident = get_num_entry("npc_ident_entry");
00600   int shape = get_num_entry("npc_shape");
00601   int frame = get_num_entry("npc_frame");
00602   GtkWidget *fw = glade_xml_get_widget(app_xml, "npc_face_frame");
00603   int face = (int) gtk_object_get_user_data(GTK_OBJECT(fw));
00604   int usecode = get_num_entry("npc_usecode_entry");
00605   short attack_mode = get_optmenu("npc_attack_mode");
00606   short alignment = get_optmenu("npc_alignment");
00607 
00608   unsigned long oflags = 0; // Object flags.
00609   unsigned long siflags = 0;  // Extra flags for SI.
00610   unsigned long type_flags = 0; // Movement flags.
00611 
00612   if (shape < 0 || shape >= vgafile->get_ifile()->get_num_shapes())
00613     {
00614     EStudio::Alert("You must set a valid shape #.");
00615     return 0;
00616     }
00617           // Set flag buttons.
00618   GtkTable *ftable = GTK_TABLE(
00619       glade_xml_get_widget(app_xml, "npc_flags_table"));
00620           // Get flags.
00621   for (GList *list = g_list_first(ftable->children); list; 
00622             list = g_list_next(list))
00623     {
00624     GtkCheckButton *cbox;
00625     unsigned long *bits;
00626     int fnum;
00627     if (Get_flag_cbox(list, &oflags, &siflags, &type_flags, cbox,
00628             bits, fnum))
00629       if (gtk_toggle_button_get_active(
00630             GTK_TOGGLE_BUTTON(cbox)))
00631         *bits |= (1<<fnum);
00632     }
00633   int properties[12];   // Get properties.
00634   GtkTable *ptable = GTK_TABLE(
00635       glade_xml_get_widget(app_xml, "npc_props_table"));
00636   for (GList *list = g_list_first(ptable->children); list; 
00637             list = g_list_next(list))
00638     {
00639     GtkSpinButton *spin;
00640     int pnum;
00641     if (Get_prop_spin(list, spin, pnum))
00642       properties[pnum] = 
00643         gtk_spin_button_get_value_as_int(spin);
00644     }
00645   short num_schedules = 0;
00646   Serial_schedule schedules[8];
00647   for (int i = 0; i < 8; i++)
00648     if (Get_schedule_line(app_xml, i, schedules[num_schedules]))
00649       num_schedules++;
00650   if (Npc_actor_out(server_socket, addr, tx, ty, tz, shape, frame, face,
00651     name, npc_num, ident, usecode, 
00652       properties, attack_mode, alignment,
00653       oflags, siflags, type_flags, 
00654       num_schedules, schedules) == -1)
00655     {
00656     cout << "Error sending npc data to server" <<endl;
00657     return 0;
00658     }
00659   cout << "Sent npc data to server" << endl;
00660   if (!addr)
00661     {
00662     npc_status_id = set_statusbar("npc_status", npc_ctx,
00663           "Click on map at place to insert npc");
00664           // Make 'apply' insensitive.
00665     set_sensitive("npc_apply_btn", false);
00666     set_sensitive("npc_cancel_btn", false);
00667     waiting_for_server = Npc_response;
00668     return 1;   // Leave window open.
00669     }
00670   close_npc_window();
00671   return 1;
00672   }
00673 
00674 /*
00675  *  Paint the shape in the NPC draw area.
00676  */
00677 
00678 void ExultStudio::show_npc_shape
00679   (
00680   int x, int y, int w, int h  // Rectangle. w=-1 to show all.
00681   )
00682   {
00683   if (!npc_draw)
00684     return;
00685   npc_draw->configure();
00686           // Yes, this is kind of redundant...
00687   int shnum = get_num_entry("npc_shape");
00688   int frnum = get_num_entry("npc_frame");
00689   if (!shnum)     // Don't draw shape 0.
00690     shnum = -1;
00691   npc_draw->draw_shape_centered(shnum, frnum);
00692   if (w != -1)
00693     npc_draw->show(x, y, w, h);
00694   else
00695     npc_draw->show();
00696   }
00697 
00698 /*
00699  *  Set NPC shape.
00700  */
00701 
00702 void ExultStudio::set_npc_shape
00703   (
00704   int shape,
00705   int frame
00706   )
00707   {
00708   set_entry("npc_shape", shape);
00709   set_entry("npc_frame", frame);
00710   show_npc_shape();
00711   }
00712 
00713 /*
00714  *  Paint the face.
00715  */
00716 
00717 void ExultStudio::show_npc_face
00718   (
00719   int x, int y, int w, int h  // Rectangle. w=-1 to show all.
00720   )
00721   {
00722   if (!npc_face_draw)
00723     return;
00724   npc_face_draw->configure();
00725   GtkWidget *frame = glade_xml_get_widget(app_xml, "npc_face_frame");
00726   int shnum = (int) gtk_object_get_user_data(GTK_OBJECT(frame));
00727   npc_face_draw->draw_shape_centered(shnum, 0);
00728   if (w != -1)
00729     npc_face_draw->show(x, y, w, h);
00730   else
00731     npc_face_draw->show();
00732   }
00733 
00734 /*
00735  *  Set NPC face.
00736  */
00737 
00738 void ExultStudio::set_npc_face
00739   (
00740   int shape,
00741   int frame
00742   )
00743   {
00744 //  set_entry("npc_shape", shape);
00745 //  set_entry("npc_frame", frame);
00746   if (shape < 0)
00747     shape = 1;    // Default to 1st after Avatar.
00748   GtkWidget *widget = glade_xml_get_widget(app_xml, "npc_face_frame");
00749   gtk_object_set_user_data(GTK_OBJECT(widget), (gpointer) shape);
00750   char *label = g_strdup_printf("Face #%d", shape);
00751   gtk_frame_set_label(GTK_FRAME(widget), label);
00752   g_free(label);
00753   show_npc_face();
00754   }
00755 
00756 /*
00757  *  A choice was clicked in the 'schedule' dialog.
00758  */
00759 
00760 void ExultStudio::schedule_btn_clicked
00761   (
00762   GtkWidget *btn,     // Button on the schedule dialog.
00763   gpointer data     // Dialog itself.
00764   )
00765   {
00766   ExultStudio *studio = ExultStudio::get_instance();
00767           // Get name assigned in Glade.
00768   const char *name = glade_get_widget_name(btn);
00769   const char *numptr = name + 5;  // Past "sched".
00770   int num = atoi(numptr);
00771   GtkWidget *schedwin = (GtkWidget *) data;
00772   GtkLabel *label = (GtkLabel *) gtk_object_get_user_data(
00773             GTK_OBJECT(schedwin));
00774           // User data = schedule #.
00775   gtk_object_set_user_data(GTK_OBJECT(label), (gpointer) num);
00776   gtk_label_set_text(label, num >= 0 && num < 32
00777     ? sched_names[num] : "-----");
00778   cout << "Chose schedule " << num << endl;
00779   gtk_widget_hide(glade_xml_get_widget(studio->get_xml(), 
00780               "schedule_dialog"));
00781   }
00782 
00783 /*
00784  *  Set signal handler for each schedule button.
00785  */
00786 
00787 static void Set_sched_btn
00788   (
00789   GtkWidget *btn,
00790   gpointer data
00791   )
00792   {
00793   gtk_signal_connect(GTK_OBJECT(btn), "clicked",
00794     GTK_SIGNAL_FUNC(ExultStudio::schedule_btn_clicked), data);
00795   }
00796 
00797 /*
00798  *  Npc window's "set schedule" button.
00799  */
00800 C_EXPORT void on_npc_set_sched
00801   (
00802   GtkWidget *btn,     // One of the 'set' buttons.
00803   gpointer user_data
00804   )
00805   {
00806   static int first = 1;   // To initialize signal handlers.
00807   const char *name = glade_get_widget_name(btn);
00808   const char *numptr = name + strlen(name) - 1;
00809   GladeXML *xml = ExultStudio::get_instance()->get_xml();
00810   char lname[20];     // Set up label name.
00811   strcpy(lname, "npc_sched");
00812   strcat(lname, numptr);    // Same number as button.
00813   GtkLabel *label = GTK_LABEL(glade_xml_get_widget(xml, lname));
00814   GtkContainer *btns = GTK_CONTAINER(
00815         glade_xml_get_widget(xml, "sched_btns"));
00816   GtkWidget *schedwin = glade_xml_get_widget(xml, "schedule_dialog");
00817   if (!label || !btns || !schedwin)
00818     return;
00819   if (first)      // First time?  Set handlers.
00820     {
00821     first = 0;
00822     gtk_container_foreach(btns, Set_sched_btn, schedwin);
00823     }
00824           // Store label as dialog's data.
00825   gtk_object_set_user_data(GTK_OBJECT(schedwin), label);
00826   gtk_widget_show(schedwin);
00827   }
00828 
00829 /*
00830  *  Received game position for schedule.
00831  */
00832 static void Game_loc_response
00833   (
00834   Exult_server::Msg_type id,
00835   unsigned char *data,
00836   int datalen,
00837   void *client
00838   )
00839   {
00840   if (id != Exult_server::game_pos)
00841     return;
00842           // Get box with loc. spin btns.
00843   GtkBox *box = (GtkBox *) client;
00844   int tx = Read2(data);
00845   int ty = Read2(data);
00846   int tz = Read2(data);
00847   if (tz != 0)
00848     {
00849     EStudio::Alert("Non-zero height (%d) not yet supported", tz);
00850     return;
00851     }
00852   GList *list = g_list_first(box->children);
00853   GtkWidget *spin = ((GtkBoxChild *) list->data)->widget;
00854   gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), tx);
00855   list = g_list_next(list);
00856   spin = ((GtkBoxChild *) list->data)->widget;
00857   gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), ty);
00858   list = g_list_next(list);
00859   spin = ((GtkBoxChild *) list->data)->widget;
00860   gtk_spin_button_set_value(GTK_SPIN_BUTTON(spin), tz);
00861   }
00862 
00863 /*
00864  *  One of the "Game" buttons to set location from current game position.
00865  */
00866 
00867 C_EXPORT void on_sched_loc_clicked
00868   (
00869   GtkWidget *btn,     // One of the 'Game' buttons.
00870   gpointer user_data
00871   )
00872   {
00873   ExultStudio *studio = ExultStudio::get_instance();
00874           // Get location box.
00875   GtkBox *box = GTK_BOX(gtk_widget_get_parent(btn));
00876   if (Send_data(studio->get_server_socket(), 
00877           Exult_server::game_pos) == -1)
00878     cout << "Error sending message to server" << endl;
00879   else
00880     studio->set_msg_callback(Game_loc_response, box);
00881   }

Generated on Mon Jul 9 14:42:47 2007 for ExultEngine by  doxygen 1.5.1