Crossfire Server, Branches 1.12  R18729
item.c
Go to the documentation of this file.
1 /*
2  * static char *rcsid_item_c =
3  * "$Id: item.c 11578 2009-02-23 22:02:27Z lalo $";
4  */
5 
6 /*
7  CrossFire, A Multiplayer game for X-windows
8 
9  Copyright (C) 2002,2006 Mark Wedel & Crossfire Development Team
10  Copyright (C) 1992 Frank Tore Johansen
11 
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or
15  (at your option) any later version.
16 
17  This program is distributed in the hope that it will be useful,
18  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20  GNU General Public License for more details.
21 
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 
26  The author can be reached via e-mail to crossfire-devel@real-time.com
27 */
28 
40 #include <global.h>
41 #include <object.h> /* LOOK_OBJ */
42 #include <newclient.h>
43 #include <newserver.h>
44 #include <sproto.h>
45 
47 #define MAXITEMLEN 300
48 
49 /*************************************************************************
50  *
51  * Functions related to sending object data to the client.
52  *
53  *************************************************************************
54  */
55 
60 static unsigned int query_flags(const object *op) {
61  unsigned int flags = 0;
62 
63  if (QUERY_FLAG(op, FLAG_APPLIED)) {
64  switch (op->type) {
65  case BOW:
66  case WAND:
67  case ROD:
68  case HORN:
69  flags = a_readied;
70  break;
71 
72  case WEAPON:
73  flags = a_wielded;
74  break;
75 
76  case SKILL:
77  case ARMOUR:
78  case HELMET:
79  case SHIELD:
80  case RING:
81  case BOOTS:
82  case GLOVES:
83  case AMULET:
84  case GIRDLE:
85  case BRACERS:
86  case CLOAK:
87  flags = a_worn;
88  break;
89 
90  case CONTAINER:
91  flags = a_active;
92  break;
93 
94  default:
95  flags = a_applied;
96  break;
97  }
98  }
99  if (op->type == CONTAINER
100  && ((op->env && op->env->container == op) || (!op->env && QUERY_FLAG(op, FLAG_APPLIED))))
101  flags |= F_OPEN;
102 
103  if (QUERY_FLAG(op, FLAG_KNOWN_CURSED)) {
104  if (QUERY_FLAG(op, FLAG_DAMNED))
105  flags |= F_DAMNED;
106  else if (QUERY_FLAG(op, FLAG_CURSED))
107  flags |= F_CURSED;
108  }
110  flags |= F_MAGIC;
111  if (QUERY_FLAG(op, FLAG_UNPAID))
112  flags |= F_UNPAID;
113  if (QUERY_FLAG(op, FLAG_INV_LOCKED))
114  flags |= F_LOCKED;
116  flags |= F_BLESSED;
117 
118  return flags;
119 }
120 
126 static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head) {
127  int flags, len, anim_speed;
128  char item_n[MAX_BUF], item_p[MAX_BUF];
129 
130  flags = query_flags(head);
131  if (QUERY_FLAG(head, FLAG_NO_PICK))
132  flags |= F_NOPICK;
133 
134  if (!(ns->faces_sent[head->face->number]&NS_FACESENT_FACE))
135  esrv_send_face(ns, head->face->number, 0);
136 
137  if (QUERY_FLAG(head, FLAG_ANIMATE) && !ns->anims_sent[head->animation_id])
139 
140  SockList_AddInt(sl, head->count);
141  SockList_AddInt(sl, flags);
142  SockList_AddInt(sl, QUERY_FLAG(head, FLAG_NO_PICK) ? -1 : WEIGHT(head));
143  SockList_AddInt(sl, head->face->number);
144 
145  if (!head->custom_name) {
146  query_base_name(head, 0, item_n, 126);
147  item_n[127] = 0;
148  len = strlen(item_n);
149  query_base_name(head, 1, item_p, MAX_BUF);
150  } else {
151  strncpy(item_n, head->custom_name, 127);
152  item_n[127] = 0;
153  len = strlen(item_n);
154  strncpy(item_p, head->custom_name, MAX_BUF);
155  }
156  strncpy(item_n+len+1, item_p, 127);
157  /* This is needed because strncpy may not add a ending \0 if the string is long enough. */
158  item_n[len+1+127] = 0;
159  len += strlen(item_n+1+len)+1;
160  SockList_AddLen8Data(sl, item_n, len);
161 
162  SockList_AddShort(sl, head->animation_id);
163  anim_speed = 0;
164  if (QUERY_FLAG(head, FLAG_ANIMATE)) {
165  if (head->anim_speed)
166  anim_speed = head->anim_speed;
167  else {
168  if (FABS(head->speed) < 0.001)
169  anim_speed = 255;
170  else if (FABS(head->speed) >= 1.0)
171  anim_speed = 1;
172  else
173  anim_speed = (int)(1.0/FABS(head->speed));
174  }
175  if (anim_speed > 255)
176  anim_speed = 255;
177  }
178  SockList_AddChar(sl, (char)anim_speed);
179  SockList_AddInt(sl, head->nrof);
180 
181  SockList_AddShort(sl, head->client_type);
182 
183  SET_FLAG(head, FLAG_CLIENT_SENT);
184 }
185 
191 void esrv_draw_look(object *pl) {
192  object *tmp, *last;
193  int got_one = 0, start_look = 0, end_look = 0, objects_sent = 0;
194  SockList sl;
195  char buf[MAX_BUF];
196 
197  if (!pl->contr->socket.update_look) {
198  LOG(llevDebug, "esrv_draw_look called when update_look was not set\n");
199  return;
200  } else {
201  pl->contr->socket.update_look = 0;
202  }
203 
204  if (QUERY_FLAG(pl, FLAG_REMOVED)
205  || pl->map == NULL
206  || pl->map->in_memory != MAP_IN_MEMORY
207  || out_of_map(pl->map, pl->x, pl->y))
208  return;
209 
210  if (pl->contr->transport)
211  for (tmp = pl->contr->transport->inv; tmp && tmp->above; tmp = tmp->above)
212  ;
213  else
214  for (tmp = GET_MAP_OB(pl->map, pl->x, pl->y); tmp && tmp->above; tmp = tmp->above)
215  ;
216 
217  SockList_Init(&sl);
218  SockList_AddString(&sl, "delinv 0");
219  Send_With_Handling(&pl->contr->socket, &sl);
220 
221  SockList_Reset(&sl);
222  SockList_AddPrintf(&sl, "item2 ");
223  SockList_AddInt(&sl, 0);
224 
227 
228  if (pl->contr->socket.look_position) {
229  int overhead = 1+(pl->contr->transport != NULL);
230  int prev_len = pl->contr->socket.num_look_objects-overhead-(pl->contr->socket.look_position > pl->contr->socket.num_look_objects-overhead);
231  SockList_AddInt(&sl, 0x80000000|MAX(0, pl->contr->socket.look_position-prev_len));
232  SockList_AddInt(&sl, 0);
233  SockList_AddInt(&sl, -1);
235  snprintf(buf, sizeof(buf), "Click here to see previous group of items");
236  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
237  SockList_AddShort(&sl, 0);
238  SockList_AddChar(&sl, 0);
239  SockList_AddInt(&sl, 0);
240  SockList_AddShort(&sl, 0);
241  objects_sent++;
242  got_one++;
243  }
244 
245  if (pl->contr->transport) {
247  objects_sent++;
248  got_one++;
249  }
250 
251  for (last = NULL; tmp != last; tmp = tmp->below) {
252  object *head;
253 
254  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !last) {
255  last = tmp->below; /* assumes double floor mode */
256  if (last && QUERY_FLAG(last, FLAG_IS_FLOOR))
257  last = last->below;
258  }
259  if (LOOK_OBJ(tmp)) {
260  if (start_look++ < pl->contr->socket.look_position)
261  continue;
262  end_look++;
263  objects_sent++;
264  if (objects_sent >= pl->contr->socket.num_look_objects) {
265  /* What we basically do is make a 'fake' object -
266  * when the user applies it, we notice the special
267  * tag the object has, and act accordingly.
268  */
269  SockList_AddInt(&sl, 0x80000000|(pl->contr->socket.look_position+end_look-1));
270  SockList_AddInt(&sl, 0);
271  SockList_AddInt(&sl, -1);
273  snprintf(buf, sizeof(buf), "Click here to see next group of items");
274  SockList_AddLen8Data(&sl, buf, MIN(strlen(buf), 255));
275  SockList_AddShort(&sl, 0);
276  SockList_AddChar(&sl, 0);
277  SockList_AddInt(&sl, 0);
278  SockList_AddShort(&sl, 0);
279  break;
280  }
281  if (tmp->head)
282  head = tmp->head;
283  else
284  head = tmp;
285 
286  add_object_to_socklist(&pl->contr->socket, &sl, head);
287  got_one++;
288 
289  if (SockList_Avail(&sl) < MAXITEMLEN) {
290  Send_With_Handling(&pl->contr->socket, &sl);
291  SockList_Reset(&sl);
292  SockList_AddPrintf(&sl, "item2 ");
293  SockList_AddInt(&sl, 0);
294  got_one = 0;
295  }
296  } /* If LOOK_OBJ() */
297  }
298  if (got_one)
299  Send_With_Handling(&pl->contr->socket, &sl);
300 
301  SockList_Term(&sl);
302 }
303 
307 void esrv_send_inventory(object *pl, object *op) {
308  object *tmp;
309  int got_one = 0;
310  SockList sl;
311 
312  SockList_Init(&sl);
313  SockList_AddPrintf(&sl, "delinv %u", op->count);
314  Send_With_Handling(&pl->contr->socket, &sl);
315 
316  SockList_Reset(&sl);
317  SockList_AddString(&sl, "item2 ");
318  SockList_AddInt(&sl, op->count);
319 
320  for (tmp = op->inv; tmp; tmp = tmp->below) {
321  object *head;
322 
323  if (tmp->head)
324  head = tmp->head;
325  else
326  head = tmp;
327 
328  if (LOOK_OBJ(head)) {
329  add_object_to_socklist(&pl->contr->socket, &sl, head);
330 
331  got_one++;
332 
333  /* It is possible for players to accumulate a huge amount of
334  * items (especially with some of the bags out there) to
335  * overflow the buffer. IF so, send multiple item commands.
336  */
337  if (SockList_Avail(&sl) < MAXITEMLEN) {
338  Send_With_Handling(&pl->contr->socket, &sl);
339  SockList_Reset(&sl);
340  SockList_AddString(&sl, "item2 ");
341  SockList_AddInt(&sl, op->count);
342  got_one = 0;
343  }
344  } /* If LOOK_OBJ() */
345  }
346  if (got_one)
347  Send_With_Handling(&pl->contr->socket, &sl);
348  SockList_Term(&sl);
349 }
350 
359 void esrv_update_item(int flags, object *pl, object *op) {
360  SockList sl;
361 
362  if (!pl->contr)
363  return;
364 
365  /* If we have a request to send the player item, skip a few checks. */
366  if (op != pl) {
367  if (!LOOK_OBJ(op))
368  return;
369  /* we remove the check for op->env, because in theory, the object
370  * is hopefully in the same place, so the client should preserve
371  * order.
372  */
373  }
374  if (!QUERY_FLAG(op, FLAG_CLIENT_SENT)) {
375  /* FLAG_CLIENT_SENT is debug only. We are using it to see where
376  * this is happening - we can set a breakpoint here in the debugger
377  * and track back the call.
378  */
379  LOG(llevDebug, "We have not sent item %s (%d)\n", op->name, op->count);
380  }
381 
382  SockList_Init(&sl);
383  SockList_AddString(&sl, "upditem ");
384  SockList_AddChar(&sl, (char)flags);
385 
386  if (op->head)
387  op = op->head;
388 
389  SockList_AddInt(&sl, op->count);
390 
391  if (flags&UPD_LOCATION)
392  SockList_AddInt(&sl, op->env ? op->env->count : 0);
393 
394  if (flags&UPD_FLAGS)
395  SockList_AddInt(&sl, query_flags(op));
396 
397  if (flags&UPD_WEIGHT) {
398  sint32 weight = WEIGHT(op);
399 
400  /* TRANSPORTS are odd - they sort of look like containers,
401  * yet can't be picked up. So we don't to send the weight,
402  * as it is odd that you see weight sometimes and not other
403  * (the draw_look won't send it for example.
404  */
405  SockList_AddInt(&sl, QUERY_FLAG(op, FLAG_NO_PICK) ? -1 : weight);
406  if (pl == op) {
407  op->contr->last_weight = weight;
408  }
409  }
410 
411  if (flags&UPD_FACE) {
413  esrv_send_face(&pl->contr->socket, op->face->number, 0);
414  SockList_AddInt(&sl, op->face->number);
415  }
416  if (flags&UPD_NAME) {
417  int len;
418  char item_p[MAX_BUF];
419  char item_n[MAX_BUF];
420 
421  if (!op->custom_name) {
422  query_base_name(op, 0, item_n, MAX_BUF);
423  len = strlen(item_n);
424  query_base_name(op, 1, item_p, MAX_BUF);
425  } else {
426  strncpy(item_n, op->custom_name, MAX_BUF-1);
427  item_n[MAX_BUF-1] = 0;
428  len = strlen(item_n);
429  strncpy(item_p, op->custom_name, MAX_BUF-1);
430  item_p[MAX_BUF-1] = 0;
431  }
432 
433  strncpy(item_n+len+1, item_p, 127);
434  item_n[254] = 0;
435  len += strlen(item_n+1+len)+1;
436  SockList_AddLen8Data(&sl, item_n, len);
437  }
438  if (flags&UPD_ANIM)
440 
441  if (flags&UPD_ANIMSPEED) {
442  int anim_speed = 0;
443 
444  if (QUERY_FLAG(op, FLAG_ANIMATE)) {
445  if (op->anim_speed)
446  anim_speed = op->anim_speed;
447  else {
448  if (FABS(op->speed) < 0.001)
449  anim_speed = 255;
450  else if (FABS(op->speed) >= 1.0)
451  anim_speed = 1;
452  else
453  anim_speed = (int)(1.0/FABS(op->speed));
454  }
455  if (anim_speed > 255)
456  anim_speed = 255;
457  }
458  SockList_AddChar(&sl, (char)anim_speed);
459  }
460  if (flags&UPD_NROF)
461  SockList_AddInt(&sl, op->nrof);
462 
463  Send_With_Handling(&pl->contr->socket, &sl);
464  SockList_Term(&sl);
465 }
466 
470 void esrv_send_item(object *pl, object*op) {
471  SockList sl;
472 
473  /* If this is not the player object, do some more checks */
474  if (op != pl) {
475  /* We only send 'visibile' objects to the client */
476  if (!LOOK_OBJ(op))
477  return;
478  /* if the item is on the ground, mark that the look needs to
479  * be updated.
480  */
481  if (!op->env) {
482  pl->contr->socket.update_look = 1;
483  return;
484  }
485  }
486 
487  SockList_Init(&sl);
488  SockList_AddString(&sl, "item2 ");
489 
490  if (op->head)
491  op = op->head;
492 
493  SockList_AddInt(&sl, op->env ? op->env->count : 0);
494 
495  add_object_to_socklist(&pl->contr->socket, &sl, op);
496 
497  Send_With_Handling(&pl->contr->socket, &sl);
499  SockList_Term(&sl);
500 }
501 
507 void esrv_del_item(player *pl, int tag) {
508  SockList sl;
509 
510  SockList_Init(&sl);
511  SockList_AddString(&sl, "delitem ");
512  SockList_AddInt(&sl, tag);
513  Send_With_Handling(&pl->socket, &sl);
514  SockList_Term(&sl);
515 }
516 
517 /**************************************************************************
518  *
519  * Client has requested us to do something with an object.
520  *
521  **************************************************************************
522  */
523 
529 static object *esrv_get_ob_from_count(object *pl, tag_t count) {
530  object *op, *tmp;
531 
532  if (pl->count == count)
533  return pl;
534 
535  for (op = pl->inv; op; op = op->below)
536  if (op->count == count)
537  return op;
538  else if (op->type == CONTAINER && pl->container == op)
539  for (tmp = op->inv; tmp; tmp = tmp->below)
540  if (tmp->count == count)
541  return tmp;
542 
543  for (op = GET_MAP_OB(pl->map, pl->x, pl->y); op; op = op->above)
544  if (op->head != NULL && op->head->count == count)
545  return op;
546  else if (op->count == count)
547  return op;
548  else if (op->type == CONTAINER && pl->container == op)
549  for (tmp = op->inv; tmp; tmp = tmp->below)
550  if (tmp->count == count)
551  return tmp;
552 
553  if (pl->contr->transport) {
554  for (tmp = pl->contr->transport->inv; tmp; tmp = tmp->below)
555  if (tmp->count == count)
556  return tmp;
557  }
558  return NULL;
559 }
560 
562 void examine_cmd(char *buf, int len, player *pl) {
563  long tag;
564  object *op;
565 
566  if (len <= 0 || !buf) {
567  LOG(llevDebug, "Player '%s' sent bogus examine_cmd information\n", pl->ob->name);
568  return;
569  }
570 
571  tag = atoi(buf);
572  op = esrv_get_ob_from_count(pl->ob, tag);
573  if (!op) {
574  LOG(llevDebug, "Player '%s' tried to examine the unknown object (%ld)\n", pl->ob->name, tag);
575  return;
576  }
577  examine(pl->ob, op);
578 }
579 
581 void apply_cmd(char *buf, int len, player *pl) {
582  uint32 tag;
583  object *op;
584 
585  if (!buf || len <= 0) {
586  LOG(llevDebug, "Player '%s' sent bogus apply_cmd information\n", pl->ob->name);
587  return;
588  }
589 
590  tag = atoi(buf);
591  op = esrv_get_ob_from_count(pl->ob, tag);
592 
593  /* sort of a hack, but if the player saves and the player then
594  * manually applies a savebed (or otherwise tries to do stuff),
595  * we run into trouble.
596  */
597  if (QUERY_FLAG(pl->ob, FLAG_REMOVED))
598  return;
599 
600  /* If the high bit is set, player applied a pseudo object. */
601  if (tag&0x80000000) {
602  pl->socket.look_position = tag&0x7fffffff;
603  pl->socket.update_look = 1;
604  return;
605  }
606 
607  if (!op) {
608  LOG(llevDebug, "Player '%s' tried to apply the unknown object (%d)\n", pl->ob->name, tag);
609  return;
610  }
611  player_apply(pl->ob, op, 0, 0);
612 }
613 
615 void lock_item_cmd(uint8 *data, int len, player *pl) {
616  int flag, tag;
617  object *op;
618  object *tmp;
619 
620  if (len != 5) {
621  LOG(llevDebug, "Player '%s' sent bogus lock_item_cmd information\n", pl->ob->name);
622  return;
623  }
624  flag = data[0];
625  tag = GetInt_String(data+1);
626  op = esrv_get_ob_from_count(pl->ob, tag);
627 
628  if (!op) {
630  "Could not find object to lock/unlock", NULL);
631  return;
632  }
633  if (!flag)
635  else
637 
638  tmp = merge_ob(op, NULL);
639  if (tmp == NULL) {
640  /* object was not merged - if it was, merge_ob sent updates for us. */
641  esrv_update_item(UPD_FLAGS, pl->ob, op);
642  }
643 }
644 
655 void mark_item_cmd(uint8 *data, int len, player *pl) {
656  int tag;
657  object *op;
658  char name[MAX_BUF];
659 
660  if (len != 4) {
661  LOG(llevDebug, "Player '%s' sent bogus mark_item_cmd information\n", pl->ob->name);
662  return;
663  }
664 
665  tag = GetInt_String(data);
666  op = esrv_get_ob_from_count(pl->ob, tag);
667  if (!op) {
669  "Could not find object to mark", NULL);
670  return;
671  }
672  pl->mark = op;
673  pl->mark_count = op->count;
674  query_name(op, name, MAX_BUF);
676  "Marked item %s",
677  "Marked item %s",
678  name);
679 }
680 
687 void look_at(object *op, int dx, int dy) {
688  object *tmp;
689  int flag = 0;
690  sint16 x, y;
691  mapstruct *m;
692  char name[MAX_BUF];
693 
694  if (out_of_map(op->map, op->x+dx, op->y+dy))
695  return;
696 
697  x = op->x+dx;
698  y = op->y+dy;
699 
700  m = get_map_from_coord(op->map, &x, &y);
701  if (!m)
702  return;
703 
704  for (tmp = GET_MAP_OB(m, x, y); tmp != NULL && tmp->above != NULL; tmp = tmp->above)
705  ;
706 
707  for (; tmp != NULL; tmp = tmp->below) {
708  if (tmp->invisible && !QUERY_FLAG(op, FLAG_WIZ))
709  continue;
710 
711  if (!flag) {
712  if (dx || dy)
714  "There you see:", NULL);
715  else {
717  "You see:", NULL);
718  }
719  flag = 1;
720  }
721 
722  query_name(tmp, name, MAX_BUF);
723  if (QUERY_FLAG(op, FLAG_WIZ))
725  "- %s (%d).",
726  "- %s (%d).",
727  name, tmp->count);
728  else
730  "- %s.",
731  "- %s.",
732  name);
733 
734  if (((tmp->inv != NULL || (tmp->head && tmp->head->inv)) && (tmp->type != CONTAINER && tmp->type != FLESH))
735  || QUERY_FLAG(op, FLAG_WIZ))
736  inventory(op, tmp->head == NULL ? tmp : tmp->head);
737 
738  /* don't continue under the floor */
739  if (QUERY_FLAG(tmp, FLAG_IS_FLOOR) && !QUERY_FLAG(op, FLAG_WIZ))
740  break;
741  }
742 
743  if (!flag) {
744  if (dx || dy)
746  "You see nothing there.", NULL);
747  else
749  "You see nothing.", NULL);
750  }
751 }
752 
754 void look_at_cmd(char *buf, int len, player *pl) {
755  int dx, dy;
756  char *cp;
757 
758  dx = atoi(buf);
759  if (!(cp = strchr(buf, ' '))) {
760  return;
761  }
762  dy = atoi(cp);
763 
764  if (FABS(dx) > MAP_CLIENT_X/2 || FABS(dy) > MAP_CLIENT_Y/2)
765  return;
766 
767  if (pl->blocked_los[dx+(pl->socket.mapx/2)][dy+(pl->socket.mapy/2)])
768  return;
769  look_at(pl->ob, dx, dy);
770 }
771 
773 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof) {
774  object *op, *env;
775 
776  op = esrv_get_ob_from_count(pl, tag);
777  if (!op) {
778  LOG(llevDebug, "Player '%s' tried to move an unknown object (%lu)\n", pl->name, (unsigned long)tag);
779  return;
780  }
781 
782  /* If on a transport, you don't drop to the ground - you drop to the
783  * transport.
784  */
785  if (!to && !pl->contr->transport) { /* drop it to the ground */
786  /* LOG(llevDebug, "Drop it on the ground.\n");*/
787 
788  if (op->map && !op->env) {
789 /* LOG(llevDebug, "Dropping object to ground that is already on ground\n");*/
790  return;
791  }
792  /* If it is an active container, then we should drop all objects
793  * in the container and not the container itself.
794  */
795  if (op->inv && QUERY_FLAG(op, FLAG_APPLIED)) {
796  object *current, *next;
797 
798  for (current = op->inv; current != NULL; current = next) {
799  next = current->below;
800  drop_object(pl, current, 0);
801  }
802  esrv_update_item(UPD_WEIGHT, pl, op);
803  } else {
804  drop_object(pl, op, nrof);
805  }
806  return;
807  } else if (to == pl->count) { /* pick it up to the inventory */
808  /* return if player has already picked it up */
809  if (op->env == pl)
810  return;
811 
812  pl->contr->count = nrof;
813  pick_up(pl, op);
814  return;
815  }
816  /* If not dropped or picked up, we are putting it into a sack */
817  if (pl->contr->transport) {
818  if (can_pick(pl, op)
819  && transport_can_hold(pl->contr->transport, op, nrof)) {
820  put_object_in_sack(pl, pl->contr->transport, op, nrof);
821  }
822  } else {
823  env = esrv_get_ob_from_count(pl, to);
824  if (!env) {
825  LOG(llevDebug, "Player '%s' tried to move object to the unknown location (%d)\n", pl->name, to);
826  return;
827  }
828  /* put_object_in_sack presumes that necessary sanity checking
829  * has already been done (eg, it can be picked up and fits in
830  * in a sack, so check for those things. We should also check
831  * an make sure env is in fact a container for that matter.
832  */
833  if (env->type == CONTAINER
834  && can_pick(pl, op)
835  && sack_can_hold(pl, env, op, nrof)) {
836  put_object_in_sack(pl, env, op, nrof);
837  }
838  }
839 }
840 
841 void inscribe_scroll_cmd(char *buf, int len, player *pl) {
842  object *scroll, *spell, *marked, *inscription, *currentspell;
843  tag_t tscroll, tspell, tmarked;
844  char type;
845 
846  if (len < 1) {
847  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
848  return;
849  }
850 
851  type = buf[0];
852 
853  inscription = find_skill_by_name(pl->ob, "inscription");
854  if (!inscription) {
855  draw_ext_info(NDI_UNIQUE, 0, pl->ob, MSG_TYPE_SKILL, MSG_TYPE_SKILL_FAILURE, "You don't know how to write!", NULL);
856  return;
857  }
858 
859  if (type == 0) {
860  if (len != 9) {
861  LOG(llevDebug, "Player %s sent an invalid inscribe command.\n", pl->ob->name);
862  return;
863  }
864  tscroll = GetInt_String((uint8 *)buf+1);
865  tspell = GetInt_String((uint8 *)buf+5);
866 
867  scroll = esrv_get_ob_from_count(pl->ob, tscroll);
868  if (!scroll) {
869  LOG(llevDebug, "Player %s sent an invalid scroll for inscribe command.\n", pl->ob->name);
870  return;
871  }
872 
873  spell = esrv_get_ob_from_count(pl->ob, tspell);
874  if (!spell) {
875  LOG(llevDebug, "Player %s sent an invalid spell for inscribe command.\n", pl->ob->name);
876  return;
877  }
878 
879  tmarked = pl->mark_count;
880  marked = pl->mark;
881  currentspell = pl->ranges[range_magic];
882 
883  pl->mark_count = tscroll;
884  pl->mark = scroll;
885  pl->ranges[range_magic] = spell;
886 
887  write_on_item(pl->ob, "", inscription);
888 
889  pl->mark_count = tmarked;
890  pl->mark = marked;
891  pl->ranges[range_magic] = currentspell;
892  } else {
893  }
894 }
#define UPD_FLAGS
Definition: newclient.h:255
#define FLAG_KNOWN_BLESSED
Definition: define.h:675
#define RING
Definition: define.h:232
void inscribe_scroll_cmd(char *buf, int len, player *pl)
Definition: item.c:841
void SockList_AddPrintf(SockList *sl, const char *format,...)
Definition: lowlevel.c:187
Definition: player.h:146
#define FLAG_DAMNED
Definition: define.h:614
#define FLAG_IS_FLOOR
Definition: define.h:599
#define FLAG_UNPAID
Definition: define.h:532
void look_at(object *op, int dx, int dy)
Definition: item.c:687
void SockList_Reset(SockList *sl)
Definition: lowlevel.c:85
signed short sint16
Definition: global.h:72
uint8 num_look_objects
Definition: newserver.h:149
#define NS_FACESENT_FACE
Definition: newserver.h:164
void SockList_Init(SockList *sl)
Definition: lowlevel.c:67
#define SET_FLAG(xyz, p)
Definition: define.h:510
#define FABS(x)
Definition: define.h:61
void esrv_draw_look(object *pl)
Definition: item.c:191
signed int sint32
Definition: global.h:64
int GetInt_String(const unsigned char *data)
Definition: lowlevel.c:239
#define WAND
Definition: define.h:291
uint16 client_type
Definition: object.h:191
void esrv_send_item(object *pl, object *op)
Definition: item.c:470
#define UPD_NAME
Definition: newclient.h:258
struct obj * container
Definition: object.h:149
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:60
#define F_CURSED
Definition: newclient.h:230
void apply_cmd(char *buf, int len, player *pl)
Definition: item.c:581
#define LOOK_OBJ(ob)
Definition: object.h:344
void SockList_AddShort(SockList *sl, uint16 data)
Definition: lowlevel.c:113
#define MSG_TYPE_SKILL_FAILURE
Definition: newclient.h:504
void pick_up(object *op, object *alt)
Definition: c_object.c:462
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:448
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:732
#define UPD_ANIM
Definition: newclient.h:259
void mark_item_cmd(uint8 *data, int len, player *pl)
Definition: item.c:655
void lock_item_cmd(uint8 *data, int len, player *pl)
Definition: item.c:615
socket_struct socket
Definition: player.h:148
sint16 invisible
Definition: object.h:211
object * merge_ob(object *op, object *top)
Definition: object.c:1724
void draw_ext_info(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *message, const char *oldmessage)
Definition: standalone.c:171
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.c:773
object * ranges[range_size]
Definition: player.h:157
uint32 in_memory
Definition: map.h:366
struct obj * above
Definition: object.h:146
#define BOOTS
Definition: define.h:281
#define CLOAK
Definition: define.h:268
sint16 x
Definition: object.h:179
#define GIRDLE
Definition: define.h:295
void look_at_cmd(char *buf, int len, player *pl)
Definition: item.c:754
void draw_ext_info_format(int flags, int pri, const object *pl, uint8 type, uint8 subtype, const char *new_format, const char *old_format,...)
Definition: standalone.c:175
#define ARMOUR
Definition: define.h:128
#define F_MAGIC
Definition: newclient.h:229
#define UPD_ANIMSPEED
Definition: newclient.h:260
#define FLAG_REMOVED
Definition: define.h:528
#define FLAG_KNOWN_MAGICAL
Definition: define.h:616
#define AMULET
Definition: define.h:153
uint16 number
Definition: face.h:43
uint32 tag_t
Definition: object.h:40
#define MAP_IN_MEMORY
Definition: map.h:151
uint8 * faces_sent
Definition: newserver.h:121
#define F_UNPAID
Definition: newclient.h:228
#define FLAG_CLIENT_SENT
Definition: define.h:645
struct mapdef * map
Definition: object.h:155
void SockList_Term(SockList *sl)
Definition: lowlevel.c:77
#define HORN
Definition: define.h:147
object * transport
Definition: player.h:249
#define FLAG_IDENTIFIED
Definition: define.h:557
#define UPD_LOCATION
Definition: newclient.h:254
void esrv_del_item(player *pl, int tag)
Definition: item.c:507
const char * name
Definition: object.h:167
struct obj * env
Definition: object.h:151
#define WEIGHT(op)
Definition: define.h:1098
#define F_LOCKED
Definition: newclient.h:234
#define FLESH
Definition: define.h:234
struct obj * below
Definition: object.h:145
object * drop_object(object *op, object *tmp, uint32 nrof)
Definition: c_object.c:847
void SockList_AddString(SockList *sl, const char *data)
Definition: lowlevel.c:154
sint32 last_weight
Definition: player.h:197
uint32 nrof
Definition: object.h:184
unsigned char uint8
Definition: global.h:75
mapstruct * get_map_from_coord(mapstruct *m, sint16 *x, sint16 *y)
Definition: map.c:2366
sint16 y
Definition: object.h:179
struct pl * contr
Definition: object.h:134
void examine(object *op, object *tmp)
Definition: c_object.c:1481
#define F_OPEN
Definition: newclient.h:232
#define WEAPON
Definition: define.h:127
int can_pick(const object *who, const object *item)
Definition: object.c:3569
static void add_object_to_socklist(socket_struct *ns, SockList *sl, object *head)
Definition: item.c:126
size_t SockList_Avail(const SockList *sl)
Definition: lowlevel.c:231
#define UPD_NROF
Definition: newclient.h:261
#define MAX(x, y)
Definition: define.h:70
uint32 count
Definition: player.h:163
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32 nrof)
Definition: c_object.c:282
#define MSG_TYPE_SKILL
Definition: newclient.h:329
float speed
Definition: object.h:181
#define QUERY_FLAG(xyz, p)
Definition: define.h:514
#define CLEAR_FLAG(xyz, p)
Definition: define.h:512
#define FLAG_WIZ
Definition: define.h:527
New_Face * empty_face
Definition: image.c:66
#define MAX_BUF
Definition: define.h:81
#define GLOVES
Definition: define.h:282
void examine_cmd(char *buf, int len, player *pl)
Definition: item.c:562
#define BRACERS
Definition: define.h:286
#define MAP_CLIENT_X
Definition: config.h:212
uint16 look_position
Definition: newserver.h:142
void SockList_AddChar(SockList *sl, char c)
Definition: lowlevel.c:103
static const flag_definition flags[]
#define MIN(x, y)
Definition: define.h:67
void inventory(object *op, object *inv)
Definition: c_object.c:1653
#define FLAG_KNOWN_CURSED
Definition: define.h:617
object * ob
Definition: player.h:207
#define FLAG_CURSED
Definition: define.h:613
#define SHIELD
Definition: define.h:145
int snprintf(char *dest, int max, const char *format,...)
Definition: porting.c:498
#define FLAG_ANIMATE
Definition: define.h:538
void esrv_update_item(int flags, object *pl, object *op)
Definition: item.c:359
#define F_DAMNED
Definition: newclient.h:231
#define MAP_CLIENT_Y
Definition: config.h:213
#define CONTAINER
Definition: define.h:306
uint32 update_look
Definition: newserver.h:131
const char * custom_name
Definition: object.h:285
void esrv_send_face(socket_struct *ns, short face_num, int nocache)
Definition: image.c:96
tag_t count
Definition: object.h:157
#define SKILL
Definition: define.h:157
void SockList_AddLen8Data(SockList *sl, const void *data, size_t len)
Definition: lowlevel.c:176
static object * esrv_get_ob_from_count(object *pl, tag_t count)
Definition: item.c:529
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.c:64
#define FLAG_APPLIED
Definition: define.h:531
int out_of_map(mapstruct *m, int x, int y)
Definition: map.c:2300
#define MSG_TYPE_COMMAND
Definition: newclient.h:326
void put_object_in_sack(object *op, object *sack, object *tmp, uint32 nrof)
Definition: c_object.c:700
uint16 animation_id
Definition: object.h:267
#define BOW
Definition: define.h:126
#define UPD_WEIGHT
Definition: newclient.h:256
#define GET_MAP_OB(M, X, Y)
Definition: map.h:193
uint8 anim_speed
Definition: object.h:268
struct obj * inv
Definition: object.h:148
#define NDI_UNIQUE
Definition: newclient.h:219
#define HELMET
Definition: define.h:146
struct obj * head
Definition: object.h:154
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:63
#define MAXITEMLEN
Definition: item.c:47
int player_apply(object *pl, object *op, int aflag, int quiet)
Definition: apply.c:557
uint8 anims_sent[MAXANIMNUM]
Definition: newserver.h:122
object * mark
Definition: player.h:248
unsigned int uint32
Definition: global.h:58
#define ROD
Definition: define.h:115
#define UPD_FACE
Definition: newclient.h:257
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:628
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:450
#define F_NOPICK
Definition: newclient.h:233
Definition: map.h:346
New_Face * face
Definition: object.h:183
#define FLAG_BLESSED
Definition: define.h:674
#define FLAG_NO_PICK
Definition: define.h:535
int write_on_item(object *pl, const char *params, object *skill)
Definition: skills.c:1695
uint32 mark_count
Definition: player.h:247
void SockList_AddInt(SockList *sl, uint32 data)
Definition: lowlevel.c:124
#define FLAG_INV_LOCKED
Definition: define.h:626
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:447
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:207
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:307
#define F_BLESSED
Definition: newclient.h:235
uint8 type
Definition: object.h:189
sint8 blocked_los[MAP_CLIENT_X][MAP_CLIENT_Y]
Definition: player.h:210
void Send_With_Handling(socket_struct *ns, SockList *sl)
Definition: lowlevel.c:541