Crossfire Server  1.75.0
item.cpp
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 (!is_identified(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  // Denote when a book has been read. This gives GUI feedback in the inventory window if the client handles the flag.
109  // NO_SKILL_IDENT is set when identification fails or when the book is read. So the book is read only when it is
110  // both identified and NO_SKILL_IDENT.
112  flags |= F_READ;
113 
114  return flags;
115 }
116 
122 static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head) {
123  int flags, len, anim_speed;
124  char item_n[MAX_BUF], item_p[MAX_BUF];
125  sstring custom_name = object_get_value(head, CUSTOM_NAME_FIELD);
126 
127  flags = query_flags(head);
128  if (QUERY_FLAG(head, FLAG_NO_PICK))
129  flags |= F_NOPICK;
130 
131  if (!(ns->faces_sent[head->face->number]&NS_FACESENT_FACE))
132  esrv_send_face(ns, head->face, 0);
133 
134  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
135  if (head->animation == NULL) {
136  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);
137  CLEAR_FLAG(head, FLAG_ANIMATE);
138  } else if (!ns->anims_sent[head->animation->num])
139  esrv_send_animation(ns, head->animation);
140  }
141 
142  SockList_AddInt(sl, head->count);
143  SockList_AddInt(sl, flags);
144  SockList_AddInt(sl, QUERY_FLAG(head, FLAG_NO_PICK) ? -1 : WEIGHT(head));
145  SockList_AddInt(sl, head->face->number);
146 
147  if (!custom_name) {
148  query_base_name(head, 0, item_n, 126);
149  item_n[127] = 0;
150  len = strlen(item_n);
151  query_base_name(head, 1, item_p, MAX_BUF);
152  } else {
153  safe_strncpy(item_n, custom_name, 127);
154  item_n[127] = 0;
155  len = strlen(item_n);
156  safe_strncpy(item_p, custom_name, sizeof(item_p));
157  }
158  strncpy(item_n+len+1, item_p, 127);
159  /* This is needed because strncpy may not add a ending \0 if the string is long enough. */
160  item_n[len+1+127] = 0;
161  len += strlen(item_n+1+len)+1;
162  SockList_AddLen8Data(sl, item_n, len);
163 
164  SockList_AddShort(sl, (QUERY_FLAG(head, FLAG_ANIMATE) && head->animation) ? head->animation->num : 0);
165  anim_speed = 0;
166  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
167  if (head->anim_speed)
168  anim_speed = head->anim_speed;
169  else {
170  if (FABS(head->speed) < 0.001)
171  anim_speed = 255;
172  else if (FABS(head->speed) >= 1.0)
173  anim_speed = 1;
174  else
175  anim_speed = (int)(1.0/FABS(head->speed));
176  }
177  if (anim_speed > 255)
178  anim_speed = 255;
179  }
180  SockList_AddChar(sl, (char)anim_speed);
181  SockList_AddInt(sl, head->nrof);
182 
183  SockList_AddShort(sl, head->client_type);
184 
185  SET_FLAG(head, FLAG_CLIENT_SENT);
186 }
187 
193 void esrv_draw_look(object *pl) {
194  object *tmp, *last;
195  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
196  SockList sl;
197  char buf[MAX_BUF];
198 
199  if (!pl->contr->socket->update_look) {
200  LOG(llevDebug, "esrv_draw_look called when update_look was not set\n");
201  return;
202  } else {
203  pl->contr->socket->update_look = 0;
204  }
205 
206  if (QUERY_FLAG(pl, FLAG_REMOVED)
207  || pl->map == NULL
208  || pl->map->in_memory != MAP_IN_MEMORY
209  || out_of_map(pl->map, pl->x, pl->y))
210  return;
211 
212  if (pl->contr->transport)
213  for (tmp = pl->contr->transport->inv; tmp && tmp->above; tmp = tmp->above)
214  ;
215  else
216  for (tmp = GET_MAP_OB(pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above)
217  ;
218 
219  SockList_Init(&sl);
220  SockList_AddString(&sl, "delinv 0");
221  Send_With_Handling(pl->contr->socket, &sl);
222 
223  SockList_Reset(&sl);
224  SockList_AddPrintf(&sl, "item2 ");
225  SockList_AddInt(&sl, 0);
226 
229 
230  if (pl->contr->socket->look_position) {
231  int overhead = 1+(pl->contr->transport != NULL);
232  int prev_len = pl->contr->socket->num_look_objects-overhead-(pl->contr->socket->look_position > pl->contr->socket->num_look_objects-overhead);
233  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket->look_position-prev_len));
234  SockList_AddInt(&sl, 0);
235  SockList_AddInt(&sl, -1);
237  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
238  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
239  SockList_AddShort(&sl, 0);
240  SockList_AddChar(&sl, 0);
241  SockList_AddInt(&sl, 0);
242  SockList_AddShort(&sl, 0);
243  objects_sent++;
244  got_one++;
245  }
246 
247  if (pl->contr->transport) {
249  objects_sent++;
250  got_one++;
251  }
252 
253  last = NULL;
255  object *head;
256 
257  if (tmp == last) {
258  break;
259  }
260 
261  if (!QUERY_FLAG(pl, FLAG_WIZ)) {
262  // Unless DM, stop at the first floor or two consecutive floor objects.
263  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) {
264  last = tmp->below; /* assumes double floor mode */
265  if (last && QUERY_FLAG(last, FLAG_IS_FLOOR))
266  last = last->below;
267  }
268  }
269  if (QUERY_FLAG(pl, FLAG_WIZ) || LOOK_OBJ(tmp)) {
270  if (start_look++ < pl->contr->socket->look_position)
271  continue;
272  end_look++;
273  objects_sent++;
274  if (objects_sent >= pl->contr->socket->num_look_objects) {
275  /* What we basically do is make a 'fake' object -
276  * when the user applies it, we notice the special
277  * tag the object has, and act accordingly.
278  */
279  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket->look_position+end_look-1));
280  SockList_AddInt(&sl, 0);
281  SockList_AddInt(&sl, -1);
283  snprintf(buf, sizeof(buf), "Click here to see next group of items");
284  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
285  SockList_AddShort(&sl, 0);
286  SockList_AddChar(&sl, 0);
287  SockList_AddInt(&sl, 0);
288  SockList_AddShort(&sl, 0);
289  break;
290  }
291  head = HEAD(tmp);
292  add_object_to_socklist(pl->contr->socket, &sl, head);
293  got_one++;
294 
295  if (SockList_Avail(&sl) < MAXITEMLEN) {
296  Send_With_Handling(pl->contr->socket, &sl);
297  SockList_Reset(&sl);
298  SockList_AddPrintf(&sl, "item2 ");
299  SockList_AddInt(&sl, 0);
300  got_one = 0;
301  }
302  } /* If LOOK_OBJ() */
304  if (got_one)
305  Send_With_Handling(pl->contr->socket, &sl);
306 
307  SockList_Term(&sl);
308 }
309 
316 void esrv_send_inventory(object *pl, object *op) {
317  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
318  SockList sl;
319  char buf[MAX_BUF];
320  int prev_len = pl->contr->socket->num_look_objects - 2 - (((pl->contr->socket->container_position > pl->contr->socket->num_look_objects - 1)) ? 1 : 0);
321 
322  SockList_Init(&sl);
323  SockList_AddPrintf(&sl, "delinv %u", op->count);
324  Send_With_Handling(pl->contr->socket, &sl);
325 
326  SockList_Reset(&sl);
327  SockList_AddString(&sl, "item2 ");
328  SockList_AddInt(&sl, op->count);
329  objects_sent++;
330 
331  if (pl != op && pl->contr->socket->container_position) {
332  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket->container_position-prev_len));
333  SockList_AddInt(&sl, 0);
334  SockList_AddInt(&sl, -1);
336  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
337  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
338  SockList_AddShort(&sl, 0);
339  SockList_AddChar(&sl, 0);
340  SockList_AddInt(&sl, 0);
341  SockList_AddShort(&sl, 0);
342  objects_sent++;
343  got_one++;
344  }
345 
346  FOR_INV_PREPARE(op, tmp) {
347  object *head;
348 
349  head = HEAD(tmp);
350  if (LOOK_OBJ(head)) {
351  if (start_look++ < pl->contr->socket->container_position && pl != op)
352  continue;
353  end_look++;
354  objects_sent++;
355  if (pl != op && objects_sent >= pl->contr->socket->num_look_objects) {
356  /* What we basically do is make a 'fake' object -
357  * when the user applies it, we notice the special
358  * tag the object has, and act accordingly.
359  */
360  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket->container_position + end_look - 1));
361  SockList_AddInt(&sl, 0);
362  SockList_AddInt(&sl, -1);
364  snprintf(buf, sizeof(buf), "Click here to see next group of items");
365  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
366  SockList_AddShort(&sl, 0);
367  SockList_AddChar(&sl, 0);
368  SockList_AddInt(&sl, 0);
369  SockList_AddShort(&sl, 0);
370  break;
371  }
372 
373  add_object_to_socklist(pl->contr->socket, &sl, head);
374 
375  got_one++;
376 
377  /* It is possible for players to accumulate a huge amount of
378  * items (especially with some of the bags out there) to
379  * overflow the buffer. IF so, send multiple item commands.
380  */
381  if (SockList_Avail(&sl) < MAXITEMLEN) {
382  Send_With_Handling(pl->contr->socket, &sl);
383  SockList_Reset(&sl);
384  SockList_AddString(&sl, "item2 ");
385  SockList_AddInt(&sl, op->count);
386  got_one = 0;
387  }
388  } /* If LOOK_OBJ() */
389  } FOR_INV_FINISH();
390  if (got_one) {
391  /* special case: only one item, the "prev group" arrow */
392  if (pl != op && pl->contr->socket->container_position) {
393  if (got_one > 1)
394  Send_With_Handling(pl->contr->socket, &sl);
395  else {
396  /* view shifted, get to previous page and resend */
397  pl->contr->socket->container_position = MAX(0, pl->contr->socket->container_position - prev_len);
398  esrv_send_inventory(pl, op);
399  }
400  } else
401  Send_With_Handling(pl->contr->socket, &sl);
402  }
403  SockList_Term(&sl);
404 }
405 
414 void esrv_update_item(int flags, object *pl, object *op) {
415  SockList sl;
416 
417  if (!pl->contr)
418  return;
419 
420  /* If we have a request to send the player item, skip a few checks. */
421  if (op != pl) {
422  if (!LOOK_OBJ(op))
423  return;
424  /* we remove the check for op->env, because in theory, the object
425  * is hopefully in the same place, so the client should preserve
426  * order.
427  */
428  }
429  if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) {
430  // Sometimes, we try to update an item that we haven't sent to the
431  // client. Don't! This can happen, for example, when a button under the
432  // floor gets toggled, but objects under floor tiles are generally not
433  // sent. There are some other places where this happens that we haven't
434  // tracked down, but in general, just don't.
435  //LOG(llevDebug, "We have not sent item %s (%d)\n", op->name, op->count);
436  return;
437  }
438 
439  SockList_Init(&sl);
440  SockList_AddString(&sl, "upditem ");
441  SockList_AddChar(&sl, (char)flags);
442 
443  op = HEAD(op);
444  SockList_AddInt(&sl, op->count);
445  sstring custom_name = object_get_value(op, CUSTOM_NAME_FIELD);
446 
447  if (flags&UPD_LOCATION)
448  SockList_AddInt(&sl, op->env ? op->env->count : 0);
449 
450  if (flags&UPD_FLAGS)
451  SockList_AddInt(&sl, query_flags(op));
452 
453  if (flags&UPD_WEIGHT) {
454  int32_t weight = WEIGHT(op);
455 
456  /* TRANSPORTS are odd - they sort of look like containers,
457  * yet can't be picked up. So we don't to send the weight,
458  * as it is odd that you see weight sometimes and not other
459  * (the draw_look won't send it for example.
460  */
461  SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight);
462  if (pl == op) {
463  op->contr->last_weight = weight;
464  }
465  }
466 
467  if (flags&UPD_FACE) {
468  if (!(pl->contr->socket->faces_sent[op->face->number]&NS_FACESENT_FACE))
469  esrv_send_face(pl->contr->socket, op->face, 0);
470  SockList_AddInt(&sl, op->face->number);
471  }
472  if (flags&UPD_NAME) {
473  int len;
474  char item_p[MAX_BUF];
475  char item_n[MAX_BUF];
476 
477  if (!custom_name) {
478  query_base_name(op, 0, item_n, sizeof(item_n)-1);
479  query_base_name(op, 1, item_p, sizeof(item_p));
480  } else {
481  strlcpy(item_n, custom_name, sizeof(item_n)-1);
482  strlcpy(item_p, custom_name, sizeof(item_p));
483  }
484 
485  len = strlen(item_n)+1;
486  snprintf(item_n+len, sizeof(item_n)-len, "%s", item_p);
487  len += strlen(item_n+len);
488  SockList_AddLen8Data(&sl, item_n, len);
489  }
490  if (flags&UPD_ANIM)
491  SockList_AddShort(&sl, op->animation ? op->animation->num : 0);
492 
493  if (flags&UPD_ANIMSPEED) {
494  int anim_speed = 0;
495 
496  if (QUERY_FLAG(op, FLAG_ANIMATE)) {
497  if (op->anim_speed)
498  anim_speed = op->anim_speed;
499  else {
500  if (FABS(op->speed) < 0.001)
501  anim_speed = 255;
502  else if (FABS(op->speed) >= 1.0)
503  anim_speed = 1;
504  else
505  anim_speed = (int)(1.0/FABS(op->speed));
506  }
507  if (anim_speed > 255)
508  anim_speed = 255;
509  }
510  SockList_AddChar(&sl, (char)anim_speed);
511  }
512  if (flags&UPD_NROF)
513  SockList_AddInt(&sl, op->nrof);
514 
515  Send_With_Handling(pl->contr->socket, &sl);
516  SockList_Term(&sl);
517 }
518 
522 void esrv_send_item(object *pl, object*op) {
523  SockList sl;
524 
525  /* If this is not the player object, do some more checks */
526  if (op != pl) {
527  /* We only send 'visibile' objects to the client */
528  if (!LOOK_OBJ(op))
529  return;
530  /* if the item is on the ground, mark that the look needs to
531  * be updated.
532  */
533  if (!op->env) {
534  pl->contr->socket->update_look = 1;
535  return;
536  }
537  }
538 
539  SockList_Init(&sl);
540  SockList_AddString(&sl, "item2 ");
541 
542  op = HEAD(op);
543  SockList_AddInt(&sl, op->env ? op->env->count : 0);
544 
545  add_object_to_socklist(pl->contr->socket, &sl, op);
546 
547  Send_With_Handling(pl->contr->socket, &sl);
549  SockList_Term(&sl);
550 
551  /* if the object is in an opened container, then it may shift the contents,
552  * so resend everything */
553  if (pl->contr != NULL && pl->container != NULL && op->env == pl->container)
554  pl->contr->socket->update_inventory = 1;
555 }
556 
562 void esrv_del_item(player *pl, object *ob) {
563  SockList sl;
564 
565  if (!QUERY_FLAG(ob, FLAG_CLIENT_SENT))
566  return;
567 
568  SockList_Init(&sl);
569  SockList_AddString(&sl, "delitem ");
570  SockList_AddInt(&sl, ob->count);
571  Send_With_Handling(pl->socket, &sl);
572  SockList_Term(&sl);
573  /* if the object is in an opened container, then it may shift the contents,
574  * so resend everything */
575  if (pl->ob->container != NULL && ob->env == pl->ob->container)
576  pl->socket->update_inventory = 1;
577 }
578 
579 /**************************************************************************
580  *
581  * Client has requested us to do something with an object.
582  *
583  **************************************************************************
584  */
585 
590 bool player_can_find(object *op, object *ob) {
591  return QUERY_FLAG(op, FLAG_WIZ) || !ob->invisible;
592 }
593 
597 static object *ob_if_can_find(object *op, object *ob) {
598  if (player_can_find(op, ob)) {
599  return ob;
600  } else {
601  return NULL;
602  }
603 }
604 
610 static object *esrv_get_ob_from_count(object *pl, tag_t count) {
611  if (pl->count == count)
612  return pl;
613 
614  FOR_INV_PREPARE(pl, op)
615  if (op->count == count)
616  return ob_if_can_find(pl, op);
617  else if (op->type == CONTAINER && pl->container == op) {
618  FOR_INV_PREPARE(op, tmp)
619  if (tmp->count == count)
620  return ob_if_can_find(pl, tmp);
621  FOR_INV_FINISH();
622  }
623  FOR_INV_FINISH();
624 
625  FOR_MAP_PREPARE(pl->map, pl->x, pl->y, op)
626  if (HEAD(op)->count == count)
627  return ob_if_can_find(pl, op);
628  else if (op->type == CONTAINER && pl->container == op) {
629  FOR_INV_PREPARE(op, tmp)
630  if (tmp->count == count)
631  return ob_if_can_find(pl, tmp);
632  FOR_INV_FINISH();
633  }
634  FOR_MAP_FINISH();
635 
636  if (pl->contr->transport) {
637  FOR_INV_PREPARE(pl->contr->transport, tmp)
638  if (tmp->count == count)
639  return ob_if_can_find(pl, tmp);
640  FOR_INV_FINISH();
641  }
642  return NULL;
643 }
644 
646 void examine_cmd(char *buf, int len, player *pl) {
647  long tag;
648  object *op;
649 
650  if (len <= 0 || !buf) {
651  LOG(llevDebug, "Player '%s' sent bogus examine_cmd information\n", pl->ob->name);
652  return;
653  }
654 
655  tag = atoi(buf);
656  op = esrv_get_ob_from_count(pl->ob, tag);
657  if (!op) {
658  LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", pl->ob->name, tag);
659  return;
660  }
661  examine(pl->ob, op);
662  if (QUERY_FLAG(pl->ob, FLAG_WIZ)) {
663  do_dump(pl->ob, op);
664  }
665 }
666 
668 void apply_cmd(char *buf, int len, player *pl) {
669  uint32_t tag;
670  object *op;
671 
672  if (!buf || len <= 0) {
673  LOG(llevDebug, "Player '%s' sent bogus apply_cmd information\n", pl->ob->name);
674  return;
675  }
676 
677  tag = atoi(buf);
678  op = esrv_get_ob_from_count(pl->ob, tag);
679 
680  /* sort of a hack, but if the player saves and the player then
681  * manually applies a savebed (or otherwise tries to do stuff),
682  * we run into trouble.
683  */
684  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
685  return;
686 
687  /* If the high bit is set, player applied a pseudo object. */
688  if (tag&0x80000000) {
689  if (pl->ob->container != NULL) {
690  pl->socket->container_position = tag&0x7fffffff;
691  esrv_send_inventory(pl->ob, pl->ob->container);
692  pl->socket->update_inventory = 0;
693  } else {
694  pl->socket->look_position = tag&0x7fffffff;
695  pl->socket->update_look = 1;
696  }
697  return;
698  }
699 
700  if (!op) {
701  LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", pl->ob->name, tag);
702  return;
703  }
704  apply_by_living(pl->ob, op, 0, 0);
705 }
706 
708 void lock_item_cmd(uint8_t *data, int len, player *pl) {
709  int flag, tag;
710  object *op;
711  object *tmp;
712  char name[HUGE_BUF];
713 
714  if (len != 5) {
715  LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name);
716  return;
717  }
718  flag = data[0];
719  tag = GetInt_String(data+1);
720  op = esrv_get_ob_from_count(pl->ob, tag);
721 
722  if (!op) {
724  "Could not find object to lock/unlock");
725  return;
726  }
727 
728  if (op->map) {
730  "Can't lock/unlock an item on the ground");
731  return;
732  }
733  if (op->env != pl->ob) {
735  "Can't lock/unlock an item not directly in your inventory");
736  return;
737  }
738 
739  query_short_name(op, name, HUGE_BUF);
740  if (!flag) {
743  "Unlocked %s.", name);
744  } else {
747  "Locked %s.", name);
748  }
749 
750  tmp = object_merge(op, NULL);
751  if (tmp == NULL) {
752  /* object was not merged - if it was, object_merge() sent updates for us. */
753  esrv_update_item(UPD_FLAGS, pl->ob, op);
754  }
755 }
756 
767 void mark_item_cmd(uint8_t *data, int len, player *pl) {
768  int tag;
769  object *op;
770  char name[MAX_BUF];
771 
772  if (len != 4) {
773  LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name);
774  return;
775  }
776 
777  tag = GetInt_String(data);
778  op = esrv_get_ob_from_count(pl->ob, tag);
779  if (!op) {
781  "Could not find object to mark");
782  return;
783  }
784  pl->mark = op;
785  pl->mark_count = op->count;
786  query_name(op, name, MAX_BUF);
788  "Marked item %s",
789  name);
790 }
791 
798 void look_at(object *op, int dx, int dy) {
799  object *tmp;
800  int flag = 0;
801  int16_t x, y;
802  mapstruct *m;
803  char name[MAX_BUF];
804 
805  if (out_of_map(op->map, op->x+dx, op->y+dy))
806  return;
807 
808  x = op->x+dx;
809  y = op->y+dy;
810 
811  m = get_map_from_coord(op->map, &x, &y);
812  if (!m)
813  return;
814 
815  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
816  ;
817 
819  if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ))
820  continue;
821 
822  if (!flag) {
823  if (dx || dy)
825  "There you see:");
826  else {
828  "You see:");
829  }
830  flag = 1;
831  }
832 
833  query_name(tmp, name, MAX_BUF);
834  if (QUERY_FLAG(op, FLAG_WIZ))
836  "- %s (%d).",
837  name, tmp->count);
838  else
840  "- %s.",
841  name);
842 
843  if ((HEAD(tmp)->inv != NULL && (tmp->type != CONTAINER && tmp->type != FLESH))
844  || QUERY_FLAG(op, FLAG_WIZ))
845  inventory(op, HEAD(tmp));
846 
847  /* don't continue under the floor */
848  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !QUERY_FLAG(op, FLAG_WIZ))
849  break;
851 
852  if (!flag) {
853  if (dx || dy)
855  "You see nothing there.");
856  else
858  "You see nothing.");
859  }
860 }
861 
862 static bool player_can_see(player *pl, int dx, int dy) {
863  // TODO: de-duplicate this with darkness check in draw_client_map2()
864  const int darkness = pl->blocked_los[dx+(pl->socket->mapx/2)][dy+(pl->socket->mapy/2)];
865  return darkness < MAX_LIGHT_RADII;
866 }
867 
869 void look_at_cmd(char *buf, int len, player *pl) {
870  int dx, dy;
871  char *cp;
872 
873  if (len <= 0 || !buf) {
874  LOG(llevDebug, "Player '%s' sent bogus look_at_cmd information\n", pl->ob->name);
875  return;
876  }
877 
878  dx = atoi(buf);
879  if (!(cp = strchr(buf, ' '))) {
880  return;
881  }
882  dy = atoi(cp);
883 
884  if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2) {
886  "You can't see there from where you're standing.");
887  return;
888  }
889 
890  if (!player_can_see(pl, dx, dy)) {
892  "You can't see there from where you're standing.");
893  return;
894  }
895  look_at(pl->ob, dx, dy);
896 }
897 
899 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) {
900  object *op, *env;
901 
902  op = esrv_get_ob_from_count(pl, tag);
903  if (!op) {
904  LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag);
905  return;
906  }
907 
908  /* If on a transport, you don't drop to the ground - you drop to the
909  * transport.
910  */
911  if (!to && !pl->contr->transport) { /* drop it to the ground */
912  /* LOG(llevDebug, "Drop it on the ground.\n");*/
913 
914  if (op->map && !op->env) {
915 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/
916  return;
917  }
918  /* If it is an active container, then we should drop all objects
919  * in the container and not the container itself.
920  */
921  if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
922  FOR_INV_PREPARE(op, current)
923  drop_object(pl, current, 0);
924  FOR_INV_FINISH();
925  esrv_update_item(UPD_WEIGHT, pl, op);
926  } else {
927  drop_object(pl, op, nrof);
928  }
929  return;
930  } else if (to == pl->count) { /* pick it up to the inventory */
931  /* return if player has already picked it up */
932  if (op->env == pl)
933  return;
934 
935  pl->contr->count = nrof;
936  pick_up(pl, op);
937  return;
938  }
939  /* If not dropped or picked up, we are putting it into a sack */
940  if (pl->contr->transport) {
941  if (object_can_pick(pl, op)
942  && transport_can_hold(pl->contr->transport, op, nrof)) {
943  put_object_in_sack(pl, pl->contr->transport, op, nrof);
944  }
945  } else {
946  env = esrv_get_ob_from_count(pl, to);
947  if (!env) {
948  LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to);
949  return;
950  }
951  /* put_object_in_sack presumes that necessary sanity checking
952  * has already been done (eg, it can be picked up and fits in
953  * in a sack, so check for those things. We should also check
954  * an make sure env is in fact a container for that matter.
955  */
956  if (env->type == CONTAINER
957  && object_can_pick(pl, op)
958  && sack_can_hold(pl, env, op, nrof)) {
959  put_object_in_sack(pl, env, op, nrof);
960  }
961  }
962 }
963 
964 void inscribe_scroll_cmd(char *buf, int len, player *pl) {
965  object *scroll, *spell, *marked, *inscription, *currentspell;
966  tag_t tscroll, tspell, tmarked;
967  char type;
968 
969  if (len < 1) {
970  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
971  return;
972  }
973 
974  type = buf[0];
975 
976  inscription = find_skill_by_name(pl->ob, "inscription");
977  if (!inscription) {
978  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!");
979  return;
980  }
981 
982  if (type == 0) {
983  if (len != 9) {
984  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
985  return;
986  }
987  tscroll = GetInt_String((uint8_t *)buf+1);
988  tspell = GetInt_String((uint8_t *)buf+5);
989 
990  scroll = esrv_get_ob_from_count(pl->ob, tscroll);
991  if (!scroll) {
992  LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name);
993  return;
994  }
995 
996  spell = esrv_get_ob_from_count(pl->ob, tspell);
997  if (!spell) {
998  LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name);
999  return;
1000  }
1001 
1002  tmarked = pl->mark_count;
1003  marked = pl->mark;
1004  currentspell = pl->ranges[range_magic];
1005 
1006  pl->mark_count = tscroll;
1007  pl->mark = scroll;
1008  pl->ranges[range_magic] = spell;
1009 
1010  write_on_item(pl->ob, "", inscription);
1011 
1012  pl->mark_count = tmarked;
1013  pl->mark = marked;
1014  pl->ranges[range_magic] = currentspell;
1015  } else {
1016  }
1017 }
Error, serious thing.
Definition: logger.h:11
#define FLAG_KNOWN_BLESSED
Item is known to be blessed.
Definition: define.h:366
void do_dump(object *who, object *what)
Definition: c_wiz.cpp:2865
void SockList_AddPrintf(SockList *sl, const char *format,...)
Adds a printf like formatted string.
Definition: lowlevel.cpp:202
void esrv_send_inventory(object *pl, object *op)
Sends inventory of a container.
Definition: item.cpp:316
object * ranges[range_size]
Object for each range.
Definition: player.h:118
#define FLAG_DAMNED
The object is very cursed.
Definition: define.h:305
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:223
static bool player_can_see(player *pl, int dx, int dy)
Definition: item.cpp:862
See Ring.
Definition: object.h:190
void SockList_Reset(SockList *sl)
Resets the length of the stored data for writing.
Definition: lowlevel.cpp:74
#define NS_FACESENT_FACE
Bitmask for the faces_sent[] array - what portion of the face have we sent?
Definition: newserver.h:141
#define MAX_LIGHT_RADII
Max radii for &#39;light&#39; object, really large values allow objects that can slow down the game...
Definition: define.h:450
void SockList_Init(SockList *sl)
Initializes the SockList instance.
Definition: lowlevel.cpp:55
void look_at(object *op, int dx, int dy)
Prints items on the specified square.
Definition: item.cpp:798
void apply_cmd(char *buf, int len, player *pl)
Client wants to apply some object.
Definition: item.cpp:668
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
See Bracers.
Definition: object.h:222
#define FABS(x)
Decstations have trouble with fabs()...
Definition: define.h:22
int GetInt_String(const unsigned char *data)
Basically does the reverse of SockList_AddInt, but on strings instead.
Definition: lowlevel.cpp:254
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:552
#define UPD_ANIM
Definition: newclient.h:335
Defines various flags that both the new client and new server use.
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
#define F_LOCKED
Definition: newclient.h:306
See Cloak.
Definition: object.h:209
uint16_t look_position
Start of drawing of look window.
Definition: newserver.h:118
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:290
#define LOOK_OBJ(ob)
This returns TRUE if the object is something that should be displayed in the look window...
Definition: object.h:521
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
uint32_t count
Any numbers typed before a command.
Definition: player.h:124
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
#define MSG_TYPE_COMMAND_EXAMINE
Player examining something.
Definition: newclient.h:553
void SockList_AddShort(SockList *sl, uint16_t data)
Adds a 16 bit value.
Definition: lowlevel.cpp:116
Socket structure, represents a client-server connection.
Definition: newserver.h:93
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.cpp:610
object * above
Pointer to the object stacked above this one.
Definition: object.h:296
See Weapon.
Definition: object.h:124
See Helmet.
Definition: object.h:141
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Array showing what spaces the player can see.
Definition: player.h:180
bool player_can_find(object *op, object *ob)
Return true if player &#39;op&#39; can see object &#39;op&#39; for purpose of locating items for partial item matchin...
Definition: item.cpp:590
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: container.cpp:66
See Rod.
Definition: object.h:114
int16_t y
Position in the map for this object.
Definition: object.h:335
#define FLAG_BLESSED
Item has a blessing, opposite of cursed/damned.
Definition: define.h:365
uint16_t container_position
Start of container contents to send to client.
Definition: newserver.h:119
void SockList_AddInt(SockList *sl, uint32_t data)
Adds a 32 bit value.
Definition: lowlevel.cpp:127
See Girdle.
Definition: object.h:228
See Amulet.
Definition: object.h:144
#define MAX(x, y)
Definition: compat.h:24
#define F_DAMNED
Definition: newclient.h:303
int16_t x
Definition: object.h:335
animal &#39;body parts&#39; -b.t.
Definition: object.h:192
Global type definitions and header inclusions.
#define safe_strncpy
Definition: compat.h:27
See Boots.
Definition: object.h:217
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
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.cpp:308
uint8_t anim_speed
Ticks between animation-frames.
Definition: object.h:429
See Wand & Staff.
Definition: object.h:225
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:777
#define MIN(x, y)
Definition: compat.h:21
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
object * transport
Transport the player is in.
Definition: player.h:216
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:307
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
void look_at_cmd(char *buf, int len, player *pl)
Client wants to look at some object.
Definition: item.cpp:869
#define MAP_IN_MEMORY
Map is fully loaded.
Definition: map.h:129
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:108
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
See Shooting Weapon.
Definition: object.h:123
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Living thing is applying an object.
Definition: apply.cpp:299
#define F_UNPAID
Definition: newclient.h:300
See Book.
Definition: object.h:119
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:126
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:551
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:550
#define FLAG_CLIENT_SENT
We use it to detect cases were the server is trying to send an upditem when we have not actually sent...
Definition: define.h:336
float speed
Frequency of object &#39;moves&#39; relative to server tick rate.
Definition: object.h:337
#define F_BLESSED
Definition: newclient.h:307
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:360
object * env
Pointer to the object which is the environment.
Definition: object.h:301
#define SET_FLAG(xyz, p)
Definition: define.h:384
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
#define F_READ
Definition: newclient.h:308
void SockList_Term(SockList *sl)
Frees all resources allocated by a SockList instance.
Definition: lowlevel.cpp:65
#define F_NOPICK
Definition: newclient.h:305
#define F_MAGIC
Definition: newclient.h:301
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
#define FLAG_IDENTIFIED
Item is identifiable (e.g.
Definition: define.h:248
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
socket_struct * socket
Socket information for this player.
Definition: player.h:109
This is a game-map.
Definition: map.h:320
const Animations * animation
Animation of this item, NULL if not animated.
Definition: object.h:428
#define WEIGHT(op)
Returns the weight of the given object.
Definition: define.h:674
int out_of_map(mapstruct *m, int x, int y)
Return 1 if coordinates X and Y are out of the map M, taking into account tiling. ...
Definition: map.cpp:2323
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
void SockList_AddString(SockList *sl, const char *data)
Adds a string without length.
Definition: lowlevel.cpp:157
void esrv_draw_look(object *pl)
Send the look window.
Definition: item.cpp:193
object * ob
The object representing the player.
Definition: player.h:179
const Face * face
Face with colors.
Definition: object.h:341
void examine_cmd(char *buf, int len, player *pl)
Client wants to examine some object.
Definition: item.cpp:646
Defines various structures and values that are used for the new client server communication method...
int is_identified(const object *op)
Return true if the item is identified, either because it is of a type that doesn&#39;t ever need identifi...
Definition: item.cpp:1357
#define UPD_FLAGS
Definition: newclient.h:331
uint32_t mark_count
Count of marked object.
Definition: player.h:214
void examine(object *op, object *tmp)
Player examines some object.
Definition: c_object.cpp:1937
int32_t last_weight
Last weight as sent to client; -1 means do not send weight.
Definition: player.h:160
#define MSG_TYPE_SKILL_FAILURE
Failure in using skill.
Definition: newclient.h:626
size_t SockList_Avail(const SockList *sl)
Returns the available bytes in a SockList instance.
Definition: lowlevel.cpp:246
uint32_t update_inventory
If true, we need to send the inventory list.
Definition: newserver.h:109
#define MAXITEMLEN
This is the maximum number of bytes we expect any one item to take up.
Definition: item.cpp:36
uint16_t number
This is the image unique identifier.
Definition: face.h:15
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Move an object to a new location.
Definition: item.cpp:899
#define UPD_WEIGHT
Definition: newclient.h:332
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
void mark_item_cmd(uint8_t *data, int len, player *pl)
Client wants to mark some object.
Definition: item.cpp:767
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:609
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
#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.cpp:889
#define F_OPEN
Definition: newclient.h:304
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
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.cpp:2351
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
uint8_t mapx
Definition: newserver.h:120
#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:237
#define UPD_ANIMSPEED
Definition: newclient.h:336
object * mark
Marked object.
Definition: player.h:215
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.cpp:3852
See Container.
Definition: object.h:236
uint32_t in_memory
Combination of IN_MEMORY_xxx flags.
Definition: map.h:340
static const flag_definition flags[]
Flag mapping.
void inventory(object *op, object *inv)
Prints object&#39;s inventory.
Definition: c_object.cpp:2117
void SockList_AddChar(SockList *sl, unsigned char c)
Adds an 8 bit value.
Definition: lowlevel.cpp:106
#define FOR_MAP_FINISH()
Finishes FOR_MAP_PREPARE().
Definition: define.h:753
#define F_UNIDENTIFIED
Definition: newclient.h:299
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:308
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.cpp:2036
#define FLAG_CURSED
The object is cursed.
Definition: define.h:304
See Shield.
Definition: object.h:140
#define FLAG_ANIMATE
The object looks at archetype for faces.
Definition: define.h:229
uint16_t num
Where we are in the array.
Definition: face.h:29
Object structure, the core of Crossfire.
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:692
#define MAP_CLIENT_Y
Definition: config.h:238
const Face * empty_face
Definition: image.cpp:36
static event_registration m
Definition: citylife.cpp:424
object * container
Current container being used.
Definition: object.h:299
void esrv_send_animation(socket_struct *ns, const Animations *anim)
Need to send an animation sequence to the client.
Definition: request.cpp:1038
void lock_item_cmd(uint8_t *data, int len, player *pl)
Client wants to apply some object.
Definition: item.cpp:708
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Sends a face to a client if they are in pixmap mode, nothing gets sent in bitmap mode.
Definition: image.cpp:72
#define UPD_NROF
Definition: newclient.h:337
Also see SKILL_TOOL (74) below.
Definition: object.h:148
sstring name
The name of the object, obviously...
Definition: object.h:319
#define UPD_FACE
Definition: newclient.h:333
Only for debugging purposes.
Definition: logger.h:13
uint32_t nrof
Number of objects.
Definition: object.h:342
uint8_t anims_sent[MAXANIMNUM]
What animations we sent.
Definition: newserver.h:101
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: item.cpp:414
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Adds a data block prepended with an 8 bit length field.
Definition: lowlevel.cpp:179
#define CLEAR_FLAG(xyz, p)
Definition: define.h:385
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
#define UPD_LOCATION
Definition: newclient.h:330
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.cpp:54
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
void esrv_send_item(object *pl, object *op)
Sends item&#39;s info to player.
Definition: item.cpp:522
#define UPD_NAME
Definition: newclient.h:334
uint16_t client_type
Public type information.
Definition: object.h:350
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
#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:773
#define GET_MAP_OB(M, X, Y)
Gets the bottom object on a map.
Definition: map.h:173
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:424
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
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.cpp:122
See Gloves.
Definition: object.h:218
Spells.
Definition: player.h:32
bool pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.cpp:470
One player.
Definition: player.h:107
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Constructs a loop iterating over all objects of a map tile.
Definition: define.h:746
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.cpp:964
StringBuffer * buf
Definition: readable.cpp:1563
Contains the base information we use to make up a packet we want to send.
Definition: newclient.h:721
const char * sstring
Definition: sstring.h:2
tag_t count
Unique object number for this object.
Definition: object.h:307
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:226
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.cpp:1771
#define FLAG_NO_SKILL_IDENT
If set, item cannot be identified w/ a skill.
Definition: define.h:323
See Breastplate Armor.
Definition: object.h:125
uint8_t mapy
How large a map the client wants.
Definition: newserver.h:120
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn&#39;t contain any information about object...
Definition: item.cpp:518
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:317
object * drop_object(object *op, object *tmp, uint32_t nrof)
Try to drop an object on the floor.
Definition: c_object.cpp:1025
void esrv_del_item(player *pl, object *ob)
Tells the client to delete an item.
Definition: item.cpp:562
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.cpp:209
uint8_t * faces_sent
This is a bitmap on sent face status.
Definition: newserver.h:100
#define F_CURSED
Definition: newclient.h:302
#define CUSTOM_NAME_FIELD
Key in an object for the player-assigned custom name.
Definition: object.h:98
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
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.cpp:49
void Send_With_Handling(socket_struct *ns, SockList *sl)
Calls Write_To_Socket to send data to the client.
Definition: lowlevel.cpp:447
static object * ob_if_can_find(object *op, object *ob)
Return object &#39;ob&#39; if player &#39;op&#39; can find it, otherwise return NULL.
Definition: item.cpp:597