Crossfire Server, Trunk
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))
93 
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;
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 
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 
227  if (!(pl->contr->socket->faces_sent[empty_face->number]&NS_FACESENT_FACE))
228  esrv_send_face(pl->contr->socket, empty_face, 0);
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) {
248  add_object_to_socklist(pl->contr->socket, &sl, 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 
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);
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);
446 
447  if (flags&UPD_LOCATION)
448  SockList_AddInt(&sl, op->env ? op->env->count : 0);
449 
450  if (flags&UPD_FLAGS)
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  SockList_Init(&sl);
566  SockList_AddString(&sl, "delitem ");
567  SockList_AddInt(&sl, ob->count);
568  Send_With_Handling(pl->socket, &sl);
569  SockList_Term(&sl);
570  /* if the object is in an opened container, then it may shift the contents,
571  * so resend everything */
572  if (pl->ob->container != NULL && ob->env == pl->ob->container)
573  pl->socket->update_inventory = 1;
574 }
575 
576 /**************************************************************************
577  *
578  * Client has requested us to do something with an object.
579  *
580  **************************************************************************
581  */
582 
587 bool player_can_find(object *op, object *ob) {
588  return QUERY_FLAG(op, FLAG_WIZ) || !ob->invisible;
589 }
590 
594 static object *ob_if_can_find(object *op, object *ob) {
595  if (player_can_find(op, ob)) {
596  return ob;
597  } else {
598  return NULL;
599  }
600 }
601 
607 static object *esrv_get_ob_from_count(object *pl, tag_t count) {
608  if (pl->count == count)
609  return pl;
610 
612  if (op->count == count)
613  return ob_if_can_find(pl, op);
614  else if (op->type == CONTAINER && pl->container == op) {
616  if (tmp->count == count)
617  return ob_if_can_find(pl, tmp);
618  FOR_INV_FINISH();
619  }
620  FOR_INV_FINISH();
621 
622  FOR_MAP_PREPARE(pl->map, pl->x, pl->y, op)
623  if (HEAD(op)->count == count)
624  return ob_if_can_find(pl, op);
625  else if (op->type == CONTAINER && pl->container == op) {
627  if (tmp->count == count)
628  return ob_if_can_find(pl, tmp);
629  FOR_INV_FINISH();
630  }
631  FOR_MAP_FINISH();
632 
633  if (pl->contr->transport) {
634  FOR_INV_PREPARE(pl->contr->transport, tmp)
635  if (tmp->count == count)
636  return ob_if_can_find(pl, tmp);
637  FOR_INV_FINISH();
638  }
639  return NULL;
640 }
641 
643 void examine_cmd(char *buf, int len, player *pl) {
644  long tag;
645  object *op;
646 
647  if (len <= 0 || !buf) {
648  LOG(llevDebug, "Player '%s' sent bogus examine_cmd information\n", pl->ob->name);
649  return;
650  }
651 
652  tag = atoi(buf);
654  if (!op) {
655  LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", pl->ob->name, tag);
656  return;
657  }
658  examine(pl->ob, op);
659  if (QUERY_FLAG(pl->ob, FLAG_WIZ)) {
660  do_dump(pl->ob, op);
661  }
662 }
663 
665 void apply_cmd(char *buf, int len, player *pl) {
666  uint32_t tag;
667  object *op;
668 
669  if (!buf || len <= 0) {
670  LOG(llevDebug, "Player '%s' sent bogus apply_cmd information\n", pl->ob->name);
671  return;
672  }
673 
674  tag = atoi(buf);
676 
677  /* sort of a hack, but if the player saves and the player then
678  * manually applies a savebed (or otherwise tries to do stuff),
679  * we run into trouble.
680  */
681  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
682  return;
683 
684  /* If the high bit is set, player applied a pseudo object. */
685  if (tag&0x80000000) {
686  if (pl->ob->container != NULL) {
687  pl->socket->container_position = tag&0x7fffffff;
688  esrv_send_inventory(pl->ob, pl->ob->container);
689  pl->socket->update_inventory = 0;
690  } else {
691  pl->socket->look_position = tag&0x7fffffff;
692  pl->socket->update_look = 1;
693  }
694  return;
695  }
696 
697  if (!op) {
698  LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", pl->ob->name, tag);
699  return;
700  }
701  apply_by_living(pl->ob, op, 0, 0);
702 }
703 
705 void lock_item_cmd(uint8_t *data, int len, player *pl) {
706  int flag, tag;
707  object *op;
708  object *tmp;
709  char name[HUGE_BUF];
710 
711  if (len != 5) {
712  LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name);
713  return;
714  }
715  flag = data[0];
716  tag = GetInt_String(data+1);
718 
719  if (!op) {
721  "Could not find object to lock/unlock");
722  return;
723  }
724 
725  if (op->map) {
727  "Can't lock/unlock an item on the ground");
728  return;
729  }
730  if (op->env != pl->ob) {
732  "Can't lock/unlock an item not directly in your inventory");
733  return;
734  }
735 
737  if (!flag) {
740  "Unlocked %s.", name);
741  } else {
744  "Locked %s.", name);
745  }
746 
747  tmp = object_merge(op, NULL);
748  if (tmp == NULL) {
749  /* object was not merged - if it was, object_merge() sent updates for us. */
751  }
752 }
753 
764 void mark_item_cmd(uint8_t *data, int len, player *pl) {
765  int tag;
766  object *op;
767  char name[MAX_BUF];
768 
769  if (len != 4) {
770  LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name);
771  return;
772  }
773 
776  if (!op) {
778  "Could not find object to mark");
779  return;
780  }
781  pl->mark = op;
782  pl->mark_count = op->count;
785  "Marked item %s",
786  name);
787 }
788 
795 void look_at(object *op, int dx, int dy) {
796  object *tmp;
797  int flag = 0;
798  int16_t x, y;
799  mapstruct *m;
800  char name[MAX_BUF];
801 
802  if (out_of_map(op->map, op->x+dx, op->y+dy))
803  return;
804 
805  x = op->x+dx;
806  y = op->y+dy;
807 
808  m = get_map_from_coord(op->map, &x, &y);
809  if (!m)
810  return;
811 
812  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
813  ;
814 
816  if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ))
817  continue;
818 
819  if (!flag) {
820  if (dx || dy)
822  "There you see:");
823  else {
825  "You see:");
826  }
827  flag = 1;
828  }
829 
831  if (QUERY_FLAG(op, FLAG_WIZ))
833  "- %s (%d).",
834  name, tmp->count);
835  else
837  "- %s.",
838  name);
839 
840  if ((HEAD(tmp)->inv != NULL && (tmp->type != CONTAINER && tmp->type != FLESH))
841  || QUERY_FLAG(op, FLAG_WIZ))
842  inventory(op, HEAD(tmp));
843 
844  /* don't continue under the floor */
846  break;
848 
849  if (!flag) {
850  if (dx || dy)
852  "You see nothing there.");
853  else
855  "You see nothing.");
856  }
857 }
858 
860 void look_at_cmd(char *buf, int len, player *pl) {
861  int dx, dy;
862  char *cp;
863 
864  if (len <= 0 || !buf) {
865  LOG(llevDebug, "Player '%s' sent bogus look_at_cmd information\n", pl->ob->name);
866  return;
867  }
868 
869  dx = atoi(buf);
870  if (!(cp = strchr(buf, ' '))) {
871  return;
872  }
873  dy = atoi(cp);
874 
875  if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2) {
877  "You can't see there from where you're standing.");
878  return;
879  }
880 
881  if (pl->blocked_los[dx+(pl->socket->mapx/2)][dy+(pl->socket->mapy/2)]) {
883  "You can't see there from where you're standing.");
884  return;
885  }
886  look_at(pl->ob, dx, dy);
887 }
888 
890 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) {
891  object *op, *env;
892 
894  if (!op) {
895  LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag);
896  return;
897  }
898 
899  /* If on a transport, you don't drop to the ground - you drop to the
900  * transport.
901  */
902  if (!to && !pl->contr->transport) { /* drop it to the ground */
903  /* LOG(llevDebug, "Drop it on the ground.\n");*/
904 
905  if (op->map && !op->env) {
906 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/
907  return;
908  }
909  /* If it is an active container, then we should drop all objects
910  * in the container and not the container itself.
911  */
912  if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
914  drop_object(pl, current, 0);
915  FOR_INV_FINISH();
917  } else {
918  drop_object(pl, op, nrof);
919  }
920  return;
921  } else if (to == pl->count) { /* pick it up to the inventory */
922  /* return if player has already picked it up */
923  if (op->env == pl)
924  return;
925 
926  pl->contr->count = nrof;
927  pick_up(pl, op);
928  return;
929  }
930  /* If not dropped or picked up, we are putting it into a sack */
931  if (pl->contr->transport) {
932  if (object_can_pick(pl, op)
933  && transport_can_hold(pl->contr->transport, op, nrof)) {
934  put_object_in_sack(pl, pl->contr->transport, op, nrof);
935  }
936  } else {
938  if (!env) {
939  LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to);
940  return;
941  }
942  /* put_object_in_sack presumes that necessary sanity checking
943  * has already been done (eg, it can be picked up and fits in
944  * in a sack, so check for those things. We should also check
945  * an make sure env is in fact a container for that matter.
946  */
947  if (env->type == CONTAINER
948  && object_can_pick(pl, op)
949  && sack_can_hold(pl, env, op, nrof)) {
950  put_object_in_sack(pl, env, op, nrof);
951  }
952  }
953 }
954 
955 void inscribe_scroll_cmd(char *buf, int len, player *pl) {
956  object *scroll, *spell, *marked, *inscription, *currentspell;
957  tag_t tscroll, tspell, tmarked;
958  char type;
959 
960  if (len < 1) {
961  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
962  return;
963  }
964 
965  type = buf[0];
966 
967  inscription = find_skill_by_name(pl->ob, "inscription");
968  if (!inscription) {
969  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!");
970  return;
971  }
972 
973  if (type == 0) {
974  if (len != 9) {
975  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
976  return;
977  }
978  tscroll = GetInt_String((uint8_t *)buf+1);
979  tspell = GetInt_String((uint8_t *)buf+5);
980 
981  scroll = esrv_get_ob_from_count(pl->ob, tscroll);
982  if (!scroll) {
983  LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name);
984  return;
985  }
986 
987  spell = esrv_get_ob_from_count(pl->ob, tspell);
988  if (!spell) {
989  LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name);
990  return;
991  }
992 
993  tmarked = pl->mark_count;
994  marked = pl->mark;
995  currentspell = pl->ranges[range_magic];
996 
997  pl->mark_count = tscroll;
998  pl->mark = scroll;
999  pl->ranges[range_magic] = spell;
1000 
1001  write_on_item(pl->ob, "", inscription);
1002 
1003  pl->mark_count = tmarked;
1004  pl->mark = marked;
1005  pl->ranges[range_magic] = currentspell;
1006  } else {
1007  }
1008 }
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:171
MAP_CLIENT_X
#define MAP_CLIENT_X
Definition: config.h:237
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.cpp:124
global.h
UPD_FACE
#define UPD_FACE
Definition: newclient.h:306
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Definition: newserver.h:137
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
esrv_move_object
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.cpp:890
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:519
BOW
@ BOW
Definition: object.h:123
BRACERS
@ BRACERS
Definition: object.h:222
F_OPEN
#define F_OPEN
Definition: newclient.h:278
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
WAND
@ WAND
Definition: object.h:225
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
mark_item_cmd
void mark_item_cmd(uint8_t *data, int len, player *pl)
Definition: item.cpp:764
FLESH
@ FLESH
Definition: object.h:192
player
Definition: player.h:105
object::client_type
uint16_t client_type
Definition: object.h:350
GLOVES
@ GLOVES
Definition: object.h:218
GIRDLE
@ GIRDLE
Definition: object.h:228
F_UNPAID
#define F_UNPAID
Definition: newclient.h:274
diamondslots.x
x
Definition: diamondslots.py:15
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:396
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
socket_struct
Definition: newserver.h:89
object_merge
object * object_merge(object *op, object *top)
Definition: object.cpp:2051
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:305
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.cpp:154
object::speed
float speed
Definition: object.h:337
object::x
int16_t x
Definition: object.h:335
ARMOUR
@ ARMOUR
Definition: object.h:125
object::map
struct mapstruct * map
Definition: object.h:305
UPD_LOCATION
#define UPD_LOCATION
Definition: newclient.h:303
do_dump
void do_dump(object *who, object *what)
Definition: c_wiz.cpp:2831
WEAPON
@ WEAPON
Definition: object.h:124
guildjoin.ob
ob
Definition: guildjoin.py:42
write_on_item
int write_on_item(object *pl, const char *params, object *skill)
Definition: skills.cpp:1762
commongive.inv
inv
Definition: commongive.py:29
AMULET
@ AMULET
Definition: object.h:144
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
MIN
#define MIN(x, y)
Definition: compat.h:21
SKILL
@ SKILL
Definition: object.h:148
examine_cmd
void examine_cmd(char *buf, int len, player *pl)
Definition: item.cpp:643
object::count
tag_t count
Definition: object.h:307
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.cpp:101
MSG_TYPE_COMMAND_EXAMINE
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:521
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: item.cpp:414
Ice.tmp
int tmp
Definition: Ice.py:207
FLAG_BLESSED
#define FLAG_BLESSED
Definition: define.h:369
UPD_NROF
#define UPD_NROF
Definition: newclient.h:310
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:518
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.cpp:71
mapstruct::path
char path[HUGE_BUF]
Definition: map.h:355
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4342
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
a_active
@ a_active
Definition: newclient.h:270
buf
StringBuffer * buf
Definition: readable.cpp:1560
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:393
MAX
#define MAX(x, y)
Definition: compat.h:24
F_READ
#define F_READ
Definition: newclient.h:282
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.cpp:243
LOOK_OBJ
#define LOOK_OBJ(ob)
Definition: object.h:512
object::y
int16_t y
Definition: object.h:335
m
static event_registration m
Definition: citylife.cpp:425
CLOAK
@ CLOAK
Definition: object.h:209
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:127
a_readied
@ a_readied
Definition: newclient.h:270
lock_item_cmd
void lock_item_cmd(uint8_t *data, int len, player *pl)
Definition: item.cpp:705
MAP_CLIENT_Y
#define MAP_CLIENT_Y
Definition: config.h:238
HELMET
@ HELMET
Definition: object.h:141
add_object_to_socklist
static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head)
Definition: item.cpp:122
F_DAMNED
#define F_DAMNED
Definition: newclient.h:277
object::anim_speed
uint8_t anim_speed
Definition: object.h:427
esrv_send_face
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Definition: image.cpp:72
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:592
FLAG_KNOWN_BLESSED
#define FLAG_KNOWN_BLESSED
Definition: define.h:370
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
Definition: define.h:320
Face::number
uint16_t number
Definition: face.h:15
a_applied
@ a_applied
Definition: newclient.h:270
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:754
HEAD
#define HEAD(op)
Definition: object.h:598
range_magic
@ range_magic
Definition: player.h:32
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.cpp:113
transport_can_hold
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.cpp:54
ROD
@ ROD
Definition: object.h:114
CONTAINER
@ CONTAINER
Definition: object.h:236
object::below
object * below
Definition: object.h:295
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.cpp:517
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.cpp:103
object::face
const Face * face
Definition: object.h:341
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.cpp:2286
is_identified
int is_identified(const object *op)
Definition: item.cpp:1352
F_CURSED
#define F_CURSED
Definition: newclient.h:276
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.cpp:316
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
navar-midane_time.data
data
Definition: navar-midane_time.py:11
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:304
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
F_UNIDENTIFIED
#define F_UNIDENTIFIED
Definition: newclient.h:273
esrv_get_ob_from_count
static object * esrv_get_ob_from_count(object *pl, tag_t count)
Definition: item.cpp:607
disinfect.count
int count
Definition: disinfect.py:7
tag_t
uint32_t tag_t
Definition: object.h:14
sproto.h
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.cpp:2359
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:750
BOOK
@ BOOK
Definition: object.h:119
object::animation
const Animations * animation
Definition: object.h:426
RING
@ RING
Definition: object.h:190
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:52
F_NOPICK
#define F_NOPICK
Definition: newclient.h:279
player_can_find
bool player_can_find(object *op, object *ob)
Definition: item.cpp:587
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.cpp:211
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2170
MAX_BUF
#define MAX_BUF
Definition: define.h:35
drop_object
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.cpp:1073
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.cpp:62
empty_face
const Face * empty_face
Definition: image.cpp:36
FLAG_CLIENT_SENT
#define FLAG_CLIENT_SENT
Definition: define.h:346
F_BLESSED
#define F_BLESSED
Definition: newclient.h:281
UPD_ANIMSPEED
#define UPD_ANIMSPEED
Definition: newclient.h:309
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:520
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
Definition: define.h:319
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
esrv_send_animation
void esrv_send_animation(socket_struct *ns, const Animations *anim)
Definition: request.cpp:1021
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
object::name
sstring name
Definition: object.h:319
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:579
esrv_send_item
void esrv_send_item(object *pl, object *op)
Definition: item.cpp:522
esrv_del_item
void esrv_del_item(player *pl, object *ob)
Definition: item.cpp:562
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.cpp:3863
esrv_draw_look
void esrv_draw_look(object *pl)
Definition: item.cpp:193
newserver.h
mapstruct
Definition: map.h:314
object::env
object * env
Definition: object.h:301
sstring
const typedef char * sstring
Definition: sstring.h:2
give.op
op
Definition: give.py:33
ob_if_can_find
static object * ob_if_can_find(object *op, object *ob)
Definition: item.cpp:594
SockList_AddLen8Data
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:176
apply_by_living
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Definition: apply.cpp:637
diamondslots.y
y
Definition: diamondslots.py:16
look_at
void look_at(object *op, int dx, int dy)
Definition: item.cpp:795
a_wielded
@ a_wielded
Definition: newclient.h:270
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
WEIGHT
#define WEIGHT(op)
Definition: define.h:651
Animations::num
uint16_t num
Definition: face.h:29
socket_struct::anims_sent
uint8_t anims_sent[MAXANIMNUM]
Definition: newserver.h:97
socket_struct::faces_sent
uint8_t * faces_sent
Definition: newserver.h:96
apply_cmd
void apply_cmd(char *buf, int len, player *pl)
Definition: item.cpp:665
MAXITEMLEN
#define MAXITEMLEN
Definition: item.cpp:36
GetInt_String
int GetInt_String(const unsigned char *data)
Definition: lowlevel.cpp:251
make_face_from_files.int
int
Definition: make_face_from_files.py:32
F_MAGIC
#define F_MAGIC
Definition: newclient.h:275
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
UPD_NAME
#define UPD_NAME
Definition: newclient.h:307
newclient.h
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.cpp:308
look_at_cmd
void look_at_cmd(char *buf, int len, player *pl)
Definition: item.cpp:860
inscribe_scroll_cmd
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.cpp:955
F_LOCKED
#define F_LOCKED
Definition: newclient.h:280
inventory
void inventory(object *op, object *inv)
Definition: c_object.cpp:2165
positioning_system.marked
marked
Definition: positioning_system.py:21
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
UPD_ANIM
#define UPD_ANIM
Definition: newclient.h:308
object::nrof
uint32_t nrof
Definition: object.h:342
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.cpp:693
query_flags
static unsigned int query_flags(const object *op)
Definition: item.cpp:49
BOOTS
@ BOOTS
Definition: object.h:217
replace.current
current
Definition: replace.py:64
SHIELD
@ SHIELD
Definition: object.h:140
a_worn
@ a_worn
Definition: newclient.h:270
FLAG_NO_SKILL_IDENT
#define FLAG_NO_SKILL_IDENT
Definition: define.h:335
FLAG_CURSED
#define FLAG_CURSED
Definition: define.h:316
pick_up
void pick_up(object *op, object *alt)
Definition: c_object.cpp:519
examine
void examine(object *op, object *tmp)
Definition: c_object.cpp:1983
sack_can_hold
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Definition: c_object.cpp:317
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.cpp:444
SockList
Definition: newclient.h:670
CUSTOM_NAME_FIELD
#define CUSTOM_NAME_FIELD
Definition: object.h:98
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
object.h
llevDebug
@ llevDebug
Definition: logger.h:13
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.cpp:199
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:261
give.name
name
Definition: give.py:27
put_object_in_sack
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.cpp:937