Crossfire Server, Trunk
item.c
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
13 
25 #include "global.h"
26 
27 #include <stdlib.h>
28 #include <string.h>
29 
30 #include "newserver.h"
31 #include "object.h"
32 #include "shared/newclient.h"
33 #include "sproto.h"
34 
36 #define MAXITEMLEN 300
37 
38 /*************************************************************************
39  *
40  * Functions related to sending object data to the client.
41  *
42  *************************************************************************
43  */
44 
49 static unsigned int query_flags(const object *op) {
50  unsigned int flags = 0;
51 
52  if (QUERY_FLAG(op, FLAG_APPLIED)) {
53  switch (op->type) {
54  case BOW:
55  case WAND:
56  case ROD:
57  flags = a_readied;
58  break;
59 
60  case WEAPON:
61  flags = a_wielded;
62  break;
63 
64  case SKILL:
65  case ARMOUR:
66  case HELMET:
67  case SHIELD:
68  case RING:
69  case BOOTS:
70  case GLOVES:
71  case AMULET:
72  case GIRDLE:
73  case BRACERS:
74  case CLOAK:
75  flags = a_worn;
76  break;
77 
78  case CONTAINER:
79  flags = a_active;
80  break;
81 
82  default:
83  flags = a_applied;
84  break;
85  }
86  }
87  if (op->type == CONTAINER
88  && ((op->env && op->env->container == op) || (!op->env && QUERY_FLAG(op, FLAG_APPLIED))))
89  flags |= F_OPEN;
90 
91  if (!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 
126  flags = query_flags(head);
127  if (QUERY_FLAG(head, FLAG_NO_PICK))
128  flags |= F_NOPICK;
129 
130  if (!(ns->faces_sent[head->face->number]&NS_FACESENT_FACE))
131  esrv_send_face(ns, head->face, 0);
132 
133  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
134  if (head->animation == NULL) {
135  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);
136  CLEAR_FLAG(head, FLAG_ANIMATE);
137  } else if (!ns->anims_sent[head->animation->num])
138  esrv_send_animation(ns, head->animation);
139  }
140 
141  SockList_AddInt(sl, head->count);
142  SockList_AddInt(sl, flags);
143  SockList_AddInt(sl, QUERY_FLAG(head, FLAG_NO_PICK) ? -1 : WEIGHT(head));
144  SockList_AddInt(sl, head->face->number);
145 
146  if (!head->custom_name) {
147  query_base_name(head, 0, item_n, 126);
148  item_n[127] = 0;
149  len = strlen(item_n);
150  query_base_name(head, 1, item_p, MAX_BUF);
151  } else {
152  safe_strncpy(item_n, head->custom_name, 127);
153  item_n[127] = 0;
154  len = strlen(item_n);
155  safe_strncpy(item_p, head->custom_name, sizeof(item_p));
156  }
157  strncpy(item_n+len+1, item_p, 127);
158  /* This is needed because strncpy may not add a ending \0 if the string is long enough. */
159  item_n[len+1+127] = 0;
160  len += strlen(item_n+1+len)+1;
161  SockList_AddLen8Data(sl, item_n, len);
162 
163  SockList_AddShort(sl, (QUERY_FLAG(head, FLAG_ANIMATE) && head->animation) ? head->animation->num : 0);
164  anim_speed = 0;
165  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
166  if (head->anim_speed)
167  anim_speed = head->anim_speed;
168  else {
169  if (FABS(head->speed) < 0.001)
170  anim_speed = 255;
171  else if (FABS(head->speed) >= 1.0)
172  anim_speed = 1;
173  else
174  anim_speed = (int)(1.0/FABS(head->speed));
175  }
176  if (anim_speed > 255)
177  anim_speed = 255;
178  }
179  SockList_AddChar(sl, (char)anim_speed);
180  SockList_AddInt(sl, head->nrof);
181 
182  SockList_AddShort(sl, head->client_type);
183 
184  SET_FLAG(head, FLAG_CLIENT_SENT);
185 }
186 
192 void esrv_draw_look(object *pl) {
193  object *tmp, *last;
194  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
195  SockList sl;
196  char buf[MAX_BUF];
197 
198  if (!pl->contr->socket.update_look) {
199  LOG(llevDebug, "esrv_draw_look called when update_look was not set\n");
200  return;
201  } else {
202  pl->contr->socket.update_look = 0;
203  }
204 
206  || pl->map == NULL
207  || pl->map->in_memory != MAP_IN_MEMORY
208  || out_of_map(pl->map, pl->x, pl->y))
209  return;
210 
211  if (pl->contr->transport)
212  for (tmp = pl->contr->transport->inv; tmp && tmp->above; tmp = tmp->above)
213  ;
214  else
215  for (tmp = GET_MAP_OB(pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above)
216  ;
217 
218  SockList_Init(&sl);
219  SockList_AddString(&sl, "delinv 0");
220  Send_With_Handling(&pl->contr->socket, &sl);
221 
222  SockList_Reset(&sl);
223  SockList_AddPrintf(&sl, "item2 ");
224  SockList_AddInt(&sl, 0);
225 
227  esrv_send_face(&pl->contr->socket, empty_face, 0);
228 
229  if (pl->contr->socket.look_position) {
230  int overhead = 1+(pl->contr->transport != NULL);
231  int prev_len = pl->contr->socket.num_look_objects-overhead-(pl->contr->socket.look_position > pl->contr->socket.num_look_objects-overhead);
232  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.look_position-prev_len));
233  SockList_AddInt(&sl, 0);
234  SockList_AddInt(&sl, -1);
236  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
237  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
238  SockList_AddShort(&sl, 0);
239  SockList_AddChar(&sl, 0);
240  SockList_AddInt(&sl, 0);
241  SockList_AddShort(&sl, 0);
242  objects_sent++;
243  got_one++;
244  }
245 
246  if (pl->contr->transport) {
247  add_object_to_socklist(&pl->contr->socket, &sl, pl->contr->transport);
248  objects_sent++;
249  got_one++;
250  }
251 
252  last = NULL;
254  object *head;
255 
256  if (tmp == last) {
257  break;
258  }
259 
260  if (!QUERY_FLAG(pl, FLAG_WIZ)) {
261  // Unless DM, stop at the first floor or two consecutive floor objects.
262  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) {
263  last = tmp->below; /* assumes double floor mode */
264  if (last && QUERY_FLAG(last, FLAG_IS_FLOOR))
265  last = last->below;
266  }
267  }
268  if (QUERY_FLAG(pl, FLAG_WIZ) || LOOK_OBJ(tmp)) {
269  if (start_look++ < pl->contr->socket.look_position)
270  continue;
271  end_look++;
272  objects_sent++;
273  if (objects_sent >= pl->contr->socket.num_look_objects) {
274  /* What we basically do is make a 'fake' object -
275  * when the user applies it, we notice the special
276  * tag the object has, and act accordingly.
277  */
278  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.look_position+end_look-1));
279  SockList_AddInt(&sl, 0);
280  SockList_AddInt(&sl, -1);
282  snprintf(buf, sizeof(buf), "Click here to see next group of items");
283  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
284  SockList_AddShort(&sl, 0);
285  SockList_AddChar(&sl, 0);
286  SockList_AddInt(&sl, 0);
287  SockList_AddShort(&sl, 0);
288  break;
289  }
290  head = HEAD(tmp);
291  add_object_to_socklist(&pl->contr->socket, &sl, head);
292  got_one++;
293 
294  if (SockList_Avail(&sl) < MAXITEMLEN) {
295  Send_With_Handling(&pl->contr->socket, &sl);
296  SockList_Reset(&sl);
297  SockList_AddPrintf(&sl, "item2 ");
298  SockList_AddInt(&sl, 0);
299  got_one = 0;
300  }
301  } /* If LOOK_OBJ() */
303  if (got_one)
304  Send_With_Handling(&pl->contr->socket, &sl);
305 
306  SockList_Term(&sl);
307 }
308 
315 void esrv_send_inventory(object *pl, object *op) {
316  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
317  SockList sl;
318  char buf[MAX_BUF];
319  int prev_len = pl->contr->socket.num_look_objects - 2 - (((pl->contr->socket.container_position > pl->contr->socket.num_look_objects - 1)) ? 1 : 0);
320 
321  SockList_Init(&sl);
322  SockList_AddPrintf(&sl, "delinv %u", op->count);
323  Send_With_Handling(&pl->contr->socket, &sl);
324 
325  SockList_Reset(&sl);
326  SockList_AddString(&sl, "item2 ");
327  SockList_AddInt(&sl, op->count);
328  objects_sent++;
329 
330  if (pl != op && pl->contr->socket.container_position) {
331  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.container_position-prev_len));
332  SockList_AddInt(&sl, 0);
333  SockList_AddInt(&sl, -1);
335  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
336  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
337  SockList_AddShort(&sl, 0);
338  SockList_AddChar(&sl, 0);
339  SockList_AddInt(&sl, 0);
340  SockList_AddShort(&sl, 0);
341  objects_sent++;
342  got_one++;
343  }
344 
346  object *head;
347 
348  head = HEAD(tmp);
349  if (LOOK_OBJ(head)) {
350  if (start_look++ < pl->contr->socket.container_position && pl != op)
351  continue;
352  end_look++;
353  objects_sent++;
354  if (pl != op && objects_sent >= pl->contr->socket.num_look_objects) {
355  /* What we basically do is make a 'fake' object -
356  * when the user applies it, we notice the special
357  * tag the object has, and act accordingly.
358  */
359  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.container_position + end_look - 1));
360  SockList_AddInt(&sl, 0);
361  SockList_AddInt(&sl, -1);
363  snprintf(buf, sizeof(buf), "Click here to see next group of items");
364  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
365  SockList_AddShort(&sl, 0);
366  SockList_AddChar(&sl, 0);
367  SockList_AddInt(&sl, 0);
368  SockList_AddShort(&sl, 0);
369  break;
370  }
371 
372  add_object_to_socklist(&pl->contr->socket, &sl, head);
373 
374  got_one++;
375 
376  /* It is possible for players to accumulate a huge amount of
377  * items (especially with some of the bags out there) to
378  * overflow the buffer. IF so, send multiple item commands.
379  */
380  if (SockList_Avail(&sl) < MAXITEMLEN) {
381  Send_With_Handling(&pl->contr->socket, &sl);
382  SockList_Reset(&sl);
383  SockList_AddString(&sl, "item2 ");
384  SockList_AddInt(&sl, op->count);
385  got_one = 0;
386  }
387  } /* If LOOK_OBJ() */
388  } FOR_INV_FINISH();
389  if (got_one) {
390  /* special case: only one item, the "prev group" arrow */
391  if (pl != op && pl->contr->socket.container_position) {
392  if (got_one > 1)
393  Send_With_Handling(&pl->contr->socket, &sl);
394  else {
395  /* view shifted, get to previous page and resend */
396  pl->contr->socket.container_position = MAX(0, pl->contr->socket.container_position - prev_len);
398  }
399  } else
400  Send_With_Handling(&pl->contr->socket, &sl);
401  }
402  SockList_Term(&sl);
403 }
404 
413 void esrv_update_item(int flags, object *pl, object *op) {
414  SockList sl;
415 
416  if (!pl->contr)
417  return;
418 
419  /* If we have a request to send the player item, skip a few checks. */
420  if (op != pl) {
421  if (!LOOK_OBJ(op))
422  return;
423  /* we remove the check for op->env, because in theory, the object
424  * is hopefully in the same place, so the client should preserve
425  * order.
426  */
427  }
428  if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) {
429  // Sometimes, we try to update an item that we haven't sent to the
430  // client. Don't! This can happen, for example, when a button under the
431  // floor gets toggled, but objects under floor tiles are generally not
432  // sent. There are some other places where this happens that we haven't
433  // tracked down, but in general, just don't.
434  //LOG(llevDebug, "We have not sent item %s (%d)\n", op->name, op->count);
435  return;
436  }
437 
438  SockList_Init(&sl);
439  SockList_AddString(&sl, "upditem ");
440  SockList_AddChar(&sl, (char)flags);
441 
442  op = HEAD(op);
443  SockList_AddInt(&sl, op->count);
444 
445  if (flags&UPD_LOCATION)
446  SockList_AddInt(&sl, op->env ? op->env->count : 0);
447 
448  if (flags&UPD_FLAGS)
450 
451  if (flags&UPD_WEIGHT) {
452  int32_t weight = WEIGHT(op);
453 
454  /* TRANSPORTS are odd - they sort of look like containers,
455  * yet can't be picked up. So we don't to send the weight,
456  * as it is odd that you see weight sometimes and not other
457  * (the draw_look won't send it for example.
458  */
459  SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight);
460  if (pl == op) {
461  op->contr->last_weight = weight;
462  }
463  }
464 
465  if (flags&UPD_FACE) {
466  if (!(pl->contr->socket.faces_sent[op->face->number]&NS_FACESENT_FACE))
467  esrv_send_face(&pl->contr->socket, op->face, 0);
468  SockList_AddInt(&sl, op->face->number);
469  }
470  if (flags&UPD_NAME) {
471  int len;
472  char item_p[MAX_BUF];
473  char item_n[MAX_BUF];
474 
475  if (!op->custom_name) {
476  query_base_name(op, 0, item_n, sizeof(item_n)-1);
477  query_base_name(op, 1, item_p, sizeof(item_p));
478  } else {
479  strlcpy(item_n, op->custom_name, sizeof(item_n)-1);
480  strlcpy(item_p, op->custom_name, sizeof(item_p));
481  }
482 
483  len = strlen(item_n)+1;
484  snprintf(item_n+len, sizeof(item_n)-len, "%s", item_p);
485  len += strlen(item_n+len);
486  SockList_AddLen8Data(&sl, item_n, len);
487  }
488  if (flags&UPD_ANIM)
489  SockList_AddShort(&sl, op->animation ? op->animation->num : 0);
490 
491  if (flags&UPD_ANIMSPEED) {
492  int anim_speed = 0;
493 
494  if (QUERY_FLAG(op, FLAG_ANIMATE)) {
495  if (op->anim_speed)
496  anim_speed = op->anim_speed;
497  else {
498  if (FABS(op->speed) < 0.001)
499  anim_speed = 255;
500  else if (FABS(op->speed) >= 1.0)
501  anim_speed = 1;
502  else
503  anim_speed = (int)(1.0/FABS(op->speed));
504  }
505  if (anim_speed > 255)
506  anim_speed = 255;
507  }
508  SockList_AddChar(&sl, (char)anim_speed);
509  }
510  if (flags&UPD_NROF)
511  SockList_AddInt(&sl, op->nrof);
512 
513  Send_With_Handling(&pl->contr->socket, &sl);
514  SockList_Term(&sl);
515 }
516 
520 void esrv_send_item(object *pl, object*op) {
521  SockList sl;
522 
523  /* If this is not the player object, do some more checks */
524  if (op != pl) {
525  /* We only send 'visibile' objects to the client */
526  if (!LOOK_OBJ(op))
527  return;
528  /* if the item is on the ground, mark that the look needs to
529  * be updated.
530  */
531  if (!op->env) {
532  pl->contr->socket.update_look = 1;
533  return;
534  }
535  }
536 
537  SockList_Init(&sl);
538  SockList_AddString(&sl, "item2 ");
539 
540  op = HEAD(op);
541  SockList_AddInt(&sl, op->env ? op->env->count : 0);
542 
543  add_object_to_socklist(&pl->contr->socket, &sl, op);
544 
545  Send_With_Handling(&pl->contr->socket, &sl);
547  SockList_Term(&sl);
548 
549  /* if the object is in an opened container, then it may shift the contents,
550  * so resend everything */
551  if (pl->contr != NULL && pl->container != NULL && op->env == pl->container)
552  pl->contr->socket.update_inventory = 1;
553 }
554 
560 void esrv_del_item(player *pl, object *ob) {
561  SockList sl;
562 
563  SockList_Init(&sl);
564  SockList_AddString(&sl, "delitem ");
565  SockList_AddInt(&sl, ob->count);
566  Send_With_Handling(&pl->socket, &sl);
567  SockList_Term(&sl);
568  /* if the object is in an opened container, then it may shift the contents,
569  * so resend everything */
570  if (pl->ob->container != NULL && ob->env == pl->ob->container)
572 }
573 
574 /**************************************************************************
575  *
576  * Client has requested us to do something with an object.
577  *
578  **************************************************************************
579  */
580 
585 bool player_can_find(object *op, object *ob) {
586  return QUERY_FLAG(op, FLAG_WIZ) || !ob->invisible;
587 }
588 
592 static object *ob_if_can_find(object *op, object *ob) {
593  if (player_can_find(op, ob)) {
594  return ob;
595  } else {
596  return NULL;
597  }
598 }
599 
605 static object *esrv_get_ob_from_count(object *pl, tag_t count) {
606  if (pl->count == count)
607  return pl;
608 
610  if (op->count == count)
611  return ob_if_can_find(pl, op);
612  else if (op->type == CONTAINER && pl->container == op) {
614  if (tmp->count == count)
615  return ob_if_can_find(pl, tmp);
616  FOR_INV_FINISH();
617  }
618  FOR_INV_FINISH();
619 
620  FOR_MAP_PREPARE(pl->map, pl->x, pl->y, op)
621  if (HEAD(op)->count == count)
622  return ob_if_can_find(pl, op);
623  else if (op->type == CONTAINER && pl->container == op) {
625  if (tmp->count == count)
626  return ob_if_can_find(pl, tmp);
627  FOR_INV_FINISH();
628  }
629  FOR_MAP_FINISH();
630 
631  if (pl->contr->transport) {
632  FOR_INV_PREPARE(pl->contr->transport, tmp)
633  if (tmp->count == count)
634  return ob_if_can_find(pl, tmp);
635  FOR_INV_FINISH();
636  }
637  return NULL;
638 }
639 
641 void examine_cmd(char *buf, int len, player *pl) {
642  long tag;
643  object *op;
644 
645  if (len <= 0 || !buf) {
646  LOG(llevDebug, "Player '%s' sent bogus examine_cmd information\n", pl->ob->name);
647  return;
648  }
649 
650  tag = atoi(buf);
652  if (!op) {
653  LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", pl->ob->name, tag);
654  return;
655  }
656  examine(pl->ob, op);
657  if (QUERY_FLAG(pl->ob, FLAG_WIZ)) {
658  do_dump(pl->ob, op);
659  }
660 }
661 
663 void apply_cmd(char *buf, int len, player *pl) {
664  uint32_t tag;
665  object *op;
666 
667  if (!buf || len <= 0) {
668  LOG(llevDebug, "Player '%s' sent bogus apply_cmd information\n", pl->ob->name);
669  return;
670  }
671 
672  tag = atoi(buf);
674 
675  /* sort of a hack, but if the player saves and the player then
676  * manually applies a savebed (or otherwise tries to do stuff),
677  * we run into trouble.
678  */
679  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
680  return;
681 
682  /* If the high bit is set, player applied a pseudo object. */
683  if (tag&0x80000000) {
684  if (pl->ob->container != NULL) {
685  pl->socket.container_position = tag&0x7fffffff;
688  } else {
689  pl->socket.look_position = tag&0x7fffffff;
690  pl->socket.update_look = 1;
691  }
692  return;
693  }
694 
695  if (!op) {
696  LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", pl->ob->name, tag);
697  return;
698  }
699  apply_by_living(pl->ob, op, 0, 0);
700 }
701 
703 void lock_item_cmd(uint8_t *data, int len, player *pl) {
704  int flag, tag;
705  object *op;
706  object *tmp;
707  char name[HUGE_BUF];
708 
709  if (len != 5) {
710  LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name);
711  return;
712  }
713  flag = data[0];
714  tag = GetInt_String(data+1);
716 
717  if (!op) {
719  "Could not find object to lock/unlock");
720  return;
721  }
722 
723  if (op->map) {
725  "Can't lock/unlock an item on the ground");
726  return;
727  }
728  if (op->env != pl->ob) {
730  "Can't lock/unlock an item not directly in your inventory");
731  return;
732  }
733 
735  if (!flag) {
738  "Unlocked %s.", name);
739  } else {
742  "Locked %s.", name);
743  }
744 
745  tmp = object_merge(op, NULL);
746  if (tmp == NULL) {
747  /* object was not merged - if it was, object_merge() sent updates for us. */
749  }
750 }
751 
762 void mark_item_cmd(uint8_t *data, int len, player *pl) {
763  int tag;
764  object *op;
765  char name[MAX_BUF];
766 
767  if (len != 4) {
768  LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name);
769  return;
770  }
771 
774  if (!op) {
776  "Could not find object to mark");
777  return;
778  }
779  pl->mark = op;
780  pl->mark_count = op->count;
783  "Marked item %s",
784  name);
785 }
786 
793 void look_at(object *op, int dx, int dy) {
794  object *tmp;
795  int flag = 0;
796  int16_t x, y;
797  mapstruct *m;
798  char name[MAX_BUF];
799 
800  if (out_of_map(op->map, op->x+dx, op->y+dy))
801  return;
802 
803  x = op->x+dx;
804  y = op->y+dy;
805 
806  m = get_map_from_coord(op->map, &x, &y);
807  if (!m)
808  return;
809 
810  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
811  ;
812 
814  if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ))
815  continue;
816 
817  if (!flag) {
818  if (dx || dy)
820  "There you see:");
821  else {
823  "You see:");
824  }
825  flag = 1;
826  }
827 
829  if (QUERY_FLAG(op, FLAG_WIZ))
831  "- %s (%d).",
832  name, tmp->count);
833  else
835  "- %s.",
836  name);
837 
838  if ((HEAD(tmp)->inv != NULL && (tmp->type != CONTAINER && tmp->type != FLESH))
839  || QUERY_FLAG(op, FLAG_WIZ))
840  inventory(op, HEAD(tmp));
841 
842  /* don't continue under the floor */
844  break;
846 
847  if (!flag) {
848  if (dx || dy)
850  "You see nothing there.");
851  else
853  "You see nothing.");
854  }
855 }
856 
858 void look_at_cmd(char *buf, int len, player *pl) {
859  int dx, dy;
860  char *cp;
861 
862  if (len <= 0 || !buf) {
863  LOG(llevDebug, "Player '%s' sent bogus look_at_cmd information\n", pl->ob->name);
864  return;
865  }
866 
867  dx = atoi(buf);
868  if (!(cp = strchr(buf, ' '))) {
869  return;
870  }
871  dy = atoi(cp);
872 
873  if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2) {
875  "You can't see there from where you're standing.");
876  return;
877  }
878 
879  if (pl->blocked_los[dx+(pl->socket.mapx/2)][dy+(pl->socket.mapy/2)]) {
881  "You can't see there from where you're standing.");
882  return;
883  }
884  look_at(pl->ob, dx, dy);
885 }
886 
888 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) {
889  object *op, *env;
890 
892  if (!op) {
893  LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag);
894  return;
895  }
896 
897  /* If on a transport, you don't drop to the ground - you drop to the
898  * transport.
899  */
900  if (!to && !pl->contr->transport) { /* drop it to the ground */
901  /* LOG(llevDebug, "Drop it on the ground.\n");*/
902 
903  if (op->map && !op->env) {
904 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/
905  return;
906  }
907  /* If it is an active container, then we should drop all objects
908  * in the container and not the container itself.
909  */
910  if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
912  drop_object(pl, current, 0);
913  FOR_INV_FINISH();
915  } else {
916  drop_object(pl, op, nrof);
917  }
918  return;
919  } else if (to == pl->count) { /* pick it up to the inventory */
920  /* return if player has already picked it up */
921  if (op->env == pl)
922  return;
923 
924  pl->contr->count = nrof;
925  pick_up(pl, op);
926  return;
927  }
928  /* If not dropped or picked up, we are putting it into a sack */
929  if (pl->contr->transport) {
930  if (object_can_pick(pl, op)
931  && transport_can_hold(pl->contr->transport, op, nrof)) {
932  put_object_in_sack(pl, pl->contr->transport, op, nrof);
933  }
934  } else {
936  if (!env) {
937  LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to);
938  return;
939  }
940  /* put_object_in_sack presumes that necessary sanity checking
941  * has already been done (eg, it can be picked up and fits in
942  * in a sack, so check for those things. We should also check
943  * an make sure env is in fact a container for that matter.
944  */
945  if (env->type == CONTAINER
946  && object_can_pick(pl, op)
947  && sack_can_hold(pl, env, op, nrof)) {
948  put_object_in_sack(pl, env, op, nrof);
949  }
950  }
951 }
952 
953 void inscribe_scroll_cmd(char *buf, int len, player *pl) {
954  object *scroll, *spell, *marked, *inscription, *currentspell;
955  tag_t tscroll, tspell, tmarked;
956  char type;
957 
958  if (len < 1) {
959  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
960  return;
961  }
962 
963  type = buf[0];
964 
965  inscription = find_skill_by_name(pl->ob, "inscription");
966  if (!inscription) {
967  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!");
968  return;
969  }
970 
971  if (type == 0) {
972  if (len != 9) {
973  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
974  return;
975  }
976  tscroll = GetInt_String((uint8_t *)buf+1);
977  tspell = GetInt_String((uint8_t *)buf+5);
978 
979  scroll = esrv_get_ob_from_count(pl->ob, tscroll);
980  if (!scroll) {
981  LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name);
982  return;
983  }
984 
985  spell = esrv_get_ob_from_count(pl->ob, tspell);
986  if (!spell) {
987  LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name);
988  return;
989  }
990 
991  tmarked = pl->mark_count;
992  marked = pl->mark;
993  currentspell = pl->ranges[range_magic];
994 
995  pl->mark_count = tscroll;
996  pl->mark = scroll;
997  pl->ranges[range_magic] = spell;
998 
999  write_on_item(pl->ob, "", inscription);
1000 
1001  pl->mark_count = tmarked;
1002  pl->mark = marked;
1003  pl->ranges[range_magic] = currentspell;
1004  } else {
1005  }
1006 }
GET_MAP_OB
#define GET_MAP_OB(M, X, Y)
Definition: map.h:173
MAP_CLIENT_X
#define MAP_CLIENT_X
Definition: config.h:237
SockList_AddInt
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.c:124
global.h
UPD_FACE
#define UPD_FACE
Definition: newclient.h:317
NS_FACESENT_FACE
#define NS_FACESENT_FACE
Definition: newserver.h:137
pl::count
uint32_t count
Definition: player.h:122
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
pl::transport
object * transport
Definition: player.h:213
obj::face
const Face * face
Definition: object.h:336
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:530
BOW
@ BOW
Definition: object.h:118
query_flags
static unsigned int query_flags(const object *op)
Definition: item.c:49
BRACERS
@ BRACERS
Definition: object.h:217
F_OPEN
#define F_OPEN
Definition: newclient.h:289
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
esrv_send_item
void esrv_send_item(object *pl, object *op)
Definition: item.c:520
WAND
@ WAND
Definition: object.h:220
inscribe_scroll_cmd
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.c:953
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
FLESH
@ FLESH
Definition: object.h:187
socket_struct::container_position
uint16_t container_position
Definition: newserver.h:115
GLOVES
@ GLOVES
Definition: object.h:213
GIRDLE
@ GIRDLE
Definition: object.h:223
socket_struct::look_position
uint16_t look_position
Definition: newserver.h:114
F_UNPAID
#define F_UNPAID
Definition: newclient.h:285
diamondslots.x
x
Definition: diamondslots.py:15
obj::count
tag_t count
Definition: object.h:302
obj::map
struct mapdef * map
Definition: object.h:300
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:407
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
socket_struct
Definition: newserver.h:89
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:116
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2312
socket_struct::num_look_objects
uint8_t num_look_objects
Definition: newserver.h:122
lock_item_cmd
void lock_item_cmd(uint8_t *data, int len, player *pl)
Definition: item.c:703
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:316
obj::anim_speed
uint8_t anim_speed
Definition: object.h:422
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:154
pl::socket
socket_struct socket
Definition: player.h:107
pl
Definition: player.h:105
pl::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:177
ARMOUR
@ ARMOUR
Definition: object.h:120
UPD_LOCATION
#define UPD_LOCATION
Definition: newclient.h:314
do_dump
void do_dump(object *who, object *what)
Definition: c_wiz.c:2839
WEAPON
@ WEAPON
Definition: object.h:119
esrv_draw_look
void esrv_draw_look(object *pl)
Definition: item.c:192
guildjoin.ob
ob
Definition: guildjoin.py:42
write_on_item
int write_on_item(object *pl, const char *params, object *skill)
Definition: skills.c:1760
socket_struct::update_inventory
uint32_t update_inventory
Definition: newserver.h:105
commongive.inv
inv
Definition: commongive.py:28
obj::custom_name
sstring custom_name
Definition: object.h:437
AMULET
@ AMULET
Definition: object.h:139
MIN
#define MIN(x, y)
Definition: compat.h:21
pl::ob
object * ob
Definition: player.h:176
SKILL
@ SKILL
Definition: object.h:143
MSG_TYPE_COMMAND_EXAMINE
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:532
esrv_del_item
void esrv_del_item(player *pl, object *ob)
Definition: item.c:560
Ice.tmp
int tmp
Definition: Ice.py:207
apply_cmd
void apply_cmd(char *buf, int len, player *pl)
Definition: item.c:663
FLAG_BLESSED
#define FLAG_BLESSED
Definition: define.h:369
UPD_NROF
#define UPD_NROF
Definition: newclient.h:321
flags
static const flag_definition flags[]
Definition: gridarta-types-convert.c:101
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:529
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:71
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
a_active
@ a_active
Definition: newclient.h:281
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:404
MAX
#define MAX(x, y)
Definition: compat.h:24
F_READ
#define F_READ
Definition: newclient.h:293
obj::nrof
uint32_t nrof
Definition: object.h:337
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
socket_struct::update_look
uint32_t update_look
Definition: newserver.h:104
SockList_Avail
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:243
object_merge
object * object_merge(object *op, object *top)
Definition: object.c:2031
look_at_cmd
void look_at_cmd(char *buf, int len, player *pl)
Definition: item.c:858
LOOK_OBJ
#define LOOK_OBJ(ob)
Definition: object.h:507
player_can_find
bool player_can_find(object *op, object *ob)
Definition: item.c:585
mark_item_cmd
void mark_item_cmd(uint8_t *data, int len, player *pl)
Definition: item.c:762
m
static event_registration m
Definition: citylife.cpp:427
CLOAK
@ CLOAK
Definition: object.h:204
socket_struct::mapy
uint8_t mapy
Definition: newserver.h:116
pl::mark
object * mark
Definition: player.h:212
MAP_IN_MEMORY
#define MAP_IN_MEMORY
Definition: map.h:131
a_readied
@ a_readied
Definition: newclient.h:281
MAP_CLIENT_Y
#define MAP_CLIENT_Y
Definition: config.h:238
HELMET
@ HELMET
Definition: object.h:136
obj::name
sstring name
Definition: object.h:314
F_DAMNED
#define F_DAMNED
Definition: newclient.h:288
esrv_move_object
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.c:888
esrv_send_face
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Definition: image.c:71
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:585
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:281
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:754
HEAD
#define HEAD(op)
Definition: object.h:593
range_magic
@ range_magic
Definition: player.h:32
SockList_AddShort
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.c:113
transport_can_hold
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.c:54
ROD
@ ROD
Definition: object.h:109
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.c:3838
CONTAINER
@ CONTAINER
Definition: object.h:231
SockList_AddChar
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:103
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:510
F_CURSED
#define F_CURSED
Definition: newclient.h:287
obj::container
struct obj * container
Definition: object.h:294
obj::x
int16_t x
Definition: object.h:330
empty_face
const Face * empty_face
Definition: image.c:35
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
add_object_to_socklist
static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head)
Definition: item.c:122
navar-midane_time.data
data
Definition: navar-midane_time.py:11
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:315
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:284
disinfect.count
int count
Definition: disinfect.py:7
obj::speed
float speed
Definition: object.h:332
tag_t
uint32_t tag_t
Definition: object.h:12
obj::env
struct obj * env
Definition: object.h:296
obj::client_type
uint16_t client_type
Definition: object.h:345
obj::below
struct obj * below
Definition: object.h:290
sproto.h
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:750
mapdef
Definition: map.h:317
BOOK
@ BOOK
Definition: object.h:114
RING
@ RING
Definition: object.h:185
obj::animation
const Animations * animation
Definition: object.h:421
SockList_Init
void SockList_Init(SockList *sl)
Definition: lowlevel.c:52
F_NOPICK
#define F_NOPICK
Definition: newclient.h:290
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:202
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:220
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2216
MAX_BUF
#define MAX_BUF
Definition: define.h:35
drop_object
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.c:1073
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.c:62
FLAG_CLIENT_SENT
#define FLAG_CLIENT_SENT
Definition: define.h:346
F_BLESSED
#define F_BLESSED
Definition: newclient.h:292
UPD_ANIMSPEED
#define UPD_ANIMSPEED
Definition: newclient.h:320
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:531
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
obj::y
int16_t y
Definition: object.h:330
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.c:972
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
MSG_TYPE_SKILL_FAILURE
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:590
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
newserver.h
give.op
op
Definition: give.py:33
SockList_AddLen8Data
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:176
apply_by_living
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Definition: apply.c:637
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:686
diamondslots.y
y
Definition: diamondslots.py:16
a_wielded
@ a_wielded
Definition: newclient.h:281
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
WEIGHT
#define WEIGHT(op)
Definition: define.h:651
buf
StringBuffer * buf
Definition: readable.c:1610
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:315
animations_struct::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
MAXITEMLEN
#define MAXITEMLEN
Definition: item.c:36
pl::ranges
object * ranges[range_size]
Definition: player.h:116
GetInt_String
int GetInt_String(const unsigned char *data)
Definition: lowlevel.c:251
pl::mark_count
uint32_t mark_count
Definition: player.h:211
ob_if_can_find
static object * ob_if_can_find(object *op, object *ob)
Definition: item.c:592
make_face_from_files.int
int
Definition: make_face_from_files.py:26
F_MAGIC
#define F_MAGIC
Definition: newclient.h:286
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
UPD_NAME
#define UPD_NAME
Definition: newclient.h:318
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.c:309
examine_cmd
void examine_cmd(char *buf, int len, player *pl)
Definition: item.c:641
F_LOCKED
#define F_LOCKED
Definition: newclient.h:291
inventory
void inventory(object *op, object *inv)
Definition: c_object.c:2016
positioning_system.marked
marked
Definition: positioning_system.py:21
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
esrv_get_ob_from_count
static object * esrv_get_ob_from_count(object *pl, tag_t count)
Definition: item.c:605
UPD_ANIM
#define UPD_ANIM
Definition: newclient.h:319
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: item.c:413
mapdef::path
char path[HUGE_BUF]
Definition: map.h:358
BOOTS
@ BOOTS
Definition: object.h:212
replace.current
current
Definition: replace.py:64
SHIELD
@ SHIELD
Definition: object.h:135
a_worn
@ a_worn
Definition: newclient.h:281
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.c:519
examine
void examine(object *op, object *tmp)
Definition: c_object.c:1702
sack_can_hold
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Definition: c_object.c:317
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
Send_With_Handling
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:440
get_map_from_coord
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.c:2385
SockList
Definition: newclient.h:681
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
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,...)
Definition: main.c:319
object.h
look_at
void look_at(object *op, int dx, int dy)
Definition: item.c:793
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.c:199
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
obj::inv
struct obj * inv
Definition: object.h:293
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.c:937
is_identified
int is_identified(const object *op)
Definition: item.c:1336