Crossfire Server, Trunk  R21466
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))
92  flags |= F_UNIDENTIFIED;
93 
94  if (QUERY_FLAG(op, FLAG_KNOWN_CURSED)) {
95  if (QUERY_FLAG(op, FLAG_DAMNED))
96  flags |= F_DAMNED;
97  else if (QUERY_FLAG(op, FLAG_CURSED))
98  flags |= F_CURSED;
99  }
101  flags |= F_MAGIC;
102  if (QUERY_FLAG(op, FLAG_UNPAID))
103  flags |= F_UNPAID;
104  if (QUERY_FLAG(op, FLAG_INV_LOCKED))
105  flags |= F_LOCKED;
107  flags |= F_BLESSED;
108 
109  return flags;
110 }
111 
117 static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head) {
118  int flags, len, anim_speed;
119  char item_n[MAX_BUF], item_p[MAX_BUF];
120 
121  flags = query_flags(head);
122  if (QUERY_FLAG(head, FLAG_NO_PICK))
123  flags |= F_NOPICK;
124 
125  if (!(ns->faces_sent[head->face->number]&NS_FACESENT_FACE))
126  esrv_send_face(ns, head->face->number, 0);
127 
128  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
129  if (head->animation_id == 0) {
130  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);
131  CLEAR_FLAG(head, FLAG_ANIMATE);
132  } else if (!ns->anims_sent[head->animation_id])
134  }
135 
136  SockList_AddInt(sl, head->count);
137  SockList_AddInt(sl, flags);
138  SockList_AddInt(sl, QUERY_FLAG(head, FLAG_NO_PICK) ? -1 : WEIGHT(head));
139  SockList_AddInt(sl, head->face->number);
140 
141  if (!head->custom_name) {
142  query_base_name(head, 0, item_n, 126);
143  item_n[127] = 0;
144  len = strlen(item_n);
145  query_base_name(head, 1, item_p, MAX_BUF);
146  } else {
147  safe_strncpy(item_n, head->custom_name, 127);
148  item_n[127] = 0;
149  len = strlen(item_n);
150  safe_strncpy(item_p, head->custom_name, sizeof(item_p));
151  }
152  strncpy(item_n+len+1, item_p, 127);
153  /* This is needed because strncpy may not add a ending \0 if the string is long enough. */
154  item_n[len+1+127] = 0;
155  len += strlen(item_n+1+len)+1;
156  SockList_AddLen8Data(sl, item_n, len);
157 
158  SockList_AddShort(sl, head->animation_id);
159  anim_speed = 0;
160  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
161  if (head->anim_speed)
162  anim_speed = head->anim_speed;
163  else {
164  if (FABS(head->speed) < 0.001)
165  anim_speed = 255;
166  else if (FABS(head->speed) >= 1.0)
167  anim_speed = 1;
168  else
169  anim_speed = (int)(1.0/FABS(head->speed));
170  }
171  if (anim_speed > 255)
172  anim_speed = 255;
173  }
174  SockList_AddChar(sl, (char)anim_speed);
175  SockList_AddInt(sl, head->nrof);
176 
177  SockList_AddShort(sl, head->client_type);
178 
179  SET_FLAG(head, FLAG_CLIENT_SENT);
180 }
181 
187 void esrv_draw_look(object *pl) {
188  object *tmp, *last;
189  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
190  SockList sl;
191  char buf[MAX_BUF];
192 
193  if (!pl->contr->socket.update_look) {
194  LOG(llevDebug, "esrv_draw_look called when update_look was not set\n");
195  return;
196  } else {
197  pl->contr->socket.update_look = 0;
198  }
199 
200  if (QUERY_FLAG(pl, FLAG_REMOVED)
201  || pl->map == NULL
202  || pl->map->in_memory != MAP_IN_MEMORY
203  || out_of_map(pl->map, pl->x, pl->y))
204  return;
205 
206  if (pl->contr->transport)
207  for (tmp = pl->contr->transport->inv; tmp && tmp->above; tmp = tmp->above)
208  ;
209  else
210  for (tmp = GET_MAP_OB(pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above)
211  ;
212 
213  SockList_Init(&sl);
214  SockList_AddString(&sl, "delinv 0");
215  Send_With_Handling(&pl->contr->socket, &sl);
216 
217  SockList_Reset(&sl);
218  SockList_AddPrintf(&sl, "item2 ");
219  SockList_AddInt(&sl, 0);
220 
223 
224  if (pl->contr->socket.look_position) {
225  int overhead = 1+(pl->contr->transport != NULL);
226  int prev_len = pl->contr->socket.num_look_objects-overhead-(pl->contr->socket.look_position > pl->contr->socket.num_look_objects-overhead);
227  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.look_position-prev_len));
228  SockList_AddInt(&sl, 0);
229  SockList_AddInt(&sl, -1);
231  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
232  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
233  SockList_AddShort(&sl, 0);
234  SockList_AddChar(&sl, 0);
235  SockList_AddInt(&sl, 0);
236  SockList_AddShort(&sl, 0);
237  objects_sent++;
238  got_one++;
239  }
240 
241  if (pl->contr->transport) {
243  objects_sent++;
244  got_one++;
245  }
246 
247  last = NULL;
249  object *head;
250 
251  if (tmp == last) {
252  break;
253  }
254 
255  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) {
256  last = tmp->below; /* assumes double floor mode */
257  if (last && QUERY_FLAG(last, FLAG_IS_FLOOR))
258  last = last->below;
259  }
260  if (LOOK_OBJ(tmp)) {
261  if (start_look++ < pl->contr->socket.look_position)
262  continue;
263  end_look++;
264  objects_sent++;
265  if (objects_sent >= pl->contr->socket.num_look_objects) {
266  /* What we basically do is make a 'fake' object -
267  * when the user applies it, we notice the special
268  * tag the object has, and act accordingly.
269  */
270  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.look_position+end_look-1));
271  SockList_AddInt(&sl, 0);
272  SockList_AddInt(&sl, -1);
274  snprintf(buf, sizeof(buf), "Click here to see next group of items");
275  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
276  SockList_AddShort(&sl, 0);
277  SockList_AddChar(&sl, 0);
278  SockList_AddInt(&sl, 0);
279  SockList_AddShort(&sl, 0);
280  break;
281  }
282  head = HEAD(tmp);
283  add_object_to_socklist(&pl->contr->socket, &sl, head);
284  got_one++;
285 
286  if (SockList_Avail(&sl) < MAXITEMLEN) {
287  Send_With_Handling(&pl->contr->socket, &sl);
288  SockList_Reset(&sl);
289  SockList_AddPrintf(&sl, "item2 ");
290  SockList_AddInt(&sl, 0);
291  got_one = 0;
292  }
293  } /* If LOOK_OBJ() */
295  if (got_one)
296  Send_With_Handling(&pl->contr->socket, &sl);
297 
298  SockList_Term(&sl);
299 }
300 
307 void esrv_send_inventory(object *pl, object *op) {
308  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
309  SockList sl;
310  char buf[MAX_BUF];
311  int prev_len = pl->contr->socket.num_look_objects - 2 - (((pl->contr->socket.container_position > pl->contr->socket.num_look_objects - 1)) ? 1 : 0);
312 
313  SockList_Init(&sl);
314  SockList_AddPrintf(&sl, "delinv %u", op->count);
315  Send_With_Handling(&pl->contr->socket, &sl);
316 
317  SockList_Reset(&sl);
318  SockList_AddString(&sl, "item2 ");
319  SockList_AddInt(&sl, op->count);
320  objects_sent++;
321 
322  if (pl != op && pl->contr->socket.container_position) {
323  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.container_position-prev_len));
324  SockList_AddInt(&sl, 0);
325  SockList_AddInt(&sl, -1);
327  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
328  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
329  SockList_AddShort(&sl, 0);
330  SockList_AddChar(&sl, 0);
331  SockList_AddInt(&sl, 0);
332  SockList_AddShort(&sl, 0);
333  objects_sent++;
334  got_one++;
335  }
336 
337  FOR_INV_PREPARE(op, tmp) {
338  object *head;
339 
340  head = HEAD(tmp);
341  if (LOOK_OBJ(head)) {
342  if (start_look++ < pl->contr->socket.container_position && pl != op)
343  continue;
344  end_look++;
345  objects_sent++;
346  if (pl != op && objects_sent >= pl->contr->socket.num_look_objects) {
347  /* What we basically do is make a 'fake' object -
348  * when the user applies it, we notice the special
349  * tag the object has, and act accordingly.
350  */
351  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.container_position + end_look - 1));
352  SockList_AddInt(&sl, 0);
353  SockList_AddInt(&sl, -1);
355  snprintf(buf, sizeof(buf), "Click here to see next group of items");
356  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
357  SockList_AddShort(&sl, 0);
358  SockList_AddChar(&sl, 0);
359  SockList_AddInt(&sl, 0);
360  SockList_AddShort(&sl, 0);
361  break;
362  }
363 
364  add_object_to_socklist(&pl->contr->socket, &sl, head);
365 
366  got_one++;
367 
368  /* It is possible for players to accumulate a huge amount of
369  * items (especially with some of the bags out there) to
370  * overflow the buffer. IF so, send multiple item commands.
371  */
372  if (SockList_Avail(&sl) < MAXITEMLEN) {
373  Send_With_Handling(&pl->contr->socket, &sl);
374  SockList_Reset(&sl);
375  SockList_AddString(&sl, "item2 ");
376  SockList_AddInt(&sl, op->count);
377  got_one = 0;
378  }
379  } /* If LOOK_OBJ() */
380  } FOR_INV_FINISH();
381  if (got_one) {
382  /* special case: only one item, the "prev group" arrow */
383  if (pl != op && pl->contr->socket.container_position) {
384  if (got_one > 1)
385  Send_With_Handling(&pl->contr->socket, &sl);
386  else {
387  /* view shifted, get to previous page and resend */
388  pl->contr->socket.container_position = MAX(0, pl->contr->socket.container_position - prev_len);
389  esrv_send_inventory(pl, op);
390  }
391  } else
392  Send_With_Handling(&pl->contr->socket, &sl);
393  }
394  SockList_Term(&sl);
395 }
396 
405 void esrv_update_item(int flags, object *pl, object *op) {
406  SockList sl;
407 
408  if (!pl->contr)
409  return;
410 
411  /* If we have a request to send the player item, skip a few checks. */
412  if (op != pl) {
413  if (!LOOK_OBJ(op))
414  return;
415  /* we remove the check for op->env, because in theory, the object
416  * is hopefully in the same place, so the client should preserve
417  * order.
418  */
419  }
420  if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) {
421  // Sometimes, we try to update an item that we haven't sent to the
422  // client. Don't! This can happen, for example, when a button under the
423  // floor gets toggled, but objects under floor tiles are generally not
424  // sent. There are some other places where this happens that we haven't
425  // tracked down, but in general, just don't.
426  //LOG(llevDebug, "We have not sent item %s (%d)\n", op->name, op->count);
427  return;
428  }
429 
430  SockList_Init(&sl);
431  SockList_AddString(&sl, "upditem ");
432  SockList_AddChar(&sl, (char)flags);
433 
434  op = HEAD(op);
435  SockList_AddInt(&sl, op->count);
436 
437  if (flags&UPD_LOCATION)
438  SockList_AddInt(&sl, op->env ? op->env->count : 0);
439 
440  if (flags&UPD_FLAGS)
441  SockList_AddInt(&sl, query_flags(op));
442 
443  if (flags&UPD_WEIGHT) {
444  int32_t weight = WEIGHT(op);
445 
446  /* TRANSPORTS are odd - they sort of look like containers,
447  * yet can't be picked up. So we don't to send the weight,
448  * as it is odd that you see weight sometimes and not other
449  * (the draw_look won't send it for example.
450  */
451  SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight);
452  if (pl == op) {
453  op->contr->last_weight = weight;
454  }
455  }
456 
457  if (flags&UPD_FACE) {
459  esrv_send_face(&pl->contr->socket, op->face->number, 0);
460  SockList_AddInt(&sl, op->face->number);
461  }
462  if (flags&UPD_NAME) {
463  int len;
464  char item_p[MAX_BUF];
465  char item_n[MAX_BUF];
466 
467  if (!op->custom_name) {
468  query_base_name(op, 0, item_n, sizeof(item_n)-1);
469  query_base_name(op, 1, item_p, sizeof(item_p));
470  } else {
471  strlcpy(item_n, op->custom_name, sizeof(item_n)-1);
472  strlcpy(item_p, op->custom_name, sizeof(item_p));
473  }
474 
475  len = strlen(item_n)+1;
476  snprintf(item_n+len, sizeof(item_n)-len, "%s", item_p);
477  len += strlen(item_n+len);
478  SockList_AddLen8Data(&sl, item_n, len);
479  }
480  if (flags&UPD_ANIM)
482 
483  if (flags&UPD_ANIMSPEED) {
484  int anim_speed = 0;
485 
486  if (QUERY_FLAG(op, FLAG_ANIMATE)) {
487  if (op->anim_speed)
488  anim_speed = op->anim_speed;
489  else {
490  if (FABS(op->speed) < 0.001)
491  anim_speed = 255;
492  else if (FABS(op->speed) >= 1.0)
493  anim_speed = 1;
494  else
495  anim_speed = (int)(1.0/FABS(op->speed));
496  }
497  if (anim_speed > 255)
498  anim_speed = 255;
499  }
500  SockList_AddChar(&sl, (char)anim_speed);
501  }
502  if (flags&UPD_NROF)
503  SockList_AddInt(&sl, op->nrof);
504 
505  Send_With_Handling(&pl->contr->socket, &sl);
506  SockList_Term(&sl);
507 }
508 
512 void esrv_send_item(object *pl, object*op) {
513  SockList sl;
514 
515  /* If this is not the player object, do some more checks */
516  if (op != pl) {
517  /* We only send 'visibile' objects to the client */
518  if (!LOOK_OBJ(op))
519  return;
520  /* if the item is on the ground, mark that the look needs to
521  * be updated.
522  */
523  if (!op->env) {
524  pl->contr->socket.update_look = 1;
525  return;
526  }
527  }
528 
529  SockList_Init(&sl);
530  SockList_AddString(&sl, "item2 ");
531 
532  op = HEAD(op);
533  SockList_AddInt(&sl, op->env ? op->env->count : 0);
534 
535  add_object_to_socklist(&pl->contr->socket, &sl, op);
536 
537  Send_With_Handling(&pl->contr->socket, &sl);
539  SockList_Term(&sl);
540 
541  /* if the object is in an opened container, then it may shift the contents,
542  * so resend everything */
543  if (pl->contr != NULL && pl->container != NULL && op->env == pl->container)
544  pl->contr->socket.update_inventory = 1;
545 }
546 
552 void esrv_del_item(player *pl, object *ob) {
553  SockList sl;
554 
555  SockList_Init(&sl);
556  SockList_AddString(&sl, "delitem ");
557  SockList_AddInt(&sl, ob->count);
558  Send_With_Handling(&pl->socket, &sl);
559  SockList_Term(&sl);
560  /* if the object is in an opened container, then it may shift the contents,
561  * so resend everything */
562  if (pl->ob->container != NULL && ob->env == pl->ob->container)
563  pl->socket.update_inventory = 1;
564 }
565 
566 /**************************************************************************
567  *
568  * Client has requested us to do something with an object.
569  *
570  **************************************************************************
571  */
572 
578 static object *esrv_get_ob_from_count(object *pl, tag_t count) {
579  if (pl->count == count)
580  return pl;
581 
582  FOR_INV_PREPARE(pl, op)
583  if (op->count == count)
584  return op;
585  else if (op->type == CONTAINER && pl->container == op) {
586  FOR_INV_PREPARE(op, tmp)
587  if (tmp->count == count)
588  return tmp;
589  FOR_INV_FINISH();
590  }
591  FOR_INV_FINISH();
592 
593  FOR_MAP_PREPARE(pl->map, pl->x, pl->y, op)
594  if (HEAD(op)->count == count)
595  return op;
596  else if (op->type == CONTAINER && pl->container == op) {
597  FOR_INV_PREPARE(op, tmp)
598  if (tmp->count == count)
599  return tmp;
600  FOR_INV_FINISH();
601  }
602  FOR_MAP_FINISH();
603 
604  if (pl->contr->transport) {
605  FOR_INV_PREPARE(pl->contr->transport, tmp)
606  if (tmp->count == count)
607  return tmp;
608  FOR_INV_FINISH();
609  }
610  return NULL;
611 }
612 
614 void examine_cmd(char *buf, int len, player *pl) {
615  long tag;
616  object *op;
617 
618  if (len <= 0 || !buf) {
619  LOG(llevDebug, "Player '%s' sent bogus examine_cmd information\n", pl->ob->name);
620  return;
621  }
622 
623  tag = atoi(buf);
624  op = esrv_get_ob_from_count(pl->ob, tag);
625  if (!op) {
626  LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", pl->ob->name, tag);
627  return;
628  }
629  examine(pl->ob, op);
630 }
631 
633 void apply_cmd(char *buf, int len, player *pl) {
634  uint32_t tag;
635  object *op;
636 
637  if (!buf || len <= 0) {
638  LOG(llevDebug, "Player '%s' sent bogus apply_cmd information\n", pl->ob->name);
639  return;
640  }
641 
642  tag = atoi(buf);
643  op = esrv_get_ob_from_count(pl->ob, tag);
644 
645  /* sort of a hack, but if the player saves and the player then
646  * manually applies a savebed (or otherwise tries to do stuff),
647  * we run into trouble.
648  */
649  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
650  return;
651 
652  /* If the high bit is set, player applied a pseudo object. */
653  if (tag&0x80000000) {
654  if (pl->ob->container != NULL) {
655  pl->socket.container_position = tag&0x7fffffff;
656  esrv_send_inventory(pl->ob, pl->ob->container);
657  pl->socket.update_inventory = 0;
658  } else {
659  pl->socket.look_position = tag&0x7fffffff;
660  pl->socket.update_look = 1;
661  }
662  return;
663  }
664 
665  if (!op) {
666  LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", pl->ob->name, tag);
667  return;
668  }
669  apply_by_living(pl->ob, op, 0, 0);
670 }
671 
673 void lock_item_cmd(uint8_t *data, int len, player *pl) {
674  int flag, tag;
675  object *op;
676  object *tmp;
677 
678  if (len != 5) {
679  LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name);
680  return;
681  }
682  flag = data[0];
683  tag = GetInt_String(data+1);
684  op = esrv_get_ob_from_count(pl->ob, tag);
685 
686  if (!op) {
688  "Could not find object to lock/unlock");
689  return;
690  }
691 
692  if (op->map) {
694  "Can't lock/unlock an item on the ground");
695  return;
696  }
697  if (op->env != pl->ob) {
699  "Can't lock/unlock an item not directly in your inventory");
700  return;
701  }
702 
703  if (!flag)
705  else
707 
708  tmp = object_merge(op, NULL);
709  if (tmp == NULL) {
710  /* object was not merged - if it was, object_merge() sent updates for us. */
711  esrv_update_item(UPD_FLAGS, pl->ob, op);
712  }
713 }
714 
725 void mark_item_cmd(uint8_t *data, int len, player *pl) {
726  int tag;
727  object *op;
728  char name[MAX_BUF];
729 
730  if (len != 4) {
731  LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name);
732  return;
733  }
734 
735  tag = GetInt_String(data);
736  op = esrv_get_ob_from_count(pl->ob, tag);
737  if (!op) {
739  "Could not find object to mark");
740  return;
741  }
742  pl->mark = op;
743  pl->mark_count = op->count;
744  query_name(op, name, MAX_BUF);
746  "Marked item %s",
747  name);
748 }
749 
756 void look_at(object *op, int dx, int dy) {
757  object *tmp;
758  int flag = 0;
759  int16_t x, y;
760  mapstruct *m;
761  char name[MAX_BUF];
762 
763  if (out_of_map(op->map, op->x+dx, op->y+dy))
764  return;
765 
766  x = op->x+dx;
767  y = op->y+dy;
768 
769  m = get_map_from_coord(op->map, &x, &y);
770  if (!m)
771  return;
772 
773  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
774  ;
775 
777  if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ))
778  continue;
779 
780  if (!flag) {
781  if (dx || dy)
783  "There you see:");
784  else {
786  "You see:");
787  }
788  flag = 1;
789  }
790 
791  query_name(tmp, name, MAX_BUF);
792  if (QUERY_FLAG(op, FLAG_WIZ))
794  "- %s (%d).",
795  name, tmp->count);
796  else
798  "- %s.",
799  name);
800 
801  if ((HEAD(tmp)->inv != NULL && (tmp->type != CONTAINER && tmp->type != FLESH))
802  || QUERY_FLAG(op, FLAG_WIZ))
803  inventory(op, HEAD(tmp));
804 
805  /* don't continue under the floor */
806  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !QUERY_FLAG(op, FLAG_WIZ))
807  break;
809 
810  if (!flag) {
811  if (dx || dy)
813  "You see nothing there.");
814  else
816  "You see nothing.");
817  }
818 }
819 
821 void look_at_cmd(char *buf, int len, player *pl) {
822  int dx, dy;
823  char *cp;
824 
825  if (len <= 0 || !buf) {
826  LOG(llevDebug, "Player '%s' sent bogus look_at_cmd information\n", pl->ob->name);
827  return;
828  }
829 
830  dx = atoi(buf);
831  if (!(cp = strchr(buf, ' '))) {
832  return;
833  }
834  dy = atoi(cp);
835 
836  if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2)
837  return;
838 
839  if (pl->blocked_los[dx+(pl->socket.mapx/2)][dy+(pl->socket.mapy/2)])
840  return;
841  look_at(pl->ob, dx, dy);
842 }
843 
845 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) {
846  object *op, *env;
847 
848  op = esrv_get_ob_from_count(pl, tag);
849  if (!op) {
850  LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag);
851  return;
852  }
853 
854  /* If on a transport, you don't drop to the ground - you drop to the
855  * transport.
856  */
857  if (!to && !pl->contr->transport) { /* drop it to the ground */
858  /* LOG(llevDebug, "Drop it on the ground.\n");*/
859 
860  if (op->map && !op->env) {
861 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/
862  return;
863  }
864  /* If it is an active container, then we should drop all objects
865  * in the container and not the container itself.
866  */
867  if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
868  FOR_INV_PREPARE(op, current)
869  drop_object(pl, current, 0);
870  FOR_INV_FINISH();
871  esrv_update_item(UPD_WEIGHT, pl, op);
872  } else {
873  drop_object(pl, op, nrof);
874  }
875  return;
876  } else if (to == pl->count) { /* pick it up to the inventory */
877  /* return if player has already picked it up */
878  if (op->env == pl)
879  return;
880 
881  pl->contr->count = nrof;
882  pick_up(pl, op);
883  return;
884  }
885  /* If not dropped or picked up, we are putting it into a sack */
886  if (pl->contr->transport) {
887  if (object_can_pick(pl, op)
888  && transport_can_hold(pl->contr->transport, op, nrof)) {
889  put_object_in_sack(pl, pl->contr->transport, op, nrof);
890  }
891  } else {
892  env = esrv_get_ob_from_count(pl, to);
893  if (!env) {
894  LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to);
895  return;
896  }
897  /* put_object_in_sack presumes that necessary sanity checking
898  * has already been done (eg, it can be picked up and fits in
899  * in a sack, so check for those things. We should also check
900  * an make sure env is in fact a container for that matter.
901  */
902  if (env->type == CONTAINER
903  && object_can_pick(pl, op)
904  && sack_can_hold(pl, env, op, nrof)) {
905  put_object_in_sack(pl, env, op, nrof);
906  }
907  }
908 }
909 
910 void inscribe_scroll_cmd(char *buf, int len, player *pl) {
911  object *scroll, *spell, *marked, *inscription, *currentspell;
912  tag_t tscroll, tspell, tmarked;
913  char type;
914 
915  if (len < 1) {
916  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
917  return;
918  }
919 
920  type = buf[0];
921 
922  inscription = find_skill_by_name(pl->ob, "inscription");
923  if (!inscription) {
924  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!");
925  return;
926  }
927 
928  if (type == 0) {
929  if (len != 9) {
930  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
931  return;
932  }
933  tscroll = GetInt_String((uint8_t *)buf+1);
934  tspell = GetInt_String((uint8_t *)buf+5);
935 
936  scroll = esrv_get_ob_from_count(pl->ob, tscroll);
937  if (!scroll) {
938  LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name);
939  return;
940  }
941 
942  spell = esrv_get_ob_from_count(pl->ob, tspell);
943  if (!spell) {
944  LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name);
945  return;
946  }
947 
948  tmarked = pl->mark_count;
949  marked = pl->mark;
950  currentspell = pl->ranges[range_magic];
951 
952  pl->mark_count = tscroll;
953  pl->mark = scroll;
954  pl->ranges[range_magic] = spell;
955 
956  write_on_item(pl->ob, "", inscription);
957 
958  pl->mark_count = tmarked;
959  pl->mark = marked;
960  pl->ranges[range_magic] = currentspell;
961  } else {
962  }
963 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:316
char path[HUGE_BUF]
Definition: map.h:365
#define FLAG_KNOWN_BLESSED
Definition: define.h:379
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.c:910
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:194
Definition: player.h:92
#define FLAG_DAMNED
Definition: define.h:318
#define FLAG_IS_FLOOR
Definition: define.h:303
#define FLAG_UNPAID
Definition: define.h:236
void look_at(object *op, int dx, int dy)
Definition: item.c:756
Definition: object.h:185
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:66
void esrv_send_face(socket_struct *ns, uint16_t face_num, int nocache)
Definition: image.c:70
#define NS_FACESENT_FACE
Definition: newserver.h:137
void lock_item_cmd(uint8_t *data, int len, player *pl)
Definition: item.c:673
void esrv_del_item(player *pl, object *ob)
Definition: item.c:552
void SockList_Init(SockList *sl)
Definition: lowlevel.c:48
#define SET_FLAG(xyz, p)
Definition: define.h:223
#define FABS(x)
Definition: define.h:22
void esrv_draw_look(object *pl)
Definition: item.c:187
unsigned char uint8_t
Definition: win32.h:161
uint16_t animation_id
Definition: object.h:418
int GetInt_String(const unsigned char *data)
Definition: lowlevel.c:246
#define UPD_ANIM
Definition: newclient.h:294
void esrv_send_item(object *pl, object *op)
Definition: item.c:512
uint8_t anim_speed
Definition: object.h:419
#define F_LOCKED
Definition: newclient.h:266
Definition: object.h:204
uint16_t look_position
Definition: newserver.h:114
struct obj * container
Definition: object.h:291
void esrv_send_animation(socket_struct *ns, short anim_num)
Definition: request.c:895
static unsigned int query_flags(const object *op)
Definition: item.c:49
void apply_cmd(char *buf, int len, player *pl)
Definition: item.c:633
#define LOOK_OBJ(ob)
Definition: object.h:507
uint32_t in_memory
Definition: map.h:345
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:512
mapstruct * get_map_from_coord(mapstruct *m, int16_t *x, int16_t *y)
Definition: map.c:2386
void pick_up(object *op, object *alt)
Definition: c_object.c:460
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:723
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.c:108
socket_struct socket
Definition: player.h:94
int16_t invisible
Definition: object.h:361
Definition: object.h:119
Definition: object.h:136
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.c:845
object * ranges[range_size]
Definition: player.h:103
Definition: object.h:109
uint32_t mark_count
Definition: player.h:193
#define FLAG_BLESSED
Definition: define.h:378
uint16_t container_position
Definition: newserver.h:115
struct obj * above
Definition: object.h:288
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.c:119
Definition: object.h:223
Definition: object.h:139
#define MAX(x, y)
Definition: compat.h:20
#define F_DAMNED
Definition: newclient.h:263
void look_at_cmd(char *buf, int len, player *pl)
Definition: item.c:821
Definition: object.h:187
#define safe_strncpy
Definition: compat.h:23
Definition: object.h:212
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:311
Definition: object.h:220
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:792
#define MIN(x, y)
Definition: compat.h:17
#define FLAG_REMOVED
Definition: define.h:232
#define FLAG_KNOWN_MAGICAL
Definition: define.h:320
uint16_t number
Definition: face.h:15
#define MAP_IN_MEMORY
Definition: map.h:130
uint32_t update_look
Definition: newserver.h:104
int16_t y
Definition: object.h:326
#define MSG_TYPE_COMMAND
Definition: newclient.h:379
Definition: object.h:118
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Definition: apply.c:648
#define F_UNPAID
Definition: newclient.h:260
int is_identified(const object *op)
Definition: item.c:1359
uint8_t num_look_objects
Definition: newserver.h:122
int object_can_pick(const object *who, const object *item)
Definition: object.c:3811
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:510
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:509
signed short int16_t
Definition: win32.h:160
#define FLAG_CLIENT_SENT
Definition: define.h:349
#define F_BLESSED
Definition: newclient.h:267
struct mapdef * map
Definition: object.h:297
void SockList_Term(SockList *sl)
Definition: lowlevel.c:58
#define snprintf
Definition: win32.h:46
#define F_NOPICK
Definition: newclient.h:265
#define F_MAGIC
Definition: newclient.h:261
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Definition: c_object.c:271
object * transport
Definition: player.h:195
#define FLAG_IDENTIFIED
Definition: define.h:261
#define FOR_INV_FINISH()
Definition: define.h:715
void mark_item_cmd(uint8_t *data, int len, player *pl)
Definition: item.c:725
const char * name
Definition: object.h:311
struct obj * env
Definition: object.h:293
#define WEIGHT(op)
Definition: define.h:689
struct obj * below
Definition: object.h:287
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:149
uint32_t nrof
Definition: object.h:333
#define UPD_FLAGS
Definition: newclient.h:290
struct pl * contr
Definition: object.h:276
void examine(object *op, object *tmp)
Definition: c_object.c:1452
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:585
static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head)
Definition: item.c:117
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:238
uint32_t update_inventory
Definition: newserver.h:105
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:159
#define UPD_WEIGHT
Definition: newclient.h:291
uint32_t tag_t
Definition: object.h:12
float speed
Definition: object.h:328
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define HEAD(op)
Definition: object.h:594
#define FLAG_WIZ
Definition: define.h:231
New_Face * empty_face
Definition: image.c:39
#define MAX_BUF
Definition: define.h:35
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.c:692
#define F_OPEN
Definition: newclient.h:264
int16_t x
Definition: object.h:326
void examine_cmd(char *buf, int len, player *pl)
Definition: item.c:614
uint8_t mapx
Definition: newserver.h:116
#define MAP_CLIENT_X
Definition: config.h:237
#define UPD_ANIMSPEED
Definition: newclient.h:295
static const flag_definition flags[]
void inventory(object *op, object *inv)
Definition: c_object.c:1725
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:98
#define FOR_MAP_FINISH()
Definition: define.h:768
#define F_UNIDENTIFIED
Definition: newclient.h:259
#define FLAG_KNOWN_CURSED
Definition: define.h:321
object * ob
Definition: player.h:158
#define FLAG_CURSED
Definition: define.h:317
unsigned int uint32_t
Definition: win32.h:162
Definition: object.h:135
#define FLAG_ANIMATE
Definition: define.h:242
void esrv_update_item(int flags, object *pl, object *op)
Definition: item.c:405
#define MAP_CLIENT_Y
Definition: config.h:238
#define UPD_NROF
Definition: newclient.h:296
Definition: object.h:143
const char * custom_name
Definition: object.h:434
int32_t last_weight
Definition: player.h:142
tag_t count
Definition: object.h:299
uint16_t client_type
Definition: object.h:341
#define UPD_FACE
Definition: newclient.h:292
uint8_t anims_sent[MAXANIMNUM]
Definition: newserver.h:97
uint8_t type
Definition: object.h:339
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:171
static object * esrv_get_ob_from_count(object *pl, tag_t count)
Definition: item.c:578
#define UPD_LOCATION
Definition: newclient.h:289
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.c:54
#define FLAG_APPLIED
Definition: define.h:235
object * object_merge(object *op, object *top)
Definition: object.c:1883
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2313
signed int int32_t
Definition: win32.h:159
#define UPD_NAME
Definition: newclient.h:293
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:788
#define GET_MAP_OB(M, X, Y)
Definition: map.h:172
#define MSG_TYPE_SKILL
Definition: newclient.h:383
struct obj * inv
Definition: object.h:290
#define NDI_UNIQUE
Definition: newclient.h:245
Definition: object.h:213
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
#define MAXITEMLEN
Definition: item.c:36
object * mark
Definition: player.h:194
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:761
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:626
Definition: map.h:325
const New_Face * face
Definition: object.h:332
#define FLAG_NO_PICK
Definition: define.h:239
int write_on_item(object *pl, const char *params, object *skill)
Definition: skills.c:1736
Definition: object.h:120
uint8_t mapy
Definition: newserver.h:116
#define FLAG_INV_LOCKED
Definition: define.h:330
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.c:828
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:192
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:307
uint8_t * faces_sent
Definition: newserver.h:96
#define F_CURSED
Definition: newclient.h:262
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:366
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:708
uint32_t count
Definition: player.h:109
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:435