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.
111  if (QUERY_FLAG(op, FLAG_IDENTIFIED) && QUERY_FLAG(op, FLAG_NO_SKILL_IDENT) && op->type == BOOK)
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(tmp, FLAG_IS_FLOOR) && !last) {
261  last = tmp->below; /* assumes double floor mode */
262  if (last && QUERY_FLAG(last, FLAG_IS_FLOOR))
263  last = last->below;
264  }
265  if (LOOK_OBJ(tmp)) {
266  if (start_look++ < pl->contr->socket.look_position)
267  continue;
268  end_look++;
269  objects_sent++;
270  if (objects_sent >= pl->contr->socket.num_look_objects) {
271  /* What we basically do is make a 'fake' object -
272  * when the user applies it, we notice the special
273  * tag the object has, and act accordingly.
274  */
275  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.look_position+end_look-1));
276  SockList_AddInt(&sl, 0);
277  SockList_AddInt(&sl, -1);
279  snprintf(buf, sizeof(buf), "Click here to see next group of items");
280  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
281  SockList_AddShort(&sl, 0);
282  SockList_AddChar(&sl, 0);
283  SockList_AddInt(&sl, 0);
284  SockList_AddShort(&sl, 0);
285  break;
286  }
287  head = HEAD(tmp);
288  add_object_to_socklist(&pl->contr->socket, &sl, head);
289  got_one++;
290 
291  if (SockList_Avail(&sl) < MAXITEMLEN) {
292  Send_With_Handling(&pl->contr->socket, &sl);
293  SockList_Reset(&sl);
294  SockList_AddPrintf(&sl, "item2 ");
295  SockList_AddInt(&sl, 0);
296  got_one = 0;
297  }
298  } /* If LOOK_OBJ() */
300  if (got_one)
301  Send_With_Handling(&pl->contr->socket, &sl);
302 
303  SockList_Term(&sl);
304 }
305 
312 void esrv_send_inventory(object *pl, object *op) {
313  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
314  SockList sl;
315  char buf[MAX_BUF];
316  int prev_len = pl->contr->socket.num_look_objects - 2 - (((pl->contr->socket.container_position > pl->contr->socket.num_look_objects - 1)) ? 1 : 0);
317 
318  SockList_Init(&sl);
319  SockList_AddPrintf(&sl, "delinv %u", op->count);
320  Send_With_Handling(&pl->contr->socket, &sl);
321 
322  SockList_Reset(&sl);
323  SockList_AddString(&sl, "item2 ");
324  SockList_AddInt(&sl, op->count);
325  objects_sent++;
326 
327  if (pl != op && pl->contr->socket.container_position) {
328  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.container_position-prev_len));
329  SockList_AddInt(&sl, 0);
330  SockList_AddInt(&sl, -1);
332  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
333  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
334  SockList_AddShort(&sl, 0);
335  SockList_AddChar(&sl, 0);
336  SockList_AddInt(&sl, 0);
337  SockList_AddShort(&sl, 0);
338  objects_sent++;
339  got_one++;
340  }
341 
343  object *head;
344 
345  head = HEAD(tmp);
346  if (LOOK_OBJ(head)) {
347  if (start_look++ < pl->contr->socket.container_position && pl != op)
348  continue;
349  end_look++;
350  objects_sent++;
351  if (pl != op && objects_sent >= pl->contr->socket.num_look_objects) {
352  /* What we basically do is make a 'fake' object -
353  * when the user applies it, we notice the special
354  * tag the object has, and act accordingly.
355  */
356  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.container_position + end_look - 1));
357  SockList_AddInt(&sl, 0);
358  SockList_AddInt(&sl, -1);
360  snprintf(buf, sizeof(buf), "Click here to see next group of items");
361  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
362  SockList_AddShort(&sl, 0);
363  SockList_AddChar(&sl, 0);
364  SockList_AddInt(&sl, 0);
365  SockList_AddShort(&sl, 0);
366  break;
367  }
368 
369  add_object_to_socklist(&pl->contr->socket, &sl, head);
370 
371  got_one++;
372 
373  /* It is possible for players to accumulate a huge amount of
374  * items (especially with some of the bags out there) to
375  * overflow the buffer. IF so, send multiple item commands.
376  */
377  if (SockList_Avail(&sl) < MAXITEMLEN) {
378  Send_With_Handling(&pl->contr->socket, &sl);
379  SockList_Reset(&sl);
380  SockList_AddString(&sl, "item2 ");
381  SockList_AddInt(&sl, op->count);
382  got_one = 0;
383  }
384  } /* If LOOK_OBJ() */
385  } FOR_INV_FINISH();
386  if (got_one) {
387  /* special case: only one item, the "prev group" arrow */
388  if (pl != op && pl->contr->socket.container_position) {
389  if (got_one > 1)
390  Send_With_Handling(&pl->contr->socket, &sl);
391  else {
392  /* view shifted, get to previous page and resend */
393  pl->contr->socket.container_position = MAX(0, pl->contr->socket.container_position - prev_len);
395  }
396  } else
397  Send_With_Handling(&pl->contr->socket, &sl);
398  }
399  SockList_Term(&sl);
400 }
401 
410 void esrv_update_item(int flags, object *pl, object *op) {
411  SockList sl;
412 
413  if (!pl->contr)
414  return;
415 
416  /* If we have a request to send the player item, skip a few checks. */
417  if (op != pl) {
418  if (!LOOK_OBJ(op))
419  return;
420  /* we remove the check for op->env, because in theory, the object
421  * is hopefully in the same place, so the client should preserve
422  * order.
423  */
424  }
425  if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) {
426  // Sometimes, we try to update an item that we haven't sent to the
427  // client. Don't! This can happen, for example, when a button under the
428  // floor gets toggled, but objects under floor tiles are generally not
429  // sent. There are some other places where this happens that we haven't
430  // tracked down, but in general, just don't.
431  //LOG(llevDebug, "We have not sent item %s (%d)\n", op->name, op->count);
432  return;
433  }
434 
435  SockList_Init(&sl);
436  SockList_AddString(&sl, "upditem ");
437  SockList_AddChar(&sl, (char)flags);
438 
439  op = HEAD(op);
440  SockList_AddInt(&sl, op->count);
441 
442  if (flags&UPD_LOCATION)
443  SockList_AddInt(&sl, op->env ? op->env->count : 0);
444 
445  if (flags&UPD_FLAGS)
447 
448  if (flags&UPD_WEIGHT) {
449  int32_t weight = WEIGHT(op);
450 
451  /* TRANSPORTS are odd - they sort of look like containers,
452  * yet can't be picked up. So we don't to send the weight,
453  * as it is odd that you see weight sometimes and not other
454  * (the draw_look won't send it for example.
455  */
456  SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight);
457  if (pl == op) {
458  op->contr->last_weight = weight;
459  }
460  }
461 
462  if (flags&UPD_FACE) {
463  if (!(pl->contr->socket.faces_sent[op->face->number]&NS_FACESENT_FACE))
464  esrv_send_face(&pl->contr->socket, op->face, 0);
465  SockList_AddInt(&sl, op->face->number);
466  }
467  if (flags&UPD_NAME) {
468  int len;
469  char item_p[MAX_BUF];
470  char item_n[MAX_BUF];
471 
472  if (!op->custom_name) {
473  query_base_name(op, 0, item_n, sizeof(item_n)-1);
474  query_base_name(op, 1, item_p, sizeof(item_p));
475  } else {
476  strlcpy(item_n, op->custom_name, sizeof(item_n)-1);
477  strlcpy(item_p, op->custom_name, sizeof(item_p));
478  }
479 
480  len = strlen(item_n)+1;
481  snprintf(item_n+len, sizeof(item_n)-len, "%s", item_p);
482  len += strlen(item_n+len);
483  SockList_AddLen8Data(&sl, item_n, len);
484  }
485  if (flags&UPD_ANIM)
486  SockList_AddShort(&sl, op->animation ? op->animation->num : 0);
487 
488  if (flags&UPD_ANIMSPEED) {
489  int anim_speed = 0;
490 
491  if (QUERY_FLAG(op, FLAG_ANIMATE)) {
492  if (op->anim_speed)
493  anim_speed = op->anim_speed;
494  else {
495  if (FABS(op->speed) < 0.001)
496  anim_speed = 255;
497  else if (FABS(op->speed) >= 1.0)
498  anim_speed = 1;
499  else
500  anim_speed = (int)(1.0/FABS(op->speed));
501  }
502  if (anim_speed > 255)
503  anim_speed = 255;
504  }
505  SockList_AddChar(&sl, (char)anim_speed);
506  }
507  if (flags&UPD_NROF)
508  SockList_AddInt(&sl, op->nrof);
509 
510  Send_With_Handling(&pl->contr->socket, &sl);
511  SockList_Term(&sl);
512 }
513 
517 void esrv_send_item(object *pl, object*op) {
518  SockList sl;
519 
520  /* If this is not the player object, do some more checks */
521  if (op != pl) {
522  /* We only send 'visibile' objects to the client */
523  if (!LOOK_OBJ(op))
524  return;
525  /* if the item is on the ground, mark that the look needs to
526  * be updated.
527  */
528  if (!op->env) {
529  pl->contr->socket.update_look = 1;
530  return;
531  }
532  }
533 
534  SockList_Init(&sl);
535  SockList_AddString(&sl, "item2 ");
536 
537  op = HEAD(op);
538  SockList_AddInt(&sl, op->env ? op->env->count : 0);
539 
540  add_object_to_socklist(&pl->contr->socket, &sl, op);
541 
542  Send_With_Handling(&pl->contr->socket, &sl);
544  SockList_Term(&sl);
545 
546  /* if the object is in an opened container, then it may shift the contents,
547  * so resend everything */
548  if (pl->contr != NULL && pl->container != NULL && op->env == pl->container)
549  pl->contr->socket.update_inventory = 1;
550 }
551 
557 void esrv_del_item(player *pl, object *ob) {
558  SockList sl;
559 
560  SockList_Init(&sl);
561  SockList_AddString(&sl, "delitem ");
562  SockList_AddInt(&sl, ob->count);
563  Send_With_Handling(&pl->socket, &sl);
564  SockList_Term(&sl);
565  /* if the object is in an opened container, then it may shift the contents,
566  * so resend everything */
567  if (pl->ob->container != NULL && ob->env == pl->ob->container)
569 }
570 
571 /**************************************************************************
572  *
573  * Client has requested us to do something with an object.
574  *
575  **************************************************************************
576  */
577 
583 static object *esrv_get_ob_from_count(object *pl, tag_t count) {
584  if (pl->count == count)
585  return pl;
586 
588  if (op->count == count)
589  return op;
590  else if (op->type == CONTAINER && pl->container == op) {
592  if (tmp->count == count)
593  return tmp;
594  FOR_INV_FINISH();
595  }
596  FOR_INV_FINISH();
597 
598  FOR_MAP_PREPARE(pl->map, pl->x, pl->y, op)
599  if (HEAD(op)->count == count)
600  return op;
601  else if (op->type == CONTAINER && pl->container == op) {
603  if (tmp->count == count)
604  return tmp;
605  FOR_INV_FINISH();
606  }
607  FOR_MAP_FINISH();
608 
609  if (pl->contr->transport) {
610  FOR_INV_PREPARE(pl->contr->transport, tmp)
611  if (tmp->count == count)
612  return tmp;
613  FOR_INV_FINISH();
614  }
615  return NULL;
616 }
617 
619 void examine_cmd(char *buf, int len, player *pl) {
620  long tag;
621  object *op;
622 
623  if (len <= 0 || !buf) {
624  LOG(llevDebug, "Player '%s' sent bogus examine_cmd information\n", pl->ob->name);
625  return;
626  }
627 
628  tag = atoi(buf);
630  if (!op) {
631  LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", pl->ob->name, tag);
632  return;
633  }
634  examine(pl->ob, op);
635 }
636 
638 void apply_cmd(char *buf, int len, player *pl) {
639  uint32_t tag;
640  object *op;
641 
642  if (!buf || len <= 0) {
643  LOG(llevDebug, "Player '%s' sent bogus apply_cmd information\n", pl->ob->name);
644  return;
645  }
646 
647  tag = atoi(buf);
649 
650  /* sort of a hack, but if the player saves and the player then
651  * manually applies a savebed (or otherwise tries to do stuff),
652  * we run into trouble.
653  */
654  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
655  return;
656 
657  /* If the high bit is set, player applied a pseudo object. */
658  if (tag&0x80000000) {
659  if (pl->ob->container != NULL) {
660  pl->socket.container_position = tag&0x7fffffff;
661  esrv_send_inventory(pl->ob, pl->ob->container);
663  } else {
664  pl->socket.look_position = tag&0x7fffffff;
665  pl->socket.update_look = 1;
666  }
667  return;
668  }
669 
670  if (!op) {
671  LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", pl->ob->name, tag);
672  return;
673  }
674  apply_by_living(pl->ob, op, 0, 0);
675 }
676 
678 void lock_item_cmd(uint8_t *data, int len, player *pl) {
679  int flag, tag;
680  object *op;
681  object *tmp;
682  char name[HUGE_BUF];
683 
684  if (len != 5) {
685  LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name);
686  return;
687  }
688  flag = data[0];
689  tag = GetInt_String(data+1);
691 
692  if (!op) {
694  "Could not find object to lock/unlock");
695  return;
696  }
697 
698  if (op->map) {
700  "Can't lock/unlock an item on the ground");
701  return;
702  }
703  if (op->env != pl->ob) {
705  "Can't lock/unlock an item not directly in your inventory");
706  return;
707  }
708 
710  if (!flag) {
713  "Unlocked %s.", name);
714  } else {
717  "Locked %s.", name);
718  }
719 
720  tmp = object_merge(op, NULL);
721  if (tmp == NULL) {
722  /* object was not merged - if it was, object_merge() sent updates for us. */
724  }
725 }
726 
737 void mark_item_cmd(uint8_t *data, int len, player *pl) {
738  int tag;
739  object *op;
740  char name[MAX_BUF];
741 
742  if (len != 4) {
743  LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name);
744  return;
745  }
746 
749  if (!op) {
751  "Could not find object to mark");
752  return;
753  }
754  pl->mark = op;
755  pl->mark_count = op->count;
758  "Marked item %s",
759  name);
760 }
761 
768 void look_at(object *op, int dx, int dy) {
769  object *tmp;
770  int flag = 0;
771  int16_t x, y;
772  mapstruct *m;
773  char name[MAX_BUF];
774 
775  if (out_of_map(op->map, op->x+dx, op->y+dy))
776  return;
777 
778  x = op->x+dx;
779  y = op->y+dy;
780 
781  m = get_map_from_coord(op->map, &x, &y);
782  if (!m)
783  return;
784 
785  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
786  ;
787 
789  if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ))
790  continue;
791 
792  if (!flag) {
793  if (dx || dy)
795  "There you see:");
796  else {
798  "You see:");
799  }
800  flag = 1;
801  }
802 
804  if (QUERY_FLAG(op, FLAG_WIZ))
806  "- %s (%d).",
807  name, tmp->count);
808  else
810  "- %s.",
811  name);
812 
813  if ((HEAD(tmp)->inv != NULL && (tmp->type != CONTAINER && tmp->type != FLESH))
814  || QUERY_FLAG(op, FLAG_WIZ))
815  inventory(op, HEAD(tmp));
816 
817  /* don't continue under the floor */
819  break;
821 
822  if (!flag) {
823  if (dx || dy)
825  "You see nothing there.");
826  else
828  "You see nothing.");
829  }
830 }
831 
833 void look_at_cmd(char *buf, int len, player *pl) {
834  int dx, dy;
835  char *cp;
836 
837  if (len <= 0 || !buf) {
838  LOG(llevDebug, "Player '%s' sent bogus look_at_cmd information\n", pl->ob->name);
839  return;
840  }
841 
842  dx = atoi(buf);
843  if (!(cp = strchr(buf, ' '))) {
844  return;
845  }
846  dy = atoi(cp);
847 
848  if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2) {
850  "You can't see there from where you're standing.");
851  return;
852  }
853 
854  if (pl->blocked_los[dx+(pl->socket.mapx/2)][dy+(pl->socket.mapy/2)]) {
856  "You can't see there from where you're standing.");
857  return;
858  }
859  look_at(pl->ob, dx, dy);
860 }
861 
863 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) {
864  object *op, *env;
865 
867  if (!op) {
868  LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag);
869  return;
870  }
871 
872  /* If on a transport, you don't drop to the ground - you drop to the
873  * transport.
874  */
875  if (!to && !pl->contr->transport) { /* drop it to the ground */
876  /* LOG(llevDebug, "Drop it on the ground.\n");*/
877 
878  if (op->map && !op->env) {
879 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/
880  return;
881  }
882  /* If it is an active container, then we should drop all objects
883  * in the container and not the container itself.
884  */
885  if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
887  drop_object(pl, current, 0);
888  FOR_INV_FINISH();
890  } else {
891  drop_object(pl, op, nrof);
892  }
893  return;
894  } else if (to == pl->count) { /* pick it up to the inventory */
895  /* return if player has already picked it up */
896  if (op->env == pl)
897  return;
898 
899  pl->contr->count = nrof;
900  pick_up(pl, op);
901  return;
902  }
903  /* If not dropped or picked up, we are putting it into a sack */
904  if (pl->contr->transport) {
905  if (object_can_pick(pl, op)
906  && transport_can_hold(pl->contr->transport, op, nrof)) {
907  put_object_in_sack(pl, pl->contr->transport, op, nrof);
908  }
909  } else {
911  if (!env) {
912  LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to);
913  return;
914  }
915  /* put_object_in_sack presumes that necessary sanity checking
916  * has already been done (eg, it can be picked up and fits in
917  * in a sack, so check for those things. We should also check
918  * an make sure env is in fact a container for that matter.
919  */
920  if (env->type == CONTAINER
921  && object_can_pick(pl, op)
922  && sack_can_hold(pl, env, op, nrof)) {
923  put_object_in_sack(pl, env, op, nrof);
924  }
925  }
926 }
927 
928 void inscribe_scroll_cmd(char *buf, int len, player *pl) {
929  object *scroll, *spell, *marked, *inscription, *currentspell;
930  tag_t tscroll, tspell, tmarked;
931  char type;
932 
933  if (len < 1) {
934  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
935  return;
936  }
937 
938  type = buf[0];
939 
940  inscription = find_skill_by_name(pl->ob, "inscription");
941  if (!inscription) {
942  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!");
943  return;
944  }
945 
946  if (type == 0) {
947  if (len != 9) {
948  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
949  return;
950  }
951  tscroll = GetInt_String((uint8_t *)buf+1);
952  tspell = GetInt_String((uint8_t *)buf+5);
953 
954  scroll = esrv_get_ob_from_count(pl->ob, tscroll);
955  if (!scroll) {
956  LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name);
957  return;
958  }
959 
960  spell = esrv_get_ob_from_count(pl->ob, tspell);
961  if (!spell) {
962  LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name);
963  return;
964  }
965 
966  tmarked = pl->mark_count;
967  marked = pl->mark;
968  currentspell = pl->ranges[range_magic];
969 
970  pl->mark_count = tscroll;
971  pl->mark = scroll;
972  pl->ranges[range_magic] = spell;
973 
974  write_on_item(pl->ob, "", inscription);
975 
976  pl->mark_count = tmarked;
977  pl->mark = marked;
978  pl->ranges[range_magic] = currentspell;
979  } else {
980  }
981 }
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:109
safe_strncpy
#define safe_strncpy
Definition: compat.h:27
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:727
pl::transport
object * transport
Definition: player.h:201
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:530
query_flags
static unsigned int query_flags(const object *op)
Definition: item.c:49
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:517
inscribe_scroll_cmd
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.c:928
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:223
socket_struct::container_position
uint16_t container_position
Definition: newserver.h:115
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
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:407
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
socket_struct
Definition: newserver.h:89
socket_struct::mapx
uint8_t mapx
Definition: newserver.h:116
make_face_from_files.type
type
Definition: make_face_from_files.py:24
out_of_map
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2318
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:678
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:316
SockList_AddString
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:154
pl::socket
socket_struct socket
Definition: player.h:94
pl
Definition: player.h:92
pl::blocked_los
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:163
UPD_LOCATION
#define UPD_LOCATION
Definition: newclient.h:314
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:1765
socket_struct::update_inventory
uint32_t update_inventory
Definition: newserver.h:105
commongive.inv
inv
Definition: commongive.py:28
MIN
#define MIN(x, y)
Definition: compat.h:21
pl::ob
object * ob
Definition: player.h:162
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:557
Ice.tmp
int tmp
Definition: Ice.py:207
apply_cmd
void apply_cmd(char *buf, int len, player *pl)
Definition: item.c:638
FLAG_BLESSED
#define FLAG_BLESSED
Definition: define.h:368
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:328
SockList_Reset
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:71
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:234
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
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:238
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:2026
look_at_cmd
void look_at_cmd(char *buf, int len, player *pl)
Definition: item.c:833
mark_item_cmd
void mark_item_cmd(uint8_t *data, int len, player *pl)
Definition: item.c:737
m
static event_registration m
Definition: citylife.cpp:410
socket_struct::mapy
uint8_t mapy
Definition: newserver.h:116
pl::mark
object * mark
Definition: player.h:200
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
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:863
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:584
FLAG_KNOWN_BLESSED
#define FLAG_KNOWN_BLESSED
Definition: define.h:369
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
Definition: define.h:319
replace.env
env
Definition: replace.py:77
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:751
range_magic
@ range_magic
Definition: player.h:19
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
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.c:3883
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:509
F_CURSED
#define F_CURSED
Definition: newclient.h:287
empty_face
const Face * empty_face
Definition: image.c:35
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:316
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:674
F_UNIDENTIFIED
#define F_UNIDENTIFIED
Definition: newclient.h:284
disinfect.count
int count
Definition: disinfect.py:7
sproto.h
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:747
mapdef
Definition: map.h:324
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
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:1071
SockList_Term
void SockList_Term(SockList *sl)
Definition: lowlevel.c:62
FLAG_CLIENT_SENT
#define FLAG_CLIENT_SENT
Definition: define.h:345
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:720
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
Definition: define.h:318
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:231
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:230
esrv_send_animation
void esrv_send_animation(socket_struct *ns, const Animations *anim)
Definition: request.c:982
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:685
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:224
WEIGHT
#define WEIGHT(op)
Definition: define.h:648
buf
StringBuffer * buf
Definition: readable.c:1606
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:312
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:103
GetInt_String
int GetInt_String(const unsigned char *data)
Definition: lowlevel.c:251
pl::mark_count
uint32_t mark_count
Definition: player.h:199
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:241
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:619
F_LOCKED
#define F_LOCKED
Definition: newclient.h:291
inventory
void inventory(object *op, object *inv)
Definition: c_object.c:2014
positioning_system.marked
marked
Definition: positioning_system.py:21
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:235
esrv_get_ob_from_count
static object * esrv_get_ob_from_count(object *pl, tag_t count)
Definition: item.c:583
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:410
replace.current
current
Definition: replace.py:64
a_worn
@ a_worn
Definition: newclient.h:281
FLAG_NO_SKILL_IDENT
#define FLAG_NO_SKILL_IDENT
Definition: define.h:334
FLAG_CURSED
#define FLAG_CURSED
Definition: define.h:315
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:1700
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:2391
SockList
Definition: newclient.h:681
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:667
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:768
llevDebug
@ llevDebug
Definition: logger.h:13
SockList_AddPrintf
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:199
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:301
FLAG_IDENTIFIED
#define FLAG_IDENTIFIED
Definition: define.h:260
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:935
is_identified
int is_identified(const object *op)
Definition: item.c:1325