Crossfire Client, Branches  R11627
x11.c
Go to the documentation of this file.
1 const char *rcsid_x11_x11_c =
2  "$Id: x11.c 9201 2008-06-01 17:32:45Z anmaster $";
3 /*
4  Crossfire client, a client program for the crossfire program.
5 
6  Copyright (C) 2001-2003,2006 Mark Wedel & Crossfire Development Team
7 
8  This program is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 2 of the License, or
11  (at your option) any later version.
12 
13  This program is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with this program; if not, write to the Free Software
20  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 
22  The author can be reached via e-mail to crossfire-devel@real-time.com
23 */
24 
25 /*
26  * This file handles mose of the windowing stuff. The idea is
27  * that all of it is in one file, so to port to different systems
28  * or toolkits, only this file needs to be updated. All windowing
29  * variables (display, gc's, windows, etc), should be stored in
30  * this file as statics.
31  *
32  * This file is largely a combination of the common/xutil.c and server/xio.c
33  * file. While I don't think this was a particulary great interface, the code
34  * was there, and I figured it was probably easier to re-use that
35  * code instead of writing new code, plus the old code worked.
36  *
37  */
38 
39 #define X_PROG_NAME "cfclient"
40 
41 /* Most functions in this file are private. Here is a list of
42  * the global functions:
43  *
44  * draw_color_info(int color, char*buf) - draws text in specified color
45  * draw_info - draw info in the info window
46  * end_windows - used when exiting
47  * init_windows - called when starting up
48  * load_images - creates the bitmaps and pixmaps (if being used)
49  * create_pixmap - creates a pixmap from given file and assigns to
50  * the given face
51  * create_xpm - as create_pixmap, but does an XPM image
52  *
53  * draw_stats(int) - draws the stat window. Pass 1 to redraw all
54  * stats, not only those that changed
55  *
56  * draw_message_window(int) - draws the message window. Pass 1 to redraw
57  * all the bars, not only those that changed.
58  *
59  * draw_look, draw_inv: Update the look and inventory windows.
60  *
61  * NOTE: create_pixmap and create_xpm can be empty functions if the
62  * client will always use fonts - in that case, it should never
63  * request Bitmap or Pixmap data, and thus not need the create
64  * functions above
65  *
66  * Only functions in this file should be calling functions like
67  * draw_stats and draw_message_window with redraw set - functions
68  * in other files should always pass 0, because they will never have
69  * the information of whether a redraw is needed.
70  */
71 
72 
73 #include <client.h>
74 #include "clientbmap.h"
75 #include <item.h>
76 #include <config.h>
77 #include <script.h>
78 #include <p_cmd.h>
79 
80 #ifdef HAVE_LIBXPM
81 #include <X11/xpm.h>
82 #endif
83 
84 #include <X11/Xlib.h>
85 #include <X11/Xutil.h>
86 
87 #include "mapdata.h"
88 #include "x11proto.h"
89 #include "x11.h"
90 
91 #include <errno.h>
92 
93 #if defined(__pyrsoft)
94 #define _Xconst
95 #endif
96 
97 /* All the following are static because these variables should
98  * be local only to this file. Since the idea is to have only
99  * this file be replaced for different windowing systems, use of
100  * any of these variables anyplace else would not be portable.
101  */
102 
103 typedef enum inventory_show {
105  show_cursed = 0x8, show_magical = 0x10, show_nonmagical = 0x20,
106  show_locked = 0x40, show_unlocked = 0x80,
109 
110 /*
111  * This is similar obwin, but totally redone for client
112  */
113 typedef struct {
114  item *env; /* Environment shown in window */
115  char title[MAX_BUF]; /* title of item list */
116  char old_title[MAX_BUF]; /* previos title (avoid redrawns) */
117 
118  Window win; /* for X-windows */
122 
123  uint8 show_icon:1; /* show status icons */
124  uint8 show_weight:1; /* show item's weight */
125 
126  char format_nw[20]; /* sprintf-format for text (name and weight) */
127  char format_nwl[20]; /* sprintf-format for text (name, weight, limit) */
128  char format_n[20]; /* sprintf-format for text (only name) */
129  sint16 text_len; /* How wide the text-field is */
130 
131  sint16 width; /* How wide the window is in pixels */
132  sint16 height; /* How height the window is in pixels */
133 
134  sint16 item_pos; /* The sequence number of the first drawn item */
135  sint16 item_used; /* How many items actually drawn. (0 - size) */
136 
137  sint16 size; /* How many items there is room to display */
138  sint16 *faces; /* [size] */
139  sint8 *icon1; /* status icon : locked */
140  sint8 *icon2; /* status icon : applied / unpaid */
141  sint8 *icon3; /* status icon : magic */
142  sint8 *icon4; /* status icon : damned / cursed */
143  char **names; /* [size][NAME_LEN] */
144 
145  /* The scrollbar */
146  sint16 bar_length; /* the length of scrollbar in pixels */
147  sint16 bar_size; /* the current size of scrollbar in pixels */
148  sint16 bar_pos; /* the starting position of scrollbar in pixels */
149  inventory_show show_what; /* What to show in inventory */
150  uint32 weight_limit; /* Weight limit for this list - used for title */
151 } itemlist;
152 
153 int noautorepeat = FALSE; /* turn off autorepeat detection */
154 
155 static char *font_name="8x13", **gargv;
156 
157 #define SCROLLBAR_WIDTH 16 /* +2+2 for border on each side */
158 #define INFOCHARS 50
159 #define INFOLINES 36
160 /* Perhaps decent defaults, but not quite right */
161 static int FONTWIDTH= 8;
162 static int FONTHEIGHT= 13;
163 #define MAX_INFO_WIDTH 80
164 #define MAXNAMELENGTH 50
165 
166 /* What follows is various constants (or calculations) for various
167  * window sizes.
168  */
169 
170 /* Width (and height) of the game window */
171 #define GAME_WIDTH (image_size * use_config[CONFIG_MAPWIDTH] + 5)
172 
173 #define STAT_HEIGHT 140
174 
175 /* Width of the inventory and look window */
176 #define INV_WIDTH 300
177 /* spacing between windows */
178 #define WINDOW_SPACING 3
179 /* Height of the master (root) window */
180 #define ROOT_HEIGHT 522
181 
182 static int gargc, old_mapx=11, old_mapy=11;
183 
184 Display *display;
185 static Window def_root; /* default root window */
186 static long def_screen; /* default screen number */
187 static unsigned long foreground,background;
190 Colormap colormap;
191 static XColor discolor[16];
192 static XFontStruct *font; /* Font loaded to display in the windows */
193 static XEvent event;
194 static XSizeHints messagehint, roothint;
195 static Atom wm_delete_window;
196 
197 /* This struct contains the information to draw 1 line of data. */
198 typedef struct {
199  char *info; /* Actual character data for a line */
200  uint8 color; /* Color to draw that line */
201 } InfoLine;
202 
203 /* This contains all other information for the info window */
204 typedef struct {
205  uint16 info_chars; /* width in chars of info window */
206  uint16 max_info_chars; /* Max value of info_chars */
207  uint16 infopos; /* Where in the info arry to put new data */
208  uint16 infoline; /* Where on the window to draw the line */
209  uint16 scroll_info_window:1; /* True if we should scroll the window */
210  uint16 numlines; /* How many have been stored the array */
211  uint16 maxlines; /* Maxlines (how large the array below is) */
212  uint16 maxdisp; /* How many lines can be displayed at once */
213  uint8 lastcolor; /* Last color text was drawn in */
214  InfoLine *data; /* An array of lines */
215  Window win_info; /* Actual info window */
216  GC gc_info; /* GC for this window */
217  /* The scrollbar */
218  sint16 bar_length; /* the max length of scrollbar in pixels */
219  sint16 bar_size; /* the current size (length) of scrollbar in pixels */
220  sint16 bar_pos; /* the starting position of scrollbar. This is
221  * an offset, which is the number of lines from
222  * 0 for the text to end out.*/
223  sint16 bar_y; /* X starting position of scrollbar */
224  uint16 has_scrollbar:1;/* True if there is a scrollbar in the window */
225  sint16 width,height; /* Width and height of window */
226 } InfoData;
227 
229  NULL, 0, 0,0,0,0,0,0,0,0};
230 
232 
233 
234 
235 static char stats_buff[7][600];
237 /* Off the 'free' space in the window, this floating number is the
238  * portion that the info takes up.
239  */
240 static float info_ratio=0;
241 
242 #define XPMGCS 100
243 
244 enum {
248 };
249 static Pixmap icons[max_icons];
250 
254  gc_blank;
256 static GC gc_copy; /* used for copying when scrolling map view */
257 
258 /*
259  * These are used for inventory and look window
260  */
262 
263 /* Used to know what stats has changed */
264 static Stats last_stats = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
265 
266 /* info win */
267 #define INFOCHARS 50
268 
269 
270 /* This is the loop that the client goes through once all the
271  * initialization is done. Basically, it checks for input and
272  * processes X events (calls function to do that.)
273  * The time for command_loop is fairly arbitrary - it can be most
274  * any value. If it is very low, however, as it will be doing a lot
275  * of checks to see if there is data instead of blocking on input.
276  *
277  * check_x_events takes all the events that are waiting.
278  */
279 
280 extern int maxfd;
281 
282 /* Handle errors. I really needed this when debugging
283  * the crashes with the big image stuff - I need to know
284  * what function is causing the crash.
285  */
286 int error_handler(Display *dp, XErrorEvent *xe)
287 {
288  char buf[MAX_BUF];
289 
290  XGetErrorText(dp, xe->error_code, buf, MAX_BUF-1);
291  fprintf(stderr,buf);
292  /* If you want to try to live through errors, comment out
293  * the abort below.
294  */
295  abort();
296 
297  return 0; /* just to prevent warnings */
298 }
299 
300 void event_loop(void)
301 {
302  fd_set tmp_read;
303  int pollret;
304  struct timeval timeout;
305 
306 
307  if (MAX_TIME==0) {
308  timeout.tv_sec = 0;
309  timeout.tv_usec = 0;
310  }
311  maxfd = csocket.fd + 1;
312  while (1) {
313  if (csocket.fd==-1) return;
314 
315  /* Do a quick check here for better performance */
316  check_x_events();
317 
318  FD_ZERO(&tmp_read);
319  FD_SET(csocket.fd, &tmp_read);
320  script_fdset(&maxfd,&tmp_read);
321  if (MAX_TIME!=0) {
322  timeout.tv_sec = MAX_TIME / 1000000;
323  timeout.tv_usec = MAX_TIME % 1000000;
324  }
325  pollret = select(maxfd, &tmp_read, NULL, NULL, &timeout);
326  if (pollret==-1) {
327  fprintf(stderr, "Got errno %d on select call.\n", errno);
328  }
329  else if (FD_ISSET(csocket.fd, &tmp_read)) {
330  DoClient(&csocket);
331  }
332  else {
333  script_process(&tmp_read);
334  }
335  animate_objects(); /* Do this before the x events, since they
336  * can redraw this for us.
337  */
338  check_x_events();
339  }
340 }
341 
343 
344 /* Draws 'face' onto 'where' at x,y.
345  * sx and sy is the the offset to draw from.
346  */
347 
348 static void gen_draw_face(Drawable where,int face,int x,int y, int sx, int sy)
349 {
350  if (face < 0 || face >= MAXPIXMAPNUM) {
351  fprintf(stderr,"Invalid face number: %d @ %d, %d\n", face, x, y);
352  return;
353  }
354  if (pixmaps[face]->mask == None) {
355  XCopyArea(display, pixmaps[face]->pixmap,
356  where,gc_floor,
357  sx,sy,image_size,image_size,x,y);
358 
359  /* Xpm and png do exactly the same thing */
360  } else {
361  /* Basically, what it looks like all this does is to try and preserve
362  * gc's with various clipmasks set. */
363 
364  int gcnum,i;
365  Pixmap mask;
366  GC gc;
367  total++;
368  mask = pixmaps[face]->mask;
369  /* Lets see if we can find a stored mask with matching gc */
370  for(gcnum=0;gcnum<XPMGCS;gcnum++) {
371  if (xpm_masks[gcnum] == mask)
372  break;
373  }
374  /* Nope - we didn't. set one up, but only temporarily */
375  if (gcnum == XPMGCS) {
376  misses++;
377  gcnum--;
378  gc = gc_xpm[gcnum];
379  XSetClipMask(display,gc,mask);
380  }
381  gc = gc_xpm[gcnum];
382  /* Now, we move all the ones up one, and then place the one just used
383  * at position 0. Thus, the one in the last position was the least
384  * used entry
385  */
386  for(i=gcnum-1;i>=0;i--) {
387  xpm_masks[i+1] = xpm_masks[i];
388  gc_xpm[i+1] = gc_xpm[i];
389  }
390  xpm_masks[0] = mask;
391  gc_xpm[0] = gc;
392  /* Hopefully, this isn't too costly - needed for the inventory and look
393  * window drawing code.
394  */
395  XSetClipOrigin(display, gc_xpm[0], x - sx , y - sy);
396  XCopyArea(display, pixmaps[face]->pixmap,
397  where,gc_xpm[0],
398  sx,sy,image_size,image_size,x,y);
399  }
400 }
401 
402 void end_windows(void)
403 {
404  XFreeGC(display, gc_root);
405  XFreeGC(display, gc_game);
406  XFreeGC(display, gc_copy);
407  XFreeGC(display, gc_stats);
408  XFreeGC(display, infodata.gc_info);
409  XFreeGC(display, inv_list.gc_text);
410  XFreeGC(display, inv_list.gc_icon);
411  XFreeGC(display, inv_list.gc_status);
412  XFreeGC(display, look_list.gc_text);
413  XFreeGC(display, look_list.gc_icon);
414  XFreeGC(display, look_list.gc_status);
415  XFreeGC(display, gc_message);
416  XFreeGC(display, gc_xpm_object);
417  XDestroyWindow(display,win_game);
418  XCloseDisplay(display);
419 }
420 
421 
422 
423 
424 
425 /***********************************************************************
426  *
427  * Stats window functions follow
428  *
429  ***********************************************************************/
430 
431 static int get_game_display(void) {
432  XSizeHints gamehint;
433  int i;
434 
435  gamehint.x=INV_WIDTH + WINDOW_SPACING;
436  gamehint.y=STAT_HEIGHT + WINDOW_SPACING;
437 
438  gamehint.width=GAME_WIDTH;
439  gamehint.height=gamehint.width;
440 
441  gamehint.max_width=gamehint.min_width=gamehint.width;
442  gamehint.max_height=gamehint.min_height=gamehint.height;
443  gamehint.flags=PPosition | PSize;
444  win_game=XCreateSimpleWindow(display,win_root,
445  gamehint.x,gamehint.y,gamehint.width,gamehint.height,2,
447  icon=XCreateBitmapFromData(display,win_game,
448  (_Xconst char *) crossfire_bits,
449  (unsigned int) crossfire_width, (unsigned int)crossfire_height);
452  &colormap, discolor);
453  foreground=discolor[0].pixel;
454  background=discolor[9].pixel;
455  } else
456  XSetWindowColormap(display, win_game, colormap);
457 
458  XSetStandardProperties(display,win_game,X_PROG_NAME, X_PROG_NAME,
459  icon,gargv,gargc, &(gamehint));
460 
461  gc_game=XCreateGC(display,win_game,0,0);
462  XSetForeground(display,gc_game,discolor[0].pixel);
463  XSetBackground(display,gc_game,discolor[9].pixel);
464 
465  XSetGraphicsExposures(display, gc_game, False);
466  gc_copy=XCreateGC(display,win_game,0,0);
467  XSetGraphicsExposures(display, gc_game, True);
468  gc_floor = XCreateGC(display,win_game,0,0);
469  XSetGraphicsExposures(display, gc_floor, False);
470  gc_blank = XCreateGC(display,win_game,0,0);
471  XSetForeground(display,gc_blank,discolor[0].pixel); /*set to black*/
472  XSetGraphicsExposures(display,gc_blank,False);
473 
474  for (i=0; i<XPMGCS; i++) {
475  gc_xpm[i] = XCreateGC(display, win_game, 0,0);
476  XSetClipOrigin(display, gc_xpm[i], 0, 0);
477  XSetGraphicsExposures(display, gc_xpm[i], False);
478  }
479  gc_xpm_object = XCreateGC(display,win_game,0,0);
480  XSetGraphicsExposures(display, gc_xpm_object, False);
481  XSetClipOrigin(display, gc_xpm_object,0, 0);
482  xpm_pixmap = XCreatePixmap(display, def_root, image_size, image_size,
483  DefaultDepth(display, DefaultScreen(display)));
484  gc_clear_xpm = XCreateGC(display,xpm_pixmap,0,0);
485  XSetGraphicsExposures(display,gc_clear_xpm,False);
486  XSetForeground(display,gc_clear_xpm,discolor[12].pixel); /* khaki */
487 
488  XSelectInput(display,win_game,
489  ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask);
490  XSetWMProtocols(display, win_game, &wm_delete_window, 1);
491  XMapRaised(display,win_game);
492  return 0;
493 }
494 
495 
496 /******************************************************************************
497  *
498  * The functions dealing with the info window follow
499  *
500  *****************************************************************************/
501 
502 static int get_info_display(void) {
503  XSizeHints infohint;
504  int i;
505 
506  /* The following could happen if bad values are given. */
507  if (infodata.maxlines<INFOLINES) infodata.maxlines=INFOLINES;
508  infohint.x=INV_WIDTH + GAME_WIDTH + WINDOW_SPACING*2;
509  infohint.y=0;
510  infohint.width=infodata.width=6+INFOCHARS*FONTWIDTH;
511  infohint.height=infodata.height=roothint.height;
512  infodata.maxdisp = roothint.height/FONTHEIGHT;
513 
514  infohint.min_width=100;
515  infohint.min_height=30;
516  infohint.flags=PPosition | PSize;
517  infodata.win_info=XCreateSimpleWindow(display, win_root,
518  infohint.x,infohint.y,infohint.width,infohint.height,2,
520  XSetWindowColormap(display, infodata.win_info, colormap);
521  icon=XCreateBitmapFromData(display,infodata.win_info,
522  (_Xconst char *) crossfire_bits,
523  (unsigned int) crossfire_width, (unsigned int)crossfire_height);
524  XSetStandardProperties(display,infodata.win_info,"Crossfire - text",
525  "Crosstext",icon,gargv,gargc,&(infohint));
526  infodata.gc_info=XCreateGC(display,infodata.win_info,0,0);
527  XSetForeground(display,infodata.gc_info,foreground);
528  XSetBackground(display,infodata.gc_info,background);
529 
530  XSetFont(display,infodata.gc_info,font->fid);
531 
532  XSelectInput(display,infodata.win_info,
533  ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask|
534  StructureNotifyMask);
535  XSetWMProtocols(display, infodata.win_info, &wm_delete_window, 1);
536  XMapRaised(display,infodata.win_info);
537  if (infodata.maxlines>infodata.maxdisp) infodata.has_scrollbar=1;
538  infodata.info_chars = (infohint.width/FONTWIDTH)-1;
539  if (infodata.has_scrollbar) infodata.info_chars -=3;
540  infodata.max_info_chars=infodata.info_chars;
541  infodata.data=(InfoLine *) malloc(sizeof(InfoLine) * infodata.maxlines);
542  infodata.bar_length=infodata.height - 8;
543  for (i=0; i<infodata.maxlines; i++) {
544  infodata.data[i].info = malloc(sizeof(char)* (infodata.info_chars+1));
545  infodata.data[i].info[0]='\0';
546  infodata.data[i].color=0;
547  }
548 
549  return 0;
550 }
551 
552 static void delete_ch(void) {
553  if(strlen(cpl.input_text)==0)
554  return;
555  cpl.input_text[strlen(cpl.input_text)-1] = '\0';
556 
557  /* If not on the first line but backspacing to the front, we need to
558  * do some special handling.
559  */
560  if ((strlen(cpl.input_text)>3) &&
561  strlen(infodata.data[infodata.infopos].info)<3) {
562  int line=infodata.infopos-1;
563  if (line<0) line=infodata.numlines;
564  strcpy(infodata.data[infodata.infopos].info,
565  infodata.data[line].info);
566  infodata.data[infodata.infopos].info[
567  strlen(infodata.data[infodata.infopos].info)-1]=0;
568  XDrawImageString(display,infodata.win_info,infodata.gc_info,
569  FONTWIDTH, (infodata.infoline+1)*FONTHEIGHT,
570  infodata.data[infodata.infopos].info,
571  strlen(infodata.data[infodata.infopos].info));
572  } else {
573  infodata.data[infodata.infopos].info[
574  strlen(infodata.data[infodata.infopos].info)-1]=0;
575  XDrawImageString(display,infodata.win_info,infodata.gc_info,
576  (strlen(infodata.data[infodata.infopos].info)+1)*FONTWIDTH,
577  (infodata.infoline+1)*FONTHEIGHT," ",1);
578  }
579 }
580 
581 /* Writes one character to the screen. Used when player is typing
582  * stuff we that we want to appear, or used to give prompts.
583  */
584 
585 void write_ch(char key)
586 {
587  char c2[2];
588 
589  /* Sort of a gross hack, but this gets it so that we actually put
590  * the command into the buffer.
591  */
592  if (key==13) {
593  /* We turn off command mode for the draw_info call, because
594  * it has special handling for normal output during command
595  * mode; but we do this manually now.
596  */
597  Input_State old_state = cpl.input_state;
599  draw_info(infodata.data[infodata.infopos].info,NDI_BLACK);
600  cpl.input_state = old_state;
601  return;
602  }
603 
604  if (infodata.lastcolor!=NDI_BLACK) {
605  XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel);
606  infodata.lastcolor=NDI_BLACK;
607  }
608 
609  if (key == 9) { /* Tab */
610  /* check for command mode */
611  if (infodata.data[infodata.infopos].info[0] == '>') {
612  const char *str = complete_command(infodata.data[infodata.infopos].info+1);
613 
614  if (str != NULL) {
615  /* +1 so that we keep our > at start of line. Don't
616  * recopy the data on top of ourself.
617  */
618  strcpy(infodata.data[infodata.infopos].info+1, str);
619  strcpy(cpl.input_text, str);
620  }
621  }
622  } else {
623 
624  if ((key < 32 || (unsigned char) key > 127) && key != 8)
625  return;
626  c2[0] = key;
627  c2[1] ='\0';
628 
629 
630  if(key==8||key==127) {
631  /* By backspacking enough, let them get out of command mode */
632  if (cpl.input_text[0]=='\0' && cpl.input_state==Command_Mode) {
634  /* Erase the prompt */
635  XDrawImageString(display,infodata.win_info,infodata.gc_info,
636  FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT," ",1);
637  }
638  delete_ch();
639  return;
640  }
641  /* Give some leeway here */
642  if(strlen(cpl.input_text)>=(MAX_BUF-15))
643  return;
644 
645  strcat(cpl.input_text,c2);
646  }
647 
648  if(strlen(infodata.data[infodata.infopos].info)>=(infodata.info_chars-2)) {
649  /* Draw the currently line and scroll down one */
650 
651  /* We turn off command mode for the draw_info call, because
652  * it has special handling for normal output during command
653  * mode; but we do this manually now.
654  */
656  draw_info(infodata.data[infodata.infopos].info,NDI_BLACK);
658  infodata.data[infodata.infopos].info[0]=(((strlen(cpl.input_text)/
659  infodata.info_chars))%10)+49;
660  infodata.data[infodata.infopos].info[1]='>';
661  infodata.data[infodata.infopos].info[2]=0;
662  XDrawImageString(display,infodata.win_info,infodata.gc_info,
663  FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
664  infodata.data[infodata.infopos].info,
665  strlen(infodata.data[infodata.infopos].info));
666  }
667 
668  if (key != 9 ) strcat(infodata.data[infodata.infopos].info,(cpl.no_echo? "?": c2));
669 
670  XDrawImageString(display,infodata.win_info,infodata.gc_info,
671  FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
672  infodata.data[infodata.infopos].info,
673  strlen(infodata.data[infodata.infopos].info));
674 }
675 
676 
677 
678 /* This is similar to draw_info below, but doesn't advance to a new
679  * line. Generally, queries use this function to draw the prompt for
680  * the name, password, etc.
681  * This also starts from character position 0. Thus, only 1 call of this
682  * per a given line is useful
683  */
684 
685 void draw_prompt(const char *str)
686 {
687  if (infodata.lastcolor!=NDI_BLACK) {
688  XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel);
689  infodata.lastcolor=NDI_BLACK;
690  }
691 
692  strncpy(infodata.data[infodata.infopos].info,str,infodata.info_chars);
693  infodata.data[infodata.infopos].info[infodata.info_chars] = '\0';
694  infodata.data[infodata.infopos].color=NDI_BLACK;
695  XDrawImageString(display,infodata.win_info,
696  infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
697  infodata.data[infodata.infopos].info,
698  strlen(infodata.data[infodata.infopos].info));
699 }
700 
701 /* If redarew is true, draw the scrollbar no matter what */
702 static void draw_info_scrollbar(int redraw)
703 {
704  static int last_length=0, last_y=0;
705 
706  if (!infodata.has_scrollbar) return;
707 
708  if (infodata.numlines <infodata.maxdisp) {
709  infodata.bar_size=infodata.bar_length;
710  infodata.bar_y=0;
711  }
712  else {
713  infodata.bar_size=infodata.bar_length*infodata.maxdisp/infodata.numlines;
714  infodata.bar_y=infodata.bar_length*(infodata.bar_pos-infodata.maxdisp)/infodata.numlines;
715  if (infodata.bar_y<0) infodata.bar_y=0;
716  }
717 /*
718  if ((infodata.bar_size+infodata.bar_y)>infodata.bar_length) {
719  infodata.bar_y=infodata.bar_length-infodata.bar_size;
720  }
721 */
722  if (!redraw && last_length==infodata.bar_size && last_y==infodata.bar_y) return;
723 
724  last_y=infodata.bar_y;
725  last_length=infodata.bar_size;
726 
727  /* Note - with the way this is set up, it wouldn't be too hard to make
728  * the scrollbar color customizable
729  */
730  if (infodata.lastcolor!=NDI_BLACK) {
731  XSetForeground(display,infodata.gc_info,discolor[NDI_BLACK].pixel);
732  infodata.lastcolor=NDI_BLACK;
733  }
734 
735  XDrawRectangle(display, infodata.win_info,
736  infodata.gc_info, infodata.width-SCROLLBAR_WIDTH-6,
737  3, 20,
738  infodata.height -6);
739  XClearArea(display, infodata.win_info,
740  infodata.width-SCROLLBAR_WIDTH-4, 4, 16,
741  infodata.bar_length, False);
742 
743  XFillRectangle(display, infodata.win_info, infodata.gc_info,
744  infodata.width - SCROLLBAR_WIDTH-4,4+infodata.bar_y,
745  16, infodata.bar_size);
746 }
747 
748 /* draw_info adds a line to the info window. */
749 
750 void draw_info(const char *str, int color) {
751  char *cp;
752  uint16 new_infopos = (infodata.infopos+1)% infodata.maxlines ;
753  size_t len;
754 
755  if(str == (char *) NULL) {
756  draw_info("[NULL]",color);
757  return;
758  }
759 
760  if((cp=strchr(str,'\n'))!=NULL) {
761  /* 4096 is probably way overkill, but 1024 could very well be too small.
762  * And I don't see the need to malloc and then free this either -
763  * this is a single user program.
764  */
765  char obuf[4096],*buf = obuf;
766 
767  strncpy(buf,str, 4095);
768  do {
769  if ((cp = strchr(buf, '\n'))) {
770  *cp='\0';
771  draw_info(buf,color);
772  buf = cp +1;
773  } else
774  draw_info(buf,color);
775  } while (cp!=NULL);
776  return;
777  }
778 
779  /* Lets do the word wrap for messages - MSW */
780  if ((int)strlen(str) >= infodata.info_chars) {
781  int i=infodata.info_chars-1;
782 
783  /* i=last space (or ')' for armor. Wrap armor, because
784  otherwise, the two sets of ()() can be about half the line */
785  while ((str[--i]!=' ') && (str[i]!=')') && (i!=0)) ;
786  /* if i==0, string has no space. Just let it be truncated */
787  if (i!=0) {
788  char *buf = (char *)malloc(sizeof(char)*(i+2));
789  int j;
790 
791  i++; /* want to keep the ')'. This also keeps
792  the space, but that really doesn't matter */
793  strncpy(buf, str, i);
794  buf[i]='\0';
795  draw_info(buf,color);
796  free(buf);
797 
798  for (j=i; j < (int)strlen(str); j++) /* if the wrap portion is */
799  if (str[j]!=' ') break; /* only space, don't wrap it*/
800  if ((((strlen(str)-i)!=1) || (str[i]!='.')) && (j!=strlen(str)))
801  draw_info((str+i),color);
802  return;
803  }
804  }
805 
806  /* This is the real code here - stuff above is just formating and making
807  * it look nice. This stuff here is actually drawing the code
808  */
809 
810  /* clear the new last line in window */
811  memset(infodata.data[new_infopos].info, 32, infodata.info_chars-1);
813  {
814  /* we copy the last command line to the new last line in window */
815  strcpy(infodata.data[new_infopos].info, infodata.data[infodata.infopos].info);
816  }
817  infodata.data[new_infopos].info[infodata.info_chars] = '\0';
818 
819  len = MIN(strlen(str), infodata.info_chars);
820  memmove(infodata.data[infodata.infopos].info, str, len);
821  infodata.data[infodata.infopos].info[len] = '\0';
822  infodata.data[infodata.infopos].color=color;
823 
824  /* This area is for scrollbar handling. The first check is to see if
825  * the scrollbar is at the very end, if it is, then we don't care about this.
826  * IF not at the end, then see if it is at the end of the window. If
827  * so, increase the bar position so that that view area keeps up with what
828  * is being drawn. If we are not at the end of the buffer, then decrease
829  * the bar position - in this way, we keep the same viewable area visible
830  * for redraws.
831  *
832  * A couple notes: If jump to end was desired on output, then this
833  * code just needs to be replaced with a line like infodata.bar_pos=
834  * infodata.numlines.
835  * If it is desired for the window to scroll up as new output is printed
836  * out, then the second case would need to be removed, and a draw_all_info
837  * call added instead.
838  */
839  if (infodata.bar_pos<infodata.maxlines) {
840  if (infodata.bar_pos==infodata.numlines) {
841  infodata.bar_pos++;
842  }
843  else if (infodata.numlines==infodata.maxlines) {
844  infodata.bar_pos--;
845  if (infodata.bar_pos<infodata.maxdisp)
846  infodata.bar_pos=infodata.maxdisp;
847  }
848  }
849  if (infodata.numlines<infodata.maxlines) infodata.numlines++;
850 
851  /* Basically, if we don't have a scrollbar, or we are at the end of it,
852  * then do the drawing stuff, otherwise don't.
853  */
854  if (!infodata.has_scrollbar || infodata.bar_pos>=infodata.numlines) {
855  /*
856  * The XDrawImageString draws the line.
857  */
858  if (infodata.lastcolor!=color) {
859  XSetForeground(display,infodata.gc_info,discolor[color].pixel);
860  infodata.lastcolor=color;
861  }
862 
863  XDrawImageString(display,infodata.win_info,
864  infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
865  infodata.data[infodata.infopos].info,
866  strlen(infodata.data[infodata.infopos].info));
867 
868  /* Now it gets potentially more complicated - now we have to handle
869  * wrapping and stuff like that.
870  */
871 
872  if(++(infodata.infoline)>=infodata.maxdisp){
873  if (infodata.scroll_info_window) {
874  XCopyArea(display,infodata.win_info,infodata.win_info,
875  infodata.gc_info,0,FONTHEIGHT,infodata.info_chars*FONTWIDTH,
876  infodata.maxdisp*FONTHEIGHT,0,0);
877  infodata.infoline--;
878  }
879  else
880  infodata.infoline=0;
881  }
882  }
883 
884  infodata.infopos = new_infopos;
885 
886  if (!infodata.has_scrollbar || infodata.bar_pos>=infodata.numlines) {
888  {
889  uint8 endpos = strlen(infodata.data[infodata.infopos].info);
890 
891  infodata.data[infodata.infopos].info[endpos] = ' ';
892  XDrawImageString(display,infodata.win_info,
893  infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
894  infodata.data[infodata.infopos].info, infodata.info_chars-1);
895  infodata.data[infodata.infopos].info[endpos] = '\0';
896  }
897  else
898  {
899  XDrawImageString(display,infodata.win_info,
900  infodata.gc_info,FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
901  infodata.data[infodata.infopos].info, infodata.info_chars-1);
902  }
903  }
904 
905  /* If in a reply state, grab the input buffer and store it.
906  */
907  if (cpl.input_state==Reply_Many) {
908  strncpy(infodata.data[infodata.infopos].info, cpl.input_text,
909  infodata.info_chars);
910  infodata.data[infodata.infopos].info[infodata.info_chars] = '\0';
911 
912  XDrawImageString(display,infodata.win_info,infodata.gc_info,
913  FONTWIDTH,(infodata.infoline+1)*FONTHEIGHT,
914  infodata.data[infodata.infopos].info,
915  strlen(infodata.data[infodata.infopos].info));
916  }
917  /* We should have some intelligent checks so it is not drawn unnecessarily */
919 }
920 
921 /* This is pretty much print_message, but the name is changed, and some
922  * unnecessary code has been removed.
923  */
924 
925 void draw_color_info(int colr, const char *buf){
926  draw_info(buf,colr);
927 }
928 
929 
930 /*
931  * draw_all_info is only needed for redraws, which includes scrollbar
932  * movement
933  */
934 
935 
936 static void draw_all_info(void) {
937  int i;
938 
939  XClearWindow(display,infodata.win_info);
940  if (infodata.numlines>=infodata.maxdisp) {
941  int startline=infodata.infopos-infodata.maxdisp-
942  (infodata.numlines-infodata.bar_pos)+1,displine=0;
943 
944  if (startline<0) startline+=infodata.maxlines;
945 
946  /* If we are scrolling back (bar_pos<numlines), then we want to
947  * start drawing from the top, and want to keep displine 0.
948  */
949  if (!infodata.scroll_info_window) {
950  if (infodata.bar_pos>=infodata.numlines) {
951  displine=(infodata.infoline+1) % infodata.maxdisp;
952  /* So that when we now that we have scrolled back */
953 
954  }
955  else infodata.infoline=infodata.maxdisp-1;
956  }
957 
958  for (i=0; i<infodata.maxdisp; i++) {
959  if (infodata.lastcolor!=infodata.data[startline].color) {
960  XSetForeground(display,infodata.gc_info,
961  discolor[infodata.data[startline].color].pixel);
962  infodata.lastcolor=infodata.data[startline].color;
963  }
964  XDrawImageString(display,infodata.win_info,
965  infodata.gc_info,FONTWIDTH,(displine+1)*FONTHEIGHT,
966  infodata.data[startline].info,
967  strlen(infodata.data[startline].info));
968  startline++;
969  startline %= infodata.maxlines;
970  displine++;
971  displine %= infodata.maxdisp;
972  }
973  }
974  else {
975  for(i=0;i<=infodata.numlines;i++) {
976  if (infodata.lastcolor!=infodata.data[i].color) {
977  XSetForeground(display,infodata.gc_info,
978  discolor[infodata.data[i].color].pixel);
979  infodata.lastcolor=infodata.data[i].color;
980  }
981  XDrawImageString(display,infodata.win_info,
982  infodata.gc_info,FONTWIDTH,(i+1)*FONTHEIGHT,
983  infodata.data[i].info,strlen(infodata.data[i].info));
984  }
985  }
987 }
988 
989 static void resize_win_message(int width, int height) {
990  messagehint.width = width;
991  messagehint.height = height;
992 }
993 
994 static void resize_win_info(int width, int height) {
995  int chars=(width/FONTWIDTH)-1;
996  int lines=(height/FONTHEIGHT)-1;
997  int i;
998  InfoLine *newlines;
999 
1000  if (infodata.width==width &&
1001  infodata.height==height) return;
1002 
1003  if(chars<3 || lines<3)
1004  return;
1005 
1006  infodata.width=width;
1007  infodata.height=height;
1008  infodata.bar_length=infodata.height - 8;
1009  if (infodata.has_scrollbar) chars-=3;
1010 
1011 
1012  /* We have a scrollback buffer. All we need to change then is maxdisp */
1013  if (infodata.maxdisp != infodata.maxlines && lines<infodata.maxlines) {
1014  /* Move insert line to bottom of the screen if we are already there
1015  * or it would otherwise be off the screen.
1016  */
1017  if (((infodata.infoline+1) == infodata.maxdisp) ||
1018  (infodata.infoline >= lines)) infodata.infoline = lines - 1;
1019  infodata.maxdisp=lines;
1020  }
1021  /* The window has changed size, but the amount of data we can display
1022  * has not. so just redraw the window and return.
1023  */
1024  if (chars == infodata.info_chars && lines == infodata.maxdisp) {
1025  draw_all_info();
1026  return;
1027  }
1028 
1029  /* Either we have a scrollbar (as above), or the window has not
1030  * changed in height, so we just need to change the size of the
1031  * buffers.
1032  */
1033  if (lines == infodata.maxdisp) {
1034  for (i=0; i<infodata.maxlines; i++) {
1035  if (chars>infodata.max_info_chars) {
1036  infodata.data[i].info= realloc(infodata.data[i].info, sizeof(char) * (chars+1));
1037  }
1038  /* Terminate buffer in both cases */
1039  infodata.data[i].info[chars]='\0';
1040  }
1041  infodata.info_chars=chars;
1042  draw_all_info();
1043  return;
1044  }
1045  /* IF we get here, the window has grown or shrunk, and we don't have
1046  * a scrollbar. This code is a lot simpler than what was here before,
1047  * but probably is not as efficient (But with the number of resize
1048  * events likely, this should not be a big deal).
1049  */
1050 
1051  /* First, allocate new storage */
1052  newlines = malloc(sizeof(InfoLine) * lines);
1053  for (i=0; i<lines; i++) {
1054  newlines[i].info = malloc(sizeof(char) * (chars +1));
1055  newlines[i].info[0]='\0';
1056  newlines[i].color=0;
1057  }
1058  /* First case - we can keep all the old data. Note that the old
1059  * buffer could have been filled up, so we still need to do some
1060  * checking to find the start
1061  */
1062  if (infodata.numlines <= lines) {
1063  int start=0,k;
1064 
1065  /* Buffer was full, so the start could be someplace else */
1066  if (infodata.numlines == infodata.maxlines) {
1067  start = infodata.infopos+1;
1068  }
1069  for (i=0; i<infodata.numlines; i++) {
1070  k= (start+i) % infodata.maxlines;
1071  strncpy(newlines[i].info, infodata.data[k].info, chars);
1072  newlines[i].info[chars]=0;
1073  newlines[i].color = infodata.data[k].color;
1074  }
1075  }
1076  else {
1077  /* We have to lose data, so keep the most recent. */
1078 
1079  int start=infodata.infopos-lines,k;
1080 
1081  if (start<0) start += infodata.maxlines;
1082  for (i=0; i<lines; i++) {
1083  k= (start+i) % infodata.maxlines;
1084  strncpy(newlines[i].info, infodata.data[k].info, chars);
1085  newlines[i].info[chars]=0;
1086  newlines[i].color = infodata.data[k].color;
1087  }
1088  infodata.infopos = 0;
1089  newlines[0].info[0] = '\0';
1090  infodata.infoline = lines-1;
1091  infodata.numlines = lines;
1092  infodata.bar_pos = lines;
1093  }
1094  infodata.maxdisp = lines;
1095  for (i=0; i<infodata.maxlines; i++) {
1096  free(infodata.data[i].info);
1097  }
1098  free(infodata.data);
1099  infodata.data = newlines;
1100  infodata.maxlines = lines;
1101  infodata.info_chars=chars;
1102  draw_all_info();
1103 }
1104 
1105 
1106 
1107 
1108 /***********************************************************************
1109  *
1110  * Stats window functions follow
1111  *
1112  ***********************************************************************/
1113 
1114 static int get_stats_display(void) {
1115  XSizeHints stathint;
1116 
1117  stathint.x=INV_WIDTH + WINDOW_SPACING;
1118  stathint.y=0;
1119  stathint.width=GAME_WIDTH;
1120  stathint.height=STAT_HEIGHT;
1121  stathint.min_width=stathint.max_width=stathint.width;
1122  stathint.min_height=stathint.max_height=stathint.height;
1123  stathint.flags=PPosition | PSize;
1124  win_stats=XCreateSimpleWindow(display,win_root,
1125  stathint.x,stathint.y,stathint.width,stathint.height,2,
1127  XSetWindowColormap(display, win_stats, colormap);
1128  icon=XCreateBitmapFromData(display,win_stats,
1129  (_Xconst char *) crossfire_bits,
1130  (unsigned int) crossfire_width, (unsigned int)crossfire_height);
1131  XSetStandardProperties(display,win_stats,"Crossfire - status",
1132  "crosstatus",icon,gargv,gargc, &(stathint));
1133 
1134  gc_stats=XCreateGC(display,win_stats,0,0);
1135  XSetForeground(display,gc_stats,foreground);
1136  XSetBackground(display,gc_stats,background);
1137  XSetFont(display,gc_stats,font->fid);
1138  XSelectInput(display,win_stats,KeyPressMask|KeyReleaseMask|ExposureMask);
1139  XMapRaised(display,win_stats);
1140  XSetWMProtocols(display, win_stats, &wm_delete_window, 1);
1141  return 0;
1142 }
1143 
1144 /* This draws the stats window. If redraw is true, it means
1145  * we need to redraw the entire thing, and not just do an
1146  * updated.
1147  */
1148 
1149 void draw_stats(int redraw) {
1150  char buff[MAX_BUF];
1151  static char last_name[MAX_BUF]="", last_range[MAX_BUF]="";
1152  int i;
1153  char *s;
1154 
1155  if (strcmp(cpl.title, last_name) || redraw) {
1156  strcpy(last_name,cpl.title);
1157  strcpy(buff,cpl.title);
1158  strcat(buff," ");
1159  XDrawImageString(display,win_stats,
1160  gc_stats,10,10, buff,strlen(buff));
1161  }
1162 
1163  if(redraw || cpl.stats.exp!=last_stats.exp ||
1164  cpl.stats.level!=last_stats.level) {
1165  sprintf(buff,"Score: %5" FMT64 " Level: %d",cpl.stats.exp,
1166  cpl.stats.level);
1167  strcat(buff," ");
1168  XDrawImageString(display,win_stats,
1169  gc_stats,10,24, buff,strlen(buff));
1170 
1171  last_stats.exp = cpl.stats.exp;
1172  last_stats.level = cpl.stats.level;
1173  }
1174 
1175  if(redraw ||
1176  cpl.stats.hp!=last_stats.hp || cpl.stats.maxhp!=last_stats.maxhp ||
1177  cpl.stats.sp!=last_stats.sp || cpl.stats.maxsp!=last_stats.maxsp ||
1178  cpl.stats.grace!=last_stats.grace ||
1179  cpl.stats.maxgrace!=last_stats.maxgrace) {
1180 
1181  sprintf(buff,"Hp %d/%d Sp %d/%d Gr %d/%d",
1185 
1186  strcat(buff," ");
1187  XDrawImageString(display,win_stats,
1188  gc_stats,10,38, buff,strlen(buff));
1189  last_stats.hp=cpl.stats.hp;
1190  last_stats.maxhp=cpl.stats.maxhp;
1191  last_stats.sp=cpl.stats.sp;
1192  last_stats.maxsp=cpl.stats.maxsp;
1193  last_stats.grace=cpl.stats.grace;
1194  last_stats.maxgrace=cpl.stats.maxgrace;
1195  }
1196 
1197  if(redraw || cpl.stats.Dex!=last_stats.Dex ||
1198  cpl.stats.Con!=last_stats.Con || cpl.stats.Str!=last_stats.Str ||
1199  cpl.stats.Int!=last_stats.Int || cpl.stats.Wis!=last_stats.Wis ||
1200  cpl.stats.Cha!=last_stats.Cha || cpl.stats.Pow!=last_stats.Pow) {
1201 
1202  sprintf(buff,"S%2d D%2d Co%2d I%2d W%2d P%2d Ch%2d",
1205  cpl.stats.Cha);
1206 
1207  strcat(buff," ");
1208  XDrawImageString(display,win_stats,
1209  gc_stats,10,52, buff,strlen(buff));
1210 
1211  last_stats.Str=cpl.stats.Str;
1212  last_stats.Con=cpl.stats.Con;
1213  last_stats.Dex=cpl.stats.Dex;
1214  last_stats.Int=cpl.stats.Int;
1215  last_stats.Wis=cpl.stats.Wis;
1216  last_stats.Cha=cpl.stats.Cha;
1217  last_stats.Pow=cpl.stats.Pow;
1218  }
1219 
1220  if(redraw || cpl.stats.wc!=last_stats.wc ||
1221  cpl.stats.ac!=last_stats.ac ||
1222  cpl.stats.resists[0]!=last_stats.resists[0] ||
1223  cpl.stats.dam!=last_stats.dam) {
1224 
1225  sprintf(buff,"Wc:%3d Dam:%3d Ac:%3d Arm:%3d",
1227  cpl.stats.resists[0]);
1228  strcat(buff," ");
1229  XDrawImageString(display,win_stats,
1230  gc_stats,10,66, buff,strlen(buff));
1231 
1232  last_stats.wc=cpl.stats.wc;
1233  last_stats.ac=cpl.stats.ac;
1234  last_stats.dam=cpl.stats.dam;
1235  last_stats.resists[0] = cpl.stats.resists[0];
1236  }
1237 
1238  if(redraw || last_stats.speed!=cpl.stats.speed ||
1239  cpl.stats.food!=last_stats.food ||
1240  cpl.stats.weapon_sp != last_stats.weapon_sp) {
1241  /* since both speed and weapon speed have been multiplied by
1242  * the same value, to get proper weapon, we only need to divide
1243  * by speed - the multiplication/division factor on both factors
1244  * out.
1245  */
1246  double weap_sp;
1247 
1248  /* Seems that weapon_sp can be 0 in some cases which caused SIGFPE's */
1249  if (cpl.stats.weapon_sp ==0) weap_sp = 0;
1250  else weap_sp = (float) cpl.stats.speed/ ((float)cpl.stats.weapon_sp);
1251 
1252  /* The following is generating an FPE on alpha systems - changed
1253  * everything to be doubles to see if that might make some
1254  * difference.
1255  */
1256  if(cpl.stats.food<100 && (cpl.stats.food&4)) {
1257  sprintf(buff,"Speed: %3.2f (%1.2f) Food: *%d* HUNGRY!",
1258  (double)cpl.stats.speed/FLOAT_MULTF,
1259  weap_sp,cpl.stats.food);
1260  if (use_config[CONFIG_FOODBEEP] && (cpl.stats.food%4==3)) XBell(display, 0);
1261  } else {
1262  sprintf(buff,"Speed: %3.2f (%1.2f) Food: %3d",
1263  (float)cpl.stats.speed/FLOAT_MULTF,
1264  weap_sp, cpl.stats.food);
1265  if (use_config[CONFIG_FOODBEEP] && cpl.stats.food<1) XBell(display,100);
1266  }
1267 
1268  strcat(buff," ");
1269  XDrawImageString(display,win_stats,
1270  gc_stats,10,80, buff,strlen(buff));
1271 
1272  last_stats.food=cpl.stats.food;
1273  last_stats.speed = cpl.stats.speed;
1274  last_stats.weapon_sp = cpl.stats.weapon_sp;
1275  }
1276  if (redraw || strcmp(cpl.range, last_range)) {
1277  strcpy(last_range, cpl.range);
1278  strcpy(buff,cpl.range);
1279  strcat(buff," ");
1280  XDrawImageString(display,win_stats,
1281  gc_stats,10,94, buff,strlen(buff));
1282  }
1283 
1284  const int skills_per_line = 2;
1285  int on_skill=1;
1286 
1287  *buff = '\0';
1288  s = buff;
1289  for(i = 0; last_used_skills[i] >= 0; ++i)
1290  {
1291  int skill_id = last_used_skills[i];
1292 
1293  if (!skill_names[skill_id] || !cpl.stats.skill_exp[skill_id]) continue;
1294 
1295  last_stats.skill_level[skill_id] = cpl.stats.skill_level[skill_id];
1296  last_stats.skill_exp[skill_id] = cpl.stats.skill_exp[skill_id];
1297  s += sprintf(s,"%.3s: %7" FMT64 " (%d) ", skill_names[skill_id], cpl.stats.skill_exp[skill_id],
1298  cpl.stats.skill_level[skill_id]);
1299  if ((on_skill % skills_per_line) == 0) {
1300  XDrawImageString(display,win_stats,gc_stats,10,
1301  108 + (14 * (on_skill / skills_per_line)), buff,strlen(buff));
1302  *buff = '\0';
1303  s = buff;
1304  }
1305  on_skill++;
1306  }
1307  if (*buff)
1308  XDrawImageString(display,win_stats,gc_stats,10,
1309  108 + (14 * (on_skill / skills_per_line)), buff,strlen(buff));
1310  }
1311 
1312 /***********************************************************************
1313 *
1314 * Handles the message window
1315 *
1316 ***********************************************************************/
1317 
1318 static int get_message_display(void) {
1319 
1321  /* Game window is square so we can use the width */
1322  messagehint.y=GAME_WIDTH + STAT_HEIGHT+WINDOW_SPACING*2;
1323  messagehint.width=GAME_WIDTH;
1324  messagehint.height=roothint.height - messagehint.y;
1325  messagehint.max_width=messagehint.min_width=messagehint.width;
1326  messagehint.max_height=STAT_HEIGHT;
1327  messagehint.min_height=messagehint.height;
1328  messagehint.flags=PPosition | PSize;
1329  win_message=XCreateSimpleWindow(display,win_root,
1331  messagehint.height,2,foreground,background);
1332  XSetWindowColormap(display, win_message, colormap);
1333  icon=XCreateBitmapFromData(display,win_message,
1334  (_Xconst char *) crossfire_bits,
1335  (unsigned int) crossfire_width, (unsigned int)crossfire_height);
1336  XSetStandardProperties(display,win_message,"Crossfire - vitals",
1337  "crossvitals",icon, gargv,gargc,&(messagehint));
1338  gc_message=XCreateGC(display,win_message,0,0);
1339  XSetForeground(display,gc_message,foreground);
1340  XSetBackground(display,gc_message,background);
1341  XSetFont(display,gc_message,font->fid);
1342  XSelectInput(display,win_message,
1343  ButtonPressMask|KeyPressMask|KeyReleaseMask|ExposureMask);
1344  XSetWMProtocols(display, win_message, &wm_delete_window, 1);
1345  XMapRaised(display,win_message);
1346  return 0;
1347 }
1348 
1349 static void xwritedown(const char *txt, int x) {
1350  int y=13;
1351  for(;*txt!='\0';txt++,y+=13)
1352  XDrawImageString(display,win_message,
1353  look_list.gc_text,x,y,txt,1);
1354 }
1355 
1356 #define MAX_BARS_MESSAGE 80
1357 
1358 static void draw_stat_bar(int bar_pos, int height, int is_alert)
1359 {
1360  if(height!=MAX_BARS_MESSAGE) /* clear the top of the bar */
1361  XClearArea(display,win_message, bar_pos, 4,
1362  10, MAX_BARS_MESSAGE-height, 0);
1363 
1364  if(height==0) /* empty bar */
1365  return;
1366 
1367  if(is_alert) /* this should have its own gc */
1368  XSetForeground(display,look_list.gc_text,
1369  discolor[3].pixel);
1370 
1371  XFillRectangle(display,win_message,
1372  look_list.gc_text, bar_pos, 4+MAX_BARS_MESSAGE-height, 10, height);
1373 
1374  if(is_alert)
1375  XSetForeground(display,look_list.gc_text,
1376  foreground);
1377 }
1378 
1379 
1380 /* This updates the status bars. If redraw, then redraw them
1381  * even if they have not changed
1382  */
1383 
1384 void draw_message_window(int redraw) {
1385  int bar,is_alert,flags;
1386  static uint16 oldflags=0;
1387  static uint16 scrollsize_hp=0, scrollsize_sp=0, scrollsize_food=0,
1388  scrollsize_grace=0;
1389  static uint8 scrollhp_alert=FALSE, scrollsp_alert=FALSE,
1390  scrollfood_alert=FALSE, scrollgrace_alert=FALSE;
1391 
1392  /* draw hp bar */
1393  if(cpl.stats.maxhp>0)
1394  {
1396  if(bar<0)
1397  bar=0;
1398  is_alert=(cpl.stats.hp <= cpl.stats.maxhp/4);
1399  }
1400  else
1401  {
1402  bar=0;
1403  is_alert=0;
1404  }
1405  if (redraw || scrollsize_hp!=bar || scrollhp_alert!=is_alert)
1406  draw_stat_bar(20, bar, is_alert);
1407  scrollsize_hp=bar;
1408  scrollhp_alert=is_alert;
1409 
1410  /* draw sp bar. spellpoints can go above max
1411  * spellpoints via supercharging with the transferrance spell,
1412  * or taking off items that raise max spellpoints.
1413  */
1414  if (cpl.stats.sp>cpl.stats.maxsp)
1415  bar = MAX_BARS_MESSAGE;
1416  else
1418  if(bar<0)
1419  bar=0;
1420 
1421  is_alert=(cpl.stats.sp <= cpl.stats.maxsp/4);
1422 
1423  if (redraw || scrollsize_sp!=bar || scrollsp_alert!=is_alert)
1424  draw_stat_bar(60, bar, is_alert);
1425 
1426  scrollsize_sp=bar;
1427  scrollsp_alert=is_alert;
1428 
1429  /* draw sp bar. grace can go above max or below min */
1431  bar = MAX_BARS_MESSAGE;
1432  else
1434  if(bar<0)
1435  bar=0;
1436 
1437  is_alert=(cpl.stats.grace <= cpl.stats.maxgrace/4);
1438 
1439  if (redraw || scrollsize_grace!=bar || scrollgrace_alert!=is_alert)
1440  draw_stat_bar(100, bar, is_alert);
1441 
1442  scrollsize_grace=bar;
1443  scrollgrace_alert=is_alert;
1444 
1445  /* draw food bar */
1446  bar=(cpl.stats.food*MAX_BARS_MESSAGE)/999;
1447  if(bar<0)
1448  bar=0;
1449  is_alert=(cpl.stats.food <= 999/4);
1450 
1451  if (redraw || scrollsize_food!=bar || scrollfood_alert!=is_alert)
1452  draw_stat_bar(140, bar, is_alert);
1453 
1454  scrollsize_food=bar;
1455  scrollfood_alert=is_alert;
1456 
1457  flags = cpl.stats.flags;
1458 
1459  if (cpl.fire_on) flags |= SF_FIREON;
1460  if (cpl.run_on) flags |= SF_RUNON;
1461 
1462  if ((flags & SF_FIREON ) != (oldflags & SF_FIREON)) {
1463  if (flags & SF_FIREON)
1464  XDrawImageString(display, win_message,
1465  look_list.gc_text, 180, 15, "Fire On", 7);
1466  else
1467  XClearArea(display, win_message,
1468  180, 0, 60, 15, False);
1469  }
1470  if ((flags & SF_RUNON ) != (oldflags & SF_RUNON)) {
1471  if (flags & SF_RUNON)
1472  XDrawImageString(display, win_message,
1473  look_list.gc_text, 180, 30, "Run On", 6);
1474  else
1475  XClearArea(display, win_message,
1476  180, 15, 60, 15, False);
1477  }
1478  oldflags = flags;
1479  if (redraw || cpl.stats.resist_change) {
1480  int x=180, y=45,i;
1481  char buf[40];
1482 
1484  XClearArea(display, win_message, 180, 30, messagehint.width-180, messagehint.height-30, False);
1485  for (i=0; i<NUM_RESISTS; i++) {
1486  if (cpl.stats.resists[i]) {
1487  XDrawImageString(display, win_message,
1488  look_list.gc_text, x, y, resists_name[i],
1489  strlen(resists_name[i]));
1490  sprintf(buf,"%+4d", cpl.stats.resists[i]);
1491  XDrawImageString(display, win_message,
1492  look_list.gc_text, x+40, y, buf, strlen(buf));
1493  y+=15;
1494  /* Move to the next draw position. If we run
1495  * out of space, just break out of the function.
1496  */
1497  if (y>messagehint.height) break;
1498  } /* If we have a resistance with value */
1499  } /* For loop of resistances */
1500  } /* If we need to draw the resistances */
1501 }
1502 
1503 
1504 static void draw_all_message(void) {
1505 
1506  XClearWindow(display,win_message);
1507  xwritedown("HP",06);
1508  XDrawRectangle(display,win_message,
1509  look_list.gc_text,18,2,14,MAX_BARS_MESSAGE+4);
1510  xwritedown("Mana",46);
1511  XDrawRectangle(display,win_message,
1512  look_list.gc_text,58,2,14,MAX_BARS_MESSAGE+4);
1513  xwritedown("Grace",86);
1514  XDrawRectangle(display,win_message,
1515  look_list.gc_text,98,2,14,MAX_BARS_MESSAGE+4);
1516  xwritedown("Food",126);
1517  XDrawRectangle(display,win_message,
1518  look_list.gc_text,138,2,14,MAX_BARS_MESSAGE+4);
1520 }
1521 
1522 /****************************************************************************
1523  *
1524  * Inventory window functions follow
1525  *
1526  ****************************************************************************/
1527 
1528 
1529 static void draw_status_icon(itemlist *l, int x, int y, int face)
1530 {
1531  XCopyPlane(display, icons[face], l->win, l->gc_status, 0,0, 24,6, x,y, 1);
1532 }
1533 
1534 
1535 /* compares the 'flags' against the item. return 1 if we should draw
1536  * that object, 0 if it should not be drawn.
1537  */
1538 
1539 static int show_object(item *ip, inventory_show flags)
1540 {
1541  if (flags==show_all) return 1;
1542  if ((flags & show_applied) && (ip->applied)) return 1;
1543  if ((flags & show_unapplied) && (!ip->applied)) return 1;
1544  if ((flags & show_unpaid) && (ip->unpaid)) return 1;
1545  if ((flags & show_cursed) && (ip->cursed || ip->damned)) return 1;
1546  if ((flags & show_magical) && (ip->magical)) return 1;
1547  if ((flags & show_nonmagical) && (!ip->magical)) return 1;
1548  if ((flags & show_locked) && (ip->locked)) return 1;
1549  if ((flags & show_unlocked) && (!ip->locked)) return 1;
1550 
1551  /* Doesn't match - probalby don't want it then */
1552  return 0;
1553 }
1554 
1555 /* This will need to be changed to do the 'right thing' for different display
1556  * modes (use bitmap data if we are using bitmaps for the game.
1557  */
1558 
1559 static void create_status_icons(void)
1560 {
1561 #include "pixmaps/clear.xbm"
1562 #include "pixmaps/locked.xbm"
1563 #include "pixmaps/applied.xbm"
1564 #include "pixmaps/unpaid.xbm"
1565 #include "pixmaps/damned.xbm"
1566 #include "pixmaps/cursed.xbm"
1567 #include "pixmaps/magic.xbm"
1568 #include "pixmaps/close.xbm"
1569 #include "pixmaps/stipple.111"
1570 #include "pixmaps/stipple.112"
1571 
1572  static int hasinit=0;
1573  int x, y;
1574  GC tmpgc;
1575 
1576  if (hasinit) return;
1577  hasinit=1;
1578 
1579 #define CREATEPM(name,data) \
1580  (icons[name] = XCreateBitmapFromData(display, def_root,\
1581  data##_bits, data##_width, data##_height))
1582 
1583  if (0
1584  || CREATEPM(no_icon, clear) == None
1585  || CREATEPM(locked_icon, locked) == None
1586  || CREATEPM(applied_icon, applied) == None
1587  || CREATEPM(unpaid_icon, unpaid) == None
1588  || CREATEPM(damned_icon, damned) == None
1589  || CREATEPM(cursed_icon, cursed) == None
1590  || CREATEPM(magic_icon, magic) == None
1591  || CREATEPM(close_icon, close) == None
1592  || CREATEPM(stipple1_icon, stipple) == None
1593  || CREATEPM(stipple2_icon, stipple1) == None
1594  )
1595  {
1596  fprintf(stderr, "Unable to create pixmaps.\n");
1597  exit (0);
1598  }
1599  dark1 = XCreatePixmap(display, def_root, image_size, image_size, 1);
1600  dark2 = XCreatePixmap(display, def_root, image_size, image_size, 1);
1601  dark3 = XCreatePixmap(display, def_root, image_size, image_size, 1);
1602  tmpgc = XCreateGC(display, dark1, 0, 0);
1603  XSetFillStyle(display, tmpgc, FillSolid);
1604  XSetForeground(display, tmpgc, 1);
1605  XFillRectangle(display, dark1, tmpgc, 0, 0, image_size, image_size);
1606  XFillRectangle(display, dark2, tmpgc, 0, 0, image_size, image_size);
1607  XFillRectangle(display, dark3, tmpgc, 0, 0, image_size, image_size);
1608  XSetForeground(display, tmpgc, 0);
1609  for (x=0; x<image_size; x++) {
1610  for (y=0; y<image_size; y++) {
1611  /* we just fill in points every X pixels - dark1 is the darkest, dark3 is the li!
1612  * dark1 has 50% of the pixels filled in, dark2 has 33%, dark3 has 25%
1613  * The formula's here are not perfect - dark2 will not match perfectly with an
1614  * adjacent dark2 image. dark3 results in diagonal stripes. OTOH, these will
1615  * change depending on the image size.
1616  */
1617  if ((x+y) % 2) {
1618  XDrawPoint(display, dark1, tmpgc, x, y);
1619  }
1620  if ((x+y) %3) {
1621  XDrawPoint(display, dark2, tmpgc, x, y);
1622  }
1623  if ((x+y) % 4) {
1624  XDrawPoint(display, dark3, tmpgc, x, y);
1625  }
1626  }
1627  }
1628  XFreeGC(display, tmpgc);
1629 }
1630 
1631 /*
1632  * draw_list redraws changed item to the window and updates a scrollbar
1633  */
1634 static void draw_list (itemlist *l)
1635 {
1636  int i, items, size, pos;
1637  item *tmp;
1638  char buf[MAX_BUF], buf2[MAX_BUF];
1639 
1640  /* draw title */
1641  strcpy(buf2, l->title);
1642  if (l->show_what & show_mask) {
1643  strcat(buf2," (");
1644  if (l->show_what & show_applied) strcat(buf2,"applied, ");
1645  if (l->show_what & show_unapplied) strcat(buf2,"unapplied, ");
1646  if (l->show_what & show_unpaid) strcat(buf2,"unpaid, ");
1647  if (l->show_what & show_cursed) strcat(buf2,"cursed, ");
1648  if (l->show_what & show_magical) strcat(buf2,"magical, ");
1649  if (l->show_what & show_nonmagical) strcat(buf2,"nonmagical, ");
1650  if (l->show_what & show_locked) strcat(buf2,"locked, ");
1651  if (l->show_what & show_unlocked) strcat(buf2,"unlocked, ");
1652  /* want to kill the comma we put in above. Replace it with the paren */
1653  buf2[strlen(buf2)-2]=')';
1654  buf2[strlen(buf2)-1]='\0';
1655  }
1656  if(l->env->weight < 0 || l->show_weight == 0)
1657  sprintf (buf, l->format_n, buf2);
1658  else if (!l->weight_limit)
1659  sprintf (buf, l->format_nw, buf2, l->env->weight);
1660  else
1661  sprintf(buf, l->format_nwl, buf2, l->env->weight,
1662  l->weight_limit/1000);
1663 
1664  if (strcmp (buf, l->old_title)) {
1665  XCopyPlane(display, icons[l->env->open ? close_icon : no_icon],
1666  l->win, l->gc_status, 0,0, image_size,13, 2,2, 1);
1667  strcpy (l->old_title, buf);
1668  XDrawImageString(display, l->win, l->gc_text,
1669  (l->show_icon ? image_size+24+4 : image_size+4),
1670  13, buf, strlen(buf));
1671  }
1672 
1673  /* Find how many objects we should draw. */
1674 
1675  for(tmp = l->env->inv, items=0; tmp ;tmp=tmp->next)
1676  if (show_object(tmp, l->show_what)) items++;
1677 
1678  if(l->item_pos > items - l->size)
1679  l->item_pos = items - l->size;
1680  if(l->item_pos < 0)
1681  l->item_pos = 0;
1682 
1683  /* Fast forward to the appropriate item location */
1684 
1685  for(tmp = l->env->inv, i=l->item_pos; tmp && i; tmp=tmp->next)
1686  if (show_object(tmp, l->show_what)) i--;
1687 
1688  for(i=0; tmp && i < l->size; tmp=tmp->next) {
1689  if (!show_object(tmp, l->show_what)) continue;
1690  /* draw face */
1691  if(l->faces[i] != tmp->face) {
1692  l->faces[i] = tmp->face;
1693  XClearArea(display, l->win, 4, 16 + image_size * i,
1694  image_size, image_size, False);
1695  gen_draw_face (l->win, tmp->face,4, 16 + image_size * i, 0, 0);
1696  }
1697  /* draw status icon */
1698  if (l->show_icon) {
1699  sint8 tmp_icon;
1700  tmp_icon = tmp->locked ? locked_icon : no_icon;
1701  if (l->icon1[i] != tmp_icon) {
1702  l->icon1[i] = tmp_icon;
1703  draw_status_icon (l, image_size+4, 16 + image_size * i, tmp_icon);
1704  }
1705  tmp_icon = tmp->applied ? applied_icon :
1706  tmp->unpaid ? unpaid_icon : no_icon;
1707  if (l->icon2[i] != tmp_icon) {
1708  l->icon2[i] = tmp_icon;
1709  draw_status_icon (l, image_size+4, 22 + image_size * i, tmp_icon);
1710  }
1711  tmp_icon = tmp->magical ? magic_icon : no_icon;
1712  if (l->icon3[i] != tmp_icon) {
1713  l->icon3[i] = tmp_icon;
1714  draw_status_icon (l, image_size+4, 28 + image_size * i, tmp_icon);
1715  }
1716  tmp_icon = tmp->damned ? damned_icon :
1717  tmp->cursed ? cursed_icon : no_icon;
1718  if (l->icon4[i] != tmp_icon) {
1719  l->icon4[i] = tmp_icon;
1720  draw_status_icon (l, image_size+4, 34 + image_size * i, tmp_icon);
1721  }
1722  }
1723  /* draw name */
1724  strcpy (buf2, tmp->d_name);
1725  if (l->show_icon == 0)
1726  strcat (buf2, tmp->flags);
1727 
1728  if(tmp->weight < 0 || l->show_weight == 0)
1729  sprintf(buf, l->format_n, buf2);
1730  else
1731  sprintf(buf, l->format_nw, buf2, tmp->nrof * tmp->weight);
1732 
1733  if(!l->names[i] || strcmp(buf, l->names[i])) {
1734  copy_name (l->names[i], buf);
1735  XDrawImageString(display, l->win, l->gc_text,
1736  (l->show_icon?image_size+24+4:image_size+4),
1737  34 + image_size * i, buf, strlen(buf));
1738  }
1739  i++;
1740  }
1741 
1742  /* If there are not enough items to fill in the display area,
1743  * then set the unused ares to nothing.
1744  */
1745  if(items < l->item_used) {
1746  XClearArea(display, l->win, 0, 16 + image_size * i, l->width - 23,
1747  image_size * (l->size - i) , False);
1748  while (i < l->item_used) {
1749  copy_name (l->names[i], "");
1750  l->faces[i] = 0;
1751  l->icon1[i] = l->icon2[i] = l->icon3[i] = l->icon4[i] = 0;
1752  i++;
1753  }
1754  }
1755  l->item_used = items > l->size ? l->size : items;
1756 
1757  /* draw the scrollbar now */
1758  if(items < l->size)
1759  items = l->size;
1760 
1761  size = (long) l->bar_length * l->size / items;
1762  pos = (long) l->bar_length * l->item_pos / items;
1763 
1764  if(l->bar_size != size || pos != l->bar_pos) {
1765 
1766  XClearArea(display, l->win, l->width-20, 17 + l->bar_pos, 16,
1767  l->bar_size, False);
1768  l->bar_size = size;
1769  l->bar_pos = pos;
1770 
1771  XFillRectangle(display, l->win, l->gc_text, l->width - 20,
1772  17 + l->bar_pos, 16, l->bar_size);
1773  }
1774 }
1775 
1776 /*
1777  * draw_all_list clears a window and after that draws all objects
1778  * and a scrollbar
1779  */
1780 static void draw_all_list(itemlist *l)
1781 {
1782  int i;
1783 
1784  strcpy (l->old_title, "");
1785 
1786  for(i=0; i<l->size; i++) {
1787  copy_name(l->names[i], "");
1788  l->faces[i] = 0;
1789  l->icon1[i] = 0;
1790  l->icon2[i] = 0;
1791  l->icon3[i] = 0;
1792  l->icon4[i] = 0;
1793  }
1794 
1795  XClearWindow(display, l->win);
1796  XDrawRectangle(display, l->win, l->gc_text, l->width - 22, 15, 20,
1797  l->bar_length + 4);
1798 
1799 #if 0
1800  /* Don't reset these - causes window position to reset too often */
1801  l->item_pos = 0;
1802  l->item_used = 0;
1803 #endif
1804  l->bar_size = 1; /* so scroll bar is drawn */
1805  draw_list (l);
1806 }
1807 
1808 
1809 /* we have received new images. update these only */
1811 {
1812  int i;
1813  for (i = 0; i < l->size; ++i)
1814  l->faces[i] = 0;
1815  draw_list(l);
1816 }
1817 
1818 
1820 {
1821  look_list.env = op;
1822  sprintf (look_list.title, "%s:", op->d_name);
1823  draw_list (&look_list);
1824 }
1825 
1827 {
1828  look_list.env = cpl.below;
1829  strcpy (look_list.title, "You see:");
1830  draw_list (&look_list);
1831 }
1832 
1833 static void resize_list_info(itemlist *l, int w, int h)
1834 {
1835  int i;
1836 
1837  free(l->faces);
1838  free(l->icon1);
1839  free(l->icon2);
1840  free(l->icon3);
1841  free(l->icon4);
1842  if (l->names) {
1843  for (i=0; i < l->size; i++)
1844  if (l->names[i])
1845  free(l->names[i]);
1846  free(l->names);
1847  }
1848  l->width = w;
1849  l->height = h;
1850  l->size = (l->height - FONTHEIGHT - 8) / image_size;
1851  l->text_len = (l->width - (l->show_icon ? 84 : 60)) / FONTWIDTH;
1852  l->bar_length = l->size * image_size;
1853  sprintf (l->format_nw, "%%-%d.%ds%%6.1f", l->text_len-6, l->text_len-6);
1854  sprintf (l->format_nwl, "%%-%d.%ds%%6.1f/%%4d", l->text_len-11, l->text_len-11);
1855  sprintf (l->format_n, "%%-%d.%ds", l->text_len, l->text_len);
1856 
1857  if ((l->faces = malloc (sizeof (*(l->faces)) * l->size )) == NULL) {
1858  printf ("Can't allocate memory.\n");
1859  exit (0);
1860  }
1861  if ((l->icon1 = malloc (sizeof (*(l->icon1)) * l->size )) == NULL) {
1862  printf ("Can't allocate memory.\n");
1863  exit (0);
1864  }
1865  if ((l->icon2 = malloc (sizeof (*(l->icon2)) * l->size )) == NULL) {
1866  printf ("Can't allocate memory.\n");
1867  exit (0);
1868  }
1869  if ((l->icon3 = malloc (sizeof (*(l->icon3)) * l->size )) == NULL) {
1870  printf ("Can't allocate memory.\n");
1871  exit (0);
1872  }
1873  if ((l->icon4 = malloc (sizeof (*(l->icon4)) * l->size )) == NULL) {
1874  printf ("Can't allocate memory.\n");
1875  exit (0);
1876  }
1877  if ((l->names = malloc (sizeof (char *) * l->size )) == NULL) {
1878  printf ("Can't allocate memory.\n");
1879  exit (0);
1880  }
1881  for (i=0; i < l->size; i++) {
1882  if ((l->names[i] = malloc (NAME_LEN)) == NULL) {
1883  printf ("Can't allocate memory.\n");
1884  exit (0);
1885  }
1886  }
1887  draw_all_list(l); /* this also initializes above allocated tables */
1888 }
1889 
1890 static void get_list_display(itemlist *l, int x, int y, int w, int h,
1891  const char *t, const char *s)
1892 {
1893  XSizeHints hint;
1894 
1895  l->faces=NULL;
1896  l->names=NULL;
1897  hint.x = x;
1898  hint.y = y;
1899  hint.width = w;
1900  hint.height = h;
1901  hint.min_width = 60 + 10 * FONTWIDTH;
1902  hint.min_height = FONTHEIGHT + 8 + image_size * 2;
1903  hint.flags = PPosition | PSize;
1904  l->win = XCreateSimpleWindow(display, win_root, hint.x, hint.y, hint.width,
1905  hint.height, 2, foreground, background);
1906  XSetWindowColormap(display, l->win, colormap);
1907  icon = XCreateBitmapFromData(display, l->win,
1908  (_Xconst char *) crossfire_bits,
1909  (unsigned int) crossfire_width,
1910  (unsigned int)crossfire_height);
1911  XSetStandardProperties(display, l->win, t, s, icon, gargv, gargc, &(hint));
1912  l->gc_text = XCreateGC (display, l->win, 0, 0);
1913  l->gc_icon = XCreateGC (display, l->win, 0, 0);
1914  l->gc_status = XCreateGC (display, l->win, 0, 0);
1915  XSetForeground (display, l->gc_text, foreground);
1916  XSetBackground (display, l->gc_text, background);
1917  XSetForeground (display, l->gc_icon, foreground);
1918  XSetBackground (display, l->gc_icon, background);
1919  XSetForeground (display, l->gc_status, foreground);
1920  XSetBackground (display, l->gc_status, background);
1921  XSetGraphicsExposures (display, l->gc_icon, False);
1922  XSetGraphicsExposures (display, l->gc_status, False);
1923  XSetFont (display, l->gc_text, font->fid);
1924  XSelectInput (display, l->win, ButtonPressMask|KeyPressMask|KeyReleaseMask|
1925  ExposureMask|StructureNotifyMask);
1926  XSetWMProtocols(display, l->win, &wm_delete_window, 1);
1927  XMapRaised(display,l->win);
1929  resize_list_info(l, w, h);
1930 }
1931 
1932 static int get_inv_display(void)
1933 {
1934  inv_list.env = cpl.ob;
1935  strcpy (inv_list.title, ""/*ET: too long: "Inventory:"*/);
1936  inv_list.show_weight = 1;
1937  inv_list.show_what = show_all;
1938  inv_list.weight_limit=0;
1939  get_list_display ( &inv_list, 0, 0, INV_WIDTH,
1940  2*(roothint.height - WINDOW_SPACING) / 3,
1941  "Crossfire - inventory",
1942  "crossinventory");
1943  return 0;
1944 }
1945 
1946 static int get_look_display(void)
1947 {
1948  look_list.env = cpl.below;
1949  strcpy (look_list.title, "You see:");
1950  look_list.show_weight = 1;
1951  look_list.show_what = show_all;
1952  inv_list.weight_limit = 0;
1953  get_list_display ( &look_list, 0,
1954  (2*(roothint.height - WINDOW_SPACING) / 3) + WINDOW_SPACING,
1955  INV_WIDTH,
1956  (roothint.height - WINDOW_SPACING) / 3,
1957  "Crossfire - look",
1958  "crosslook");
1959  return 0;
1960 }
1961 
1962 /*
1963  * draw_lists() redraws inventory and look windows when necessary
1964  */
1965 void draw_lists(void)
1966 {
1967  if (inv_list.env->inv_updated) {
1968  draw_list (&inv_list);
1969  inv_list.env->inv_updated = 0;
1970  }
1971  if (look_list.env->inv_updated) {
1972  draw_list (&look_list);
1973  look_list.env->inv_updated = 0;
1974  }
1975 }
1976 
1977 
1978 void set_show_icon (const char *s)
1979 {
1980  if (s == NULL || *s == 0 || strncmp ("inventory", s, strlen(s)) == 0) {
1981  inv_list.show_icon = ! inv_list.show_icon; /* toggle */
1982  resize_list_info(&inv_list, inv_list.width, inv_list.height);
1983  } else if (strncmp ("look", s, strlen(s)) == 0) {
1984  look_list.show_icon = ! look_list.show_icon; /* toggle */
1985  resize_list_info(&look_list, look_list.width, look_list.height);
1986  }
1987 }
1988 
1989 void set_show_weight (const char *s)
1990 {
1991  if (s == NULL || *s == 0 || strncmp ("inventory", s, strlen(s)) == 0) {
1992  inv_list.show_weight = ! inv_list.show_weight; /* toggle */
1993  draw_list (&inv_list);
1994  } else if (strncmp ("look", s, strlen(s)) == 0) {
1995  look_list.show_weight = ! look_list.show_weight; /* toggle */
1996  draw_list (&look_list);
1997  }
1998 }
1999 
2001 {
2002  inv_list.weight_limit = wlim;
2003 }
2004 
2005 void set_scroll(const char *s)
2006 {
2007  if (!infodata.scroll_info_window) {
2008  infodata.scroll_info_window=1;
2009  if (infodata.numlines>=infodata.maxdisp) {
2010  infodata.infoline=infodata.maxdisp-1;
2011  }
2012  draw_all_info();
2013  draw_info("Scroll is enabled", NDI_BLACK);
2014  }
2015  else {
2016  draw_info("Scroll is disabled", NDI_BLACK);
2017  infodata.scroll_info_window=0;
2018  }
2019 }
2020 
2021 void set_autorepeat(const char *s)
2022 {
2024  draw_info(noautorepeat ? "Autorepeat is disabled":"Autorepeat is enabled",
2025  NDI_BLACK);
2026 }
2027 
2029 {
2030  return infodata.info_chars;
2031 }
2032 
2033 void menu_clear(void)
2034 {
2035  draw_info("clearinfo command not implemented for this client", NDI_BLACK);
2036  return;
2037 }
2038 
2039 /* TODO Figure out if/how to *use* these events here. */
2043 
2044 /******************************************************************************
2045  * Root Window code
2046  ****************************************************************************/
2047 
2048 /* get_root_display:
2049  * this sets up the root window (or none, if in split
2050  * windows mode, and also scans for any Xdefaults. Right now, only
2051  * splitwindow and image are used. image is the display
2052  * mechanism to use. I thought having one type that is set
2053  * to font, xpm, or pixmap was better than using xpm and pixmap
2054  * resources with on/off values (which gets pretty weird
2055  * if one of this is set to off.
2056  */
2057 
2058 /* Error handlers removed. Right now, there is nothing for
2059  * the client to do if it gets a fatal error - it doesn't have
2060  * any information to save. And we might as well let the standard
2061  * X11 error handler handle non fatal errors.
2062  */
2064 
2065 static int get_root_display(char *display_name) {
2066  char *cp;
2067 
2068  display=XOpenDisplay(display_name);
2069  if (!display) {
2070  fprintf(stderr, "Can't open display %s.\n", display_name);
2071  return 1;
2072  }
2073 
2074  wm_delete_window = XInternAtom(display, "WM_DELETE_WINDOW", 0);
2075  /* This generates warnings, but looking at the documenation,
2076  * it seems like it _should_ be ok.
2077  */
2078  XSetErrorHandler(error_handler);
2079 
2080  if ((getenv("ERIC_SYNC")!= NULL) || sync_display)
2081  XSynchronize(display,True);
2082 
2083  def_root = DefaultRootWindow(display);
2084  def_screen = DefaultScreen(display);
2085 
2086  /* For both split_windows and display mode, check to make sure that
2087  * the command line has not set the value. Command line settings
2088  * should always have precedence over settings in the Xdefaults file.
2089  *
2090  * Also, if you add new defaults, make sure that the same rules for
2091  * the command line defaults are used. The client assumes that certain
2092  * values can only be set if they have meaning (save_data will not
2093  * be set unless the data can actually be saved, for example.) If
2094  * this is not followed for then the client might very well crash.
2095  */
2096  if (!want_config[CONFIG_SPLITWIN] &&
2097  (cp=XGetDefault(display,X_PROG_NAME,"splitwindow")) != NULL) {
2098  if (!strcmp("on",cp) || !strcmp("yes",cp))
2100  else if (!strcmp("off",cp) || !strcmp("no",cp))
2102  }
2103  if (!use_config[CONFIG_ECHO] &&
2104  (cp=XGetDefault(display,X_PROG_NAME,"echo")) != NULL) {
2105  if (!strcmp("on",cp) || !strcmp("yes",cp))
2107  else if (!strcmp("off",cp) || !strcmp("no",cp))
2109  }
2110  if ((cp=XGetDefault(display,X_PROG_NAME, "scrollLines"))!=NULL) {
2111  infodata.maxlines=atoi(cp);
2112  }
2113  if ((cp=XGetDefault(display,X_PROG_NAME,"font")) != NULL) {
2114  font_name = strdup_local(cp);
2115  }
2116  /* Failure will result in an uncaught X11 error */
2117  font=XLoadQueryFont(display,font_name);
2118  if (!font) {
2119  fprintf(stderr,"Could not load font %s\n", font_name);
2120  exit(1);
2121  }
2122  FONTWIDTH=font->max_bounds.width;
2123  FONTHEIGHT=font->max_bounds.ascent + font->max_bounds.descent;
2124 
2125  background=WhitePixel(display,def_screen);
2126  foreground=BlackPixel(display,def_screen);
2127  roothint.x=0;
2128  roothint.y=0;
2129  roothint.width=582+6+INFOCHARS*FONTWIDTH;
2130  roothint.height=ROOT_HEIGHT;
2131  /* Make up for the extra size of the game window. 88 is
2132  * 11 tiles * 8 pixels/tile bigger size.
2133  */
2134  roothint.width += 88;
2135  roothint.height+= 88;
2137 
2138  roothint.max_width=roothint.min_width=roothint.width;
2139  roothint.max_height=roothint.min_height=roothint.height;
2140  roothint.flags=PSize; /*ET: no PPosition. let window manager handle that. */
2141 
2143  win_root=XCreateSimpleWindow(display,def_root,
2144  roothint.x,roothint.y,roothint.width,roothint.height,2,
2146 
2148  foreground=discolor[0].pixel;
2149  background=discolor[9].pixel;
2150  icon=XCreateBitmapFromData(display,win_root,
2151  (_Xconst char *) crossfire_bits,
2152  (unsigned int) crossfire_width, (unsigned int)crossfire_height);
2153  XSetStandardProperties(display,win_root,X_PROG_NAME,X_PROG_NAME,
2154  icon,gargv,gargc,&(roothint));
2155  gc_root=XCreateGC(display,win_root,0,0);
2156  XSetForeground(display,gc_root,foreground);
2157  XSetBackground(display,gc_root,background);
2158 
2159  XSelectInput(display,win_root,KeyPressMask|
2160  KeyReleaseMask|ExposureMask|StructureNotifyMask);
2161  XMapRaised(display,win_root);
2162  XNextEvent(display,&event); /*ET: this is bogus */
2163  XSetWMProtocols(display, win_root, &wm_delete_window, 1);
2164  }
2165  else
2166  win_root = def_root;
2167  return 0;
2168 }
2169 
2170 static void resize_win_root(XEvent *event) {
2171  int width, inv_width, info_width;
2172 
2174  fprintf(stderr,"Got a resize root window in split windows mode\n");
2175  return;
2176  }
2177 
2178  /* The middle 3 windows don't really benefit from the resize, so keep
2179  * them the same size, and use the leftover equally between the left
2180  * and right windows.
2181  */
2182  width = (event->xconfigure.width - GAME_WIDTH -WINDOW_SPACING*2);
2183  info_width = width * info_ratio;
2184  inv_width = width - info_width;
2185 
2186  /* With png (and 32x32 images), the message window can get scrunched,
2187  * so lets make it taller if we can - there is no reason not to, as otherwise
2188  * that space is lost anyways.
2189  */
2190  XMoveResizeWindow(display, win_message, inv_width + WINDOW_SPACING,
2192  event->xconfigure.height - GAME_WIDTH + STAT_HEIGHT + WINDOW_SPACING*2);
2193  messagehint.width=GAME_WIDTH;
2194  messagehint.height=event->xconfigure.height - GAME_WIDTH + STAT_HEIGHT + WINDOW_SPACING*2;
2195 
2196  /* These windows just need to be relocated. The y constants are
2197  * hardcoded - those windows don't really benefit from being resized
2198  * (actually, no code in place to currently do it), so no reason
2199  * to get trick with those just now.
2200  */
2201 
2202  XMoveWindow(display, win_game, inv_width + WINDOW_SPACING, STAT_HEIGHT + WINDOW_SPACING);
2203  XMoveWindow(display, win_stats, inv_width + WINDOW_SPACING, 0);
2204 
2205  /* Resize the info window */
2206  XMoveResizeWindow(display, infodata.win_info,
2207  inv_width + GAME_WIDTH + WINDOW_SPACING * 2, 0,
2208  info_width, event->xconfigure.height);
2209 
2210 
2211  /* Resize the inventory, message window */
2212  XResizeWindow(display, inv_list.win, inv_width,
2213  2 * (event->xconfigure.height - WINDOW_SPACING) / 3);
2214 
2215 
2216  XMoveResizeWindow(display, look_list.win, 0,
2217  (2*(event->xconfigure.height - WINDOW_SPACING) / 3) + WINDOW_SPACING,
2218  inv_width,
2219  (event->xconfigure.height - WINDOW_SPACING) / 3);
2220 
2221  /* The Resize requests will generate events. As such, we don't call
2222  * the resize functions here - the event handler would get those anyways,
2223  * so there isn't a big gain in doing it here.
2224  */
2225 }
2226 
2227 
2228 /***********************************************************************
2229  *
2230  * Here is the start of event handling functions
2231  *
2232  ***********************************************************************/
2233 
2234 static void parse_game_button_press(int button, int x, int y)
2235 {
2236  int dx, dy, i, xmidl, xmidh, ymidl, ymidh;
2237 
2238  dx = (x-2)/image_size-use_config[CONFIG_MAPWIDTH]/2;
2239  dy= (y-2)/image_size-use_config[CONFIG_MAPHEIGHT]/2;
2240  xmidl=(use_config[CONFIG_MAPWIDTH]/2) * image_size;
2241  xmidh=(use_config[CONFIG_MAPWIDTH]/2 + 1) * image_size;
2242  ymidl=(use_config[CONFIG_MAPHEIGHT]/2) * image_size;
2243  ymidh=(use_config[CONFIG_MAPHEIGHT]/2 + 1) * image_size;
2244 
2245  switch (button) {
2246  case 1:
2247  {
2248  /* Its unlikely this will happen, but if the window is
2249  * resized, its possible to be out of bounds.
2250  */
2252  look_at(dx,dy);
2253  }
2254  break;
2255  case 2:
2256  case 3:
2257  if (x<xmidl)
2258  i = 0;
2259  else if (x>xmidh)
2260  i = 6;
2261  else i =3;
2262 
2263  if (y>ymidh)
2264  i += 2;
2265  else if (y>ymidl)
2266  i++;
2267 
2268  if (button==2) {
2269  switch (i) {
2270  case 0: fire_dir (8);break;
2271  case 1: fire_dir (7);break;
2272  case 2: fire_dir (6);break;
2273  case 3: fire_dir (1);break;
2274  case 5: fire_dir (5);break;
2275  case 6: fire_dir (2);break;
2276  case 7: fire_dir (3);break;
2277  case 8: fire_dir (4);break;
2278  }
2279  /* Only want to fire once */
2280  clear_fire();
2281  }
2282  else switch (i) {
2283  case 0: move_player (8);break;
2284  case 1: move_player (7);break;
2285  case 2: move_player (6);break;
2286  case 3: move_player (1);break;
2287  case 5: move_player (5);break;
2288  case 6: move_player (2);break;
2289  case 7: move_player (3);break;
2290  case 8: move_player (4);break;
2291  }
2292  }
2293 }
2294 
2295 
2296 /* Handles key presses. Note that the client really doesn't know
2297  * much about states. But there are at least a couple that the
2298  * client needs to know about - game play, where it parses keystrokes,
2299  * applies any bindings, and sends the command to the server,
2300  * and reply states. The only time reply's are used right now is for rolling
2301  * up a character - sending 'SAY' commands is not appropriate.
2302  *
2303  * After input is completed in either of the reply states, the program
2304  * sets the game back to Play state. May not be appropriate, but let
2305  * the server ignore the commands if they are not proper - a hack
2306  * client could always send such commands anyways.
2307  * If the server expect additional reply's, it should send an query.
2308  * Note that these can not be stacked up, (ie, server can not send
2309  * 5 queries and expect 5 replies). But in no place does the server
2310  * do this anyways, so it is not a problem.
2311  */
2312 
2313 static void do_key_press(int repeated)
2314 {
2315  KeySym gkey;
2316  char text[10];
2317 
2318  /* Turn off the magic map. Perhaps this should be more selective? */
2319  if (cpl.showmagic) {
2320  cpl.showmagic=0;
2322  }
2323  if(!XLookupString(&event.xkey,text,10, &gkey,NULL)) {
2324 /*
2325  * This happens quite a bit - most modifier keys (shift, control, etc)
2326  * can not be mapped to a value.
2327  */
2328  /*
2329  fprintf(stderr,"XLookupString failed, xkey.code=%d, gkey=%ld\n",
2330  event.xkey.keycode, gkey);
2331 */
2332  text[0]='\0';
2333  }
2334  switch(cpl.input_state) {
2335  case Playing:
2336  parse_key(text[0],event.xkey.keycode,gkey,repeated);
2337  break;
2338 
2339  case Reply_One:
2340  /* Don't send modifier keys as reply to query. Tries to prevent
2341  * from getting into the "...state is not ST_PLAYING" state. */
2342  if (text[0]) {
2343  text[1]='\0';
2344  send_reply(text);
2346  }
2347  break;
2348 
2349  case Configure_Keys:
2350  configure_keys(event.xkey.keycode, gkey);
2351  break;
2352 
2353  case Reply_Many:
2354  case Command_Mode:
2355  case Metaserver_Select:
2356  if (text[0]==13) {
2357  enum Input_State old_state=cpl.input_state;
2360  return;
2361  }
2362  if (cpl.input_state==Reply_Many)
2364  else {
2365  write_ch(13);
2367  }
2368  /* Only set state to playing if the state has otherwise
2369  * not changed - this check is needed because 'bind
2370  * changes the state, and we don't want to change to playing
2371  * again.
2372  */
2373  if (old_state==cpl.input_state)
2375  cpl.input_text[0]='\0';
2376  cpl.no_echo=0; /* By default, start echoing thing again */
2377  }
2378  else {
2379  write_ch(text[0]);
2380  }
2381  break;
2382 
2383  default:
2384  fprintf(stderr,"Unknown input state: %d\n", cpl.input_state);
2385  }
2386 }
2387 
2388 
2389 static void buttonpress_in_info(XButtonEvent *xbutton)
2390 {
2391  int y = xbutton->y-16, x=xbutton->x, button = xbutton->button,dy,pos=0;
2392 
2393  if (!infodata.has_scrollbar)
2394  return;
2395 
2396  if (button < 4 && x <= infodata.width-SCROLLBAR_WIDTH-4)
2397  return;
2398 
2399  dy = y / FONTHEIGHT > 0 ? y / FONTHEIGHT : 1;
2400 
2401  switch(button) {
2402  case 1:
2403  pos = infodata.bar_pos - dy;
2404  break;
2405 
2406  case 2:
2407  pos = y * infodata.numlines / infodata.bar_length;
2408  break;
2409 
2410  case 3:
2411  pos = infodata.bar_pos + dy;
2412  break;
2413 
2414  case 4:
2415  pos = infodata.bar_pos - 1;
2416  break;
2417 
2418  case 5:
2419  pos = infodata.bar_pos + 1;
2420  break;
2421 
2422  }
2423  if (pos<infodata.maxdisp) {
2424  if (infodata.numlines<infodata.maxdisp)
2425  pos=infodata.numlines;
2426  else
2427  pos=infodata.maxdisp;
2428  }
2429  if (pos>infodata.numlines) pos=infodata.numlines;
2430  if (pos != infodata.bar_pos) {
2431  infodata.bar_pos = pos;
2432  draw_all_info();
2433  }
2434 }
2435 
2436 
2437 /*
2438  * buttonpress_in_list handles mouse button event in list window.
2439  * It updates scrollbar or calls right function for item
2440  * (apply/examine/move). It's probably better move calling the
2441  * functions to the upper level.
2442  */
2443 
2444 static int buttonpress_in_list (itemlist *l, XButtonEvent *xbutton)
2445 {
2446  item *tmp;
2447  int y = xbutton->y - 16, x=xbutton->x, button = xbutton->button;
2448  int items, pos=0, dy;
2449 
2450  if (y < 0 && l->env->open) /* close the sack */
2451  client_send_apply (l->env->tag);
2452 
2453  if (y < 0 || y > image_size * l->size)
2454  return 1;
2455 
2456  if (button == 4 || button == 5)
2457  {
2458  if (button == 4)
2459  l->item_pos--;
2460  else
2461  l->item_pos++;
2462  draw_list(l);
2463  return 1;
2464  }
2465 
2466  if (x > l->width-23) { /* scrollbar */
2467 
2468  dy = y / image_size > 0 ? y / image_size : 1;
2469 
2470  switch(button) {
2471  case 1:
2472  pos = l->item_pos - dy;
2473  break;
2474 
2475  case 2:
2476  for(tmp=l->env->inv, items=0; tmp; tmp=tmp->next)
2477  items++;
2478  pos = y * items / l->bar_length;
2479  break;
2480 
2481  case 3:
2482  pos = l->item_pos + dy;
2483  break;
2484 
2485  }
2486  if (pos != l->item_pos) {
2487  l->item_pos = pos;
2488  draw_list (l);
2489  }
2490  return 1;
2491  }
2492 
2493  pos = l->item_pos + y / image_size;
2494  for(tmp=l->env->inv, items=0; tmp; tmp=tmp->next) {
2495  if (show_object(tmp, l->show_what)) items++;
2496  if (items>pos) break;
2497  }
2498  if (tmp) {
2499  switch(button) {
2500  case 1:
2501  if (xbutton->state & ShiftMask)
2502  toggle_locked(tmp);
2503  else
2504  client_send_examine (tmp->tag);
2505  break;
2506  case 2:
2507  if (xbutton->state & ShiftMask)
2508  send_mark_obj(tmp);
2509  else
2510  client_send_apply (tmp->tag);
2511  break;
2512  case 3:
2513  if (tmp->locked) {
2514  draw_info ("This item is locked. To drop it, first unlock by shift+leftclicking on it.",
2515  NDI_BLACK);
2516  } else if (l == &inv_list)
2517  client_send_move (look_list.env->tag, tmp->tag, cpl.count);
2518  else
2519  client_send_move (inv_list.env->tag, tmp->tag, cpl.count);
2520  cpl.count=0;
2521  break;
2522  }
2523  }
2524  return 1;
2525 }
2526 
2527 
2528 /* get_metaserver returns a string for what the user has selected as
2529  * their metaserver. It basically does a subset of check_x_events.
2530  * and keeps looping until the user finishes selecting the metaserver
2531  * (detected by change of state.
2532  */
2533 char *get_metaserver(void)
2534 {
2535  static char ret_buf[MAX_BUF];
2536 
2538  draw_prompt(":");
2539  while (cpl.input_state == Metaserver_Select) {
2540  check_x_events();
2541  usleep(50000); /* 1/20 sec */
2542  } /* while input state is metaserver select. */
2543 
2544  /* We need to clear out cpl.input_text - otherwise the next
2545  * long input (like player name) won't work right.
2546  * so copy it to a private buffer and return.
2547  */
2548  strncpy(ret_buf, cpl.input_text, MAX_BUF-1);
2549  ret_buf[MAX_BUF-1]=0;
2550  cpl.input_text[0]=0;
2551  return ret_buf;
2552 }
2553 
2554 
2555 /* This function handles the reading of the X Events and then
2556  * doing the appropriate action. For most input events, it is calling
2557  * another function.
2558  *
2559  * It can also call display functions to make sure the information is
2560  * correct - in this way, updates will not be done so often (like
2561  * for every ITEM command received), but less frequently but still
2562  * update the display fully. All the functions above are optimized to
2563  * only draw stuff that needs drawing. So calling them a lot is not
2564  * going to draw stuff too much.
2565  */
2566 
2567 void check_x_events(void) {
2568  KeySym gkey=0;
2569  static int lastupdate=0;
2570  static XEvent prev_event; /* to detect autorepeated keys */
2571 
2572  /* If not connected, the below area does not apply, so don't deal with it */
2574 
2575  /* We need to periodically redraw stuff if we are caching images - otherwise
2576  * the default images might be display indefinately. This is tuned so
2577  * that we should only be redrawing stuff if we got new images from
2578  * the last draw and enough time has passed. This should be a bit
2579  * more efficient than redrawing everything anytime we get a new image -
2580  * especially since we might get a bunch of images at the same time.
2581  */
2582  if (want_config[CONFIG_CACHE] && lastupdate>5 && newimages) {
2583  update_icons_list(&inv_list);
2584  update_icons_list(&look_list);
2586  newimages=0;
2587  lastupdate=0;
2588  }
2589  else {
2590  if (newimages)
2591  lastupdate++;
2592  draw_lists(); /* testing if this can work this way */
2593  }
2594  }
2595 
2596 
2597  while (XPending(display)!=0) {
2598  prev_event = event;
2599  XNextEvent(display,&event);
2600  switch(event.type) {
2601 
2602  case ConfigureNotify:
2603  if(event.xconfigure.window==infodata.win_info)
2604  resize_win_info(event.xconfigure.width, event.xconfigure.height);
2605  else if(event.xconfigure.window==inv_list.win)
2606  resize_list_info(&inv_list, event.xconfigure.width,
2607  event.xconfigure.height);
2608  else if(event.xconfigure.window==look_list.win)
2609  resize_list_info(&look_list, event.xconfigure.width,
2610  event.xconfigure.height);
2611  else if(event.xconfigure.window==win_root)
2613  else if(event.xconfigure.window==win_message)
2614  resize_win_message(event.xconfigure.width, event.xconfigure.height);
2615  break;
2616 
2617  case Expose:
2618  /* No point redrawing windows if there are more Expose's to
2619  * come.
2620  */
2621  if (event.xexpose.count!=0) continue;
2622  if(event.xexpose.window==win_stats) {
2623  XClearWindow(display,win_stats);
2624  draw_stats(1);
2625  } else if(event.xexpose.window==infodata.win_info)
2626  draw_all_info();
2627  else if(event.xexpose.window==inv_list.win)
2628  draw_all_list(&inv_list);
2629  else if(event.xexpose.window==look_list.win)
2630  draw_all_list(&look_list);
2631  else if(event.xexpose.window==win_message)
2632  draw_all_message();
2633  else if(event.xexpose.window==win_game) {
2634  if (cpl.showmagic) draw_magic_map();
2636  } else if(want_config[CONFIG_SPLITWIN]==FALSE && event.xexpose.window==win_root) {
2637  XClearWindow(display,win_root);
2638  }
2639  break;
2640 
2641  case GraphicsExpose:
2642  /* No point redrawing windows if there are more GraphicExpose's
2643  * to come.
2644  */
2645  if (event.xgraphicsexpose.count!=0) continue;
2646  if(event.xgraphicsexpose.drawable==win_game) {
2647  if (cpl.showmagic) draw_magic_map();
2649  }
2650  break;
2651 
2652  case MappingNotify:
2653  XRefreshKeyboardMapping(&event.xmapping);
2654  break;
2655 
2656 
2657  case ButtonPress:
2658  /* Most of these will try to send requests to the server - since we
2659  * are not connected, this will probably fail in some bad way.
2660  */
2662 
2663  if(event.xbutton.window==win_game) {
2664  parse_game_button_press(event.xbutton.button,event.xbutton.x,
2665  event.xbutton.y);
2666  } else if(event.xbutton.window==inv_list.win) {
2667  buttonpress_in_list(&inv_list, &event.xbutton);
2668 
2669  } else if(event.xbutton.window==look_list.win) {
2670  buttonpress_in_list(&look_list, &event.xbutton);
2671  }
2672  else if (event.xbutton.window==infodata.win_info) {
2673  buttonpress_in_info(&event.xbutton);
2674  }
2675  break;
2676  }
2677 
2678  case KeyRelease:
2679  parse_key_release(event.xkey.keycode, gkey);
2680  break;
2681 
2682  case KeyPress:
2683  if (noautorepeat
2684  && prev_event.type == KeyRelease
2685  && prev_event.xkey.keycode == event.xkey.keycode
2686  && prev_event.xkey.state == event.xkey.state
2687  && prev_event.xkey.time == event.xkey.time)
2688  do_key_press(1); /* auto-repeated key */
2689  else
2690  do_key_press(0); /* regular key */
2691  break;
2692  case ClientMessage:
2693  if(event.xclient.data.l[0] == wm_delete_window){
2694  LOG(LOG_INFO,"x11::check_x_events","Window closed. Exiting.");
2695  exit(0);
2696  }
2697  break;
2698  }
2699  }
2700  /* Below does not apply if we're not connected */
2702  /* Since we cycle through all the Xevents, there is no need to do
2703  * keyboard flushing. All commands get sent to the server. There really
2704  * does need to be some decent way to flush the commands we have sent,
2705  * but there is no real way to do that. This is at least somewhat
2706  * true because the client and server will never be completely
2707  * synchronized.
2708  */
2709 
2710  /* Need to do this to show the players position */
2712  clear_fire_run();
2713  }
2714  /* a good place to check for childs */
2715  monitorChilds();
2716 }
2717 
2718 
2719 /***********************************************************************
2720  *
2721  * Here starts the X11 init functions. It will call other
2722  * functions that were grouped previously by window
2723  *
2724  ***********************************************************************/
2725 
2726 /* Usage routine. All clients should support server, port and
2727  * display options, with -pix and -xpm also suggested. -split
2728  * does not need to be supported - it is in this copy because
2729  * the old code supported it.
2730  */
2731 
2732 static void usage(char *progname)
2733 {
2734  puts("Usage of cfclient:\n\n");
2735  puts("-server <name> - Connect to <name> instead of localhost.");
2736  puts("-port <number> - Use port <number> instead of the standard port number");
2737  puts("-display <name> - Use <name> instead if DISPLAY environment variable.\n");
2738  puts("-split - Use split windows.");
2739  puts("-nosplit - Disable split windows (default action).");
2740  puts("-echo - Echo the bound commands");
2741  puts("-pix - Use bitmaps for display.");
2742 #ifdef HAVE_LIBXPM
2743  puts("-xpm - Use color pixmaps (XPM) for display.");
2744 #endif
2745 #ifdef HAVE_LIBPNG
2746  puts("-png - Use png images for display.");
2747 #endif
2748  puts("-showicon - Print status icons in inventory window");
2749  puts("-scrolllines <number> - number of lines for scrollback");
2750  puts("-sync - Synchronize on display");
2751  puts("-help - Display this message.");
2752  puts("-cache - Cache images for future use.");
2753  puts("-nocache - Do not cache images (default action).");
2754  puts("-mapscroll - Enable mapscrolling by bitmap operations");
2755  puts("-nomapscroll - Disable mapscrolling by bitmap operations");
2756  puts("-darkness - Enables darkness code (default)");
2757  puts("-nodarkness - Disables darkness code");
2758  puts("-nosound - Disable sound output.");
2759  puts("-updatekeycodes - Update the saved bindings for this keyboard.");
2760  puts("-keepcache - Keep already cached images even if server has different ones.");
2761  puts("-font <name> - Use <name> as font to display data.");
2762  puts("-pngfile <name> - Use <name> for source of images");
2763  puts("-mapsize xXy - Set the mapsize to be X by Y spaces.");
2764  puts("-noautorepeat - Auto repeat on directional keys is ignored.");
2765  puts("-faceset <num> - Select a specific facset to use.");
2766  exit(0);
2767 }
2768 
2769 /* init_windows: This initiliazes all the windows - it is an
2770  * interface routine. The command line arguments are passed to
2771  * this function to interpert. Note that it is not in fact
2772  * required to parse anything, but doing at least -server and
2773  * -port would be a good idea. This is a little messy, as non window
2774  * related options as well as those relating to windowing are parsed here,
2775  * but this file is meant for only the X11 stuff.
2776  *
2777  * This function returns 0 on success, nonzero on failure.
2778  */
2779 
2780 int init_windows(int argc, char **argv)
2781 {
2782  int on_arg=1;
2783  char *display_name="";
2784 
2785  strcpy(VERSION_INFO,"X11 Unix Client " FULL_VERSION);
2786 
2787  load_defaults(); /* Load these first, so they can get overwritten by
2788  * command line options.
2789  */
2790  want_skill_exp=1;
2791  for (on_arg=1; on_arg<argc; on_arg++) {
2792  if (!strcmp(argv[on_arg],"-display")) {
2793  if (++on_arg == argc) {
2794  fprintf(stderr,"-display requires a display name\n");
2795  return 1;
2796  }
2797  display_name = argv[on_arg];
2798  continue;
2799  }
2800  if (strcmp(argv[on_arg],"-sync")==0) {
2801  sync_display = 1;
2802  continue;
2803  }
2804  if (!strcmp(argv[on_arg],"-port")) {
2805  if (++on_arg == argc) {
2806  fprintf(stderr,"-port requires a port number\n");
2807  return 1;
2808  }
2809  use_config[CONFIG_PORT] = atoi(argv[on_arg]);
2810  continue;
2811  }
2812  if (!strcmp(argv[on_arg],"-mapsize")) {
2813  char *cp, x, y=0;
2814 
2815  if (++on_arg == argc) {
2816  fprintf(stderr,"-mapsize requires a XxY value\n");
2817  return 1;
2818  }
2819  x = atoi(argv[on_arg]);
2820  for (cp = argv[on_arg]; *cp!='\0'; cp++)
2821  if (*cp == 'x' || *cp == 'X') break;
2822 
2823  if (*cp==0) {
2824  fprintf(stderr,"-mapsize requires both and X and Y value (ie, XxY - note the\nx in between.\n");
2825  } else {
2826  y = atoi(cp+1);
2827  }
2828  if (x<=9 || y<=9) {
2829  fprintf(stderr,"map size must be positive values of at least 9\n");
2830  } if (x>MAP_MAX_SIZE || y>MAP_MAX_SIZE) {
2831  fprintf(stderr,"Map size can not be larger than %d x %d \n", MAP_MAX_SIZE, MAP_MAX_SIZE);
2832  } else {
2835  }
2836  continue;
2837  }
2838  if (!strcmp(argv[on_arg],"-server")) {
2839  if (++on_arg == argc) {
2840  fprintf(stderr,"-server requires a host name\n");
2841  return 1;
2842  }
2843  server = argv[on_arg];
2844  continue;
2845  }
2846  else if (!strcmp(argv[on_arg],"-nofasttcpsend")) {
2848  continue;
2849  }
2850  else if (!strcmp(argv[on_arg],"-cache")) {
2852  continue;
2853  }
2854  else if (!strcmp(argv[on_arg],"-nocache")) {
2856  continue;
2857  }
2858  else if (!strcmp(argv[on_arg],"-mapscroll")) {
2860  }
2861  else if (!strcmp(argv[on_arg],"-nomapscroll")) {
2863  }
2864  else if (!strcmp(argv[on_arg],"-darkness")) {
2866  continue;
2867  }
2868  else if (!strcmp(argv[on_arg],"-nodarkness")) {
2870  continue;
2871  }
2872  else if (!strcmp(argv[on_arg],"-fogofwar")) {
2874  continue;
2875  }
2876  else if (!strcmp(argv[on_arg],"-nofogofwar")) {
2878  continue;
2879  }
2880  else if (!strcmp(argv[on_arg],"-split")) {
2882  continue;
2883  }
2884  else if (!strcmp(argv[on_arg],"-nosplit")) {
2886  continue;
2887  }
2888  else if (!strcmp(argv[on_arg],"-showicon")) {
2889  inv_list.show_icon = TRUE;
2890  continue;
2891  }
2892  else if (!strcmp(argv[on_arg],"-download_all_faces")) {
2894  continue;
2895  }
2896  else if (!strcmp(argv[on_arg],"-echo")) {
2898  continue;
2899  }
2900  else if (!strcmp(argv[on_arg],"-faceset")) {
2901  if (++on_arg == argc) {
2902  fprintf(stderr,"-faceset requires a faceset name/number\n");
2903  return 1;
2904  }
2905  face_info.want_faceset = argv[on_arg];
2906  continue;
2907  }
2908  else if (!strcmp(argv[on_arg],"-scrolllines")) {
2909  if (++on_arg == argc) {
2910  fprintf(stderr,"-scrolllines requires a number\n");
2911  return 1;
2912  }
2913  infodata.maxlines = atoi(argv[on_arg]);
2914  continue;
2915  }
2916  else if (!strcmp(argv[on_arg],"-font")) {
2917  if (++on_arg == argc) {
2918  fprintf(stderr,"-font requires a font name\n");
2919  return 1;
2920  }
2921  font_name = argv[on_arg];
2922  continue;
2923  }
2924  else if (!strcmp(argv[on_arg],"-help")) {
2925  usage(argv[0]);
2926  continue;
2927  }
2928  else if (!strcmp(argv[on_arg],"-nosound")) {
2930  continue;
2931  }
2932  else if (!strcmp(argv[on_arg],"-updatekeycodes")) {
2934  continue;
2935  }
2936  else if (!strcmp(argv[on_arg],"-autorepeat")) {
2938  continue;
2939  }
2940  else {
2941  fprintf(stderr,"Do not understand option %s\n", argv[on_arg]);
2942  usage(argv[0]);
2943  return 1;
2944  }
2945  }
2946  /* Moving processing and setting of display attributes down here.
2947  * This is because a default display mode may also require special
2948  * handling.
2949  * This is not ideal, as if we don't have one of the optional modes,
2950  * we just fall back to pixmap mode. But I don't really want to get into
2951  * a big nest of #ifdefs checking/setting modes.
2952  */
2953 #ifndef HAVE_LIBPNG
2954  fprintf(stderr,"Client not configured with Png display mode enabled\n");
2955  fprintf(stderr,"Install the png library and try recompiling.\n");
2956  exit(1);
2957 #else
2958  image_size=32;
2959 #endif
2960 
2961  mapdata_init();
2962 
2963  /* Finished parsing all the command line options. Now start
2964  * working on the display.
2965  */
2966  gargc=argc;
2967  gargv=argv;
2968 
2969  if (get_root_display(display_name) ||
2970  get_game_display() ||
2971  get_stats_display() ||
2972  get_info_display() ||
2973  get_inv_display() ||
2974  get_look_display() ||
2976  return 1;
2977 
2978  init_keys();
2979  init_cache_data();
2980  set_window_pos();
2981  info_ratio=(float) infodata.width/ (float) (infodata.width + INV_WIDTH);
2982  return 0;
2983 }
2984 
2985 
2987 {
2988  reset_map();
2989 }
2990 
2991 /* This can also get called for png. Really, anything that gets rendered
2992  * into a pixmap that does not need colors set or other specials done.
2993  */
2994 static void display_mapcell(int ax, int ay)
2995 {
2996  int layer, mx, my, got_one = 0;
2997 
2998  mx = pl_pos.x+ax;
2999  my = pl_pos.y+ay;
3000 
3001  if (!use_config[CONFIG_FOGWAR] && the_map.cells[mx][my].cleared) {
3003  return;
3004  }
3005 
3006  XFillRectangle(display,xpm_pixmap,gc_clear_xpm,0,0,image_size,image_size);
3007  for (layer=0; layer<MAXLAYERS; layer++) {
3008  int sx, sy;
3009 
3010  /* draw single-tile faces first */
3011  int face = mapdata_face(ax, ay, layer);
3012  if (face > 0) {
3013  int w = pixmaps[face]->width;
3014  int h = pixmaps[face]->height;
3015  gen_draw_face(xpm_pixmap, face, 0, 0, (w-1)*image_size, (h-1)*image_size);
3016  got_one = 1;
3017  }
3018 
3019  /* draw big faces last (should overlap other objects) */
3020  face = mapdata_bigface(ax, ay, layer, &sx, &sy);
3021  if (face > 0) {
3022  gen_draw_face(xpm_pixmap, face, 0, 0, sx*image_size, sy*image_size);
3023  got_one = 1;
3024  }
3025  }
3026  if (got_one) {
3027  if (the_map.cells[mx][my].cleared) {
3028  XSetClipOrigin(display, gc_xpm[XPMGCS-1], 0, 0);
3029  XSetForeground(display, gc_xpm[XPMGCS-1], discolor[0].pixel);
3030  XSetClipMask(display, gc_xpm[XPMGCS-1], dark2);
3031  XCopyPlane(display, dark2, xpm_pixmap, gc_xpm[XPMGCS-1], 0, 0, image_size, image_size, 0, 0, 1);
3032  xpm_masks[XPMGCS-1] = dark2;
3033  }
3034  else if (use_config[CONFIG_DARKNESS] && the_map.cells[mx][my].have_darkness) {
3035  int darkness;
3036  XSetClipOrigin(display, gc_xpm[XPMGCS-1], 0, 0);
3037  XSetForeground(display, gc_xpm[XPMGCS-1], discolor[0].pixel);
3038  darkness = the_map.cells[mx][my].darkness;
3039  if (darkness > 192) {
3040  XSetClipMask(display, gc_xpm[XPMGCS-1], dark1);
3041  XCopyPlane(display, dark1, xpm_pixmap, gc_xpm[XPMGCS-1], 0, 0, image_size, image_size, 0, 0, 1);
3042  xpm_masks[XPMGCS-1] = dark1;
3043  }
3044  else if (darkness > 128) {
3045  XSetClipMask(display, gc_xpm[XPMGCS-1], dark2);
3046  XCopyPlane(display, dark2, xpm_pixmap, gc_xpm[XPMGCS-1], 0, 0, image_size, image_size, 0, 0, 1);
3047  xpm_masks[XPMGCS-1] = dark2;
3048  }
3049  else if (darkness > 64) {
3050  XSetClipMask(display, gc_xpm[XPMGCS-1], dark3);
3051  XCopyPlane(display, dark3, xpm_pixmap, gc_xpm[XPMGCS-1], 0, 0, image_size, image_size, 0, 0, 1);
3052  xpm_masks[XPMGCS-1] = dark3;
3053  }
3054  }
3056  } else {
3057  XFillRectangle(display, win_game, gc_blank, image_size*ax, image_size*ay, image_size, image_size);
3058  }
3059 }
3060 
3061 void resize_map_window(int x, int y)
3062 {
3063  if (!want_config[CONFIG_SPLITWIN]) {
3064  XWindowAttributes attrib;
3065  int width=0, height=0;
3066 
3067  /* width and height are how much larger we need to make
3068  * the window to keep it displayable. This isn't perfect,
3069  * but does a reasonable job. Don't do shrinks
3070  */
3071 
3073 
3075 
3076  /* if somethign to do */
3077  if (width>0 || height > 0) {
3078  XGetWindowAttributes(display, win_root, &attrib);
3079  width += attrib.width;
3080  height += attrib.height;
3081  XResizeWindow(display, win_game, x*image_size, y*image_size);
3082  XResizeWindow(display, win_root, width, height);
3083  }
3086  }
3087  else {
3088  XResizeWindow(display, win_game, x*image_size, y*image_size);
3089  }
3090 }
3091 
3092 /* we don't need to do anything, as we figure this out as needed */
3093 void x_set_echo(void) { }
3094 
3095 
3101 void display_map_doneupdate(int redraw, int notice)
3102 {
3103  int ax,ay, mx, my;
3104 
3105  if(notice) {
3106  return;
3107  }
3108 
3109  if (cpl.showmagic) {
3111  return;
3112  }
3113 
3114  XSetClipMask(display,gc_floor,None);
3115  for(ax=0;ax<use_config[CONFIG_MAPWIDTH];ax++) {
3116  for(ay=0;ay<use_config[CONFIG_MAPHEIGHT];ay++) {
3117  mx = pl_pos.x+ax;
3118  my = pl_pos.y+ay;
3119  if (redraw || the_map.cells[mx][my].need_update) {
3120  display_mapcell(ax, ay);
3121  the_map.cells[mx][my].need_update = 0;
3122  }
3123  }
3124  }
3125  XFlush(display);
3126 }
3127 
3128 int display_mapscroll(int dx, int dy)
3129 {
3130  int srcx, srcy;
3131  int dstx, dsty;
3132  int w, h;
3133 
3134  srcx = dx > 0 ? image_size*dx : 0;
3135  srcy = dy > 0 ? image_size*dy : 0;
3136  dstx = dx < 0 ? image_size*-dx : 0;
3137  dsty = dy < 0 ? image_size*-dy : 0;
3138 
3140  w -= abs(dx);
3142  h -= abs(dy);
3143 
3144  XCopyArea(display, win_game, win_game, gc_copy,
3145  srcx, srcy,
3146  w*image_size, h*image_size,
3147  dstx, dsty);
3148 
3149  return 1;
3150 }
3151 
3152 /* This functions associates the image_data in the cache entry
3153  * with the specific pixmap number. Returns 0 on success, -1
3154  * on failure. Currently, there is no failure condition, but
3155  * there is the potential that in the future, we want to more
3156  * closely look at the data and if it isn't valid, return
3157  * the failure code.
3158  */
3160 {
3161  pixmaps[pixnum] = ce->image_data;
3162  return 0;
3163 }
3164 
3166 {
3167  int i;
3168  for(i=0;i<7;i++) {
3169  XDrawImageString(display,win_stats,
3170  gc_stats,10,i*14+10, stats_buff[i],strlen(stats_buff[i]));
3171 }
3172  XFlush(display);
3173 }
3174 
3176 {
3177 }
3178 
3179 /* This function draws the magic map in the game window. I guess if
3180  * we wanted to get clever, we could open up some other window or
3181  * something.
3182  *
3183  * A lot of this code was taken from server/xio.c But being all
3184  * the map data has been figured, it tends to be much simpler.
3185  */
3186 void draw_magic_map(void)
3187 {
3188  XWindowAttributes win_info;
3189  int x, y;
3190 
3191  if (!cpl.magicmap) {
3192  draw_info ("You have yet to cast magic map.",NDI_BLACK);
3193  return;
3194  }
3195 
3196  /* Do this in case the window has been resized. */
3197  XGetWindowAttributes(display, win_game, &win_info);
3198 
3199  /* server used to set a grey background because grey was not used much.
3200  * however, with the magic map cleanup, that is not necessarily true,
3201  * so just set it to the default.
3202  */
3203  XClearWindow(display,win_game);
3204 
3205  cpl.mapxres = (win_info.width-4)/cpl.mmapx;
3206  cpl.mapyres = (win_info.height-4)/cpl.mmapy;
3207  if (cpl.mapxres < 1 || cpl.mapyres<1) {
3208  fprintf(stderr,"magic map resolution less than 1, map is %dx%d\n",
3209  cpl.mmapx, cpl.mmapy);
3210  return;
3211  }
3212  /* In theory, cpl.mapxres and cpl.mapyres do not have to be the same. However,
3213  * it probably makes sense to keep them the same value.
3214  * Need to take the smaller value.
3215  */
3217  else cpl.mapyres=cpl.mapxres;
3218 
3219  if (cpl.mapxres>24) {
3220  cpl.mapxres=24;
3221  cpl.mapyres=24;
3222  }
3223  /* this is keeping the same unpacking scheme that the server uses
3224  * to pack it up.
3225  */
3226  for (y = 0; y < cpl.mmapy; y++) {
3227  for (x = 0; x < cpl.mmapx; x++) {
3228  uint8 val = cpl.magicmap[y*cpl.mmapx + x];
3229  XSetForeground(display,gc_game,
3230  discolor[val&FACE_COLOR_MASK].pixel);
3231  XFillRectangle(display,win_game,
3233  } /* Saw into this space */
3234  }
3235 }
3236 
3237 /* Basically, this just flashes the player position on the magic map */
3239 {
3240  if (!cpl.showmagic) return;
3241  cpl.showmagic ^=2;
3242  if (cpl.showmagic & 2) {
3243  XSetForeground(display, gc_game, foreground);
3244  XSetBackground(display, gc_game, background);
3245  } else {
3246  XSetForeground(display, gc_game, background);
3247  XSetBackground(display, gc_game, foreground);
3248  }
3249  XFillRectangle(display, win_game, gc_game, cpl.mapxres*cpl.pmapx,
3251 }
3252 
3253 /* We can now connect to different servers, so we need to clear out
3254  * any old images. We try to free the data also to prevent memory
3255  * leaks.
3256  * This could be more clever, ie, if we're caching images and go to
3257  * a new server and get a name, we should try to re-arrange our cache
3258  * or the like.
3259  */
3260 
3262 {
3263  int i;
3264 
3266 
3267  for (i=1; i<MAXPIXMAPNUM; i++) {
3268  if (!want_config[CONFIG_CACHE] && pixmaps[i] != pixmaps[0]) {
3269  XFreePixmap(display, pixmaps[i]->pixmap);
3270  if (pixmaps[i]->mask) {
3271  XFreePixmap(display, pixmaps[i]->mask);
3272  }
3273  free(pixmaps[i]);
3274  pixmaps[i] = pixmaps[0];
3275  }
3276  }
3277  look_list.env=cpl.below;
3278 }
3279 
3280 
3281 /* Gets a specified windows coordinates. This function is pretty much
3282  * an exact copy out of the server.
3283  */
3284 
3285 static void get_window_coord(Window win,
3286  int *x,int *y,
3287  int *wx,int *wy,
3288  unsigned int *w,unsigned int *h)
3289 {
3290  Window root,child;
3291  unsigned int tmp;
3292 
3293  XGetGeometry(display,win,&root,x,y,w,h,&tmp,&tmp);
3294  XTranslateCoordinates(display,win,root,0,0,wx,wy, &child);
3295 }
3296 
3297 
3298 
3299 void save_winpos(void)
3300 {
3301  char savename[MAX_BUF],buf[MAX_BUF];
3302  FILE *fp;
3303  int x,y,wx,wy;
3304  unsigned int w,h;
3305 
3306  if (!want_config[CONFIG_SPLITWIN]) {
3307  draw_info("You can only save window positions in split windows mode", NDI_BLUE);
3308  return;
3309  }
3310  sprintf(savename,"%s/.crossfire/winpos", getenv("HOME"));
3311  if (!(fp=fopen(savename,"w"))) {
3312  sprintf(buf,"Unable to open %s, window positions not saved",savename);
3313  draw_info(buf,NDI_BLUE);
3314  return;
3315  }
3316  /* This is a bit simpler than what the server was doing - it has
3317  * some code to handle goofy window managers which I am not sure
3318  * is still needed.
3319  */
3320  get_window_coord(win_game, &x,&y, &wx,&wy,&w,&h);
3321  fprintf(fp,"win_game: %d %d %d %d\n", wx,wy, w, h);
3322  get_window_coord(win_stats, &x,&y, &wx,&wy,&w,&h);
3323  fprintf(fp,"win_stats: %d %d %d %d\n", wx,wy, w, h);
3324  get_window_coord(infodata.win_info, &x,&y, &wx,&wy,&w,&h);
3325  fprintf(fp,"win_info: %d %d %d %d\n", wx,wy, w, h);
3326  get_window_coord(inv_list.win, &x,&y, &wx,&wy,&w,&h);
3327  fprintf(fp,"win_inv: %d %d %d %d\n", wx,wy, w, h);
3328  get_window_coord(look_list.win, &x,&y, &wx,&wy,&w,&h);
3329  fprintf(fp,"win_look: %d %d %d %d\n", wx,wy, w, h);
3330  get_window_coord(win_message, &x,&y, &wx,&wy,&w,&h);
3331  fprintf(fp,"win_message: %d %d %d %d\n", wx,wy, w, h);
3332  fclose(fp);
3333  sprintf(buf,"Window positions saved to %s",savename);
3334  draw_info(buf,NDI_BLUE);
3335 }
3336 
3337 /* Reads in the winpos file created by the above function and sets the
3338  * the window positions appropriately.
3339  */
3340 void set_window_pos(void)
3341 {
3342  unsigned int xwc_mask = CWX|CWY|CWWidth|CWHeight;
3343  XWindowChanges xwc;
3344  char buf[MAX_BUF],*cp;
3345  FILE *fp;
3346 
3347  if (!want_config[CONFIG_SPLITWIN]) return;
3348 
3349  sprintf(buf,"%s/.crossfire/winpos", getenv("HOME"));
3350  if (!(fp=fopen(buf,"r"))) return;
3351 
3352  while(fgets(buf,MAX_BUF-1, fp)!=NULL) {
3353  buf[MAX_BUF-1]='\0';
3354  if (!(cp=strchr(buf,' '))) continue;
3355  *cp++='\0';
3356  if (sscanf(cp,"%d %d %d %d",&xwc.x,&xwc.y,&xwc.width,&xwc.height)!=4)
3357  continue;
3358  if (!strcmp(buf,"win_game:"))
3359  XConfigureWindow(display,win_game,xwc_mask, &xwc);
3360  if (!strcmp(buf,"win_stats:"))
3361  XConfigureWindow(display,win_stats,xwc_mask, &xwc);
3362  if (!strcmp(buf,"win_info:"))
3363  XConfigureWindow(display,infodata.win_info,xwc_mask, &xwc);
3364  if (!strcmp(buf,"win_inv:"))
3365  XConfigureWindow(display,inv_list.win,xwc_mask, &xwc);
3366  if (!strcmp(buf,"win_look:"))
3367  XConfigureWindow(display,look_list.win,xwc_mask, &xwc);
3368  if (!strcmp(buf,"win_message:"))
3369  XConfigureWindow(display,win_message,xwc_mask, &xwc);
3370 
3371  }
3372  fclose(fp);
3373 }
3374 
3375 
3376 void load_defaults(void)
3377 {
3378  char path[MAX_BUF],inbuf[MAX_BUF],*cp;
3379  FILE *fp;
3380 
3381  sprintf(path,"%s/.crossfire/defaults", getenv("HOME"));
3382  if ((fp=fopen(path,"r"))==NULL) return;
3383  while (fgets(inbuf, MAX_BUF-1, fp)) {
3384  inbuf[MAX_BUF-1]='\0';
3385  inbuf[strlen(inbuf)-1]='\0'; /* kill newline */
3386 
3387  if (inbuf[0]=='#') continue;
3388  /* IF no colon, then we certainly don't have a real value, so just skip */
3389  if (!(cp=strchr(inbuf,':'))) continue;
3390  *cp='\0';
3391  cp+=2; /* colon, space, then value */
3392 
3393  if (!strcmp(inbuf, "port")) {
3394  use_config[CONFIG_PORT] = atoi(cp);
3395  continue;
3396  }
3397  if (!strcmp(inbuf, "server")) {
3398  server = strdup_local(cp); /* memory leak ! */
3399  continue;
3400  }
3401  if (!strcmp(inbuf,"cacheimages")) {
3402  if (!strcmp(cp,"True")) want_config[CONFIG_CACHE]=TRUE;
3404  continue;
3405  }
3406  if (!strcmp(inbuf,"split")) {
3407  if (!strcmp(cp,"True")) want_config[CONFIG_SPLITWIN]=TRUE;
3409  continue;
3410  }
3411  if (!strcmp(inbuf,"showicon")) {
3412  if (!strcmp(cp,"True")) inv_list.show_icon=TRUE;
3413  else inv_list.show_icon=FALSE;
3414  continue;
3415  }
3416  if (!strcmp(inbuf,"scrolllines")) {
3417  infodata.maxlines = atoi(cp);
3418  continue;
3419  }
3420  if (!strcmp(inbuf,"scrollinfo")) {
3421  if (!strcmp(cp,"True")) infodata.scroll_info_window=TRUE;
3422  else infodata.scroll_info_window=FALSE;
3423  continue;
3424  }
3425  if (!strcmp(inbuf,"sound")) {
3426  if (!strcmp(cp,"True")) want_config[CONFIG_SOUND]=TRUE;
3428  continue;
3429  }
3430  if (!strcmp(inbuf,"command_window")) {
3431  use_config[CONFIG_CWINDOW] = atoi(cp);
3434  continue;
3435  }
3436  if (!strcmp(inbuf,"foodbeep")) {
3437  if (!strcmp(cp,"True")) use_config[CONFIG_FOODBEEP]=TRUE;
3439  continue;
3440  }
3441  if (!strcmp(inbuf,"noautorepeat")) {
3442  if (!strcmp(cp,"True")) noautorepeat=TRUE;
3443  else noautorepeat=FALSE;
3444  continue;
3445  }
3446  if (!strcmp(inbuf,"font")) {
3447  font_name = strdup_local(cp);
3448  continue;
3449  }
3450  fprintf(stderr,"Got line we did not understand: %s: %s\n", inbuf, cp);
3451  }
3452  fclose(fp);
3453 }
3454 
3455 void save_defaults(void)
3456 {
3457  char path[MAX_BUF],buf[MAX_BUF];
3458  FILE *fp;
3459 
3460  sprintf(path,"%s/.crossfire/defaults", getenv("HOME"));
3461  if (make_path_to_file(path)==-1) {
3462  fprintf(stderr,"Could not create %s\n", path);
3463  return;
3464  }
3465  if ((fp=fopen(path,"w"))==NULL) {
3466  fprintf(stderr,"Could not open %s\n", path);
3467  return;
3468  }
3469  fprintf(fp,"# This file is generated automatically by cfclient.\n");
3470  fprintf(fp,"# Manually editing is allowed, however cfclient may be a bit finicky about\n");
3471  fprintf(fp,"# some of the matching it does. all comparissons are case sensitive.\n");
3472  fprintf(fp,"# 'True' and 'False' are the proper cases for those two values\n");
3473 
3474  fprintf(fp,"port: %d\n", use_config[CONFIG_PORT]);
3475  fprintf(fp,"server: %s\n", server);
3476  fprintf(fp,"font: %s\n", font_name);
3477  fprintf(fp,"cacheimages: %s\n", want_config[CONFIG_CACHE]?"True":"False");
3478  fprintf(fp,"split: %s\n", want_config[CONFIG_SPLITWIN]?"True":"False");
3479  fprintf(fp,"showicon: %s\n", inv_list.show_icon?"True":"False");
3480  fprintf(fp,"scrolllines: %d\n", infodata.maxlines);
3481  fprintf(fp,"scrollinfo: %s\n", infodata.scroll_info_window?"True":"False");
3482  fprintf(fp,"sound: %s\n", want_config[CONFIG_SOUND]?"True":"False");
3483  fprintf(fp,"command_window: %d\n", use_config[CONFIG_CWINDOW]);
3484  fprintf(fp,"foodbeep: %s\n", use_config[CONFIG_FOODBEEP]?"True":"False");
3485  fprintf(fp,"noautorepeat: %s\n", noautorepeat?"True":"False");
3486 
3487  fclose(fp);
3488  sprintf(buf,"Defaults saved to %s",path);
3489  draw_info(buf,NDI_BLUE);
3490 }
3491 
3492 /* determine what we show in the inventory window. This is a slightly
3493  * more complicated version than the server side, since we use a bitmask
3494  * which means we could show things like magical and cursed, or unpaid
3495  * and magical, etc. Current time, we don't really support setting it
3496  * all that well.
3497  *
3498  */
3499 
3500 void command_show (const char *params)
3501 {
3502  if(!params) {
3503  if (inv_list.show_what==show_all) inv_list.show_what = show_applied;
3504  else { /* rotate the bit. If no valid bits are set, start over */
3505  inv_list.show_what = inv_list.show_what << 1;
3506  if (!(inv_list.show_what & show_mask))
3507  inv_list.show_what = show_all;
3508  }
3509  inv_list.env->inv_updated =1;
3510  return;
3511  }
3512 
3513  if (!strncmp(params, "all", strlen(params)))
3514  inv_list.show_what = show_all;
3515  else if (!strncmp(params, "applied", strlen(params)))
3516  inv_list.show_what = show_applied;
3517  else if (!strncmp(params, "unapplied", strlen(params)))
3518  inv_list.show_what = show_unapplied;
3519  else if (!strncmp(params, "unpaid", strlen(params)))
3520  inv_list.show_what = show_unpaid;
3521  else if (!strncmp(params, "cursed", strlen(params)))
3522  inv_list.show_what = show_cursed;
3523  else if (!strncmp(params, "magical", strlen(params)))
3524  inv_list.show_what = show_magical;
3525  else if (!strncmp(params, "nonmagical", strlen(params)))
3526  inv_list.show_what = show_nonmagical;
3527  else if (!strncmp(params, "locked", strlen(params)))
3528  inv_list.show_what = show_locked;
3529  else if (!strncmp(params, "unlocked", strlen(params)))
3530  inv_list.show_what = show_unlocked;
3531 
3532  inv_list.env->inv_updated =1;
3533 }
3534 
3535 /* This doesn't need to do anything for x11 client */
3536 void cleanup_connection(void) { }
3537 
3538 
3539 int main(int argc, char *argv[])
3540 {
3541  int sound,got_one=0;
3542 
3543  /* This needs to be done first. In addition to being quite quick,
3544  * it also sets up some paths (client_libdir) that are needed by
3545  * the other functions.
3546  */
3547 
3548  init_client_vars();
3549 
3550  /* Call this very early. It should parse all command
3551  * line arguments and set the pertinent ones up in
3552  * globals. Also call it early so that if it can't set up
3553  * the windowing system, we get an error before trying to
3554  * to connect to the server. And command line options will
3555  * likely change on the server we connect to.
3556  */
3557  if (init_windows(argc, argv)) { /* x11.c */
3558  fprintf(stderr,"Failure to init windows.\n");
3559  exit(1);
3560  }
3561  csocket.inbuf.buf=malloc(MAXSOCKBUF);
3562 
3563 #ifdef HAVE_SYSCONF
3564  maxfd = sysconf(_SC_OPEN_MAX);
3565 #else
3566  maxfd = getdtablesize();
3567 #endif
3568 
3569  sound = init_sounds();
3570 
3571  /* Loop to connect to server/metaserver and play the game */
3572  while (1) {
3574  csocket.inbuf.len=0;
3575  csocket.cs_version=0;
3576 
3577  /* Perhaps not the best assumption, but we are taking it that
3578  * if the player has not specified a server (ie, server
3579  * matches compiled in default), we use the meta server.
3580  * otherwise, use the server provided, bypassing metaserver.
3581  * Also, if the player has already played on a server once (defined
3582  * by got_one), go to the metaserver. That gives them the oppurtunity
3583  * to quit the client or select another server. We should really add
3584  * an entry for the last server there also.
3585  */
3586 
3588  if (!server || got_one) {
3589  char *ms;
3592  do {
3593  ms=get_metaserver();
3594  } while (metaserver_select(ms));
3595  negotiate_connection(sound);
3596  } else {
3598  if (csocket.fd == -1) { /* specified server no longer valid */
3599  server = NULL;
3600  continue;
3601  }
3602  negotiate_connection(sound);
3603  }
3604 
3605  got_one=1;
3606  event_loop();
3607  /* if event_loop has exited, we most of lost our connection, so we
3608  * loop again to establish a new one.
3609  */
3610 
3611  mapdata_reset();
3612  /* Need to reset the images so they match up properly and prevent
3613  * memory leaks.
3614  */
3615  reset_image_data();
3617  /* We know the following is the private map structure in
3618  * item.c. But we don't have direct access to it, so
3619  * we still use locate.
3620  */
3622  look_list.env=cpl.below;
3623  }
3624  exit(0); /* never reached */
3625 }
sint16 bar_size
Definition: x11.c:219
uint16 pmapx
Definition: client.h:297
float weight
Definition: item.h:56
void negotiate_connection(int sound)
Definition: client.c:338
static int get_message_display(void)
Definition: x11.c:1318
sint16 bar_pos
Definition: x11.c:220
static int gargc
Definition: x11.c:182
uint16 maxlines
Definition: x11.c:211
static void get_list_display(itemlist *l, int x, int y, int w, int h, const char *t, const char *s)
Definition: x11.c:1890
signed short sint16
Definition: client-types.h:80
static XFontStruct * font
Definition: x11.c:192
static int height
Definition: mapdata.c:104
void end_windows(void)
Definition: x11.c:402
#define COMMAND_WINDOW
Definition: client.h:54
uint16 infopos
Definition: x11.c:207
#define copy_name(t, f)
Definition: item.h:38
#define INFOLINES
Definition: x11.c:159
static void draw_info_scrollbar(int redraw)
Definition: x11.c:702
static Window def_root
Definition: x11.c:185
uint32 count
Definition: client.h:295
sint8 level
Definition: client.h:215
#define NAME_LEN
Definition: item.h:37
static void resize_list_info(itemlist *l, int w, int h)
Definition: x11.c:1833
void move_player(int dir)
Definition: player.c:99
void menu_clear(void)
Definition: x11.c:2033
int init_pngx_loader(Display *display)
Definition: png.c:482
static Pixmap xpm_masks[XPMGCS]
Definition: x11.c:251
sint16 hp
Definition: client.h:216
void clear_fire_run(void)
Definition: player.c:122
static int FONTHEIGHT
Definition: x11.c:162
static GC gc_root
Definition: x11.c:252
void redisplay_stats(void)
Definition: x11.c:3165
void init_client_vars(void)
Definition: init.c:97
Window win_info
Definition: x11.c:215
sint8 Int
Definition: client.h:211
void monitorChilds(void)
Definition: misc.c:239
sint32 speed
Definition: client.h:229
void close_container(item *op)
Definition: x11.c:1826
char old_title[MAX_BUF]
Definition: x11.c:116
struct PixmapInfo * pixmaps[MAXPIXMAPNUM]
Definition: x11.c:236
sint16 width
Definition: x11.c:225
static void init_cache_data(void)
Definition: gx11.c:504
sint8 * icon2
Definition: x11.c:140
static XEvent event
Definition: x11.c:193
static itemlist look_list
Definition: x11.c:261
void clear_fire(void)
Definition: player.c:134
#define CONFIG_ECHO
Definition: client.h:153
static Pixmap dark1
Definition: x11.c:251
char flags[NAME_LEN]
Definition: item.h:53
void draw_stats(int redraw)
Definition: x11.c:1149
sint8 Str
Definition: client.h:206
void set_scroll(const char *s)
Definition: x11.c:2005
void item_event_item_deleting(item *it)
Definition: x11.c:2040
static long def_screen
Definition: x11.c:186
static int get_look_display(void)
Definition: x11.c:1946
void animate_objects(void)
Definition: item.c:687
item * ob
Definition: client.h:272
GC gc_text
Definition: x11.c:119
sint16 food
Definition: client.h:223
snd_pcm_hw_params_t * params
Definition: alsa9.c:111
int display_mapscroll(int dx, int dy)
Definition: x11.c:3128
const char * rcsid_x11_x11_c
Definition: x11.c:1
#define INFOCHARS
Definition: x11.c:267
#define MAP_MAX_SIZE
Definition: client.h:447
void metaserver_show(int show_selection)
Definition: metaserver.c:807
#define FACE_COLOR_MASK
Definition: newclient.h:251
int metaserver_select(char *sel)
Definition: metaserver.c:861
static XColor discolor[16]
Definition: x11.c:191
uint8 * magicmap
Definition: client.h:299
sint16 bar_length
Definition: x11.c:146
uint16 scroll_info_window
Definition: x11.c:209
void command_show(const char *params)
Definition: x11.c:3500
struct item_struct * next
Definition: item.h:46
ClientSocket csocket
Definition: client.c:78
sint16 maxhp
Definition: client.h:217
static unsigned long background
Definition: x11.c:187
Definition: x11.c:204
static Pixmap dark3
Definition: x11.c:251
void mapdata_reset(void)
Definition: mapdata.c:572
void reset_image_data(void)
Definition: x11.c:3261
static void parse_key_release(uint32 ks)
Definition: keys.c:407
Window win_root
Definition: x11.c:189
int make_path_to_file(char *filename)
Definition: misc.c:94
Face_Information face_info
Definition: image.c:167
void draw_color_info(int colr, const char *buf)
Definition: x11.c:925
void item_event_item_changed(item *it)
Definition: x11.c:2042
sint8 ac
Definition: client.h:214
Stats stats
Definition: client.h:285
#define MAXPIXMAPNUM
Definition: client.h:470
static void draw_list(itemlist *l)
Definition: x11.c:1634
#define CONFIG_FOGWAR
Definition: client.h:157
sint16 want_config[CONFIG_NUMS]
Definition: init.c:50
#define WINDOW_SPACING
Definition: x11.c:178
static void configure_keys(uint32 keysym)
Definition: keys.c:855
sint16 bar_size
Definition: x11.c:147
inventory_show show_what
Definition: x11.c:149
sint16 height
Definition: x11.c:132
int meta_port
Definition: client.c:67
uint32 resist_change
Definition: client.h:242
const char *const resists_name[NUM_RESISTS]
Definition: client.c:80
uint32 no_echo
Definition: client.h:294
sint8 * icon1
Definition: x11.c:139
uint16 maxdisp
Definition: x11.c:212
static int get_inv_display(void)
Definition: x11.c:1932
sint64 skill_exp[MAX_SKILL]
Definition: client.h:244
sint8 Con
Definition: client.h:208
uint16 inv_updated
Definition: item.h:70
sint8 Cha
Definition: client.h:210
void set_window_pos(void)
Definition: x11.c:3340
uint16 pmapy
Definition: client.h:297
Definition: x11.c:247
static char stats_buff[7][600]
Definition: x11.c:235
sint16 bar_y
Definition: x11.c:223
void display_map_startupdate(void)
Definition: x11.c:3175
Input_State
Definition: client.h:113
void draw_magic_map(void)
Definition: x11.c:3186
char * server
Definition: client.c:56
Window win_message
Definition: x11.c:188
void * image_data
Definition: client.h:484
static GC gc_clear_xpm
Definition: x11.c:252
static GC gc_copy
Definition: x11.c:256
void draw_message_window(int redraw)
Definition: x11.c:1384
sint16 item_used
Definition: x11.c:135
char * skill_names[MAX_SKILL]
Definition: client.c:63
uint8 have_darkness
Definition: mapdata.h:82
char format_n[20]
Definition: x11.c:128
int sync_display
Definition: x11.c:2063
static GC gc_message
Definition: x11.c:252
GC gc_info
Definition: x11.c:216
uint8 height
Definition: x11.h:38
void display_map_doneupdate(int redraw, int notice)
Definition: x11.c:3101
int init_sounds(void)
Definition: sound.c:60
#define STAT_HEIGHT
Definition: x11.c:173
sint16 item_pos
Definition: x11.c:134
GC gc_icon
Definition: x11.c:120
sint8 Pow
Definition: client.h:212
uint8 need_update
Definition: mapdata.h:81
static Stats last_stats
Definition: x11.c:264
static int get_info_display(void)
Definition: x11.c:502
static void do_key_press(int repeated)
Definition: x11.c:2313
int init_connection(char *host, int port)
Definition: client.c:205
static int show_object(item *ip, inventory_show flags)
Definition: x11.c:1539
uint16 applied
Definition: item.h:67
static void draw_status_icon(itemlist *l, int x, int y, int face)
Definition: x11.c:1529
static void parse_game_button_press(int button, int x, int y)
Definition: x11.c:2234
int maxfd
Definition: client.c:68
static int width
Definition: mapdata.c:104
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
void client_send_apply(int tag)
Definition: player.c:80
uint8 updatekeycodes
Definition: gx11.c:204
void reset_client_vars(void)
Definition: init.c:249
#define TRUE
Definition: client-types.h:71
static Pixmap icons[max_icons]
Definition: x11.c:249
Window win_stats
Definition: x11.c:188
int main(int argc, char *argv[])
Definition: x11.c:3539
#define CONFIG_CWINDOW
Definition: client.h:155
#define SF_RUNON
Definition: newclient.h:188
void resize_map_window(int x, int y)
Definition: x11.c:3061
uint16 numlines
Definition: x11.c:210
gchar * text
Definition: about.h:2
void look_at(int x, int y)
Definition: player.c:75
sint16 grace
Definition: client.h:220
sint16 bar_length
Definition: x11.c:218
#define NUM_RESISTS
Definition: client.h:432
#define CONFIG_FOODBEEP
Definition: client.h:172
void x_set_echo(void)
Definition: x11.c:3093
sint16 resists[30]
Definition: client.h:241
uint16 max_info_chars
Definition: x11.c:206
Pixmap mask
Definition: xutil.c:67
uint16 has_scrollbar
Definition: x11.c:224
#define CONFIG_PORT
Definition: client.h:174
static const unsigned char crossfire_bits[]
Definition: clientbmap.h:30
int associate_cache_entry(Cache_Entry *ce, int pixnum)
Definition: x11.c:3159
uint16 locked
Definition: item.h:66
sint8 Dex
Definition: client.h:207
static int old_mapy
Definition: x11.c:182
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
static GC gc_xpm[XPMGCS]
Definition: x11.c:252
static int old_mapx
Definition: x11.c:182
#define X_PROG_NAME
Definition: x11.c:39
char d_name[NAME_LEN]
Definition: item.h:50
sint16 mapdata_face(int x, int y, int layer)
Definition: mapdata.c:955
static unsigned long foreground
Definition: x11.c:187
static void buttonpress_in_info(XButtonEvent *xbutton)
Definition: x11.c:2389
uint8 darkness
Definition: mapdata.h:80
static void update_icons_list(itemlist *l)
Definition: x11.c:1810
Pixmap mask
Definition: x11.h:37
#define CREATEPM(name, data)
item * below
Definition: client.h:273
void reset_map(void)
Definition: map.c:76
static void display_mapcell(int ax, int ay)
Definition: x11.c:2994
#define SCROLLBAR_WIDTH
Definition: x11.c:157
int newimages
Definition: x11.c:342
Client_Player cpl
Definition: client.c:77
sint16 size
Definition: x11.c:137
uint16 flags
Definition: client.h:240
static int buttonpress_in_list(itemlist *l, XButtonEvent *xbutton)
Definition: x11.c:2444
uint8 cleared
Definition: mapdata.h:84
sint32 tag
Definition: item.h:54
item * env
Definition: gx11.h:86
uint16 mapxres
Definition: client.h:302
void client_send_move(int loc, int tag, int nrof)
Definition: player.c:92
InfoData infodata
Definition: x11.c:228
#define CONFIG_CACHE
Definition: client.h:156
struct Map the_map
Definition: mapdata.c:121
void save_winpos(void)
Definition: x11.c:3299
void mapdata_init(void)
Definition: mapdata.c:514
struct MapCell ** cells
Definition: mapdata.h:95
#define CONFIG_MAPSCROLL
Definition: client.h:180
uint8 show_weight
Definition: gx11.h:97
int error_handler(Display *dp, XErrorEvent *xe)
Definition: x11.c:286
GC gc_status
Definition: x11.c:121
static void xwritedown(const char *txt, int x)
Definition: x11.c:1349
#define CONFIG_FASTTCP
Definition: client.h:154
int fd
Definition: client.h:97
void reset_image_cache_data(void)
Definition: image.c:474
uint16 magical
Definition: item.h:62
static void get_window_coord(Window win, int *x, int *y, int *wx, int *wy, unsigned int *w, unsigned int *h)
Definition: x11.c:3285
Display * display
Definition: x11.c:184
void cleanup_connection(void)
Definition: x11.c:3536
#define XPMGCS
Definition: x11.c:242
sint16 text_len
Definition: x11.c:129
static Pixmap xpm_pixmap
Definition: x11.c:251
unsigned short uint16
Definition: client-types.h:79
void extended_command(const char *ocommand)
Definition: p_cmd.c:890
static GC gc_xpm_object
Definition: x11.c:252
void load_defaults(void)
Definition: x11.c:3376
static int get_game_display(void)
Definition: x11.c:431
#define crossfire_height
Definition: clientbmap.h:29
uint16 mmapy
Definition: client.h:296
void check_x_events(void)
Definition: x11.c:2567
uint8 image_size
Definition: x11.c:231
static void resize_win_info(int width, int height)
Definition: x11.c:994
uint32 weight_limit
Definition: gx11.h:99
static Atom wm_delete_window
Definition: x11.c:195
void send_reply(const char *text)
Definition: commands.c:769
void allocate_colors(Display *disp, Window w, long screen_num, Colormap *colormap, XColor discolor[16])
Definition: xutil.c:172
void send_mark_obj(item *op)
Definition: item.c:590
uint32 run_on
Definition: client.h:291
sint16 maxgrace
Definition: client.h:221
static void draw_all_info(void)
Definition: x11.c:936
static char * font_name
Definition: x11.c:155
uint32 fire_on
Definition: client.h:290
void toggle_locked(item *op)
Definition: item.c:573
void event_loop(void)
Definition: x11.c:300
const char * complete_command(const char *command)
Definition: p_cmd.c:972
int last_used_skills[MAX_SKILL+1]
Definition: client.c:65
sint16 height
Definition: x11.c:225
uint8 color
Definition: x11.c:200
static void delete_ch(void)
Definition: x11.c:552
char * get_metaserver(void)
Definition: x11.c:2533
sint16 maxsp
Definition: client.h:219
#define MAX_BUF
Definition: client-types.h:128
sint16 * faces
Definition: x11.c:138
uint16 unpaid
Definition: item.h:65
#define MAX_TIME
Definition: cconfig.h:39
#define SF_FIREON
Definition: newclient.h:187
static itemlist inv_list
Definition: x11.c:261
sint16 dam
Definition: client.h:226
unsigned int uint32
Definition: client-types.h:77
static Pixmap dark2
Definition: x11.c:251
char format_nwl[20]
Definition: x11.c:127
#define MAXLAYERS
Definition: mapdata.h:32
#define CONFIG_MAPWIDTH
Definition: client.h:170
item * locate_item(sint32 tag)
Definition: item.c:292
uint16 open
Definition: item.h:68
unsigned char * buf
Definition: newclient.h:573
int len
Definition: newclient.h:572
static XSizeHints messagehint
Definition: x11.c:194
#define GAME_WIDTH
Definition: x11.c:171
sint32 weapon_sp
Definition: client.h:230
Definition: x11.c:245
static void draw_stat_bar(int bar_pos, int height, int is_alert)
Definition: x11.c:1358
int get_info_width(void)
Definition: x11.c:2028
static char ** gargv
Definition: x11.c:155
sint16 width
Definition: x11.c:131
void set_autorepeat(const char *s)
Definition: x11.c:2021
uint8 showmagic
Definition: client.h:300
void draw_info(const char *str, int color)
Definition: x11.c:750
#define MAXSOCKBUF
Definition: newclient.h:79
char * strdup_local(const char *str)
Definition: misc.c:125
uint8 lastcolor
Definition: x11.c:213
void item_event_container_clearing(item *container)
Definition: x11.c:2041
#define MAX_BARS_MESSAGE
Definition: x11.c:1356
void script_fdset(int *maxfd, fd_set *set)
Definition: script.c:559
void magic_map_flash_pos(void)
Definition: x11.c:3238
signed char sint8
Definition: client-types.h:82
void remove_item_inventory(item *op)
Definition: item.c:382
char format_nw[20]
Definition: x11.c:126
#define CONFIG_MAPHEIGHT
Definition: client.h:171
uint32 nrof
Definition: item.h:55
Definition: client.h:480
sint8 * icon4
Definition: x11.c:142
#define CONFIG_DOWNLOAD
Definition: client.h:152
sint16 sp
Definition: client.h:218
InfoLine * data
Definition: x11.c:214
sint16 mapdata_bigface(int x, int y, int layer, int *ww, int *hh)
Definition: mapdata.c:966
static void usage(char *progname)
Definition: x11.c:2732
void draw_lists(void)
Definition: x11.c:1965
Window win
Definition: x11.c:118
int want_skill_exp
Definition: client.c:67
static void gen_draw_face(Drawable where, int face, int x, int y, int sx, int sy)
Definition: x11.c:348
static float info_ratio
Definition: x11.c:240
static void parse_key(char key, uint32 keysym)
Definition: keys.c:437
SockList inbuf
Definition: client.h:98
Pixmap pixmap
Definition: xutil.c:67
void client_send_examine(int tag)
Definition: player.c:85
Input_State input_state
Definition: client.h:277
char range[MAX_BUF]
Definition: client.h:288
static int FONTWIDTH
Definition: x11.c:161
uint16 mapyres
Definition: client.h:302
static void create_status_icons(void)
Definition: x11.c:1559
uint8 show_icon
Definition: gx11.h:96
static double weight_limit
Definition: inventory.c:55
uint8 width
Definition: x11.h:38
void DoClient(ClientSocket *csocket)
Definition: client.c:149
uint16 infoline
Definition: x11.c:208
char title[MAX_BUF]
Definition: client.h:287
int metaserver_get_info(char *metaserver, int meta_port)
Definition: metaserver.c:791
Definition: x11.c:107
char VERSION_INFO[256]
Definition: client.c:59
static Pixmap icon
Definition: x11.c:251
#define ROOT_HEIGHT
Definition: x11.c:180
char input_text[MAX_BUF]
Definition: client.h:279
void set_show_weight(const char *s)
Definition: x11.c:1989
GC gc_game
Definition: x11.c:255
static GC gc_floor
Definition: x11.c:252
unsigned char uint8
Definition: client-types.h:81
#define FULL_VERSION
Definition: version.h:6
Colormap colormap
Definition: x11.c:190
#define crossfire_width
Definition: clientbmap.h:28
sint16 bar_pos
Definition: x11.c:148
void set_weight_limit(uint32 wlim)
Definition: x11.c:2000
static int get_root_display(char *display_name)
Definition: x11.c:2065
static void draw_all_list(itemlist *l)
Definition: x11.c:1780
void open_container(item *op)
Definition: x11.c:1819
uint16 damned
Definition: item.h:64
int misses
Definition: x11.c:342
uint16 mmapx
Definition: client.h:296
sint8 wc
Definition: client.h:213
char * meta_server
Definition: client.c:61
#define NDI_BLACK
Definition: newclient.h:201
struct item_struct * inv
Definition: item.h:49
char ** names
Definition: x11.c:143
sint16 skill_level[MAX_SKILL]
Definition: client.h:243
int noautorepeat
Definition: x11.c:153
#define FALSE
Definition: client-types.h:68
static void resize_win_message(int width, int height)
Definition: x11.c:989
void draw_prompt(const char *str)
Definition: x11.c:685
sint8 Wis
Definition: client.h:209
#define FLOAT_MULTF
Definition: newclient.h:102
sint64 exp
Definition: client.h:222
static int get_stats_display(void)
Definition: x11.c:1114
sint8 * icon3
Definition: x11.c:141
static void draw_all_message(void)
Definition: x11.c:1504
void save_defaults(void)
Definition: x11.c:3455
int init_windows(int argc, char **argv)
Definition: x11.c:2780
#define CONFIG_SPLITWIN
Definition: client.h:166
void script_process(fd_set *set)
Definition: script.c:572
#define INV_WIDTH
Definition: x11.c:176
static GC gc_blank
Definition: x11.c:252
Window win_game
Definition: x11.c:189
Definition: gx11.h:85
void display_map_newmap(void)
Definition: x11.c:2986
char title[MAX_BUF]
Definition: gx11.h:87
#define CONFIG_DARKNESS
Definition: client.h:173
uint16 cursed
Definition: item.h:63
static GC gc_stats
Definition: x11.c:252
void write_ch(char key)
Definition: x11.c:585
sint16 face
Definition: item.h:57
#define MIN(X__, Y__)
Definition: client.h:520
Definition: x11.c:104
void fire_dir(int dir)
Definition: player.c:151
inventory_show
Definition: x11.c:103
void set_show_icon(const char *s)
Definition: x11.c:1978
PlayerPosition pl_pos
Definition: map.c:69
static XSizeHints roothint
Definition: x11.c:194
#define NDI_BLUE
Definition: newclient.h:206
#define CONFIG_SOUND
Definition: client.h:164
Definition: x11.c:198
void init_keys(void)
Definition: keys.c:302
int cs_version
Definition: client.h:99
uint16 info_chars
Definition: x11.c:205
int total
Definition: x11.c:342
static void resize_win_root(XEvent *event)
Definition: x11.c:2170
char * info
Definition: x11.c:199