Crossfire Client, Branches  R11627
commands.c
Go to the documentation of this file.
1 const char * const rcsid_common_commands_c =
2  "$Id: commands.c 9719 2008-08-04 18:57:47Z ryo_saeba $";
3 /*
4  Crossfire client, a client program for the crossfire program.
5 
6  Copyright (C) 2001 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 /* Handles commands received by the server. This does not necessarily
27  * handle all commands - some might be in other files (like init.c)
28  *
29  * This file handles commans from the server->client. See player.c
30  * for client->server commands.
31  *
32  * this file contains most of the commands for the dispatch loop most of
33  * the functions are self-explanatory, the pixmap/bitmap commands recieve
34  * the picture, and display it. The drawinfo command draws a string
35  * in the info window, the stats command updates the local copy of the stats
36  * and displays it. handle_query prompts the user for input.
37  * send_reply sends off the reply for the input.
38  * player command gets the player information.
39  * MapScroll scrolls the map on the client by some amount
40  * MapCmd displays the map either with layer packing or stack packing.
41  * packing/unpacking is best understood by looking at the server code
42  * (server/ericserver.c)
43  * stack packing is easy, for every map entry that changed, we pack
44  * 1 byte for the x/y location, 1 byte for the count, and 2 bytes per
45  * face in the stack.
46  * layer packing is harder, but I seem to remember more efficient:
47  * first we pack in a list of all map cells that changed and are now
48  * empty. The end of this list is a 255, which is bigger that 121, the
49  * maximum packed map location.
50  * For each changed location we also pack in a list of all the faces and
51  * X/Y coordinates by layer, where the layer is the depth in the map.
52  * This essentially takes slices through the map rather than stacks.
53  * Then for each layer, (max is MAXMAPCELLFACES, a bad name) we start
54  * packing the layer into the message. First we pack in a face, then
55  * for each place on the layer with the same face, we pack in the x/y
56  * location. We mark the last x/y location with the high bit on
57  * (11*11 = 121 < 128). We then continue on with the next face, which
58  * is why the code marks the faces as -1 if they are finished. Finally
59  * we mark the last face in the layer again with the high bit, clearly
60  * limiting the total number of faces to 32767, the code comments it's
61  * 16384, I'm not clear why, but the second bit may be used somewhere
62  * else as well.
63  * The unpacking routines basically perform the opposite operations.
64  */
65 
66 int mapupdatesent = 0;
67 
68 #include <client.h>
69 #include <external.h>
70 #include <assert.h>
71 
72 #include "mapdata.h"
73 
74 
75 static void get_exp_info(const unsigned char *data, int len) {
76  int pos, level;
77 
78  if (len < 2) {
79  LOG(LOG_ERROR, "common::get_exp_info", "no max level info from server provided");
80  return;
81  }
82 
84  pos = 2;
85  exp_table = calloc(exp_table_max, sizeof(uint64));
86  for (level = 1; level <= exp_table_max && pos < len; level++) {
87  exp_table[level] = GetInt64_String(data+pos);
88  pos += 8;
89  }
90  if (level != exp_table_max) {
91  LOG(LOG_ERROR, "common::get_exp_info",
92  "Incomplete table sent - got %d entries, wanted %d", level, exp_table_max);
93  }
94 }
95 
96 static void get_skill_info(char *data, int len) {
97  char *cp, *nl, *sn;
98  int val;
99 
100  cp = data;
101  do {
102  nl = strchr(cp, '\n');
103  if (nl) {
104  *nl = 0;
105  nl++;
106  }
107  sn = strchr(cp, ':');
108  if (!sn) {
109  LOG(LOG_WARNING, "common::get_skill_info", "corrupt line: /%s/", cp);
110  return;
111  }
112 
113  *sn = 0;
114  sn++;
115  val = atoi(cp);
116  val -= CS_STAT_SKILLINFO;
117  if (val < 0 || val> CS_NUM_SKILLS) {
118  LOG(LOG_WARNING, "common::get_skill_info", "invalid skill number %d", val);
119  return;
120  }
121 
122  free(skill_names[val]);
123  skill_names[val] = strdup_local(sn);
124  cp = nl;
125  } while (cp < data+len);
126 }
127 
128 /* handles the response from a 'requestinfo' command. This function doesn't
129  * do much itself other than dispatch to other functions.
130  */
131 void ReplyInfoCmd(uint8 *buf, int len) {
132  uint8 *cp;
133  int i;
134 
135  /* Covers a bug in the server in that it could send a replyinfo with no parameters */
136  if (!buf) {
137  return;
138  }
139 
140  for (i = 0; i < len; i++) {
141  /* Either a space or newline represents a break */
142  if (*(buf+i) == ' ' || *(buf+i) == '\n') {
143  break;
144  }
145  }
146  if (i >= len) {
147  /* Don't print buf, as it may contain binary data */
148  /* Downgrade this to DEBUG - if the client issued an unsupported requestinfo
149  * info to the server, we'll end up here - this could be normal behaviour
150  */
151  LOG(LOG_DEBUG, "common::ReplyInfoCmd", "Never found a space in the replyinfo");
152  return;
153  }
154 
155  /* Null out the space and put cp beyond it */
156  cp = buf+i;
157  *cp++ = '\0';
158  if (!strcmp((char*)buf, "image_info")) {
159  get_image_info(cp, len-i-1); /* located in common/image.c */
160  } else if (!strcmp((char*)buf, "image_sums")) {
161  get_image_sums((char*)cp, len-i-1); /* located in common/image.c */
162  } else if (!strcmp((char*)buf, "skill_info")) {
163  get_skill_info((char*)cp, len-i-1); /* located in common/commands.c */
164  } else if (!strcmp((char*)buf, "exp_table")) {
165  get_exp_info(cp, len-i-1); /* located in common/commands.c */
166  }
167 }
168 
169 /* Received a response to a setup from the server.
170  * This function is basically the same as the server side function - we
171  * just do some different processing on the data.
172  */
173 void SetupCmd(char *buf, int len) {
174  int s;
175  char *cmd, *param;
176 
177  /* run through the cmds of setup
178  * syntax is setup <cmdname1> <parameter> <cmdname2> <parameter> ...
179  *
180  * we send the status of the cmd back, or a FALSE is the cmd is the server unknown
181  * The client then must sort this out
182  */
183 
184  LOG(LOG_DEBUG, "common::SetupCmd", "%s", buf);
185  for (s = 0; ; ) {
186  if (s >= len) { /* ugly, but for secure...*/
187  break;
188  }
189 
190  cmd = &buf[s];
191 
192  /* find the next space, and put a null there */
193  for (; buf[s] && buf[s] != ' '; s++)
194  ;
195  buf[s++] = 0;
196  while (buf[s] == ' ') {
197  s++;
198  }
199  if (s >= len) {
200  break;
201  }
202 
203  param = &buf[s];
204 
205  for (; buf[s] && buf[s] != ' '; s++)
206  ;
207  buf[s++] = 0;
208  while (s < len && buf[s] == ' ') {
209  s++;
210  }
211 
212  /* what we do with the returned data depends on what the server
213  * returns to us. In some cases, we may fall back to other
214  * methods, just report on error, or try another setup command.
215  */
216  if (!strcmp(cmd, "sound2")) {
217  /* No parsing needed, but we don't want a warning about unknown
218  * setup option below.
219  */
220  } else if (!strcmp(cmd, "sound")) {
221  /* No, this should not be !strcmp()... */
222  if (strcmp(param, "FALSE")) {
224  }
225  } else if (!strcmp(cmd, "mapsize")) {
226  int x, y = 0;
227  char *cp, tmpbuf[MAX_BUF];
228 
229  if (!strcasecmp(param, "false")) {
230  draw_info("Server only supports standard sized maps (11x11)", NDI_RED);
231  /* Do this because we may have been playing on a big server before */
235  resize_map_window(use_config[CONFIG_MAPWIDTH], use_config[CONFIG_MAPHEIGHT]);
236  continue;
237  }
238  x = atoi(param);
239  for (cp = param; *cp != 0; cp++) {
240  if (*cp == 'x' || *cp == 'X') {
241  y = atoi(cp+1);
242  break;
243  }
244  }
245  /* we wanted a size larger than the server supports. Reduce our
246  * size to server maximum, and re-sent the setup command.
247  * Update our want sizes, and also tell the player what we are doing
248  */
254  "setup mapsize %dx%d", use_config[CONFIG_MAPWIDTH], use_config[CONFIG_MAPHEIGHT]);
255  snprintf(tmpbuf, sizeof(tmpbuf), "Server supports a max mapsize of %d x %d - requesting a %d x %d mapsize",
256  x, y, use_config[CONFIG_MAPWIDTH], use_config[CONFIG_MAPHEIGHT]);
257  draw_info(tmpbuf, NDI_RED);
258  } else if (use_config[CONFIG_MAPWIDTH] == x && use_config[CONFIG_MAPHEIGHT] == y) {
260  resize_map_window(use_config[CONFIG_MAPWIDTH], use_config[CONFIG_MAPHEIGHT]);
261  } else {
262  /* Our request was not bigger than what server supports, and
263  * not the same size, so whats the problem? Tell the user that
264  * something is wrong.
265  */
266  snprintf(tmpbuf, sizeof(tmpbuf), "Unable to set mapsize on server - we wanted %d x %d, server returned %d x %d",
268  draw_info(tmpbuf, NDI_RED);
269  }
270  } else if (!strcmp(cmd, "sexp") || !strcmp(cmd, "darkness") ||
271  !strcmp(cmd, "newmapcmd") || !strcmp(cmd, "spellmon")) {
272  /* this really isn't an error or bug - in fact, it is expected if
273  * the user is playing on an older server.
274  */
275  if (!strcmp(param, "FALSE")) {
276  LOG(LOG_WARNING, "common::SetupCmd", "Server returned FALSE on setup command %s", cmd);
277 #if 0
278 /* This should really be a callback to the gui if it needs to re-examine
279  * the results here.
280  */
281  if (!strcmp(cmd, "newmapcmd") && fog_of_war == TRUE) {
282  fprintf(stderr, "**Warning: Fog of war is active but server does not support the newmap command\n");
283  }
284 #endif
285  }
286  } else if (!strcmp(cmd, "facecache")) {
287  if (!strcmp(param, "FALSE") && want_config[CONFIG_CACHE]) {
289  } else {
290  use_config[CONFIG_CACHE] = atoi(param);
291  }
292  } else if (!strcmp(cmd, "faceset")) {
293  if (!strcmp(param, "FALSE")) {
294  draw_info("Server does not support other image sets, will use default", NDI_RED);
295  face_info.faceset = 0;
296  }
297  } else if (!strcmp(cmd, "map2cmd")) {
298  if (!strcmp(param, "FALSE")) {
299  draw_info("Server does not support map2cmd!", NDI_RED);
300  draw_info("This server is too old to support this client!", NDI_RED);
301 #ifdef WIN32
302  closesocket(csocket.fd);
303 #else
304  close(csocket.fd);
305 #endif
306  csocket.fd = -1;
307  }
308  } else if (!strcmp(cmd, "itemcmd")) {
309  /* don't really care - currently, the server will just
310  * fall back to the item1 transport mode. If more item modes
311  * are used in the future, we should probably fall back one at
312  * a time or the like.
313  */
314  } else if (!strcmp(cmd, "exp64")) {
315  /* If this server does not support the new skill code,
316  * error out. If the server does support new exp system,
317  * send a request to get the mapping information.
318  */
319  if (!strcmp(param, "FALSE")) {
320  draw_info("Server does not support exp64!", NDI_RED);
321  draw_info("This server is too old to support this client!", NDI_RED);
322 #ifdef WIN32
323  closesocket(csocket.fd);
324 #else
325  close(csocket.fd);
326 #endif
327  csocket.fd = -1;
328  } else {
329  cs_print_string(csocket.fd, "requestinfo skill_info");
330  }
331  } else if (!strcmp(cmd, "extendedMapInfos")) {
332  if (!strcmp(param, "FALSE")) {
334  } else {
335  /* Request all extended infos we want
336  * Should regroup everything for easyness
337  */
338  if (use_config[CONFIG_SMOOTH]) {
339  cs_print_string(csocket.fd, "toggleextendedinfos smooth");
340  }
341  }
342  } else if (!strcmp(cmd, "extendedTextInfos")) {
343  if (strcmp(param, "FALSE")) { /* server didn't send FALSE*/
344  /* Server seems to accept extended text infos. Let's tell
345  * it what extended text info we want
346  */
347  char exttext[MAX_BUF];
348  TextManager *manager = firstTextManager;
349 
350  while (manager) {
351  snprintf(exttext, sizeof(exttext), "toggleextendedtext %d", manager->type);
352  cs_print_string(csocket.fd, exttext);
353  manager = manager->next;
354  }
355  }
356  } else if (!strcmp(cmd, "want_pickup")) {
357  /* Nothing to do specially, it's info pushed from server, not having it isn't that bad. */
358  } else if (!strcmp(cmd, "inscribe")) {
359  if (strcmp(param, "FALSE"))
360  command_inscribe = atoi(param);
361  else
362  command_inscribe = 0;
363  } else {
364  LOG(LOG_INFO, "common::SetupCmd", "Got setup for a command we don't understand: %s %s",
365  cmd, param);
366  }
367  }
368 }
369 
370 void ExtendedInfoSetCmd(char *data, int len) {
371  (void)data; /* __UNUSED__ */
372  (void)len; /* __UNUSED__ */
373 
374  /* Do nothing for now, perhaps later add some
375  * support to check what server knows.
376  */
377  /* commented, no waranty string data is null terminated
378  draw_info("ExtendedInfoSet returned from server: ", NDI_BLACK);
379  draw_info(data, NDI_BLACK);
380  */
381 }
382 
383 /* Handles when the server says we can't be added. In reality, we need to
384  * close the connection and quit out, because the client is going to close
385  * us down anyways.
386  */
387 void AddMeFail(char *data, int len) {
388  (void)data; /* __UNUSED__ */
389  (void)len; /* __UNUSED__ */
390 
391  LOG(LOG_INFO, "common::AddMeFail", "addme_failed received.");
392  return;
393 }
394 
395 /* This is really a throwaway command - there really isn't any reason to
396  * send addme_success commands.
397  */
398 void AddMeSuccess(char *data, int len) {
399  (void)data; /* __UNUSED__ */
400  (void)len; /* __UNUSED__ */
401 
402  LOG(LOG_INFO, "common::AddMeSuccess", "addme_success received.");
403  return;
404 }
405 
406 void GoodbyeCmd(char *data, int len) {
407  (void)data; /* __UNUSED__ */
408  (void)len; /* __UNUSED__ */
409 
410  /* This could probably be greatly improved - I am not sure if anything
411  * needs to be saved here, but certainly it should be possible to
412  * reconnect to the server or a different server without having to
413  * rerun the client.
414  */
415  LOG(LOG_WARNING, "common::GoodbyeCmd", "Received goodbye command from server - exiting");
416  exit(0);
417 }
418 
420 
421 void AnimCmd(unsigned char *data, int len) {
422  short anum;
423  int i, j;
424 
425  anum = GetShort_String(data);
426  if (anum < 0 || anum > MAXANIM) {
427  LOG(LOG_WARNING, "common::AnimCmd", "animation number invalid: %d", anum);
428  return;
429  }
430 
431  animations[anum].flags = GetShort_String(data+2);
432  animations[anum].num_animations = (len-4)/2;
433  if (animations[anum].num_animations < 1) {
434  LOG(LOG_WARNING, "common::AnimCmd", "num animations invalid: %d",
435  animations[anum].num_animations);
436  return;
437  }
438  animations[anum].faces = malloc(sizeof(uint16)*animations[anum].num_animations);
439  for (i = 4, j = 0; i < len; i += 2, j++) {
440  animations[anum].faces[j] = GetShort_String(data+i);
441  }
442 
443  if (j != animations[anum].num_animations) {
444  LOG(LOG_WARNING, "common::AnimCmd",
445  "Calculated animations does not equal stored animations? (%d!=%d)",
446  j, animations[anum].num_animations);
447  }
448 
449  animations[anum].speed = 0;
450  animations[anum].speed_left = 0;
451  animations[anum].phase = 0;
452 
453  LOG(LOG_DEBUG, "common::AnimCmd", "Received animation %d, %d faces", anum, animations[anum].num_animations);
454 }
455 
456 /* This receives the smooth mapping from the server. Because this
457  * information is reference a lot, the smoothing face is stored
458  * in the pixmap data - this makes access much faster than searching
459  * an array of data for the face to use.
460  */
461 void SmoothCmd(unsigned char *data, int len) {
462  uint16 faceid;
463  uint16 smoothing;
464 
465  /* len is unused.
466  * We should check that we don't have an invalid short command.
467  * Hence, the compiler warning is valid.
468  */
469 
470  faceid = GetShort_String(data);
471  smoothing = GetShort_String(data+2);
472  addsmooth(faceid, smoothing);
473 }
474 
475 void DrawInfoCmd(char *data, int len) {
476  int color = atoi(data);
477  char *buf;
478 
479  (void)len; /* __UNUSED__ */
480 
481  buf = strchr(data, ' ');
482  if (!buf) {
483  LOG(LOG_WARNING, "common::DrawInfoCmd", "got no data");
484  buf = "";
485  } else {
486  buf++;
487  }
488  if (color != NDI_BLACK) {
489  draw_color_info(color, buf);
490  } else {
491  draw_info(buf, NDI_BLACK);
492  }
493 }
494 
496 
497 void setTextManager(int type, ExtTextManager callback) {
498  TextManager *current = firstTextManager;
499 
500  while (current != NULL) {
501  if (current->type == type) {
502  current->callback = callback;
503  return;
504  }
505  current = current->next;
506  }
507  current = malloc(sizeof(TextManager));
508  current->type = type;
509  current->callback = callback;
510  current->next = firstTextManager;
511  firstTextManager = current;
512 }
513 
514 static ExtTextManager getTextManager(int type) {
515  TextManager *current = firstTextManager;
516  while (current != NULL) {
517  if (current->type == type) {
518  return current->callback;
519  }
520  current = current->next;
521  }
522  return NULL;
523 }
524 
525 /* We must extract color, type, subtype and dispatch to callback*/
526 void DrawExtInfoCmd(char *data, int len) {
527  int color;
528  int type, subtype;
529  char *buf = data;
530  int wordCount = 3;
531  ExtTextManager fnct;
532 
533  while (wordCount > 0) {
534  while (buf[0] == ' ') {
535  buf++;
536  }
537  wordCount--;
538  while (buf[0] != ' ') {
539  if (buf[0] == '\0') {
541  "common::DrawExtInfoCmd", "Data is missing %d parameters %s",
542  wordCount,
543  data);
544  return;
545  } else {
546  buf++;
547  }
548  }
549  if (buf[0] == ' ') {
550  buf++; /*remove trailing space to send clean data to callback */
551  }
552  }
553  wordCount = sscanf(data, "%d %d %d", &color, &type, &subtype);
554  if (wordCount != 3) {
556  "common::DrawExtInfoCmd", "Wrong parameters received. Could only parse %d out of 3 int in %s",
557  wordCount,
558  data);
559  return;
560  }
561  fnct = getTextManager(type);
562  if (fnct == NULL) {
564  "common::DrawExtInfoCmd", "Server send us a type %d but i can't find any callback for it",
565  type);
566  return;
567  }
568  fnct(color, type, subtype, buf);
569 }
570 
571 /* Maintain the last_used_skills LRU list for displaying the recently used
572  * skills first. */
573 void use_skill(int skill_id)
574 {
575  int i = 0;
576  int next;
577  int prev = last_used_skills[0];
578  /*
579  char buf[100];
580  sprintf(buf, "use_skill(%d '%s')\n", skill_id, skill_names(skill_id));
581  draw_info(, NDI_BLUE);
582  */
583 
584  if(last_used_skills[0] == skill_id) return;
585 
586  do
587  {
588  next = last_used_skills[i+1];
589  last_used_skills[i+1] = prev;
590  prev = next;
591  ++i;
592  } while(next != skill_id && next >= 0);
593  last_used_skills[0] = skill_id;
594 }
595 
596 void StatsCmd(unsigned char *data, int len) {
597  int i = 0, c, redraw = 0;
598  sint64 last_exp;
599 
600  while (i < len) {
601  c = data[i++];
602  if (c >= CS_STAT_RESIST_START && c <= CS_STAT_RESIST_END) {
604  i += 2;
605  cpl.stats.resist_change = 1;
606  } else if (c >= CS_STAT_SKILLINFO && c < (CS_STAT_SKILLINFO+CS_NUM_SKILLS)) {
607  /* We track to see if the exp has gone from 0 to some total value -
608  * we do this because the draw logic currently only draws skills where
609  * the player has exp. We need to communicate to the draw function
610  * that it should draw all the players skills. Using redraw is
611  * a little overkill, because a lot of the data may not be changing.
612  * OTOH, such a transition should only happen rarely, not not be a very
613  * big deal.
614  */
615  cpl.stats.skill_level[c-CS_STAT_SKILLINFO] = data[i++];
616  last_exp = cpl.stats.skill_exp[c-CS_STAT_SKILLINFO];
619  if (last_exp == 0 && cpl.stats.skill_exp[c-CS_STAT_SKILLINFO]) {
620  redraw = 1;
621  }
622  i += 8;
623  } else {
624  switch (c) {
625  case CS_STAT_HP: cpl.stats.hp = GetShort_String(data+i); i += 2; break;
626  case CS_STAT_MAXHP: cpl.stats.maxhp = GetShort_String(data+i); i += 2; break;
627  case CS_STAT_SP: cpl.stats.sp = GetShort_String(data+i); i += 2; break;
628  case CS_STAT_MAXSP: cpl.stats.maxsp = GetShort_String(data+i); i += 2; break;
629  case CS_STAT_GRACE: cpl.stats.grace = GetShort_String(data+i); i += 2; break;
630  case CS_STAT_MAXGRACE:cpl.stats.maxgrace = GetShort_String(data+i); i += 2; break;
631  case CS_STAT_STR: cpl.stats.Str = GetShort_String(data+i); i += 2; break;
632  case CS_STAT_INT: cpl.stats.Int = GetShort_String(data+i); i += 2; break;
633  case CS_STAT_POW: cpl.stats.Pow = GetShort_String(data+i); i += 2; break;
634  case CS_STAT_WIS: cpl.stats.Wis = GetShort_String(data+i); i += 2; break;
635  case CS_STAT_DEX: cpl.stats.Dex = GetShort_String(data+i); i += 2; break;
636  case CS_STAT_CON: cpl.stats.Con = GetShort_String(data+i); i += 2; break;
637  case CS_STAT_CHA: cpl.stats.Cha = GetShort_String(data+i); i += 2; break;
638  case CS_STAT_EXP: cpl.stats.exp = GetInt_String(data+i); i += 4; break;
639  case CS_STAT_EXP64: cpl.stats.exp = GetInt64_String(data+i); i += 8; break;
640  case CS_STAT_LEVEL: cpl.stats.level = GetShort_String(data+i); i += 2; break;
641  case CS_STAT_WC: cpl.stats.wc = GetShort_String(data+i); i += 2; break;
642  case CS_STAT_AC: cpl.stats.ac = GetShort_String(data+i); i += 2; break;
643  case CS_STAT_DAM: cpl.stats.dam = GetShort_String(data+i); i += 2; break;
644  case CS_STAT_ARMOUR: cpl.stats.resists[0] = GetShort_String(data+i); i += 2; break;
645  case CS_STAT_SPEED: cpl.stats.speed = GetInt_String(data+i); i += 4; break;
646  case CS_STAT_FOOD: cpl.stats.food = GetShort_String(data+i); i += 2; break;
647  case CS_STAT_WEAP_SP: cpl.stats.weapon_sp = GetInt_String(data+i); i += 4; break;
648  case CS_STAT_SPELL_ATTUNE:cpl.stats.attuned = GetInt_String(data+i); i += 4; cpl.spells_updated = 1; break;
649  case CS_STAT_SPELL_REPEL:cpl.stats.repelled = GetInt_String(data+i); i += 4; cpl.spells_updated = 1; break;
650  case CS_STAT_SPELL_DENY:cpl.stats.denied = GetInt_String(data+i); i += 4; cpl.spells_updated = 1; break;
651 
652  case CS_STAT_FLAGS: cpl.stats.flags = GetShort_String(data+i); i += 2; break;
654 
655  /* Skill experience handling */
656  /* We make the assumption based on current bindings in the protocol
657  * that these skip 2 values and are otherwise in order.
658  */
665  {
666  int skill_id = (c-CS_STAT_SKILLEXP_START)/2;
667  cpl.stats.skill_exp[skill_id] = GetInt_String(data+i);
668  use_skill(skill_id);
669  i += 4;
670  }
671  break;
672 
680  i += 2;
681  break;
682 
683  case CS_STAT_RANGE: {
684  int rlen = data[i++];
685  strncpy(cpl.range, (const char*)data+i, rlen);
686  cpl.range[rlen] = '\0';
687  i += rlen;
688  break;
689  }
690 
691  case CS_STAT_TITLE: {
692  int rlen = data[i++];
693  strncpy(cpl.title, (const char*)data+i, rlen);
694  cpl.title[rlen] = '\0';
695  i += rlen;
696  break;
697  }
698 
699  default:
700  LOG(LOG_WARNING, "common::StatsCmd", "Unknown stat number %d", c);
701 /* abort();*/
702  break;
703  }
704  }
705  }
706 
707  if (i > len) {
708  LOG(LOG_WARNING, "common::StatsCmd", "got stats overflow, processed %d bytes out of %d", i, len);
709  }
710  draw_stats(redraw);
712 #ifdef HAVE_LUA
714 #endif
715 }
716 
717 void handle_query(char *data, int len) {
718  char *buf, *cp;
719  uint8 flags = atoi(data);
720 
721  (void)len; /* __UNUSED__ */
722 
723  if (flags&CS_QUERY_HIDEINPUT) { /* no echo */
724  cpl.no_echo = 1;
725  } else {
726  cpl.no_echo = 0;
727  }
728 
729  /* Let the window system know this may have changed */
730  x_set_echo();
731 
732  /* The actual text is optional */
733  buf = strchr(data, ' ');
734  if (buf) {
735  buf++;
736  }
737 
738  /* If we just get passed an empty string, why draw this? */
739  if (buf) {
740  cp = buf;
741  while ((buf = strchr(buf, '\n')) != NULL) {
742  *buf++ = '\0';
743  draw_info(cp, NDI_BLACK);
744  cp = buf;
745  }
746  /* Yes/no - don't do anything with it now */
747  if (flags&CS_QUERY_YESNO) {
748  }
749 
750  /* one character response expected */
751  if (flags&CS_QUERY_SINGLECHAR) {
753  } else {
755  }
756 
757  if (cp) {
758  draw_prompt(cp);
759  }
760  }
761 
762  LOG(LOG_DEBUG, "common::handle_query", "Received query. Input state now %d", cpl.input_state);
763 }
764 
765 /* Sends a reply to the server. text contains the null terminated
766  * string of text to send. This function basically just packs
767  * the stuff up.
768  */
769 void send_reply(const char *text) {
770  cs_print_string(csocket.fd, "reply %s", text);
771 
772  /* Let the window system know that the (possibly hidden) query is over. */
773  cpl.no_echo = 0;
774  x_set_echo();
775 }
776 
777 /* This function copies relevant data from the archetype to the
778  * object. Only copies data that was not set in the object
779  * structure.
780  *
781  */
782 void PlayerCmd(unsigned char *data, int len) {
783  char name[MAX_BUF];
784  int tag, weight, face, i = 0, nlen;
785 
787  tag = GetInt_String(data); i += 4;
788  weight = GetInt_String(data+i); i += 4;
789  face = GetInt_String(data+i); i += 4;
790  nlen = data[i++];
791  memcpy(name, (const char*)data+i, nlen);
792  name[nlen] = '\0';
793  i += nlen;
794 
795  if (i != len) {
796  LOG(LOG_WARNING, "common::PlayerCmd", "lengths do not match (%d!=%d)", len, i);
797  }
798  new_player(tag, name, weight, face);
799 }
800 
801 void item_actions(item *op) {
802  if (!op) {
803  return;
804  }
805 
806  if (op->open) {
807  open_container(op);
808  cpl.container = op;
809  } else if (op->was_open) {
810  close_container(op);
811  cpl.container = NULL;
812  }
813 }
814 
815 /* common_item_cmd parses the data send to us from the server.
816  * revision is what item command the data came from - newer
817  * ones have addition fields.
818  */
819 static void common_item_command(uint8 *data, int len) {
820 
821  int weight, loc, tag, face, flags, pos = 0, nlen, anim, nrof, type;
822  uint8 animspeed;
823  char name[MAX_BUF];
824 
825  loc = GetInt_String(data);
826  pos += 4;
827 
828  if (pos == len) {
829  LOG(LOG_WARNING, "common::common_item_command", "Got location with no other data");
830  return;
831  } else if (loc < 0) { /* delete following items */
832  LOG(LOG_WARNING, "common::common_item_command", "Got location with negative value (%d)", loc);
833  return;
834  } else {
835  while (pos < len) {
836  tag = GetInt_String(data+pos); pos += 4;
837  flags = GetInt_String(data+pos); pos += 4;
838  weight = GetInt_String(data+pos); pos += 4;
839  face = GetInt_String(data+pos); pos += 4;
840  nlen = data[pos++];
841  memcpy(name, (char*)data+pos, nlen);
842  pos += nlen;
843  name[nlen] = '\0';
844  anim = GetShort_String(data+pos); pos += 2;
845  animspeed = data[pos++];
846  nrof = GetInt_String(data+pos); pos += 4;
847  type = GetShort_String(data+pos); pos += 2;
848  update_item(tag, loc, name, weight, face, flags, anim, animspeed, nrof, type);
850  }
851  if (pos > len) {
852  LOG(LOG_WARNING, "common::common_item_cmd", "Overread buffer: %d > %d", pos, len);
853  }
854  }
855 }
856 
857 void Item2Cmd(unsigned char *data, int len) {
858  common_item_command(data, len);
859 }
860 
861 /* UpdateItemCmd updates some attributes of an item */
862 void UpdateItemCmd(unsigned char *data, int len) {
863  int weight, loc, tag, face, sendflags, flags, pos = 0, nlen, anim;
864  uint32 nrof;
865  char name[MAX_BUF];
866  item *ip, *env = NULL;
867  uint8 animspeed;
868 
869  sendflags = data[0];
870  pos += 1;
871  tag = GetInt_String(data+pos);
872  pos += 4;
873  ip = locate_item(tag);
874  if (!ip) {
875 /*
876  fprintf(stderr, "Got update_item command for item we don't have (%d)\n", tag);
877 */
878  return;
879  }
880 
881  /* Copy all of these so we can pass the values to update_item and
882  * don't need to figure out which ones were modified by this function.
883  */
884  *name = '\0';
885  loc = ip->env ? ip->env->tag : 0;
886  weight = ip->weight*1000;
887  face = ip->face;
888  flags = ip->flagsval;
889  anim = ip->animation_id;
890  animspeed = ip->anim_speed;
891  nrof = ip->nrof;
892 
893  if (sendflags&UPD_LOCATION) {
894  loc = GetInt_String(data+pos);
895  env = locate_item(loc);
896  LOG(LOG_WARNING, "common::UpdateItemCmd", "Got tag of unknown object (%d) for new location", loc);
897  pos += 4;
898  }
899  if (sendflags&UPD_FLAGS) {
900  flags = GetInt_String(data+pos);
901  pos += 4;
902  }
903  if (sendflags&UPD_WEIGHT) {
904  weight = GetInt_String(data+pos);
905  pos += 4;
906  }
907  if (sendflags&UPD_FACE) {
908  face = GetInt_String(data+pos);
909  pos += 4;
910  }
911  if (sendflags&UPD_NAME) {
912  nlen = data[pos++];
913  memcpy(name, (char*)data+pos, nlen);
914  pos += nlen;
915  name[nlen] = '\0';
916  }
917  if (pos > len) {
918  LOG(LOG_WARNING, "common::UpdateItemCmd", "Overread buffer: %d > %d", pos, len);
919  return; /* we have bad data, probably don't want to store it then */
920  }
921  if (sendflags&UPD_ANIM) {
922  anim = GetShort_String(data+pos);
923  pos += 2;
924  }
925  if (sendflags&UPD_ANIMSPEED) {
926  animspeed = data[pos++];
927  }
928  if (sendflags&UPD_NROF) {
929  nrof = (uint32)GetInt_String(data+pos);
930  pos += 4;
931  }
932  /* update_item calls set_item_values which will then set the list
933  * redraw flag, so we don't need to do an explicit redraw here. Actually,
934  * calling update_item is a little bit of overkill, since we
935  * already determined some of the values in this function.
936  */
937  update_item(tag, loc, name, weight, face, flags, anim, animspeed, nrof, ip->type);
939 }
940 
941 void DeleteItem(unsigned char *data, int len) {
942  int pos = 0, tag;
943 
944  while (pos < len) {
945  item *op;
946 
947  tag = GetInt_String(data+pos); pos += 4;
948  op = locate_item(tag);
949  if (op != NULL) {
950  remove_item(op);
951  } else {
952  LOG(LOG_WARNING, "common::DeleteItem", "Cannot find tag %d", tag);
953  }
954  }
955  if (pos > len) {
956  LOG(LOG_WARNING, "common::DeleteItem", "Overread buffer: %d > %d", pos, len);
957  }
958 }
959 
960 void DeleteInventory(unsigned char *data, int len) {
961  int tag;
962  item *op;
963 
964  (void)len; /* __UNUSED__ */
965 
966  tag = atoi((const char*)data);
967  op = locate_item(tag);
968  if (op != NULL) {
970  } else {
971  LOG(LOG_WARNING, "common::DeleteInventory", "Invalid tag: %d", tag);
972  }
973 }
974 
975 /******************************************************************************
976  * Start of spell commands
977  *****************************************************************************/
978 
979 void AddspellCmd(unsigned char *data, int len) {
980  uint8 nlen;
981  uint16 mlen, pos = 0;
982  Spell *newspell, *tmp;
983 
984  while (pos < len) {
985  newspell = calloc(1, sizeof(Spell));
986  newspell->tag = GetInt_String(data+pos); pos += 4;
987  newspell->level = GetShort_String(data+pos); pos += 2;
988  newspell->time = GetShort_String(data+pos); pos += 2;
989  newspell->sp = GetShort_String(data+pos); pos += 2;
990  newspell->grace = GetShort_String(data+pos); pos += 2;
991  newspell->dam = GetShort_String(data+pos); pos += 2;
992  newspell->skill_number = GetChar_String(data+pos); pos += 1;
993  newspell->path = GetInt_String(data+pos); pos += 4;
994  newspell->face = GetInt_String(data+pos); pos += 4;
995  nlen = GetChar_String(data+pos); pos += 1;
996  strncpy(newspell->name, (char*)data+pos, nlen); pos += nlen;
997  newspell->name[nlen] = '\0'; /* to ensure we are null terminated */
998  mlen = GetShort_String(data+pos); pos += 2;
999  strncpy(newspell->message, (char*)data+pos, mlen); pos += mlen;
1000  newspell->message[mlen] = '\0'; /* to ensure we are null terminated */
1001  newspell->skill = skill_names[newspell->skill_number-CS_STAT_SKILLINFO];
1002 
1003  /* ok, we're done with putting in data, now to add to the player struct */
1004  if (!cpl.spelldata) {
1005  cpl.spelldata = newspell;
1006  } else {
1007  for (tmp = cpl.spelldata; tmp->next; tmp = tmp->next)
1008  ;
1009  tmp->next = newspell;
1010  }
1011  /* now we'll check to see if we have more spells */
1012  }
1013  if (pos > len) {
1014  LOG(LOG_WARNING, "common::AddspellCmd", "Overread buffer: %d > %d", pos, len);
1015  }
1016  cpl.spells_updated = 1;
1017 }
1018 
1019 void UpdspellCmd(unsigned char *data, int len) {
1020  int flags, tag, pos = 0;
1021  Spell *tmp;
1022 
1023  if (!cpl.spelldata) {
1024  LOG(LOG_WARNING, "common::UpdspellCmd", "I know no spells to update");
1025  return;
1026  }
1027 
1028  flags = GetChar_String(data+pos); pos += 1;
1029  tag = GetInt_String(data+pos); pos += 4;
1030  for (tmp = cpl.spelldata; tmp && tmp->tag != tag; tmp = tmp->next)
1031  ;
1032  if (!tmp) {
1033  LOG(LOG_WARNING, "common::UpdspellCmd", "Invalid tag: %d", tag);
1034  return;
1035  }
1036  if (flags&UPD_SP_MANA) {
1037  tmp->sp = GetShort_String(data+pos); pos += 2;
1038  }
1039  if (flags&UPD_SP_GRACE) {
1040  tmp->grace = GetShort_String(data+pos); pos += 2;
1041  }
1042  if (flags&UPD_SP_DAMAGE) {
1043  tmp->dam = GetShort_String(data+pos); pos += 2;
1044  }
1045  if (pos > len) {
1046  LOG(LOG_WARNING, "common::UpdspellCmd", "Overread buffer: %d > %d", pos, len);
1047  }
1048  cpl.spells_updated = 1;
1049 }
1050 
1051 void DeleteSpell(unsigned char *data, int len) {
1052  int tag;
1053  Spell *tmp, *target;
1054 
1055  if (!cpl.spelldata) {
1056  LOG(LOG_WARNING, "common::DeleteSpell", "I know no spells to delete");
1057  return;
1058  }
1059 
1060  tag = GetInt_String(data);
1061  /* special case, the first spell is the one removed */
1062  if (cpl.spelldata->tag == tag) {
1063  target = cpl.spelldata;
1064  if (target->next) {
1065  cpl.spelldata = target->next;
1066  } else {
1067  cpl.spelldata = NULL;
1068  }
1069  free(target);
1070  return;
1071  }
1072 
1073  for (tmp = cpl.spelldata; tmp->next && tmp->next->tag != tag; tmp = tmp->next)
1074  ;
1075  if (!tmp->next) {
1076  LOG(LOG_WARNING, "common::DeleteSpell", "Invalid tag: %d", tag);
1077  return;
1078  }
1079  target = tmp->next;
1080  if (target->next) {
1081  tmp->next = target->next;
1082  } else {
1083  tmp->next = NULL;
1084  }
1085  free(target);
1086  cpl.spells_updated = 1;
1087 }
1088 
1089 /******************************************************************************
1090  * Start of map commands
1091  *****************************************************************************/
1092 
1093 void NewmapCmd(unsigned char *data, int len) {
1094  (void)data; /* __UNUSED__ */
1095  (void)len; /* __UNUSED__ */
1096 
1097  mapdata_newmap();
1098 }
1099 
1100 /* This is the common processing block for the map1 and
1101  * map1a protocol commands. The map1a mieks minor extensions
1102  * and are easy to deal with inline (in fact, this code
1103  * doesn't even care what rev is - just certain bits will
1104  * only bet set when using the map1a command.
1105  * rev is 0 for map1,
1106  * 1 for map1a. It conceivable that there could be future
1107  * revisions.
1108  */
1109 
1110 /* NUM_LAYERS should only be used for the map1{a} which only
1111  * has a few layers. Map2 has 10 layers. However, some of the
1112  * map1 logic requires this to be set right.
1113  */
1114 #define NUM_LAYERS (MAP1_LAYERS-1)
1115 
1116 void Map2Cmd(unsigned char *data, int len) {
1117  int mask, x, y, pos = 0, space_len, value;
1118  uint8 type;
1119 
1121  /* Not really using map1 protocol, but some draw logic differs from
1122  * the original draw logic, and map2 is closest.
1123  */
1124  while (pos < len) {
1125  mask = GetShort_String(data+pos); pos += 2;
1126  x = ((mask>>10)&0x3f)-MAP2_COORD_OFFSET;
1127  y = ((mask>>4)&0x3f)-MAP2_COORD_OFFSET;
1128 
1129  /* This is a scroll then. Go back and fetch another coordinate */
1130  if (mask&0x1) {
1131  mapdata_scroll(x, y);
1132  continue;
1133  }
1134 
1135  if (x<0) {
1136  LOG(LOG_WARNING, "commands.c::Map2Cmd", "got negative x!");
1137  x = 0;
1138  } else if (x >= MAX_VIEW) {
1139  LOG(LOG_WARNING, "commands.c::Map2Cmd", "got x >= MAX_VIEW!");
1140  x = MAX_VIEW - 1;
1141  }
1142 
1143  if (y<0) {
1144  LOG(LOG_WARNING, "commands.c::Map2Cmd", "got negative y!");
1145  y = 0;
1146  } else if (y >= MAX_VIEW) {
1147  LOG(LOG_WARNING, "commands.c::Map2Cmd", "got y >= MAX_VIEW!");
1148  y = MAX_VIEW - 1;
1149  }
1150 
1151  assert(0 <= x && x < MAX_VIEW);
1152  assert(0 <= y && y < MAX_VIEW);
1153  /* Clear the old cell data if needed. Used to be done in
1154  * mapdata_set_face_layer() however that caused darkness to only
1155  * work if sent after the layers.
1156  */
1157  mapdata_clear_old(x, y);
1158 
1159  /* Inner loop is for the data on the space itself */
1160  while (pos < len) {
1161  type = data[pos++];
1162  /* type == 255 means nothing more for this space */
1163  if (type == 255) {
1165  break;
1166  }
1167  space_len = type>>5;
1168  type &= 0x1f;
1169  /* Clear the space */
1170  if (type == 0) {
1171  mapdata_clear_space(x, y);
1172  continue;
1173  } else if (type == 1) {
1174  value = data[pos++];
1175  mapdata_set_darkness(x, y, value);
1176  continue;
1177  } else if (type >= 0x10 && type <= 0x1a) {
1178  int layer, opt;
1179 
1180  /* This is face information for a layer. */
1181  layer = type&0xf;
1182 
1183  if (layer < 0) {
1184  LOG(LOG_WARNING, "commands.c::Map2Cmd", "got negative layer!");
1185  layer = 0;
1186  } else if (layer >= MAXLAYERS) {
1187  LOG(LOG_WARNING, "commands.c::Map2Cmd", "got layer >= MAXLAYERS!");
1188  layer = MAXLAYERS - 1;
1189  }
1190  assert(0 <= layer && layer < MAXLAYERS);
1191 
1192  /* This is the face */
1193  value = GetShort_String(data+pos); pos += 2;
1194  if (!(value&FACE_IS_ANIM)) {
1195  mapdata_set_face_layer(x, y, value, layer);
1196  }
1197 
1198  if (space_len > 2) {
1199  opt = data[pos++];
1200  if (value&FACE_IS_ANIM) {
1201  /* Animation speed */
1202  mapdata_set_anim_layer(x, y, value, opt, layer);
1203  } else {
1204  /* Smooth info */
1205  mapdata_set_smooth(x, y, opt, layer);
1206  }
1207  }
1208  /* Currently, if 4 bytes, must be a smooth byte */
1209  if (space_len > 3) {
1210  opt = data[pos++];
1211  mapdata_set_smooth(x, y, opt, layer);
1212  }
1213  continue;
1214  } /* if image layer */
1215  } /* while pos<len inner loop for space */
1216  } /* While pos<len outer loop */
1217  mapupdatesent = 0;
1219 }
1220 
1221 void map_scrollCmd(char *data, int len) {
1222  int dx, dy;
1223  char *buf;
1224 
1225  (void)len; /* __UNUSED__ */
1226 
1227  dx = atoi(data);
1228  buf = strchr(data, ' ');
1229  if (!buf) {
1230  LOG(LOG_WARNING, "common::map_scrollCmd", "Got short packet.");
1231  return;
1232  }
1233  buf++;
1234  dy = atoi(buf);
1235 
1237  mapdata_scroll(dx, dy);
1239 }
1240 
1241 /* Extract smoothing infos from an extendedmapinfo packet part
1242  * data is located at the beginning of the smooth datas
1243  */
1244 int ExtSmooth(unsigned char *data, int len, int x, int y, int layer) {
1245  static int dx[8] = { 0, 1, 1, 1, 0, -1, -1, -1, };
1246  static int dy[8] = { -1, -1, 0, 1, 1, 1, 0, -1, };
1247  int i, rx, ry;
1248  int newsm;
1249 
1250  if (len < 1) {
1251  return 0;
1252  }
1253 
1254  x += pl_pos.x;
1255  y += pl_pos.y;
1256  newsm = GetChar_String(data);
1257 
1258  if (the_map.cells[x][y].smooth[layer] != newsm) {
1259  for (i = 0; i < 8; i++) {
1260  rx = x+dx[i];
1261  ry = y+dy[i];
1262  if (rx < 0 || ry < 0 || the_map.x <= rx || the_map.y <= ry) {
1263  continue;
1264  }
1265  the_map.cells[x][y].need_resmooth = 1;
1266  }
1267  }
1268  the_map.cells[x][y].smooth[layer] = newsm;
1269  return 1;/*Cause smooth infos only use 1 byte*/
1270 }
1271 
1272 /* Handle MapExtended command
1273  * Warning! if you add commands to extended, take
1274  * care that the 'layer' argument of main loop is
1275  * the opposite of the layer of the map.
1276  * so if you reference a layer, use NUM_LAYERS-layer
1277  */
1278 void MapExtendedCmd(unsigned char *data, int len) {
1279  int mask, x, y, pos = 0, layer;
1280  int noredraw = 0;
1281  int hassmooth = 0;
1282  int entrysize;
1283  int startpackentry;
1284 
1285  if (!mapupdatesent) {
1287  }
1288  mapupdatesent = 1;
1289  mask = GetChar_String(data+pos); pos += 1;
1290  if (mask&EMI_NOREDRAW) {
1291  noredraw = 1;
1292  }
1293  if (mask&EMI_SMOOTH) {
1294  hassmooth = 1;
1295  }
1296  while (mask&EMI_HASMOREBITS) {
1297  /*There may be bits we ignore about*/
1298  mask = GetChar_String(data+pos);
1299  pos += 1;
1300  }
1301  entrysize = GetChar_String(data+pos);
1302  pos = pos+1;
1303 
1304  while (pos+entrysize+2 <= len) {
1305  mask = GetShort_String(data+pos); pos += 2;
1306  x = (mask>>10)&0x3f;
1307  y = (mask>>4)&0x3f;
1308  for (layer = NUM_LAYERS; layer >= 0; layer--) {
1309  if (mask&(1<<layer)) {
1310  /*handle an entry*/
1311  if (pos+entrysize > len) { /*erroneous packet*/
1312  break;
1313  }
1314  startpackentry = pos;
1315  /* If you had extended infos to the server, this
1316  * is where, in the client, you may add your code
1317  */
1318  if (hassmooth) {
1319  pos = pos+ExtSmooth(data+pos, len-pos, x, y, NUM_LAYERS-layer);
1320  }
1321  /* continue with other if you add new extended
1322  * infos to server
1323  */
1324 
1325  /* Now point to the next data */
1326  pos = startpackentry+entrysize;
1327  }
1328  }
1329  }
1330  if (!noredraw) {
1332  mapupdatesent = 0;
1333  }
1334 }
1335 
1336 void MagicMapCmd(unsigned char *data, int len) {
1337  unsigned char *cp;
1338  int i;
1339 
1340  /* First, extract the size/position information. */
1341  if (sscanf((const char*)data, "%hd %hd %hd %hd", &cpl.mmapx, &cpl.mmapy, &cpl.pmapx, &cpl.pmapy) != 4) {
1342  LOG(LOG_WARNING, "common::MagicMapCmd", "Was not able to properly extract magic map size, pos");
1343  return;
1344  }
1345 
1346  /* Now we need to find the start of the actual data. There are 4
1347  * space characters we need to skip over.
1348  */
1349  for (cp = data, i = 0; i < 4 && cp < data+len; cp++) {
1350  if (*cp == ' ') {
1351  i++;
1352  }
1353  }
1354  if (i != 4) {
1355  LOG(LOG_WARNING, "common::MagicMapCmd", "Was unable to find start of magic map data");
1356  return;
1357  }
1358  i = len-(cp-data); /* This should be the number of bytes left */
1359  if (i != cpl.mmapx*cpl.mmapy) {
1360  LOG(LOG_WARNING, "common::MagicMapCmd", "Magic map size mismatch. Have %d bytes, should have %d",
1361  i, cpl.mmapx*cpl.mmapy);
1362  return;
1363  }
1364  free(cpl.magicmap);
1365  cpl.magicmap = malloc(cpl.mmapx*cpl.mmapy);
1366  /* Order the server puts it in should be just fine. Note that
1367  * the only requirement that this works is that magicmap by 8 bits,
1368  * being that is the size specified in the protocol and what the
1369  * server sends us.
1370  */
1371  memcpy(cpl.magicmap, cp, cpl.mmapx*cpl.mmapy);
1372  cpl.showmagic = 1;
1373  draw_magic_map();
1374 }
1375 
1376 void SinkCmd(unsigned char *data, int len) {
1377 }
1378 
1379 /* got a tick from the server. We currently
1380  * don't care what tick number it is, but
1381  * just have the code in case at some time we do.
1382  */
1383 void TickCmd(uint8 *data, int len) {
1384 
1385  tick = GetInt_String(data);
1386 
1387  /* Up to the specific client to decide what to do */
1388  client_tick(tick);
1389 }
1390 
1399 void PickupCmd(uint8 *data, int len) {
1400  uint32 pickup = GetInt_String(data);
1401  client_pickup(pickup);
1402 }
uint16 pmapx
Definition: client.h:297
#define CS_STAT_RANGE
Definition: newclient.h:125
float weight
Definition: item.h:56
#define UPD_FLAGS
Definition: newclient.h:254
void DeleteItem(unsigned char *data, int len)
Definition: commands.c:941
#define CS_STAT_SPELL_DENY
Definition: newclient.h:135
void handle_query(char *data, int len)
Definition: commands.c:717
uint32 spells_updated
Definition: client.h:289
#define CS_STAT_SPEED
Definition: newclient.h:122
#define CS_STAT_ARMOUR
Definition: newclient.h:121
void SetupCmd(char *buf, int len)
Definition: commands.c:173
uint8 skill_number
Definition: client.h:262
int y
Definition: mapdata.h:93
sint8 level
Definition: client.h:215
#define FACE_IS_ANIM
Definition: newclient.h:270
uint16 grace
Definition: client.h:260
uint16 exp_table_max
Definition: client.c:72
sint32 face
Definition: client.h:268
sint16 hp
Definition: client.h:216
void mapdata_set_anim_layer(int x, int y, uint16 anim, uint8 anim_speed, int layer)
Definition: mapdata.c:802
sint8 Int
Definition: client.h:211
sint32 speed
Definition: client.h:229
#define CS_STAT_MAXGRACE
Definition: newclient.h:129
void DrawInfoCmd(char *data, int len)
Definition: commands.c:475
void mapdata_set_check_space(int x, int y)
Definition: mapdata.c:638
#define UPD_NAME
Definition: newclient.h:257
void mapdata_clear_space(int x, int y)
Definition: mapdata.c:596
#define CS_STAT_SKILLEXP_PHYSIQUE
Definition: newclient.h:168
#define CS_STAT_SKILLEXP_WISDOM
Definition: newclient.h:172
#define CS_STAT_SPELL_ATTUNE
Definition: newclient.h:133
sint8 Str
Definition: client.h:206
void set_weight_limit(uint32 wlim)
Definition: inventory.c:1245
void setTextManager(int type, ExtTextManager callback)
Definition: commands.c:497
uint8 anim_speed
Definition: item.h:59
void AddMeFail(char *data, int len)
Definition: commands.c:387
short GetShort_String(const unsigned char *data)
Definition: newsocket.c:162
Animations animations[MAXANIM]
Definition: commands.c:419
struct item_struct * env
Definition: item.h:48
sint16 food
Definition: client.h:223
void(* ExtTextManager)(int flag, int type, int subtype, char *message)
Definition: client-types.h:133
#define CS_STAT_SKILLEXP_START
Definition: newclient.h:160
#define UPD_ANIM
Definition: newclient.h:258
uint8 * magicmap
Definition: client.h:299
char GetChar_String(const unsigned char *data)
Definition: newsocket.c:136
void close_container(item *op)
Definition: inventory.c:1342
void ExtendedInfoSetCmd(char *data, int len)
Definition: commands.c:370
ClientSocket csocket
Definition: client.c:78
sint16 maxhp
Definition: client.h:217
#define CS_STAT_SKILLEXP_WILEVEL
Definition: newclient.h:173
Face_Information face_info
Definition: image.c:167
void DeleteSpell(unsigned char *data, int len)
Definition: commands.c:1051
void MagicMapCmd(unsigned char *data, int len)
Definition: commands.c:1336
sint8 ac
Definition: client.h:214
uint32 repelled
Definition: client.h:236
#define CS_STAT_SPELL_REPEL
Definition: newclient.h:134
int command_inscribe
Definition: client.c:75
Stats stats
Definition: client.h:285
sint16 want_config[CONFIG_NUMS]
Definition: init.c:50
#define CS_STAT_FOOD
Definition: newclient.h:123
void reset_player_data(void)
Definition: init.c:234
uint32 resist_change
Definition: client.h:242
uint32 no_echo
Definition: client.h:294
int mapupdatesent
Definition: commands.c:66
sint64 skill_exp[MAX_SKILL]
Definition: client.h:244
sint8 Con
Definition: client.h:208
sint8 Cha
Definition: client.h:210
uint16 pmapy
Definition: client.h:297
void DeleteInventory(unsigned char *data, int len)
Definition: commands.c:960
void display_map_startupdate(void)
Definition: gx11.c:5428
#define UPD_ANIMSPEED
Definition: newclient.h:259
uint32 tag
Definition: client.h:255
char * skill_names[MAX_SKILL]
Definition: client.c:63
#define EMI_SMOOTH
Definition: newclient.h:297
void mapdata_newmap(void)
Definition: mapdata.c:935
#define CS_STAT_MAXSP
Definition: newclient.h:109
#define UPD_SP_GRACE
Definition: newclient.h:264
#define CS_STAT_POW
Definition: newclient.h:127
void Item2Cmd(unsigned char *data, int len)
Definition: commands.c:857
void client_pickup(uint32 pickup)
Definition: gx11.c:4524
#define CS_STAT_SKILLEXP_PELEVEL
Definition: newclient.h:165
#define CS_STAT_SKILLEXP_MELEVEL
Definition: newclient.h:167
sint8 Pow
Definition: client.h:212
#define EMI_HASMOREBITS
Definition: newclient.h:304
void draw_stats(int redraw)
Definition: gx11.c:2015
uint16 flags
Definition: client.h:72
#define CS_STAT_SKILLEXP_MAGIC
Definition: newclient.h:170
uint32 denied
Definition: client.h:239
uint32 flagsval
Definition: item.h:74
void LOG(LogLevel level, const char *origin, const char *format,...)
Definition: misc.c:178
#define CS_STAT_GRACE
Definition: newclient.h:128
uint8 phase
Definition: client.h:78
#define NDI_RED
Definition: newclient.h:204
#define TRUE
Definition: client-types.h:71
void Map2Cmd(unsigned char *data, int len)
Definition: commands.c:1116
#define CS_STAT_SKILLEXP_AGILITY
Definition: newclient.h:162
int ExtSmooth(unsigned char *data, int len, int x, int y, int layer)
Definition: commands.c:1244
#define CS_STAT_SKILLINFO
Definition: newclient.h:181
uint32 tick
Definition: client.c:70
gchar * text
Definition: about.h:2
uint8 speed
Definition: client.h:76
sint16 grace
Definition: client.h:220
void SinkCmd(unsigned char *data, int len)
Definition: commands.c:1376
uint8 speed_left
Definition: client.h:77
void x_set_echo(void)
Definition: gx11.c:4488
sint16 resists[30]
Definition: client.h:241
#define CS_QUERY_YESNO
Definition: newclient.h:89
#define EMI_NOREDRAW
Definition: newclient.h:296
TextManager * firstTextManager
Definition: commands.c:495
void display_map_doneupdate(int redraw, int notice)
Definition: gx11.c:5300
Pixmap mask
Definition: xutil.c:67
#define CS_STAT_DAM
Definition: newclient.h:120
ExtTextManager callback
Definition: client-types.h:137
void SmoothCmd(unsigned char *data, int len)
Definition: commands.c:461
void TickCmd(uint8 *data, int len)
Definition: commands.c:1383
int cs_print_string(int fd, const char *str,...)
Definition: newsocket.c:259
void addsmooth(uint16 face, uint16 smooth_face)
Definition: image.c:360
sint8 Dex
Definition: client.h:207
void draw_message_window(int redraw)
Definition: gx11.c:2458
sint16 use_config[CONFIG_NUMS]
Definition: init.c:50
void use_skill(int skill_id)
Definition: commands.c:573
uint16 animation_id
Definition: item.h:58
#define CS_STAT_WIS
Definition: newclient.h:112
#define CS_STAT_WC
Definition: newclient.h:118
uint16 time
Definition: client.h:258
void item_actions(item *op)
Definition: commands.c:801
void UpdateItemCmd(unsigned char *data, int len)
Definition: commands.c:862
void mapdata_clear_old(int x, int y)
Definition: mapdata.c:744
#define UPD_LOCATION
Definition: newclient.h:253
Client_Player cpl
Definition: client.c:77
void PickupCmd(uint8 *data, int len)
Definition: commands.c:1399
uint16 flags
Definition: client.h:240
#define CS_STAT_FLAGS
Definition: newclient.h:130
item * container
Definition: client.h:275
const char *const rcsid_common_commands_c
Definition: commands.c:1
sint32 tag
Definition: item.h:54
#define CS_STAT_LEVEL
Definition: newclient.h:117
#define CONFIG_CACHE
Definition: client.h:156
struct Map the_map
Definition: mapdata.c:121
char * name
Definition: image.c:61
struct MapCell ** cells
Definition: mapdata.h:95
#define CS_STAT_SKILLEXP_AGLEVEL
Definition: newclient.h:163
static void get_skill_info(char *data, int len)
Definition: commands.c:96
void StatsCmd(unsigned char *data, int len)
Definition: commands.c:596
#define CS_QUERY_SINGLECHAR
Definition: newclient.h:90
int fd
Definition: client.h:97
void NewmapCmd(unsigned char *data, int len)
Definition: commands.c:1093
char message[10000]
Definition: client.h:253
int x
Definition: mapdata.h:92
void get_image_sums(char *data, int len)
Definition: image.c:737
unsigned short uint16
Definition: client-types.h:79
#define CS_STAT_DEX
Definition: newclient.h:113
void new_player(long tag, char *name, long weight, long face)
Definition: player.c:55
#define UPD_NROF
Definition: newclient.h:260
#define CS_STAT_EXP64
Definition: newclient.h:132
uint16 mmapy
Definition: client.h:296
#define CS_STAT_SKILLEXP_PHLEVEL
Definition: newclient.h:169
#define UPD_SP_MANA
Definition: newclient.h:263
void draw_color_info(int colr, const char *buf)
Definition: gx11.c:1851
void send_reply(const char *text)
Definition: commands.c:769
sint16 maxgrace
Definition: client.h:221
void mapdata_set_face_layer(int x, int y, sint16 face, int layer)
Definition: mapdata.c:770
#define CS_STAT_WEAP_SP
Definition: newclient.h:124
#define CS_STAT_RESIST_END
Definition: newclient.h:139
#define CONFIG_SMOOTH
Definition: client.h:177
int last_used_skills[MAX_SKILL+1]
Definition: client.c:65
void GoodbyeCmd(char *data, int len)
Definition: commands.c:406
struct Spell_struct * next
Definition: client.h:249
sint16 maxsp
Definition: client.h:219
#define UPD_SP_DAMAGE
Definition: newclient.h:265
uint16 dam
Definition: client.h:261
void SendSetFaceMode(ClientSocket csock, int mode)
Definition: init.c:91
#define MAX_BUF
Definition: client-types.h:128
uint8 need_resmooth
Definition: mapdata.h:83
uint16 type
Definition: item.h:75
void script_lua_stats(void)
sint16 dam
Definition: client.h:226
#define CS_STAT_TITLE
Definition: newclient.h:126
#define CS_NUM_SKILLS
Definition: newclient.h:182
void AddMeSuccess(char *data, int len)
Definition: commands.c:398
void map_scrollCmd(char *data, int len)
Definition: commands.c:1221
Spell * spelldata
Definition: client.h:286
unsigned int uint32
Definition: client-types.h:77
#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
void AnimCmd(unsigned char *data, int len)
Definition: commands.c:421
char name[256]
Definition: client.h:250
void mapdata_scroll(int dx, int dy)
Definition: mapdata.c:859
uint16 was_open
Definition: item.h:69
static void get_exp_info(const unsigned char *data, int len)
Definition: commands.c:75
sint32 weapon_sp
Definition: client.h:230
void update_item(int tag, int loc, char *name, int weight, int face, int flags, int anim, int animspeed, uint32 nrof, int type)
Definition: item.c:618
void DrawExtInfoCmd(char *data, int len)
Definition: commands.c:526
void UpdspellCmd(unsigned char *data, int len)
Definition: commands.c:1019
uint16 smooth[MAXLAYERS]
Definition: mapdata.h:79
#define CS_STAT_SKILLEXP_MENTAL
Definition: newclient.h:166
static ExtTextManager getTextManager(int type)
Definition: commands.c:514
#define CS_STAT_SKILLEXP_PERSONAL
Definition: newclient.h:164
uint8 showmagic
Definition: client.h:300
char * strdup_local(const char *str)
Definition: misc.c:125
void client_tick(uint32 tick)
Definition: gx11.c:4510
struct TextManager * next
Definition: client-types.h:138
void PlayerCmd(unsigned char *data, int len)
Definition: commands.c:782
void remove_item_inventory(item *op)
Definition: item.c:382
#define MAP2_COORD_OFFSET
Definition: newclient.h:86
#define CONFIG_MAPHEIGHT
Definition: client.h:171
uint32 nrof
Definition: item.h:55
uint32 attuned
Definition: client.h:233
sint16 sp
Definition: client.h:218
void ReplyInfoCmd(uint8 *buf, int len)
Definition: commands.c:131
#define CS_STAT_HP
Definition: newclient.h:106
uint16 sp
Definition: client.h:259
#define CS_STAT_RESIST_START
Definition: newclient.h:138
#define CF_FACE_CACHE
Definition: newclient.h:241
uint16 level
Definition: client.h:257
Input_State input_state
Definition: client.h:277
char range[MAX_BUF]
Definition: client.h:288
void AddspellCmd(unsigned char *data, int len)
Definition: commands.c:979
void draw_info(const char *str, int color)
Definition: gx11.c:1773
#define UPD_WEIGHT
Definition: newclient.h:255
void draw_magic_map(void)
Definition: gx11.c:4571
char title[MAX_BUF]
Definition: client.h:287
void resize_map_window(int x, int y)
Definition: gx11.c:5324
void open_container(item *op)
Definition: inventory.c:1334
#define MAX_VIEW
Definition: mapdata.h:37
#define CS_QUERY_HIDEINPUT
Definition: newclient.h:91
#define CS_STAT_INT
Definition: newclient.h:111
#define CS_STAT_CON
Definition: newclient.h:114
unsigned char uint8
Definition: client-types.h:81
#define CS_STAT_SP
Definition: newclient.h:108
#define MAXANIM
Definition: client.h:63
uint16 mmapx
Definition: client.h:296
#define UPD_FACE
Definition: newclient.h:256
sint8 wc
Definition: client.h:213
#define NDI_BLACK
Definition: newclient.h:201
sint64 GetInt64_String(const unsigned char *data)
Definition: newsocket.c:149
sint16 skill_level[MAX_SKILL]
Definition: client.h:243
#define CS_STAT_CHA
Definition: newclient.h:115
#define FALSE
Definition: client-types.h:68
uint8 num_animations
Definition: client.h:73
#define NUM_LAYERS
Definition: commands.c:1114
void draw_prompt(const char *str)
Definition: gx11.c:1310
sint8 Wis
Definition: client.h:209
static void common_item_command(uint8 *data, int len)
Definition: commands.c:819
sint64 exp
Definition: client.h:222
uint32 weight_limit
Definition: client.h:245
#define CS_STAT_WEIGHT_LIM
Definition: newclient.h:131
#define CS_STAT_SKILLEXP_MALEVEL
Definition: newclient.h:171
uint32 path
Definition: client.h:266
int GetInt_String(const unsigned char *data)
Definition: newsocket.c:143
void mapdata_set_size(int viewx, int viewy)
Definition: mapdata.c:577
sint16 face
Definition: item.h:57
void get_image_info(uint8 *data, int len)
Definition: image.c:653
uint64 * exp_table
Definition: client.c:73
void remove_item(item *op)
Definition: item.c:321
void mapdata_set_darkness(int x, int y, int darkness)
Definition: mapdata.c:688
PlayerPosition pl_pos
Definition: map.c:69
#define CS_STAT_STR
Definition: newclient.h:110
#define CS_STAT_AC
Definition: newclient.h:119
#define CONFIG_SOUND
Definition: client.h:164
uint16 * faces
Definition: client.h:79
char * skill
Definition: client.h:264
#define CS_STAT_EXP
Definition: newclient.h:116
void MapExtendedCmd(unsigned char *data, int len)
Definition: commands.c:1278
void mapdata_set_smooth(int x, int y, int smooth, int layer)
Definition: mapdata.c:711
#define CS_STAT_MAXHP
Definition: newclient.h:107