Crossfire Server, Trunk  R22047
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, 0);
127 
128  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
129  if (head->animation == NULL) {
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->num])
133  esrv_send_animation(ns, head->animation);
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, (QUERY_FLAG(head, FLAG_ANIMATE) && head->animation) ? head->animation->num : 0);
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 
221  if (!(pl->contr->socket.faces_sent[empty_face->number]&NS_FACESENT_FACE))
222  esrv_send_face(&pl->contr->socket, empty_face, 0);
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) {
242  add_object_to_socklist(&pl->contr->socket, &sl, 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) {
458  if (!(pl->contr->socket.faces_sent[op->face->number]&NS_FACESENT_FACE))
459  esrv_send_face(&pl->contr->socket, op->face, 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)
481  SockList_AddShort(&sl, op->animation ? op->animation->num : 0);
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  char name[HUGE_BUF];
678 
679  if (len != 5) {
680  LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name);
681  return;
682  }
683  flag = data[0];
684  tag = GetInt_String(data+1);
685  op = esrv_get_ob_from_count(pl->ob, tag);
686 
687  if (!op) {
689  "Could not find object to lock/unlock");
690  return;
691  }
692 
693  if (op->map) {
695  "Can't lock/unlock an item on the ground");
696  return;
697  }
698  if (op->env != pl->ob) {
700  "Can't lock/unlock an item not directly in your inventory");
701  return;
702  }
703 
704  query_short_name(op, name, HUGE_BUF);
705  if (!flag) {
708  "Unlocked %s.", name);
709  } else {
712  "Locked %s.", name);
713  }
714 
715  tmp = object_merge(op, NULL);
716  if (tmp == NULL) {
717  /* object was not merged - if it was, object_merge() sent updates for us. */
718  esrv_update_item(UPD_FLAGS, pl->ob, op);
719  }
720 }
721 
732 void mark_item_cmd(uint8_t *data, int len, player *pl) {
733  int tag;
734  object *op;
735  char name[MAX_BUF];
736 
737  if (len != 4) {
738  LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name);
739  return;
740  }
741 
742  tag = GetInt_String(data);
743  op = esrv_get_ob_from_count(pl->ob, tag);
744  if (!op) {
746  "Could not find object to mark");
747  return;
748  }
749  pl->mark = op;
750  pl->mark_count = op->count;
751  query_name(op, name, MAX_BUF);
753  "Marked item %s",
754  name);
755 }
756 
763 void look_at(object *op, int dx, int dy) {
764  object *tmp;
765  int flag = 0;
766  int16_t x, y;
767  mapstruct *m;
768  char name[MAX_BUF];
769 
770  if (out_of_map(op->map, op->x+dx, op->y+dy))
771  return;
772 
773  x = op->x+dx;
774  y = op->y+dy;
775 
776  m = get_map_from_coord(op->map, &x, &y);
777  if (!m)
778  return;
779 
780  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
781  ;
782 
784  if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ))
785  continue;
786 
787  if (!flag) {
788  if (dx || dy)
790  "There you see:");
791  else {
793  "You see:");
794  }
795  flag = 1;
796  }
797 
798  query_name(tmp, name, MAX_BUF);
799  if (QUERY_FLAG(op, FLAG_WIZ))
801  "- %s (%d).",
802  name, tmp->count);
803  else
805  "- %s.",
806  name);
807 
808  if ((HEAD(tmp)->inv != NULL && (tmp->type != CONTAINER && tmp->type != FLESH))
809  || QUERY_FLAG(op, FLAG_WIZ))
810  inventory(op, HEAD(tmp));
811 
812  /* don't continue under the floor */
813  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !QUERY_FLAG(op, FLAG_WIZ))
814  break;
816 
817  if (!flag) {
818  if (dx || dy)
820  "You see nothing there.");
821  else
823  "You see nothing.");
824  }
825 }
826 
828 void look_at_cmd(char *buf, int len, player *pl) {
829  int dx, dy;
830  char *cp;
831 
832  if (len <= 0 || !buf) {
833  LOG(llevDebug, "Player '%s' sent bogus look_at_cmd information\n", pl->ob->name);
834  return;
835  }
836 
837  dx = atoi(buf);
838  if (!(cp = strchr(buf, ' '))) {
839  return;
840  }
841  dy = atoi(cp);
842 
843  if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2)
844  return;
845 
846  if (pl->blocked_los[dx+(pl->socket.mapx/2)][dy+(pl->socket.mapy/2)])
847  return;
848  look_at(pl->ob, dx, dy);
849 }
850 
852 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) {
853  object *op, *env;
854 
855  op = esrv_get_ob_from_count(pl, tag);
856  if (!op) {
857  LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag);
858  return;
859  }
860 
861  /* If on a transport, you don't drop to the ground - you drop to the
862  * transport.
863  */
864  if (!to && !pl->contr->transport) { /* drop it to the ground */
865  /* LOG(llevDebug, "Drop it on the ground.\n");*/
866 
867  if (op->map && !op->env) {
868 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/
869  return;
870  }
871  /* If it is an active container, then we should drop all objects
872  * in the container and not the container itself.
873  */
874  if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
875  FOR_INV_PREPARE(op, current)
876  drop_object(pl, current, 0);
877  FOR_INV_FINISH();
878  esrv_update_item(UPD_WEIGHT, pl, op);
879  } else {
880  drop_object(pl, op, nrof);
881  }
882  return;
883  } else if (to == pl->count) { /* pick it up to the inventory */
884  /* return if player has already picked it up */
885  if (op->env == pl)
886  return;
887 
888  pl->contr->count = nrof;
889  pick_up(pl, op);
890  return;
891  }
892  /* If not dropped or picked up, we are putting it into a sack */
893  if (pl->contr->transport) {
894  if (object_can_pick(pl, op)
895  && transport_can_hold(pl->contr->transport, op, nrof)) {
896  put_object_in_sack(pl, pl->contr->transport, op, nrof);
897  }
898  } else {
899  env = esrv_get_ob_from_count(pl, to);
900  if (!env) {
901  LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to);
902  return;
903  }
904  /* put_object_in_sack presumes that necessary sanity checking
905  * has already been done (eg, it can be picked up and fits in
906  * in a sack, so check for those things. We should also check
907  * an make sure env is in fact a container for that matter.
908  */
909  if (env->type == CONTAINER
910  && object_can_pick(pl, op)
911  && sack_can_hold(pl, env, op, nrof)) {
912  put_object_in_sack(pl, env, op, nrof);
913  }
914  }
915 }
916 
917 void inscribe_scroll_cmd(char *buf, int len, player *pl) {
918  object *scroll, *spell, *marked, *inscription, *currentspell;
919  tag_t tscroll, tspell, tmarked;
920  char type;
921 
922  if (len < 1) {
923  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
924  return;
925  }
926 
927  type = buf[0];
928 
929  inscription = find_skill_by_name(pl->ob, "inscription");
930  if (!inscription) {
931  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!");
932  return;
933  }
934 
935  if (type == 0) {
936  if (len != 9) {
937  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
938  return;
939  }
940  tscroll = GetInt_String((uint8_t *)buf+1);
941  tspell = GetInt_String((uint8_t *)buf+5);
942 
943  scroll = esrv_get_ob_from_count(pl->ob, tscroll);
944  if (!scroll) {
945  LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name);
946  return;
947  }
948 
949  spell = esrv_get_ob_from_count(pl->ob, tspell);
950  if (!spell) {
951  LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name);
952  return;
953  }
954 
955  tmarked = pl->mark_count;
956  marked = pl->mark;
957  currentspell = pl->ranges[range_magic];
958 
959  pl->mark_count = tscroll;
960  pl->mark = scroll;
961  pl->ranges[range_magic] = spell;
962 
963  write_on_item(pl->ob, "", inscription);
964 
965  pl->mark_count = tmarked;
966  pl->mark = marked;
967  pl->ranges[range_magic] = currentspell;
968  } else {
969  }
970 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:313
#define FLAG_KNOWN_BLESSED
Definition: define.h:379
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.c:917
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:763
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:66
#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
StringBuffer * buf
Definition: readable.c:1591
int GetInt_String(const unsigned char *data)
Definition: lowlevel.c:246
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:511
#define UPD_ANIM
Definition: newclient.h:294
void esrv_send_item(object *pl, object *op)
Definition: item.c:512
#define F_LOCKED
Definition: newclient.h:266
uint16_t look_position
Definition: newserver.h:114
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 HUGE_BUF
Definition: define.h:37
#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:2394
void pick_up(object *op, object *alt)
Definition: c_object.c:509
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:680
void SockList_AddShort(SockList *sl, uint16_t data)
Definition: lowlevel.c:108
socket_struct socket
Definition: player.h:94
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.c:852
object * ranges[range_size]
Definition: player.h:103
uint32_t mark_count
Definition: player.h:193
#define FLAG_BLESSED
Definition: define.h:378
uint16_t container_position
Definition: newserver.h:115
void SockList_AddInt(SockList *sl, uint32_t data)
Definition: lowlevel.c:119
#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:828
#define safe_strncpy
Definition: compat.h:23
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:308
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:791
#define MIN(x, y)
Definition: compat.h:17
#define FLAG_REMOVED
Definition: define.h:232
#define FLAG_KNOWN_MAGICAL
Definition: define.h:320
#define MAP_IN_MEMORY
Definition: map.h:131
uint32_t update_look
Definition: newserver.h:104
#define MSG_TYPE_COMMAND
Definition: newclient.h:379
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Definition: apply.c:637
#define F_UNPAID
Definition: newclient.h:260
int is_identified(const object *op)
Definition: item.c:1316
int object_can_pick(const object *who, const object *item)
Definition: object.c:3657
#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
const Face * empty_face
Definition: image.c:35
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:316
#define FLAG_IDENTIFIED
Definition: define.h:261
#define FOR_INV_FINISH()
Definition: define.h:714
void mark_item_cmd(uint8_t *data, int len, player *pl)
Definition: item.c:732
#define WEIGHT(op)
Definition: define.h:688
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:149
#define UPD_FLAGS
Definition: newclient.h:290
void examine(object *op, object *tmp)
Definition: c_object.c:1691
#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
uint16_t number
Definition: face.h:15
int8_t blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:159
#define UPD_WEIGHT
Definition: newclient.h:291
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define FLAG_WIZ
Definition: define.h:231
#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:925
#define F_OPEN
Definition: newclient.h:264
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:2005
void SockList_AddChar(SockList *sl, unsigned char c)
Definition: lowlevel.c:98
#define FOR_MAP_FINISH()
Definition: define.h:767
#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
#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
void esrv_send_animation(socket_struct *ns, const Animations *anim)
Definition: request.c:898
void esrv_send_face(socket_struct *ns, const Face *face, int nocache)
Definition: image.c:71
#define UPD_NROF
Definition: newclient.h:296
#define UPD_FACE
Definition: newclient.h:292
uint8_t anims_sent[MAXANIMNUM]
Definition: newserver.h:97
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:1800
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:508
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2321
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:787
#define GET_MAP_OB(M, X, Y)
Definition: map.h:173
#define MSG_TYPE_SKILL
Definition: newclient.h:383
#define NDI_UNIQUE
Definition: newclient.h:245
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:760
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:583
Definition: map.h:326
#define FLAG_NO_PICK
Definition: define.h:239
int write_on_item(object *pl, const char *params, object *skill)
Definition: skills.c:1768
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:1061
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:202
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:370
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:707
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:435