Crossfire Server, Trunk  R20513
item.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
25 #include "global.h"
26 
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "newserver.h"
31 #include "object.h"
32 #include "shared/newclient.h"
33 #include "sproto.h"
34 
36 #define MAXITEMLEN 300
37 
38 /*************************************************************************
39  *
40  * Functions related to sending object data to the client.
41  *
42  *************************************************************************
43  */
44 
49 static unsigned int query_flags(const object *op) {
50  unsigned int flags = 0;
51 
52  if (QUERY_FLAG(op, FLAG_APPLIED)) {
53  switch (op->type) {
54  case BOW:
55  case WAND:
56  case ROD:
57  flags = a_readied;
58  break;
59 
60  case WEAPON:
61  flags = a_wielded;
62  break;
63 
64  case SKILL:
65  case ARMOUR:
66  case HELMET:
67  case SHIELD:
68  case RING:
69  case BOOTS:
70  case GLOVES:
71  case AMULET:
72  case GIRDLE:
73  case BRACERS:
74  case CLOAK:
75  flags = a_worn;
76  break;
77 
78  case CONTAINER:
79  flags = a_active;
80  break;
81 
82  default:
83  flags = a_applied;
84  break;
85  }
86  }
87  if (op->type == CONTAINER
88  && ((op->env && op->env->container == op) || (!op->env && QUERY_FLAG(op, FLAG_APPLIED))))
89  flags |= F_OPEN;
90 
91  if (!QUERY_FLAG(op, FLAG_IDENTIFIED) && need_identify(op))
92  flags |= F_UNIDENTIFIED;
93 
94  if (QUERY_FLAG(op, FLAG_KNOWN_CURSED)) {
95  if (QUERY_FLAG(op, FLAG_DAMNED))
96  flags |= F_DAMNED;
97  else if (QUERY_FLAG(op, FLAG_CURSED))
98  flags |= F_CURSED;
99  }
101  flags |= F_MAGIC;
102  if (QUERY_FLAG(op, FLAG_UNPAID))
103  flags |= F_UNPAID;
104  if (QUERY_FLAG(op, FLAG_INV_LOCKED))
105  flags |= F_LOCKED;
107  flags |= F_BLESSED;
108 
109  return flags;
110 }
111 
117 static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head) {
118  int flags, len, anim_speed;
119  char item_n[MAX_BUF], item_p[MAX_BUF];
120 
121  flags = query_flags(head);
122  if (QUERY_FLAG(head, FLAG_NO_PICK))
123  flags |= F_NOPICK;
124 
125  if (!(ns->faces_sent[head->face->number]&NS_FACESENT_FACE))
126  esrv_send_face(ns, head->face->number, 0);
127 
128  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
129  if (head->animation_id == 0) {
130  LOG(llevError, "Item %s in %s (%d,%d) has FLAG_ANIMATE but animation_id 0\n", head->name, (head->env ? head->env->name : (head->map ? head->map->path : "???")), head->x, head->y);
131  CLEAR_FLAG(head, FLAG_ANIMATE);
132  } else if (!ns->anims_sent[head->animation_id])
134  }
135 
136  SockList_AddInt(sl, head->count);
137  SockList_AddInt(sl, flags);
138  SockList_AddInt(sl, QUERY_FLAG(head, FLAG_NO_PICK) ? -1 : WEIGHT(head));
139  SockList_AddInt(sl, head->face->number);
140 
141  if (!head->custom_name) {
142  query_base_name(head, 0, item_n, 126);
143  item_n[127] = 0;
144  len = strlen(item_n);
145  query_base_name(head, 1, item_p, MAX_BUF);
146  } else {
147  safe_strncpy(item_n, head->custom_name, 127);
148  item_n[127] = 0;
149  len = strlen(item_n);
150  safe_strncpy(item_p, head->custom_name, sizeof(item_p));
151  }
152  strncpy(item_n+len+1, item_p, 127);
153  /* This is needed because strncpy may not add a ending \0 if the string is long enough. */
154  item_n[len+1+127] = 0;
155  len += strlen(item_n+1+len)+1;
156  SockList_AddLen8Data(sl, item_n, len);
157 
158  SockList_AddShort(sl, head->animation_id);
159  anim_speed = 0;
160  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
161  if (head->anim_speed)
162  anim_speed = head->anim_speed;
163  else {
164  if (FABS(head->speed) < 0.001)
165  anim_speed = 255;
166  else if (FABS(head->speed) >= 1.0)
167  anim_speed = 1;
168  else
169  anim_speed = (int)(1.0/FABS(head->speed));
170  }
171  if (anim_speed > 255)
172  anim_speed = 255;
173  }
174  SockList_AddChar(sl, (char)anim_speed);
175  SockList_AddInt(sl, head->nrof);
176 
177  SockList_AddShort(sl, head->client_type);
178 
179  SET_FLAG(head, FLAG_CLIENT_SENT);
180 }
181 
187 void esrv_draw_look(object *pl) {
188  object *tmp, *last;
189  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
190  SockList sl;
191  char buf[MAX_BUF];
192 
193  if (!pl->contr->socket.update_look) {
194  LOG(llevDebug, "esrv_draw_look called when update_look was not set\n");
195  return;
196  } else {
197  pl->contr->socket.update_look = 0;
198  }
199 
200  if (QUERY_FLAG(pl, FLAG_REMOVED)
201  || pl->map == NULL
202  || pl->map->in_memory != MAP_IN_MEMORY
203  || out_of_map(pl->map, pl->x, pl->y))
204  return;
205 
206  if (pl->contr->transport)
207  for (tmp = pl->contr->transport->inv; tmp && tmp->above; tmp = tmp->above)
208  ;
209  else
210  for (tmp = GET_MAP_OB(pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above)
211  ;
212 
213  SockList_Init(&sl);
214  SockList_AddString(&sl, "delinv 0");
215  Send_With_Handling(&pl->contr->socket, &sl);
216 
217  SockList_Reset(&sl);
218  SockList_AddPrintf(&sl, "item2 ");
219  SockList_AddInt(&sl, 0);
220 
223 
224  if (pl->contr->socket.look_position) {
225  int overhead = 1+(pl->contr->transport != NULL);
226  int prev_len = pl->contr->socket.num_look_objects-overhead-(pl->contr->socket.look_position > pl->contr->socket.num_look_objects-overhead);
227  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.look_position-prev_len));
228  SockList_AddInt(&sl, 0);
229  SockList_AddInt(&sl, -1);
231  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
232  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
233  SockList_AddShort(&sl, 0);
234  SockList_AddChar(&sl, 0);
235  SockList_AddInt(&sl, 0);
236  SockList_AddShort(&sl, 0);
237  objects_sent++;
238  got_one++;
239  }
240 
241  if (pl->contr->transport) {
243  objects_sent++;
244  got_one++;
245  }
246 
247  last = NULL;
249  object *head;
250 
251  if (tmp == last) {
252  break;
253  }
254 
255  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) {
256  last = tmp->below; /* assumes double floor mode */
257  if (last && QUERY_FLAG(last, FLAG_IS_FLOOR))
258  last = last->below;
259  }
260  if (LOOK_OBJ(tmp)) {
261  if (start_look++ < pl->contr->socket.look_position)
262  continue;
263  end_look++;
264  objects_sent++;
265  if (objects_sent >= pl->contr->socket.num_look_objects) {
266  /* What we basically do is make a 'fake' object -
267  * when the user applies it, we notice the special
268  * tag the object has, and act accordingly.
269  */
270  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.look_position+end_look-1));
271  SockList_AddInt(&sl, 0);
272  SockList_AddInt(&sl, -1);
274  snprintf(buf, sizeof(buf), "Click here to see next group of items");
275  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
276  SockList_AddShort(&sl, 0);
277  SockList_AddChar(&sl, 0);
278  SockList_AddInt(&sl, 0);
279  SockList_AddShort(&sl, 0);
280  break;
281  }
282  head = HEAD(tmp);
283  add_object_to_socklist(&pl->contr->socket, &sl, head);
284  got_one++;
285 
286  if (SockList_Avail(&sl) < MAXITEMLEN) {
287  Send_With_Handling(&pl->contr->socket, &sl);
288  SockList_Reset(&sl);
289  SockList_AddPrintf(&sl, "item2 ");
290  SockList_AddInt(&sl, 0);
291  got_one = 0;
292  }
293  } /* If LOOK_OBJ() */
295  if (got_one)
296  Send_With_Handling(&pl->contr->socket, &sl);
297 
298  SockList_Term(&sl);
299 }
300 
307 void esrv_send_inventory(object *pl, object *op) {
308  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
309  SockList sl;
310  char buf[MAX_BUF];
311  int prev_len = pl->contr->socket.num_look_objects - 2 - (((pl->contr->socket.container_position > pl->contr->socket.num_look_objects - 1)) ? 1 : 0);
312 
313  SockList_Init(&sl);
314  SockList_AddPrintf(&sl, "delinv %u", op->count);
315  Send_With_Handling(&pl->contr->socket, &sl);
316 
317  SockList_Reset(&sl);
318  SockList_AddString(&sl, "item2 ");
319  SockList_AddInt(&sl, op->count);
320  objects_sent++;
321 
322  if (pl != op && pl->contr->socket.container_position) {
323  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.container_position-prev_len));
324  SockList_AddInt(&sl, 0);
325  SockList_AddInt(&sl, -1);
327  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
328  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
329  SockList_AddShort(&sl, 0);
330  SockList_AddChar(&sl, 0);
331  SockList_AddInt(&sl, 0);
332  SockList_AddShort(&sl, 0);
333  objects_sent++;
334  got_one++;
335  }
336 
337  FOR_INV_PREPARE(op, tmp) {
338  object *head;
339 
340  head = HEAD(tmp);
341  if (LOOK_OBJ(head)) {
342  if (start_look++ < pl->contr->socket.container_position && pl != op)
343  continue;
344  end_look++;
345  objects_sent++;
346  if (pl != op && objects_sent >= pl->contr->socket.num_look_objects) {
347  /* What we basically do is make a 'fake' object -
348  * when the user applies it, we notice the special
349  * tag the object has, and act accordingly.
350  */
351  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.container_position + end_look - 1));
352  SockList_AddInt(&sl, 0);
353  SockList_AddInt(&sl, -1);
355  snprintf(buf, sizeof(buf), "Click here to see next group of items");
356  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
357  SockList_AddShort(&sl, 0);
358  SockList_AddChar(&sl, 0);
359  SockList_AddInt(&sl, 0);
360  SockList_AddShort(&sl, 0);
361  break;
362  }
363 
364  add_object_to_socklist(&pl->contr->socket, &sl, head);
365 
366  got_one++;
367 
368  /* It is possible for players to accumulate a huge amount of
369  * items (especially with some of the bags out there) to
370  * overflow the buffer. IF so, send multiple item commands.
371  */
372  if (SockList_Avail(&sl) < MAXITEMLEN) {
373  Send_With_Handling(&pl->contr->socket, &sl);
374  SockList_Reset(&sl);
375  SockList_AddString(&sl, "item2 ");
376  SockList_AddInt(&sl, op->count);
377  got_one = 0;
378  }
379  } /* If LOOK_OBJ() */
380  } FOR_INV_FINISH();
381  if (got_one) {
382  /* special case: only one item, the "prev group" arrow */
383  if (pl != op && pl->contr->socket.container_position) {
384  if (got_one > 1)
385  Send_With_Handling(&pl->contr->socket, &sl);
386  else {
387  /* view shifted, get to previous page and resend */
388  pl->contr->socket.container_position = MAX(0, pl->contr->socket.container_position - prev_len);
389  esrv_send_inventory(pl, op);
390  }
391  } else
392  Send_With_Handling(&pl->contr->socket, &sl);
393  }
394  SockList_Term(&sl);
395 }
396 
405 void esrv_update_item(int flags, object *pl, object *op) {
406  SockList sl;
407 
408  if (!pl->contr)
409  return;
410 
411  /* If we have a request to send the player item, skip a few checks. */
412  if (op != pl) {
413  if (!LOOK_OBJ(op))
414  return;
415  /* we remove the check for op->env, because in theory, the object
416  * is hopefully in the same place, so the client should preserve
417  * order.
418  */
419  }
420  if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) {
421  /* FLAG_CLIENT_SENT is debug only. We are using it to see where
422  * this is happening - we can set a breakpoint here in the debugger
423  * and track back the call.
424  */
425  LOG(llevDebug, "We have not sent item %s (%d)\n", op->name, op->count);
426  }
427 
428  SockList_Init(&sl);
429  SockList_AddString(&sl, "upditem ");
430  SockList_AddChar(&sl, (char)flags);
431 
432  op = HEAD(op);
433  SockList_AddInt(&sl, op->count);
434 
435  if (flags&UPD_LOCATION)
436  SockList_AddInt(&sl, op->env ? op->env->count : 0);
437 
438  if (flags&UPD_FLAGS)
439  SockList_AddInt(&sl, query_flags(op));
440 
441  if (flags&UPD_WEIGHT) {
442  int32_t weight = WEIGHT(op);
443 
444  /* TRANSPORTS are odd - they sort of look like containers,
445  * yet can't be picked up. So we don't to send the weight,
446  * as it is odd that you see weight sometimes and not other
447  * (the draw_look won't send it for example.
448  */
449  SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight);
450  if (pl == op) {
451  op->contr->last_weight = weight;
452  }
453  }
454 
455  if (flags&UPD_FACE) {
457  esrv_send_face(&pl->contr->socket, op->face->number, 0);
458  SockList_AddInt(&sl, op->face->number);
459  }
460  if (flags&UPD_NAME) {
461  int len;
462  char item_p[MAX_BUF];
463  char item_n[MAX_BUF];
464 
465  if (!op->custom_name) {
466  query_base_name(op, 0, item_n, sizeof(item_n)-1);
467  query_base_name(op, 1, item_p, sizeof(item_p));
468  } else {
469  snprintf(item_n, sizeof(item_n)-1, "%s", op->custom_name);
470  snprintf(item_p, sizeof(item_p), "%s", op->custom_name);
471  }
472 
473  len = strlen(item_n)+1;
474  snprintf(item_n+len, sizeof(item_n)-len, "%s", item_p);
475  len += strlen(item_n+len);
476  SockList_AddLen8Data(&sl, item_n, len);
477  }
478  if (flags&UPD_ANIM)
480 
481  if (flags&UPD_ANIMSPEED) {
482  int anim_speed = 0;
483 
484  if (QUERY_FLAG(op, FLAG_ANIMATE)) {
485  if (op->anim_speed)
486  anim_speed = op->anim_speed;
487  else {
488  if (FABS(op->speed) < 0.001)
489  anim_speed = 255;
490  else if (FABS(op->speed) >= 1.0)
491  anim_speed = 1;
492  else
493  anim_speed = (int)(1.0/FABS(op->speed));
494  }
495  if (anim_speed > 255)
496  anim_speed = 255;
497  }
498  SockList_AddChar(&sl, (char)anim_speed);
499  }
500  if (flags&UPD_NROF)
501  SockList_AddInt(&sl, op->nrof);
502 
503  Send_With_Handling(&pl->contr->socket, &sl);
504  SockList_Term(&sl);
505 }
506 
510 void esrv_send_item(object *pl, object*op) {
511  SockList sl;
512 
513  /* If this is not the player object, do some more checks */
514  if (op != pl) {
515  /* We only send 'visibile' objects to the client */
516  if (!LOOK_OBJ(op))
517  return;
518  /* if the item is on the ground, mark that the look needs to
519  * be updated.
520  */
521  if (!op->env) {
522  pl->contr->socket.update_look = 1;
523  return;
524  }
525  }
526 
527  SockList_Init(&sl);
528  SockList_AddString(&sl, "item2 ");
529 
530  op = HEAD(op);
531  SockList_AddInt(&sl, op->env ? op->env->count : 0);
532 
533  add_object_to_socklist(&pl->contr->socket, &sl, op);
534 
535  Send_With_Handling(&pl->contr->socket, &sl);
537  SockList_Term(&sl);
538 
539  /* if the object is in an opened container, then it may shift the contents,
540  * so resend everything */
541  if (pl->contr != NULL && pl->container != NULL && op->env == pl->container)
542  pl->contr->socket.update_inventory = 1;
543 }
544 
550 void esrv_del_item(player *pl, object *ob) {
551  SockList sl;
552 
553  SockList_Init(&sl);
554  SockList_AddString(&sl, "delitem ");
555  SockList_AddInt(&sl, ob->count);
556  Send_With_Handling(&pl->socket, &sl);
557  SockList_Term(&sl);
558  /* if the object is in an opened container, then it may shift the contents,
559  * so resend everything */
560  if (pl->ob->container != NULL && ob->env == pl->ob->container)
561  pl->socket.update_inventory = 1;
562 }
563 
564 /**************************************************************************
565  *
566  * Client has requested us to do something with an object.
567  *
568  **************************************************************************
569  */
570 
576 static object *esrv_get_ob_from_count(object *pl, tag_t count) {
577  if (pl->count == count)
578  return pl;
579 
580  FOR_INV_PREPARE(pl, op)
581  if (op->count == count)
582  return op;
583  else if (op->type == CONTAINER && pl->container == op) {
584  FOR_INV_PREPARE(op, tmp)
585  if (tmp->count == count)
586  return tmp;
587  FOR_INV_FINISH();
588  }
589  FOR_INV_FINISH();
590 
591  FOR_MAP_PREPARE(pl->map, pl->x, pl->y, op)
592  if (HEAD(op)->count == count)
593  return op;
594  else if (op->type == CONTAINER && pl->container == op) {
595  FOR_INV_PREPARE(op, tmp)
596  if (tmp->count == count)
597  return tmp;
598  FOR_INV_FINISH();
599  }
600  FOR_MAP_FINISH();
601 
602  if (pl->contr->transport) {
603  FOR_INV_PREPARE(pl->contr->transport, tmp)
604  if (tmp->count == count)
605  return tmp;
606  FOR_INV_FINISH();
607  }
608  return NULL;
609 }
610 
612 void examine_cmd(char *buf, int len, player *pl) {
613  long tag;
614  object *op;
615 
616  if (len <= 0 || !buf) {
617  LOG(llevDebug, "Player '%s' sent bogus examine_cmd information\n", pl->ob->name);
618  return;
619  }
620 
621  tag = atoi(buf);
622  op = esrv_get_ob_from_count(pl->ob, tag);
623  if (!op) {
624  LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", pl->ob->name, tag);
625  return;
626  }
627  examine(pl->ob, op);
628 }
629 
631 void apply_cmd(char *buf, int len, player *pl) {
632  uint32_t tag;
633  object *op;
634 
635  if (!buf || len <= 0) {
636  LOG(llevDebug, "Player '%s' sent bogus apply_cmd information\n", pl->ob->name);
637  return;
638  }
639 
640  tag = atoi(buf);
641  op = esrv_get_ob_from_count(pl->ob, tag);
642 
643  /* sort of a hack, but if the player saves and the player then
644  * manually applies a savebed (or otherwise tries to do stuff),
645  * we run into trouble.
646  */
647  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
648  return;
649 
650  /* If the high bit is set, player applied a pseudo object. */
651  if (tag&0x80000000) {
652  if (pl->ob->container != NULL) {
653  pl->socket.container_position = tag&0x7fffffff;
654  esrv_send_inventory(pl->ob, pl->ob->container);
655  pl->socket.update_inventory = 0;
656  } else {
657  pl->socket.look_position = tag&0x7fffffff;
658  pl->socket.update_look = 1;
659  }
660  return;
661  }
662 
663  if (!op) {
664  LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", pl->ob->name, tag);
665  return;
666  }
667  apply_by_living(pl->ob, op, 0, 0);
668 }
669 
671 void lock_item_cmd(uint8_t *data, int len, player *pl) {
672  int flag, tag;
673  object *op;
674  object *tmp;
675 
676  if (len != 5) {
677  LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name);
678  return;
679  }
680  flag = data[0];
681  tag = GetInt_String(data+1);
682  op = esrv_get_ob_from_count(pl->ob, tag);
683 
684  if (!op) {
686  "Could not find object to lock/unlock");
687  return;
688  }
689 
690  if (op->map) {
692  "Can't lock/unlock an item on the ground");
693  return;
694  }
695  if (op->env != pl->ob) {
697  "Can't lock/unlock an item not directly in your inventory");
698  return;
699  }
700 
701  if (!flag)
703  else
705 
706  tmp = object_merge(op, NULL);
707  if (tmp == NULL) {
708  /* object was not merged - if it was, object_merge() sent updates for us. */
709  esrv_update_item(UPD_FLAGS, pl->ob, op);
710  }
711 }
712 
723 void mark_item_cmd(uint8_t *data, int len, player *pl) {
724  int tag;
725  object *op;
726  char name[MAX_BUF];
727 
728  if (len != 4) {
729  LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name);
730  return;
731  }
732 
733  tag = GetInt_String(data);
734  op = esrv_get_ob_from_count(pl->ob, tag);
735  if (!op) {
737  "Could not find object to mark");
738  return;
739  }
740  pl->mark = op;
741  pl->mark_count = op->count;
742  query_name(op, name, MAX_BUF);
744  "Marked item %s",
745  name);
746 }
747 
754 void look_at(object *op, int dx, int dy) {
755  object *tmp;
756  int flag = 0;
757  int16_t x, y;
758  mapstruct *m;
759  char name[MAX_BUF];
760 
761  if (out_of_map(op->map, op->x+dx, op->y+dy))
762  return;
763 
764  x = op->x+dx;
765  y = op->y+dy;
766 
767  m = get_map_from_coord(op->map, &x, &y);
768  if (!m)
769  return;
770 
771  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
772  ;
773 
775  if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ))
776  continue;
777 
778  if (!flag) {
779  if (dx || dy)
781  "There you see:");
782  else {
784  "You see:");
785  }
786  flag = 1;
787  }
788 
789  query_name(tmp, name, MAX_BUF);
790  if (QUERY_FLAG(op, FLAG_WIZ))
792  "- %s (%d).",
793  name, tmp->count);
794  else
796  "- %s.",
797  name);
798 
799  if ((HEAD(tmp)->inv != NULL && (tmp->type != CONTAINER && tmp->type != FLESH))
800  || QUERY_FLAG(op, FLAG_WIZ))
801  inventory(op, HEAD(tmp));
802 
803  /* don't continue under the floor */
804  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !QUERY_FLAG(op, FLAG_WIZ))
805  break;
807 
808  if (!flag) {
809  if (dx || dy)
811  "You see nothing there.");
812  else
814  "You see nothing.");
815  }
816 }
817 
819 void look_at_cmd(char *buf, int len, player *pl) {
820  int dx, dy;
821  char *cp;
822 
823  if (len <= 0 || !buf) {
824  LOG(llevDebug, "Player '%s' sent bogus look_at_cmd information\n", pl->ob->name);
825  return;
826  }
827 
828  dx = atoi(buf);
829  if (!(cp = strchr(buf, ' '))) {
830  return;
831  }
832  dy = atoi(cp);
833 
834  if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2)
835  return;
836 
837  if (pl->blocked_los[dx+(pl->socket.mapx/2)][dy+(pl->socket.mapy/2)])
838  return;
839  look_at(pl->ob, dx, dy);
840 }
841 
843 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) {
844  object *op, *env;
845 
846  op = esrv_get_ob_from_count(pl, tag);
847  if (!op) {
848  LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag);
849  return;
850  }
851 
852  /* If on a transport, you don't drop to the ground - you drop to the
853  * transport.
854  */
855  if (!to && !pl->contr->transport) { /* drop it to the ground */
856  /* LOG(llevDebug, "Drop it on the ground.\n");*/
857 
858  if (op->map && !op->env) {
859 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/
860  return;
861  }
862  /* If it is an active container, then we should drop all objects
863  * in the container and not the container itself.
864  */
865  if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
866  FOR_INV_PREPARE(op, current)
867  drop_object(pl, current, 0);
868  FOR_INV_FINISH();
869  esrv_update_item(UPD_WEIGHT, pl, op);
870  } else {
871  drop_object(pl, op, nrof);
872  }
873  return;
874  } else if (to == pl->count) { /* pick it up to the inventory */
875  /* return if player has already picked it up */
876  if (op->env == pl)
877  return;
878 
879  pl->contr->count = nrof;
880  pick_up(pl, op);
881  return;
882  }
883  /* If not dropped or picked up, we are putting it into a sack */
884  if (pl->contr->transport) {
885  if (object_can_pick(pl, op)
886  && transport_can_hold(pl->contr->transport, op, nrof)) {
887  put_object_in_sack(pl, pl->contr->transport, op, nrof);
888  }
889  } else {
890  env = esrv_get_ob_from_count(pl, to);
891  if (!env) {
892  LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to);
893  return;
894  }
895  /* put_object_in_sack presumes that necessary sanity checking
896  * has already been done (eg, it can be picked up and fits in
897  * in a sack, so check for those things. We should also check
898  * an make sure env is in fact a container for that matter.
899  */
900  if (env->type == CONTAINER
901  && object_can_pick(pl, op)
902  && sack_can_hold(pl, env, op, nrof)) {
903  put_object_in_sack(pl, env, op, nrof);
904  }
905  }
906 }
907 
908 void inscribe_scroll_cmd(char *buf, int len, player *pl) {
909  object *scroll, *spell, *marked, *inscription, *currentspell;
910  tag_t tscroll, tspell, tmarked;
911  char type;
912 
913  if (len < 1) {
914  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
915  return;
916  }
917 
918  type = buf[0];
919 
920  inscription = find_skill_by_name(pl->ob, "inscription");
921  if (!inscription) {
922  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!");
923  return;
924  }
925 
926  if (type == 0) {
927  if (len != 9) {
928  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
929  return;
930  }
931  tscroll = GetInt_String((uint8_t *)buf+1);
932  tspell = GetInt_String((uint8_t *)buf+5);
933 
934  scroll = esrv_get_ob_from_count(pl->ob, tscroll);
935  if (!scroll) {
936  LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name);
937  return;
938  }
939 
940  spell = esrv_get_ob_from_count(pl->ob, tspell);
941  if (!spell) {
942  LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name);
943  return;
944  }
945 
946  tmarked = pl->mark_count;
947  marked = pl->mark;
948  currentspell = pl->ranges[range_magic];
949 
950  pl->mark_count = tscroll;
951  pl->mark = scroll;
952  pl->ranges[range_magic] = spell;
953 
954  write_on_item(pl->ob, "", inscription);
955 
956  pl->mark_count = tmarked;
957  pl->mark = marked;
958  pl->ranges[range_magic] = currentspell;
959  } else {
960  }
961 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
#define FLAG_KNOWN_BLESSED
Item is known to be blessed.
Definition: define.h:379
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.c:908
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.c:194
One player.
Definition: player.h:92
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:318
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:303
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:236
void look_at(object *op, int dx, int dy)
Prints items on the specified square.
Definition: item.c:754
See Ring.
Definition: object.h:185
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.c:66
void esrv_send_face(socket_struct *ns, uint16_t face_num, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.c:70
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:149
void lock_item_cmd(uint8_t *data, int len, player *pl)
Client wants to apply some object.
Definition: item.c:671
void esrv_del_item(player *pl, object *ob)
Tells the client to delete an item.
Definition: item.c:550
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.c:48
#define SET_FLAG(xyz, p)
Definition: define.h:223
See Bracers.
Definition: object.h:217
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
void esrv_draw_look(object *pl)
Send the look window.
Definition: item.c:187
unsigned char uint8_t
Definition: win32.h:161
uint16_t animation_id
An index into the animation array.
Definition: object.h:416
int GetInt_String(const unsigned char *data)
Basically does the reverse of SockList_AddInt, but on strings instead.
Definition: lowlevel.c:246
#define UPD_ANIM
Definition: newclient.h:294
void esrv_send_item(object *pl, object *op)
Sends item&#39;s info to player.
Definition: item.c:510
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:417
Defines various flags that both the new client and new server use.
#define F_LOCKED
Definition: newclient.h:266
See Cloak.
Definition: object.h:204
uint16_t look_position
Start of drawing of look window.
Definition: newserver.h:126
struct obj * container
Current container being used.
Definition: object.h:291
void esrv_send_animation(socket_struct *ns, short anim_num)
Need to send an animation sequence to the client.
Definition: request.c:883
static unsigned int query_flags(const object *op)
This is a similar to query_name, but returns flags to be sended to client.
Definition: item.c:49
void apply_cmd(char *buf, int len, player *pl)
Client wants to apply some object.
Definition: item.c:631
#define LOOK_OBJ(ob)
This returns TRUE if the object is something that should be displayed in the look window...
Definition: object.h:507
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:345
#define MSG_TYPE_COMMAND_EXAMINE
Player examining something.
Definition: newclient.h:512
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
This is basically the same as out_of_map above(), but instead we return NULL if no map is valid (coor...
Definition: map.c:2366
void pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.c:446
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.c:722
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.c:108
Socket structure, represents a client-server connection.
Definition: newserver.h:99
socket_struct socket
Socket information for this player.
Definition: player.h:94
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
See Weapon.
Definition: object.h:119
See Helmet.
Definition: object.h:136
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Move an object to a new location.
Definition: item.c:843
object * ranges[range_size]
Object for each range.
Definition: player.h:103
See Rod.
Definition: object.h:109
uint32_t mark_count
Count of marked object.
Definition: player.h:193
#define FLAG_BLESSED
Item has a blessing, opposite of cursed/damned.
Definition: define.h:378
uint16_t container_position
Start of container contents to send to client.
Definition: newserver.h:127
struct obj * above
Pointer to the object stacked above this one.
Definition: object.h:288
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.c:119
See Girdle.
Definition: object.h:223
See Amulet.
Definition: object.h:139
#define MAX(x, y)
Definition: compat.h:20
#define F_DAMNED
Definition: newclient.h:263
void look_at_cmd(char *buf, int len, player *pl)
Client wants to look at some object.
Definition: item.c:819
animal &#39;body parts&#39; -b.t.
Definition: object.h:187
Global type definitions and header inclusions.
#define safe_strncpy
Definition: compat.h:23
See Boots.
Definition: object.h:212
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.c:310
See Wand & Staff.
Definition: object.h:220
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:789
#define MIN(x, y)
Definition: compat.h:17
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:320
uint16_t number
This is the image id.
Definition: face.h:15
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:130
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:115
int16_t y
Position in the map for this object.
Definition: object.h:326
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:379
See Shooting Weapon.
Definition: object.h:118
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Living thing is applying an object.
Definition: apply.c:557
#define F_UNPAID
Definition: newclient.h:260
uint8_t num_look_objects
The maximum number of objects to show on the ground view; this number includes the prev/next group fa...
Definition: newserver.h:134
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.c:3793
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:510
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:509
signed short int16_t
Definition: win32.h:160
#define FLAG_CLIENT_SENT
THIS IS A DEBUG FLAG ONLY.
Definition: define.h:349
#define F_BLESSED
Definition: newclient.h:267
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.c:58
#define snprintf
Definition: win32.h:46
#define F_NOPICK
Definition: newclient.h:265
#define F_MAGIC
Definition: newclient.h:261
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Check if an item op can be put into a sack.
Definition: c_object.c:257
object * transport
Transport the player is in.
Definition: player.h:195
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
void mark_item_cmd(uint8_t *data, int len, player *pl)
Client wants to mark some object.
Definition: item.c:723
const char * name
The name of the object, obviously...
Definition: object.h:311
struct obj * env
Pointer to the object which is the environment.
Definition: object.h:293
#define WEIGHT(op)
Returns the weight of the given object.
Definition: define.h:686
struct obj * below
Pointer to the object stacked below this one.
Definition: object.h:287
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.c:149
uint32_t nrof
How many of the objects.
Definition: object.h:333
Defines various structures and values that are used for the new client server communication method...
#define UPD_FLAGS
Definition: newclient.h:290
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
void examine(object *op, object *tmp)
Player examines some object.
Definition: c_object.c:1424
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:585
static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head)
Used in the send_look to put object head into SockList sl for socket ns.
Definition: item.c:117
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.c:238
uint32_t update_inventory
If true, we need to send the inventory list.
Definition: newserver.h:116
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:159
#define UPD_WEIGHT
Definition: newclient.h:291
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
float speed
The overall speed of this object.
Definition: object.h:328
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:594
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
New_Face * empty_face
Definition: image.c:39
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Something tries to put an object into another.
Definition: c_object.c:678
#define F_OPEN
Definition: newclient.h:264
int16_t x
Definition: object.h:326
void examine_cmd(char *buf, int len, player *pl)
Client wants to examine some object.
Definition: item.c:612
uint8_t mapx
Definition: newserver.h:128
#define MAP_CLIENT_X
This determines the maximum map size the client can request (and thus what the server will send to th...
Definition: config.h:236
#define UPD_ANIMSPEED
Definition: newclient.h:295
void SockList_AddChar(SockList *sl, char c)
Adds an 8 bit value.
Definition: lowlevel.c:98
See Container.
Definition: object.h:231
static const flag_definition flags[]
Flag mapping.
void inventory(object *op, object *inv)
Prints object&#39;s inventory.
Definition: c_object.c:1694
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:765
#define F_UNIDENTIFIED
Definition: newclient.h:259
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:321
object * ob
The object representing the player.
Definition: player.h:158
int need_identify(const object *op)
This function really should not exist - by default, any item not identified should need it...
Definition: item.c:1331
#define FLAG_CURSED
The object is cursed.
Definition: define.h:317
unsigned int uint32_t
Definition: win32.h:162
See Shield.
Definition: object.h:135
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:242
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: item.c:405
Object structure, the core of Crossfire.
#define MAP_CLIENT_Y
Definition: config.h:237
#define UPD_NROF
Definition: newclient.h:296
Also see SKILL_TOOL (74) below.
Definition: object.h:143
const char * custom_name
Custom name assigned by player.
Definition: object.h:432
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:142
tag_t count
Unique object number for this object.
Definition: object.h:299
uint16_t client_type
Public type information.
Definition: object.h:340
#define UPD_FACE
Definition: newclient.h:292
Only for debugging purposes.
Definition: logger.h:13
uint8_t anims_sent[MAXANIMNUM]
What animations we sent.
Definition: newserver.h:107
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 8 bit length field.
Definition: lowlevel.c:171
static object * esrv_get_ob_from_count(object *pl, tag_t count)
Takes a player and object count (tag) and returns the actual object pointer, or null if it can&#39;t be f...
Definition: item.c:576
#define UPD_LOCATION
Definition: newclient.h:289
int transport_can_hold(const object *transport, const object *op, int nrof)
Can transport hold object op? This is a pretty trivial function, but in the future, possible transport may have more restrictions or weight reduction like containers.
Definition: apply.c:54
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object * object_merge(object *op, object *top)
This function goes through all objects below and including top, and merges op to the first matching o...
Definition: object.c:1869
int out_of_map(mapstruct *m, int x, int y)
this returns TRUE if the coordinates (x,y) are out of map m.
Definition: map.c:2294
signed int int32_t
Definition: win32.h:159
#define UPD_NAME
Definition: newclient.h:293
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:785
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:172
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:383
struct obj * inv
Pointer to the first object in the inventory.
Definition: object.h:290
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
See Gloves.
Definition: object.h:213
Spells.
Definition: player.h:19
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
#define MAXITEMLEN
This is the maximum number of bytes we expect any one item to take up.
Definition: item.c:36
object * mark
Marked object.
Definition: player.h:194
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:758
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:680
This is a game-map.
Definition: map.h:325
const New_Face * face
Face with colors.
Definition: object.h:332
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:239
int write_on_item(object *pl, const char *params, object *skill)
Implement the &#39;inscription&#39; skill, which checks for the required skills and marked items before runni...
Definition: skills.c:1735
See Breastplate Armor.
Definition: object.h:120
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:128
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:330
object * drop_object(object *op, object *tmp, uint32_t nrof)
Try to drop an object on the floor.
Definition: c_object.c:814
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: skill_util.c:213
void esrv_send_inventory(object *pl, object *op)
Sends inventory of a container.
Definition: item.c:307
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:106
#define F_CURSED
Definition: newclient.h:262
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
uint32_t count
Any numbers typed before a command.
Definition: player.h:109
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.c:542