Atrinik Server  4.0
item.c
Go to the documentation of this file.
1 /*************************************************************************
2  * Atrinik, a Multiplayer Online Role Playing Game *
3  * *
4  * Copyright (C) 2009-2014 Alex Tokar and Atrinik Development Team *
5  * *
6  * Fork from Crossfire (Multiplayer game for X-windows). *
7  * *
8  * This program is free software; you can redistribute it and/or modify *
9  * it under the terms of the GNU General Public License as published by *
10  * the Free Software Foundation; either version 2 of the License, or *
11  * (at your option) any later version. *
12  * *
13  * This program is distributed in the hope that it will be useful, *
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
16  * GNU General Public License for more details. *
17  * *
18  * You should have received a copy of the GNU General Public License *
19  * along with this program; if not, write to the Free Software *
20  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
21  * *
22  * The author can be reached at admin@atrinik.org *
23  ************************************************************************/
24 
32 #include <global.h>
33 #include <toolkit/packet.h>
34 #include <arch.h>
35 #include <player.h>
36 #include <object.h>
37 
38 static int check_container(object *pl, object *con);
39 
41 #define MAXITEMLEN 300
42 
51 unsigned int query_flags(object *op)
52 {
53  uint32_t flags = 0;
54 
55  if (QUERY_FLAG(op, FLAG_APPLIED)) {
56  flags |= CS_FLAG_APPLIED;
57  }
58 
59  if (op->type == CONTAINER && (op->attacked_by || (!op->env && QUERY_FLAG(op, FLAG_APPLIED)))) {
60  flags |= CS_FLAG_CONTAINER_OPEN;
61  }
62 
63  if (QUERY_FLAG(op, FLAG_IS_TRAPPED)) {
64  flags |= CS_FLAG_IS_TRAPPED;
65  }
66 
68  if (QUERY_FLAG(op, FLAG_DAMNED)) {
69  flags |= CS_FLAG_DAMNED;
70  } else if (QUERY_FLAG(op, FLAG_CURSED)) {
71  flags |= CS_FLAG_CURSED;
72  }
73  }
74 
76  flags |= CS_FLAG_IS_MAGICAL;
77  }
78 
79  if (QUERY_FLAG(op, FLAG_UNPAID)) {
80  flags |= CS_FLAG_UNPAID;
81  }
82 
83  if (QUERY_FLAG(op, FLAG_INV_LOCKED)) {
84  flags |= CS_FLAG_LOCKED;
85  }
86 
87  if (QUERY_FLAG(op, FLAG_TWO_HANDED)) {
88  flags |= CS_FLAG_WEAPON_2H;
89  }
90 
91  return flags;
92 }
93 
109 void add_object_to_packet(struct packet_struct *packet, object *op, object *pl,
110  uint8_t apply_action, uint32_t flags, int level)
111 {
112  packet_debug_data(packet, level, "\nTag");
113 
114  if (apply_action == CMD_APPLY_ACTION_NORMAL) {
115  packet_append_uint32(packet, op->count);
116  } else {
117  packet_append_uint32(packet, 0);
118  packet_append_uint8(packet, apply_action);
119  }
120 
121  if (flags & UPD_LOCATION) {
122  packet_debug_data(packet, level, "Location");
123  packet_append_uint32(packet, op->env ? op->env->count : 0);
124  }
125 
126  if (flags & UPD_FLAGS) {
127  packet_debug_data(packet, level, "Flags");
128  packet_append_uint32(packet, query_flags(op));
129  }
130 
131  if (flags & UPD_WEIGHT) {
132  packet_debug_data(packet, level, "Weight");
133  packet_append_uint32(packet, WEIGHT(op));
134  }
135 
136  if (flags & UPD_FACE) {
137  packet_debug_data(packet, level, "Face");
138 
139  if (op->inv_face && QUERY_FLAG(op, FLAG_IDENTIFIED)) {
140  packet_append_uint16(packet, op->inv_face->number);
141  } else {
142  packet_append_uint16(packet, op->face->number);
143  }
144  }
145 
146  if (flags & UPD_DIRECTION) {
147  packet_debug_data(packet, level, "Direction");
148  packet_append_uint8(packet, op->direction);
149  }
150 
151  if (flags & UPD_TYPE) {
152  packet_debug(packet, level, "Item info");
153  packet_debug_data(packet, level + 1, "Type");
154  packet_append_uint8(packet, op->type);
155  packet_debug_data(packet, level + 1, "Sub-type");
156  packet_append_uint8(packet, op->sub_type);
157 
158  packet_debug_data(packet, level + 1, "Quality");
159 
160  if (QUERY_FLAG(op, FLAG_IDENTIFIED)) {
161  uint8_t item_level, item_skill;
162 
163  if (op->type == BOOK_SPELL && op->stats.sp >= 0 &&
164  op->stats.sp < NROFREALSPELLS) {
165  spell_struct *spell = &spells[op->stats.sp];
166  item_level = spell->at->clone.level;
167  item_skill = SK_WIZARDRY_SPELLS + 1;
168  } else {
169  item_level = op->item_level;
170  item_skill = op->item_skill;
171  }
172 
173  packet_append_uint8(packet, op->item_quality);
174  packet_debug_data(packet, level + 1, "Condition");
175  packet_append_uint8(packet, op->item_condition);
176  packet_debug_data(packet, level + 1, "Level");
177  packet_append_uint8(packet, item_level);
178 
179  packet_debug_data(packet, level + 1, "Skill object ID");
180 
181  if (item_skill && CONTR(pl)->skill_ptr[item_skill - 1] != NULL) {
182  packet_append_uint32(packet,
183  CONTR(pl)->skill_ptr[item_skill - 1]->count);
184  } else {
185  packet_append_uint32(packet, 0);
186  }
187  } else {
188  packet_append_uint8(packet, 255);
189  }
190  }
191 
192  if (flags & UPD_NAME) {
193  packet_debug_data(packet, level, "Name");
194 
195  if (op->custom_name != NULL) {
196  packet_append_string_terminated(packet, op->custom_name);
197  } else {
198  StringBuffer *sb = object_get_base_name(op, pl, NULL);
199  packet_append_string_len_terminated(packet, stringbuffer_data(sb),
200  stringbuffer_length(sb));
201  stringbuffer_free(sb);
202  }
203  }
204 
205  if (flags & UPD_ANIM) {
206  packet_debug_data(packet, level, "Animation");
207 
208  if (QUERY_FLAG(op, FLAG_ANIMATE)) {
209  packet_append_uint16(packet, op->animation_id);
210  } else {
211  packet_append_uint16(packet, 0);
212  }
213  }
214 
215  if (flags & UPD_ANIMSPEED) {
216  int anim_speed = 0;
217 
218  if (QUERY_FLAG(op, FLAG_ANIMATE)) {
219  if (op->anim_speed) {
220  anim_speed = op->anim_speed;
221  } else {
222  if (FABS(op->speed) < 0.001) {
223  anim_speed = 255;
224  } else if (FABS(op->speed) >= 1.0) {
225  anim_speed = 1;
226  } else {
227  anim_speed = (int) (1.0 / FABS(op->speed));
228  }
229  }
230 
231  if (anim_speed > 255) {
232  anim_speed = 255;
233  }
234  }
235 
236  packet_debug_data(packet, level, "Animation speed");
237  packet_append_uint8(packet, anim_speed);
238  }
239 
240  if (flags & UPD_NROF) {
241  packet_debug_data(packet, level, "Nrof");
242  packet_append_uint32(packet, op->nrof);
243  }
244 
245  if (flags & UPD_EXTRA) {
246  if (op->type == SPELL) {
247  packet_debug(packet, level, "Spell info:\n");
248  packet_debug_data(packet, level + 1, "Cost");
249  packet_append_uint16(packet, SP_level_spellpoint_cost(pl,
250  op->stats.sp,
251  CONTR(pl)->skill_ptr[SK_WIZARDRY_SPELLS]->level));
252  packet_debug_data(packet, level + 1, "Path");
253  packet_append_uint32(packet, spells[op->stats.sp].path);
254  packet_debug_data(packet, level + 1, "Flags");
255  packet_append_uint32(packet, spells[op->stats.sp].flags);
256  packet_debug_data(packet, level + 1, "Message");
257  packet_append_string_terminated(packet, op->msg ? op->msg : "");
258  } else if (op->type == SKILL) {
259  packet_debug(packet, level, "Skill info:\n");
260  packet_debug_data(packet, level + 1, "Level");
261  packet_append_uint8(packet, op->level);
262  packet_debug_data(packet, level + 1, "Experience");
263  packet_append_int64(packet, op->stats.exp);
264 
265  if (CONTR(pl)->cs->socket_version >= 1065) {
266  packet_debug_data(packet, level + 1, "Message");
267  packet_append_string_terminated(packet, op->msg ? op->msg : "");
268  }
269  } else if (op->type == FORCE || op->type == POISONING) {
270  int32_t sec;
271 
272  packet_debug(packet, level, "Force info:\n");
273 
274  sec = -1;
275 
276  if (QUERY_FLAG(op, FLAG_IS_USED_UP)) {
277  double tmp_sec = op->speed_left / op->speed / MAX_TICKS;
278  tmp_sec = ABS(tmp_sec);
279  double tmp_sec2 = 1.0 / op->speed / MAX_TICKS;
280  tmp_sec2 *= op->stats.food - 1;
281  tmp_sec2 = ABS(tmp_sec2);
282  sec = tmp_sec + tmp_sec2;
283  }
284 
285  packet_debug_data(packet, level + 1, "Seconds");
286  packet_append_int32(packet, sec);
287  packet_debug_data(packet, level + 1, "Message");
288  packet_append_string_terminated(packet,
289  op->msg != NULL ? op->msg : "");
290  }
291  }
292 
293  if (flags & UPD_GLOW && CONTR(pl)->cs->socket_version >= 1060) {
294  packet_debug_data(packet, level, "Glow color");
295  packet_append_string_terminated(packet,
296  op->glow != NULL ? op->glow : "");
297  packet_debug_data(packet, level, "Glow speed");
298  packet_append_uint8(packet, op->glow_speed);
299  }
300 }
301 
313 static void esrv_draw_look_rec(object *pl, packet_struct *packet, object *op,
314  int level)
315 {
316  uint32_t flags = UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION |
317  UPD_NAME | UPD_ANIM | UPD_ANIMSPEED | UPD_NROF | UPD_GLOW;
318 
319  packet_debug(packet, level, "Inventory:");
320 
321  if (CONTR(pl)->cs->socket_version >= 1062) {
322  add_object_to_packet(packet, &arches[ARCH_INV_START]->clone, pl,
323  CMD_APPLY_ACTION_NONE, flags, level + 1);
324  } else {
325  packet_debug_data(packet, level + 1, "\nTag");
326  packet_append_uint32(packet, 0);
327  packet_debug_data(packet, level + 1, "Flags");
328  packet_append_uint32(packet, 0);
329  packet_debug_data(packet, level + 1, "Weight");
330  packet_append_int32(packet, -1);
331  packet_debug_data(packet, level + 1, "Face");
332  packet_append_uint16(packet,
333  arches[ARCH_INV_START]->clone.face->number);
334  packet_debug_data(packet, level + 1, "Direction");
335  packet_append_uint8(packet, 0);
336  packet_debug_data(packet, level + 1, "Name");
337  packet_append_string_terminated(packet, "in inventory");
338  packet_debug_data(packet, level + 1, "Animation");
339  packet_append_uint16(packet, 0);
340  packet_debug_data(packet, level + 1, "Animation speed");
341  packet_append_uint8(packet, 0);
342  packet_debug_data(packet, level + 1, "Nrof");
343  packet_append_uint32(packet, 0);
344  packet_debug_data(packet, level + 1, "Glow color");
345  packet_append_string_terminated(packet, "");
346  packet_debug_data(packet, level + 1, "Glow speed");
347  packet_append_uint8(packet, 0);
348  }
349 
350  for (object *tmp = op->inv; tmp != NULL; tmp = tmp->below) {
351  add_object_to_packet(packet, HEAD(tmp), pl, CMD_APPLY_ACTION_NORMAL,
352  flags, level + 1);
353 
354  if (tmp->inv && tmp->type != PLAYER) {
355  esrv_draw_look_rec(pl, packet, tmp, level + 1);
356  }
357  }
358 
359  if (CONTR(pl)->cs->socket_version >= 1062) {
360  add_object_to_packet(packet, &arches[ARCH_INV_END]->clone, pl,
361  CMD_APPLY_ACTION_NONE, flags, level + 1);
362  } else {
363  packet_debug_data(packet, level + 1, "\nTag");
364  packet_append_uint32(packet, 0);
365  packet_debug_data(packet, level + 1, "Flags");
366  packet_append_uint32(packet, 0);
367  packet_debug_data(packet, level + 1, "Weight");
368  packet_append_int32(packet, -1);
369  packet_debug_data(packet, level + 1, "Face");
370  packet_append_uint16(packet, arches[ARCH_INV_END]->clone.face->number);
371  packet_debug_data(packet, level + 1, "Direction");
372  packet_append_uint8(packet, 0);
373  packet_debug_data(packet, level + 1, "Name");
374  packet_append_string_terminated(packet, "end inventory");
375  packet_debug_data(packet, level + 1, "Animation");
376  packet_append_uint16(packet, 0);
377  packet_debug_data(packet, level + 1, "Animation speed");
378  packet_append_uint8(packet, 0);
379  packet_debug_data(packet, level + 1, "Nrof");
380  packet_append_uint32(packet, 0);
381  packet_debug_data(packet, level + 1, "Glow color");
382  packet_append_string_terminated(packet, "");
383  packet_debug_data(packet, level + 1, "Glow speed");
384  packet_append_uint8(packet, 0);
385  }
386 }
387 
396 void esrv_draw_look(object *pl)
397 {
398  if (QUERY_FLAG(pl, FLAG_REMOVED) || pl->map == NULL ||
399  pl->map->in_memory != MAP_IN_MEMORY ||
400  OUT_OF_MAP(pl->map, pl->x, pl->y)) {
401  return;
402  }
403 
404  uint32_t flags = UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION |
405  UPD_NAME | UPD_ANIM | UPD_ANIMSPEED | UPD_NROF | UPD_GLOW;
406 
407  packet_struct *packet = packet_new(CLIENT_CMD_ITEM, 512, 256);
408  packet_enable_ndelay(packet);
409  packet_debug_data(packet, 0, "Delete inventory flag");
410  packet_append_uint8(packet, 1);
411  packet_debug_data(packet, 0, "Inventory to delete ID");
412  packet_append_uint32(packet, 0);
413  packet_debug_data(packet, 0, "Target inventory ID");
414  packet_append_uint32(packet, 0);
415  packet_debug_data(packet, 0, "End flag");
416  packet_append_uint8(packet, 1);
417 
418  packet_debug(packet, 0, "Below inventory:\n");
419 
420  if (CONTR(pl)->cs->look_position) {
421  if (CONTR(pl)->cs->socket_version >= 1062) {
423  pl, CMD_APPLY_ACTION_BELOW_PREV, flags, 1);
424  } else {
425  packet_debug_data(packet, 1, "\nTag");
426  packet_append_uint32(packet, 0x80000000 |
427  (CONTR(pl)->cs->look_position - NUM_LOOK_OBJECTS));
428  packet_debug_data(packet, 1, "Flags");
429  packet_append_uint32(packet, 0);
430  packet_debug_data(packet, 1, "Weight");
431  packet_append_int32(packet, -1);
432  packet_debug_data(packet, 1, "Face");
433  packet_append_uint16(packet,
434  arches[ARCH_INV_GROUP_PREV]->clone.face->number);
435  packet_debug_data(packet, 1, "Direction");
436  packet_append_uint8(packet, 0);
437  packet_debug_data(packet, 1, "Name");
438  packet_append_string_terminated(packet, "Previous group of items");
439  packet_debug_data(packet, 1, "Animation");
440  packet_append_uint16(packet, 0);
441  packet_debug_data(packet, 1, "Animation speed");
442  packet_append_uint8(packet, 0);
443  packet_debug_data(packet, 1, "Nrof");
444  packet_append_uint32(packet, 0);
445  packet_debug_data(packet, 1, "Glow color");
446  packet_append_string_terminated(packet, "");
447  packet_debug_data(packet, 1, "Glow speed");
448  packet_append_uint8(packet, 0);
449  }
450  }
451 
452  uint32_t start_look = 0, end_look = 0;
453 
454  for (object *tmp = GET_MAP_OB_LAST(pl->map, pl->x, pl->y); tmp != NULL;
455  tmp = tmp->below) {
456  if (tmp == pl) {
457  continue;
458  }
459 
460  /* Skip map mask, sys_objects and invisible objects when we can't
461  * see them. */
462  if ((tmp->layer <= LAYER_FMASK || IS_INVISIBLE(tmp, pl)) &&
463  !CONTR(pl)->tsi) {
464  continue;
465  }
466 
467  if (++start_look < CONTR(pl)->cs->look_position) {
468  continue;
469  }
470 
471  if (++end_look > NUM_LOOK_OBJECTS) {
472  if (CONTR(pl)->cs->socket_version >= 1062) {
473  add_object_to_packet(packet,
474  &arches[ARCH_INV_GROUP_NEXT]->clone, pl,
475  CMD_APPLY_ACTION_BELOW_NEXT, flags, 1);
476  } else {
477  packet_debug_data(packet, 1, "\nTag");
478  packet_append_uint32(packet, 0x80000000 |
479  (CONTR(pl)->cs->look_position + NUM_LOOK_OBJECTS));
480  packet_debug_data(packet, 1, "Flags");
481  packet_append_uint32(packet, 0);
482  packet_debug_data(packet, 1, "Weight");
483  packet_append_int32(packet, -1);
484  packet_debug_data(packet, 1, "Face");
485  packet_append_uint16(packet,
486  arches[ARCH_INV_GROUP_NEXT]->clone.face->number);
487  packet_debug_data(packet, 1, "Direction");
488  packet_append_uint8(packet, 0);
489  packet_debug_data(packet, 1, "Name");
490  packet_append_string_terminated(packet, "Next group of items");
491  packet_debug_data(packet, 1, "Animation");
492  packet_append_uint16(packet, 0);
493  packet_debug_data(packet, 1, "Animation speed");
494  packet_append_uint8(packet, 0);
495  packet_debug_data(packet, 1, "Nrof");
496  packet_append_uint32(packet, 0);
497  packet_debug_data(packet, 1, "Glow color");
498  packet_append_string_terminated(packet, "");
499  packet_debug_data(packet, 1, "Glow speed");
500  packet_append_uint8(packet, 0);
501  }
502 
503  break;
504  }
505 
506  add_object_to_packet(packet, HEAD(tmp), pl, CMD_APPLY_ACTION_NORMAL,
507  flags, 1);
508 
509  if (CONTR(pl)->tsi && tmp->inv != NULL && tmp->type != PLAYER) {
510  esrv_draw_look_rec(pl, packet, tmp, 1);
511  }
512  }
513 
514  socket_send_packet(CONTR(pl)->cs, packet);
515 }
516 
524 void esrv_close_container(object *pl, object *op)
525 {
526  packet_struct *packet;
527 
528  SOFT_ASSERT(pl != NULL, "pl is NULL");
529  SOFT_ASSERT(op != NULL, "op is NULL");
530 
531  packet = packet_new(CLIENT_CMD_ITEM, 32, 0);
532  packet_enable_ndelay(packet);
533 
534  if (CONTR(pl)->cs->socket_version >= 1061) {
535  packet_debug_data(packet, 0, "Delete inventory flag");
536  packet_append_uint8(packet, 1);
537  packet_debug_data(packet, 0, "Inventory to delete ID");
538  packet_append_uint32(packet, op->count);
539  } else {
540  packet_debug_data(packet, 0, "Container mode flag");
541  packet_append_int32(packet, -1);
542  packet_debug_data(packet, 0, "Target inventory ID");
543  packet_append_int32(packet, -1);
544  }
545 
546  socket_send_packet(CONTR(pl)->cs, packet);
547 }
548 
557 void esrv_send_inventory(object *pl, object *op)
558 {
559  packet_struct *packet;
560  object *tmp;
561 
562  packet = packet_new(CLIENT_CMD_ITEM, 128, 256);
563  packet_enable_ndelay(packet);
564 
565  if (CONTR(pl)->cs->socket_version >= 1061) {
566  packet_debug_data(packet, 0, "Delete inventory flag");
567  packet_append_uint8(packet, 1);
568  packet_debug_data(packet, 0, "Inventory to delete ID");
569  packet_append_uint32(packet, op->count);
570  } else {
571  packet_debug_data(packet, 0, "Container mode flag");
572 
573  /* In this case we're sending a container inventory */
574  if (pl != op) {
575  /* Container mode flag */
576  packet_append_int32(packet, -1);
577  } else {
578  packet_append_int32(packet, op->count);
579  }
580  }
581 
582  packet_debug_data(packet, 0, "Target inventory ID");
583  packet_append_uint32(packet, op->count);
584  packet_debug_data(packet, 0, "End flag");
585  packet_append_uint8(packet, 1);
586 
587  for (tmp = op->inv; tmp; tmp = tmp->below) {
588  if (IS_INVISIBLE(tmp, pl)) {
589  continue;
590  }
591 
592  add_object_to_packet(packet, tmp, pl, CMD_APPLY_ACTION_NORMAL,
593  UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION | UPD_TYPE |
594  UPD_NAME | UPD_ANIM | UPD_ANIMSPEED | UPD_NROF | UPD_EXTRA |
595  UPD_GLOW, 0);
596  }
597 
598  socket_send_packet(CONTR(pl)->cs, packet);
599 }
600 
610 static void esrv_update_item_send(int flags, object *pl, object *op)
611 {
612  packet_struct *packet;
613 
614  if (!CONTR(pl)) {
615  return;
616  }
617 
618  /* Can't see that item... */
619  if (IS_INVISIBLE(op, pl)) {
620  return;
621  }
622 
623  packet = packet_new(CLIENT_CMD_ITEM_UPDATE, 64, 128);
624  packet_enable_ndelay(packet);
625  packet_debug_data(packet, 0, "Flags");
626  packet_append_uint16(packet, flags);
627  add_object_to_packet(packet, op, pl, CMD_APPLY_ACTION_NORMAL, flags, 0);
628  socket_send_packet(CONTR(pl)->cs, packet);
629 }
630 
639 void esrv_update_item(int flags, object *op)
640 {
641  if (op->type == PLAYER) {
642  esrv_update_item_send(flags, op, op);
643  } else if (op->env) {
644  if (op->env->type == CONTAINER) {
645  object *tmp;
646 
647  for (tmp = op->env->attacked_by; tmp; tmp = CONTR(tmp)->container_above) {
648  esrv_update_item_send(flags, tmp, op);
649  }
650  } else if (op->env->type == PLAYER) {
651  esrv_update_item_send(flags, op->env, op);
652  }
653  }
654 }
655 
663 static void esrv_send_item_send(object *pl, object *op)
664 {
665  packet_struct *packet;
666 
667  if (!CONTR(pl) || CONTR(pl)->cs->state != ST_PLAYING) {
668  return;
669  }
670 
671  /* Can't see that item... */
672  if (IS_INVISIBLE(op, pl)) {
673  return;
674  }
675 
676  packet = packet_new(CLIENT_CMD_ITEM, 64, 128);
677  packet_enable_ndelay(packet);
678 
679  if (CONTR(pl)->cs->socket_version >= 1061) {
680  packet_debug_data(packet, 0, "Delete inventory flag");
681  packet_append_uint8(packet, 0);
682  } else {
683  packet_debug_data(packet, 0, "Container mode flag");
684  packet_append_int32(packet, -4);
685  }
686 
687  packet_debug_data(packet, 0, "Target inventory ID");
688  packet_append_uint32(packet, op->env->count);
689  packet_debug_data(packet, 0, "End flag");
690  packet_append_uint8(packet, 0);
691  add_object_to_packet(packet, HEAD(op), pl, CMD_APPLY_ACTION_NORMAL,
692  UPD_FLAGS | UPD_WEIGHT | UPD_FACE | UPD_DIRECTION | UPD_TYPE |
693  UPD_NAME | UPD_ANIM | UPD_ANIMSPEED | UPD_NROF | UPD_EXTRA |
694  UPD_GLOW, 0);
695  socket_send_packet(CONTR(pl)->cs, packet);
696 }
697 
703 void esrv_send_item(object *op)
704 {
705  object *tmp;
706 
707  /* No object or object is not in inventory, nothing to do here. */
708  if (!op || !op->env) {
709  return;
710  }
711 
712  if (op->env->type == CONTAINER) {
713  /* Send the item information to all players that are looking
714  * inside this container. */
715  for (tmp = op->env->attacked_by; tmp; tmp = CONTR(tmp)->container_above) {
716  esrv_send_item_send(tmp, op);
717  }
718  } else if (op->env->type == PLAYER) {
719  esrv_send_item_send(op->env, op);
720  }
721 }
722 
730 static void esrv_del_item_send(object *pl, object *op)
731 {
732  packet_struct *packet;
733 
734  if (!CONTR(pl)) {
735  return;
736  }
737 
738  /* Can't see that item... */
739  if (IS_INVISIBLE(op, pl)) {
740  return;
741  }
742 
743  packet = packet_new(CLIENT_CMD_ITEM_DELETE, 16, 0);
744  packet_enable_ndelay(packet);
745  packet_debug_data(packet, 0, "Object ID");
746  packet_append_uint32(packet, op->count);
747  socket_send_packet(CONTR(pl)->cs, packet);
748 }
749 
755 void esrv_del_item(object *op)
756 {
757  /* No object or object is not inside an inventory, nothing to do. */
758  if (!op || !op->env) {
759  return;
760  }
761 
762  if (op->env->type == CONTAINER) {
763  object *tmp;
764 
765  for (tmp = op->env->attacked_by; tmp; tmp = CONTR(tmp)->container_above) {
766  esrv_del_item_send(tmp, op);
767  }
768  } else if (op->env->type == PLAYER) {
769  esrv_del_item_send(op->env, op);
770  }
771 }
772 
776 static object *get_ob_from_count_rec(object *pl, object *where, tag_t count)
777 {
778  for (object *tmp = where; tmp != NULL; tmp = tmp->below) {
779  object *head = HEAD(tmp);
780 
781  if (IS_INVISIBLE(head, pl)) {
782  continue;
783  }
784 
785  if (head->count == count) {
786  return head;
787  }
788 
789  if (head->inv == NULL) {
790  continue;
791  }
792 
793  if (CONTR(pl)->container == head || CONTR(pl)->tsi) {
794  object *tmp2 = get_ob_from_count_rec(pl, head->inv, count);
795  if (tmp2 != NULL) {
796  return tmp2;
797  }
798  }
799  }
800 
801  return NULL;
802 }
803 
814 object *esrv_get_ob_from_count(object *pl, tag_t count)
815 {
816  if (pl->count == count) {
817  return pl;
818  }
819 
820  object *tmp = get_ob_from_count_rec(pl, pl->inv, count);
821  if (tmp != NULL) {
822  return tmp;
823  }
824 
825  tmp = get_ob_from_count_rec(pl, GET_MAP_OB_LAST(pl->map, pl->x, pl->y),
826  count);
827  if (tmp != NULL) {
828  return tmp;
829  }
830 
831  return NULL;
832 }
833 
834 void socket_command_item_examine(socket_struct *ns, player *pl, uint8_t *data, size_t len, size_t pos)
835 {
836  tag_t tag;
837  object *op;
838 
839  tag = packet_to_uint32(data, len, &pos);
840 
841  if (!tag) {
842  return;
843  }
844 
845  op = esrv_get_ob_from_count(pl->ob, tag);
846 
847  if (!op) {
848  return;
849  }
850 
851  examine(pl->ob, op, NULL);
852 
853  if (pl->tsi) {
854  StringBuffer *sb;
855  char *cp;
856 
857  sb = stringbuffer_new();
858  object_dump(op, sb);
859  cp = stringbuffer_finish(sb);
860  draw_info(COLOR_WHITE, pl->ob, cp);
861  efree(cp);
862  }
863 }
864 
871 {
872  HARD_ASSERT(pl != NULL);
873 
874  packet_struct *packet = NULL;
875 
876  for (object *tmp = pl->ob->inv; tmp != NULL; tmp = tmp->below) {
877  if (tmp->quickslot != 0) {
878  if (packet == NULL) {
879  packet = packet_new(CLIENT_CMD_QUICKSLOT, 256, 256);
880  }
881 
882  packet_debug_data(packet, 0, "\nQuickslot ID");
883  packet_append_uint8(packet, tmp->quickslot - 1);
884  packet_debug_data(packet, 0, "Object ID");
885  packet_append_uint32(packet, tmp->count);
886  }
887  }
888 
889  if (packet != NULL) {
890  socket_send_packet(pl->cs, packet);
891  }
892 }
893 
894 void socket_command_quickslot(socket_struct *ns, player *pl, uint8_t *data,
895  size_t len, size_t pos)
896 {
897  uint8_t quickslot = packet_to_uint8(data, len, &pos);
898  if (quickslot < 1 || quickslot > MAX_QUICKSLOT) {
899  return;
900  }
901 
902  // TODO: replace with tag_t once the compatibility code is removed.
903  int64_t tag;
904  if (ns->socket_version >= 1061) {
905  tag = packet_to_uint32(data, len, &pos);
906  } else {
907  tag = packet_to_int32(data, len, &pos);
908  }
909 
910  bool removed_quickslot = false;
911  // TODO: replace with "tag == 0" once the compatibility code is removed.
912  bool set_quickslot = tag <= 0;
913  for (object *tmp = pl->ob->inv; tmp != NULL && (!removed_quickslot ||
914  !set_quickslot); tmp = tmp->below) {
915  if (!removed_quickslot && tmp->quickslot == quickslot) {
916  tmp->quickslot = 0;
917  removed_quickslot = true;
918  }
919 
920  if (!set_quickslot && tmp->count == tag) {
921  tmp->quickslot = quickslot;
922  set_quickslot = true;
923  }
924  }
925 }
926 
927 void socket_command_item_apply(socket_struct *ns, player *pl, uint8_t *data,
928  size_t len, size_t pos)
929 {
930  tag_t tag = packet_to_uint32(data, len, &pos);
931 
932  if (tag == 0) {
933  uint8_t apply_action = packet_to_uint8(data, len, &pos);
934 
935  if (apply_action == CMD_APPLY_ACTION_BELOW_NEXT) {
936  ns->look_position += MIN(UINT32_MAX - ns->look_position,
938  pl->cs->update_tile = 0;
939  return;
940  } else if (apply_action == CMD_APPLY_ACTION_BELOW_PREV) {
942  pl->cs->update_tile = 0;
943  return;
944  } else {
945  return;
946  }
947  }
948 
949  if (ns->socket_version < 1062) {
950  if (tag & 0x80000000) {
951  pl->cs->look_position = tag & 0x7fffffff;
952  pl->cs->update_tile = 0;
953  return;
954  }
955  }
956 
957  if (QUERY_FLAG(pl->ob, FLAG_REMOVED)) {
958  return;
959  }
960 
961  object *op = esrv_get_ob_from_count(pl->ob, tag);
962  if (op == NULL) {
963  return;
964  }
965 
966  player_apply(pl->ob, op, 0, 0);
967 }
968 
969 void socket_command_item_lock(socket_struct *ns, player *pl, uint8_t *data, size_t len, size_t pos)
970 {
971  tag_t tag;
972  object *op;
973 
974  tag = packet_to_uint32(data, len, &pos);
975 
976  if (!tag) {
977  return;
978  }
979 
980  op = esrv_get_ob_from_count(pl->ob, tag);
981 
982  if (!op) {
983  return;
984  }
985 
986  /* Only lock item inside the player's own inventory */
987  if (!object_is_in_inventory(op, pl->ob)) {
988  draw_info(COLOR_WHITE, pl->ob, "You can't lock items outside your inventory!");
989  return;
990  }
991 
993  esrv_update_item(UPD_FLAGS, op);
994 }
995 
996 void socket_command_item_mark(socket_struct *ns, player *pl, uint8_t *data, size_t len, size_t pos)
997 {
998  tag_t tag;
999  object *op;
1000 
1001  tag = packet_to_uint32(data, len, &pos);
1002 
1003  if (!tag) {
1004  return;
1005  }
1006 
1007  op = esrv_get_ob_from_count(pl->ob, tag);
1008 
1009  if (!op) {
1010  return;
1011  }
1012 
1013  char *name = object_get_name_s(op, pl->ob);
1014 
1015  if (pl->mark_count == op->count) {
1016  draw_info_format(COLOR_WHITE, pl->ob, "Unmarked item %s.", name);
1017  pl->mark = NULL;
1018  pl->mark_count = 0;
1019  } else {
1020  draw_info_format(COLOR_WHITE, pl->ob, "Marked item %s.", name);
1021  pl->mark_count = op->count;
1022  pl->mark = op;
1023  }
1024 
1025  efree(name);
1026 }
1027 
1039 void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
1040 {
1041  object *op, *env;
1042  int tmp;
1043 
1044  op = esrv_get_ob_from_count(pl, tag);
1045 
1046  if (!op) {
1047  return;
1048  }
1049 
1050  /* drop it to the ground */
1051  if (!to) {
1052  if (op->map && !op->env) {
1053  return;
1054  }
1055 
1057 
1058  if ((tmp = check_container(pl, op))) {
1059  draw_info(COLOR_WHITE, pl, "First remove all god-given items from this container!");
1060  } else if (QUERY_FLAG(pl, FLAG_INV_LOCKED)) {
1061  draw_info(COLOR_WHITE, pl, "You can't drop a container with locked items inside!");
1062  } else {
1063  drop_object(pl, op, nrof, 0);
1064  }
1065 
1067 
1068  return;
1069  } else if (to == pl->count || (to == op->count && !op->env)) {
1070  /* Pick it up to the inventory */
1071 
1072  /* Return if player has already picked it up */
1073  if (op->env == pl) {
1074  return;
1075  }
1076 
1077  CONTR(pl)->count = nrof;
1078  /* It goes in player inv or readied container */
1079  pick_up(pl, op, 0);
1080  return;
1081  }
1082 
1083  /* If not dropped or picked up, we are putting it into a sack */
1084  env = esrv_get_ob_from_count(pl, to);
1085 
1086  if (!env) {
1087  return;
1088  }
1089 
1090  /* put_object_in_sack() presumes that necessary sanity checking has
1091  * already been done (eg, it can be picked up and fits in in a sack,
1092  * so check for those things. We should also check and make sure env
1093  * is in fact a container for that matter. */
1094  if (env->type == CONTAINER && object_can_pick(pl, op) && sack_can_hold(pl, env, op, nrof)) {
1096  tmp = check_container(pl, op);
1097 
1098  if (QUERY_FLAG(pl, FLAG_INV_LOCKED) && env->env != pl) {
1099  draw_info(COLOR_WHITE, pl, "You can't drop a container with locked items inside!");
1100  } else if (tmp && env->env != pl) {
1101  draw_info(COLOR_WHITE, pl, "First remove all god-given items from this container!");
1102  } else if (QUERY_FLAG(op, FLAG_STARTEQUIP) && env->env != pl) {
1103  draw_info(COLOR_WHITE, pl, "You can't store god-given items outside your inventory!");
1104  } else {
1105  put_object_in_sack(pl, env, op, nrof);
1106  }
1107 
1109 
1110  return;
1111  }
1112 }
1113 
1126 static int check_container(object *pl, object *con)
1127 {
1128  object *current, *next;
1129  int ret = 0;
1130 
1131  /* Only check stuff *inside* a container */
1132  if (con->type != CONTAINER) {
1133  return 0;
1134  }
1135 
1136  for (current = con->inv; current != NULL; current = next) {
1137  next = current->below;
1138  ret += check_container(pl, current);
1139 
1140  if (QUERY_FLAG(current, FLAG_STARTEQUIP)) {
1141  ret += 1;
1142  }
1143 
1144  if (QUERY_FLAG(current, FLAG_INV_LOCKED)) {
1146  }
1147  }
1148 
1149  return ret;
1150 }
static object * get_ob_from_count_rec(object *pl, object *where, tag_t count)
Definition: item.c:776
#define MAP_IN_MEMORY
Definition: map.h:170
bool object_is_in_inventory(const object *op, const object *inv)
Definition: object.c:655
uint8_t item_level
Definition: object.h:375
void esrv_close_container(object *pl, object *op)
Definition: item.c:524
The 'inv_group_prev' archetype.
Definition: arch.h:64
void add_object_to_packet(struct packet_struct *packet, object *op, object *pl, uint8_t apply_action, uint32_t flags, int level)
Definition: item.c:109
uint32_t update_tile
Definition: newserver.h:134
#define FLAG_CURSED
Definition: define.h:1154
#define LAYER_FMASK
Definition: map.h:51
object * mark
Definition: player.h:197
#define FLAG_IS_TRAPPED
Definition: define.h:1239
void esrv_draw_look(object *pl)
Definition: item.c:396
The 'inv_start' archetype.
Definition: arch.h:65
#define FLAG_ANIMATE
Definition: define.h:912
#define NROFREALSPELLS
Definition: define.h:664
double speed_left
Definition: object.h:472
The 'inv_end' archetype.
Definition: arch.h:66
uint32_t in_memory
Definition: map.h:627
uint8_t item_skill
Definition: object.h:378
uint32_t mark_count
Definition: player.h:314
void esrv_move_object(object *pl, tag_t to, tag_t tag, long nrof)
Definition: item.c:1039
object * ob
Definition: player.h:185
int64_t exp
Definition: living.h:69
uint8_t item_quality
Definition: object.h:366
#define OUT_OF_MAP(M, X, Y)
Definition: map.h:240
#define PLAYER
Definition: define.h:122
int SP_level_spellpoint_cost(object *caster, int spell_type, int caster_level)
Definition: spell_util.c:1072
int16_t sp
Definition: living.h:78
uint32_t socket_version
Definition: newserver.h:130
#define QUERY_FLAG(xyz, p)
Definition: define.h:761
#define POISONING
Definition: define.h:437
#define FLAG_STARTEQUIP
Definition: define.h:1004
char * object_get_name_s(const object *op, const object *caller)
Definition: item.c:398
uint16_t number
Definition: face.h:46
#define FLIP_FLAG(xyz, p)
Definition: define.h:771
#define FLAG_DAMNED
Definition: define.h:1158
int16_t y
Definition: object.h:276
archetype_t * arches[ARCH_MAX]
Definition: arch.c:45
uint8_t glow_speed
Definition: object.h:466
void pick_up(object *op, object *alt, int no_mevent)
Definition: player.c:2019
New_Face * inv_face
Definition: object.h:237
int8_t direction
Definition: object.h:350
StringBuffer * object_get_base_name(const object *op, const object *caller, StringBuffer *sb)
Definition: item.c:513
uint8_t item_condition
Definition: object.h:369
struct sound_ambient_match * next
Next match rule in a linked list.
Definition: sound_ambient.c:39
uint16_t animation_id
Definition: object.h:322
struct mapdef * map
Definition: object.h:139
#define FLAG_UNPAID
Definition: define.h:1251
static int check_container(object *pl, object *con)
Definition: item.c:1126
union @21 data
Data about the rule.
int sack_can_hold(object *pl, object *sack, object *op, int nrof)
Definition: player.c:1870
#define SET_FLAG(xyz, p)
Definition: define.h:741
struct obj * env
Definition: object.h:130
struct archetype * at
Definition: spells.h:198
uint32_t flags
Definition: spells.h:189
struct obj * below
Definition: object.h:114
#define CONTAINER
Definition: define.h:493
static void esrv_update_item_send(int flags, object *pl, object *op)
Definition: item.c:610
uint32_t nrof
Definition: object.h:264
uint8_t anim_speed
Definition: object.h:393
#define BOOK_SPELL
Definition: define.h:373
#define IS_INVISIBLE(__ob_, __player_)
Definition: define.h:1356
#define FLAG_IS_USED_UP
Definition: define.h:976
double speed
Definition: object.h:469
#define HEAD(op)
Definition: object.h:657
void esrv_del_item(object *op)
Definition: item.c:755
void object_dump(const object *op, StringBuffer *sb)
Definition: object.c:680
#define WEIGHT(op)
Definition: object.h:40
void esrv_send_item(object *op)
Definition: item.c:703
static void esrv_del_item_send(object *pl, object *op)
Definition: item.c:730
int16_t x
Definition: object.h:273
object * esrv_get_ob_from_count(object *pl, tag_t count)
Definition: item.c:814
#define FLAG_REMOVED
Definition: define.h:930
uint8_t tsi
Definition: player.h:537
#define FLAG_TWO_HANDED
Definition: define.h:1082
spell_struct spells[NROFREALSPELLS]
Definition: spellist.h:34
unsigned int query_flags(object *op)
Definition: item.c:51
#define FLAG_APPLIED
Definition: define.h:1182
static void esrv_draw_look_rec(object *pl, packet_struct *packet, object *op, int level)
Definition: item.c:313
#define NUM_LOOK_OBJECTS
Definition: newserver.h:37
The 'inv_group_next' archetype.
Definition: arch.h:63
uint32_t path
Definition: spells.h:192
#define MAX_QUICKSLOT
Definition: player.h:89
tag_t count
Definition: object.h:142
living stats
Definition: object.h:481
void esrv_update_item(int flags, object *op)
Definition: item.c:639
uint32_t look_position
Definition: newserver.h:149
socket_struct * cs
Definition: player.h:148
#define SKILL
Definition: define.h:246
uint8_t type
Definition: object.h:360
#define CLEAR_FLAG(xyz, p)
Definition: define.h:751
void send_quickslots(player *pl)
Definition: item.c:870
void examine(object *op, object *tmp, StringBuffer *sb_capture)
Definition: player.c:1521
const char * msg
Definition: object.h:183
static void esrv_send_item_send(object *pl, object *op)
Definition: item.c:663
#define FLAG_IS_MAGICAL
Definition: define.h:1129
struct obj * inv
Definition: object.h:123
int player_apply(object *pl, object *op, int aflag, int quiet)
Definition: apply.c:123
shstr * custom_name
Definition: object.h:190
void put_object_in_sack(object *op, object *sack, object *tmp, long nrof)
Definition: player.c:2122
bool object_can_pick(const object *op, const object *item)
Definition: object.c:2335
void drop_object(object *op, object *tmp, long nrof, int no_mevent)
Definition: player.c:2195
#define FLAG_INV_LOCKED
Definition: define.h:1186
New_Face * face
Definition: object.h:234
int8_t level
Definition: object.h:347
#define FORCE
Definition: define.h:465
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:557
object clone
An object from which to do object_copy().
Definition: arch.h:47
shstr * glow
Definition: object.h:193
#define FLAG_IDENTIFIED
Definition: define.h:980
struct obj * attacked_by
Definition: object.h:199
int16_t food
Definition: living.h:84
#define SPELL
Definition: define.h:210
uint8_t sub_type
Definition: object.h:363