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 
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 
615  if (op->count == count)
616  return ob_if_can_find(pl, op);
617  else if (op->type == CONTAINER && pl->container == op) {
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) {
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);
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);
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);
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 
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. */
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 
779  if (!op) {
781  "Could not find object to mark");
782  return;
783  }
784  pl->mark = op;
785  pl->mark_count = op->count;
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 
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 */
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 
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)) {
923  drop_object(pl, current, 0);
924  FOR_INV_FINISH();
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 {
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 }
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:170
MAP_CLIENT_X
#define MAP_CLIENT_X
Definition: config.h:237
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.cpp:127
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:899
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:58
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:767
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:157
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:2845
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:646
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:74
mapstruct::path
char path[HUGE_BUF]
Definition: map.h:353
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:1565
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:246
LOOK_OBJ
#define LOOK_OBJ(ob)
Definition: object.h:521
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:126
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:708
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:429
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:588
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:607
range_magic
@ range_magic
Definition: player.h:32
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.cpp:116
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:513
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.cpp:106
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:2289
player_can_see
static bool player_can_see(player *pl, int dx, int dy)
Definition: item.cpp:862
is_identified
int is_identified(const object *op)
Definition: item.cpp:1348
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:610
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:2362
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:428
RING
@ RING
Definition: object.h:190
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.cpp:55
F_NOPICK
#define F_NOPICK
Definition: newclient.h:279
player_can_find
bool player_can_find(object *op, object *ob)
Definition: item.cpp:590
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:2168
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:65
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:1045
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:313
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:597
SockList_AddLen8Data
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.cpp:179
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:798
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:668
MAXITEMLEN
#define MAXITEMLEN
Definition: item.cpp:36
GetInt_String
int GetInt_String(const unsigned char *data)
Definition: lowlevel.cpp:254
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:869
inscribe_scroll_cmd
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.cpp:964
F_LOCKED
#define F_LOCKED
Definition: newclient.h:280
inventory
void inventory(object *op, object *inv)
Definition: c_object.cpp:2167
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:689
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:1985
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:447
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
MAX_LIGHT_RADII
#define MAX_LIGHT_RADII
Definition: define.h:450
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:202
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