Crossfire Server, Trunk
apply.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 
19 #include "global.h"
20 
21 /* need math lib for double-precision and pow() in dragon_eat_flesh() */
22 #include <math.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "living.h"
27 #include "skills.h"
28 #include "sounds.h"
29 #include "spells.h"
30 #include "sproto.h"
31 #include "tod.h"
32 
33 static int apply_check_apply_restrictions(object *who, object *op, int aflags);
34 static int apply_check_personalized_blessings(object *who, const object *op);
35 static int apply_check_item_power(const object *who, const object *op, int aflags);
36 static int apply_check_owner(const object *who, const object *op, int aflags);
37 static void apply_update_ranged_skill(const object *who, object *op, int aflags);
38 
54 int transport_can_hold(const object *transport, const object *op, int nrof) {
55  return op->weight*nrof+transport->carrying <= transport->weight_limit;
56 }
57 
68 int should_director_abort(const object *op, const object *victim) {
69  int arch_flag, name_flag, race_flag;
70 
71  /* Never move doors, it messes things. */
72  if (victim->type == DOOR)
73  return 1;
74 
75  /* Get flags to determine what of arch, name, and race should be
76  * checked. This is stored in subtype, and is a bitmask, the LSB
77  * is the arch flag, the next is the name flag, and the last is
78  * the race flag. Also note, if subtype is set to zero, that also
79  * goes to defaults of all affecting it. Examples:
80  * subtype 1: only arch
81  * subtype 3: arch or name
82  * subtype 5: arch or race
83  * subtype 7: all three
84  */
85  if (op->subtype) {
86  arch_flag = op->subtype&1;
87  name_flag = op->subtype&2;
88  race_flag = op->subtype&4;
89  } else {
90  arch_flag = 1;
91  name_flag = 1;
92  race_flag = 1;
93  }
94  /* If the director has race set, only affect objects with a arch,
95  * name or race that matches.
96  */
97  if (op->race
98  && (!(victim->arch && arch_flag && victim->arch->name) || strcmp(op->race, victim->arch->name))
99  && (!(victim->name && name_flag) || strcmp(op->race, victim->name))
100  && (!(victim->race && race_flag) || strcmp(op->race, victim->race)))
101  return 1;
102 
103  /* If the director has slaying set, only affect objects where none
104  * of arch, name, or race match.
105  */
106  if (op->slaying
107  && ((victim->arch && arch_flag && victim->arch->name && !strcmp(op->slaying, victim->arch->name))
108  || (victim->name && name_flag && !strcmp(op->slaying, victim->name))
109  || (victim->race && race_flag && !strcmp(op->slaying, victim->race))))
110  return 1;
111 
112  return 0;
113 }
114 
122 void apply_handle_yield(object *tmp) {
123  const char *yield;
124 
125  yield = object_get_value(tmp, "on_use_yield");
126  if (yield != NULL) {
127  object *drop = create_archetype(yield);
128  if (tmp->env)
129  drop = object_insert_in_ob(drop, tmp->env);
130  else
132  }
133 }
134 
146 int set_object_face_main(object *op) {
147  const Face *newface = op->arch->clone.face;
148  sstring saved = object_get_value(op, "face_closed");
149 
150  if (op->more)
151  set_object_face_main(op->more);
152 
153  if (saved)
154  newface = try_find_face(saved, newface);
155  if (newface && op->face != newface) {
156  op->face = newface;
157  return TRUE;
158  }
159  return FALSE;
160 }
161 
173 static int set_object_face_other(object *op) {
174  sstring custom;
175  const Face *newface = NULL;
176  object *head = op->head ? op->head : op;
177 
178  if (op->more)
179  set_object_face_other(op->more);
180 
181  if (head->face && head->other_arch && head->other_arch->clone.face)
182  newface = head->other_arch->clone.face;
183 
184  if (op->face != op->arch->clone.face) {
185  /* object has a custom face, save it so it gets correctly restored later. */
186  object_set_value(op, "face_closed", op->face->name, 1);
187  }
188 
189  custom = object_get_value(head, "face_opened");
190  if (custom)
191  newface = try_find_face(custom, newface);
192  if (newface && op->face != newface) {
193  op->face = newface;
194  return TRUE;
195  }
196  return FALSE;
197 }
198 
222 int apply_container(object *op, object *sack, int aflags) {
223  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
224  object *tmp = op->container;
225 
226  if (op->type != PLAYER)
227  return 0; /* This might change */
228 
229  if (sack == NULL || sack->type != CONTAINER) {
230  LOG(llevError, "apply_container: '%s' tried to apply %s, which is not a container\n", op->name, sack ? sack->name : "(null)");
231  return 0;
232  }
233 
234  if (sack->head)
235  sack = sack->head;
236 
237  query_name(sack, name_sack, MAX_BUF);
238 
239  if ( aflags == AP_APPLY || aflags == AP_UNAPPLY || aflags == AP_OPEN ) {
240  // What if the container isn't in the player's inventory?
241  if ( sack->env != op ) {
243  "Not in your inventory: %s",
244  name_sack);
245  return 0;
246  }
247  }
248  if ( aflags == AP_APPLY ) {
249  // What if the container is open? Make it just ready!
250  if ( op->container == sack ) {
251  op->container = NULL;
252  if (op->contr != NULL)
253  op->contr->socket.container_position = 0;
254  CLEAR_FLAG(sack, FLAG_APPLIED);
256  "You readied %s.",
257  name_sack);
258  SET_FLAG(sack, FLAG_APPLIED);
259  // FIXME: This is not flipping the face!
260  if (set_object_face_main(sack)) // change image to closed
262  else
263  esrv_update_item(UPD_FLAGS, op, sack);
264  return 0;
265  }
266  // What if the container is already applied? Do nothing!
267  if (QUERY_FLAG(sack, FLAG_APPLIED)) {
269  "Already readied %s.",
270  name_sack);
271  return 0;
272  }
273  // What if the container is closed? Same as no aflags.
274  aflags = AP_NULL;
275  }
276 
277  if ( aflags == AP_OPEN ) {
278  // What if the container is already open?
279  if ( op->container == sack ) {
281  "Already opened %s.",
282  name_sack);
283  return 0;
284  }
285  // Set the container as applied and then proceed as if no special flags
286  SET_FLAG(sack, FLAG_APPLIED);
287  aflags = AP_NULL;
288  }
289 
290  if ( aflags == AP_UNAPPLY ) {
291  // If not open, two cases:
292  if ( op->container != sack ) {
293  if (QUERY_FLAG(sack, FLAG_APPLIED)) {
294  CLEAR_FLAG(sack, FLAG_APPLIED);
296  "You closed %s.",
297  name_sack);
298  esrv_update_item(UPD_FLAGS, op, sack);
299  return 0;
300  }
301  else {
303  "Already closed %s.",
304  name_sack);
305  return 0;
306  }
307  }
308  // open; same as no special flags
309  aflags = AP_NULL;
310  }
311 
312  /* If we have a currently open container, then it needs
313  * to be closed in all cases if we are opening this one up.
314  * We then fall through if appropriate for opening the new
315  * container.
316  */
317  if (op->container && QUERY_FLAG(op->container, FLAG_APPLIED) &&
318  (QUERY_FLAG(sack, FLAG_APPLIED) || sack->env != op) )
319  {
320  tag_t tmp_tag = op->container->count;
321 
322  if (op->container->env != op) { /* if container is on the ground */
323  object *part = op->container->head ? op->container->head : op->container;
324  while (part) {
325  part->move_off = 0;
326  part = part->more;
327  }
328  }
329 
330  /* Query name before the close event, as the container could be destroyed. */
331  query_name(op->container, name_tmp, MAX_BUF);
332 
334  return 1;
335 
338  "You close %s.",
339  name_tmp);
340 
341  op->container = NULL;
342  if (op->contr != NULL)
343  op->contr->socket.container_position = 0;
344 
345  /* The container may have been destroyed by the event handler. */
346  if (!object_was_destroyed(tmp, tmp_tag)) {
350  else
352  }
353  if (tmp == sack)
354  return 1;
355  }
356 
357  /* If the player is trying to open it (which he must be doing
358  * if we got here), and it is locked, check to see if player
359  * has the equipment to open it.
360  */
361 
362  if (sack->slaying) { /* it's locked */
363  tmp = find_key(op, op, sack);
364  if (tmp) {
365  query_name(tmp, name_tmp, MAX_BUF);
368  "You unlock %s with %s.",
369  name_sack, name_tmp);
370  } else {
373  "You don't have the key to unlock %s.",
374  name_sack);
375  return 0;
376  }
377  }
378 
379  /* By the time we get here, we have made sure any other container
380  * has been closed and if this is a locked container, the player
381  * has the key to open it.
382  */
383 
384  /* There are really two cases - the sack is either on the ground,
385  * or the sack is part of the player's inventory. If on the ground,
386  * we assume that the player is opening it, since if it was being
387  * closed, that would have been taken care of above.
388  */
389 
390 
391  if (sack->env != op) {
392  /* Hypothetical case - the player is trying to open a sack
393  * that belongs to someone else. This normally should not
394  * happen, but a misbehaving client/player could
395  * try to do it, so let's handle it gracefully.
396  */
397  if (sack->env) {
399  "You can't open %s",
400  name_sack);
401  return 0;
402  }
403 
404  if (sack->nrof > 1) {
405  object *left = object_split(sack, sack->nrof-1, NULL, 0);
406 
407  object_insert_in_map_at(left, sack->map, NULL, INS_NO_MERGE, sack->x, sack->y);
408  /* recompute the name so it's nice */
409  query_name(sack, name_sack, MAX_BUF);
410  }
411 
412  /* set it so when the player walks off, we can unapply the sack */
413  {
414  object *part = sack->head ? sack->head : sack;
415  while (part) {
416  part->move_off = MOVE_ALL;
417  part = part->more;
418  }
419  }
420 
421  CLEAR_FLAG(sack, FLAG_APPLIED);
423  "You open %s.",
424  name_sack);
425  SET_FLAG(sack, FLAG_APPLIED);
426  op->container = sack;
427  if (op->contr != NULL)
428  op->contr->socket.container_position = 0;
429 
430  if (set_object_face_other(sack))
432  else
433  esrv_update_item(UPD_FLAGS, op, sack);
434  esrv_send_inventory(op, sack);
435  } else { /* sack is in players inventory */
436  if (QUERY_FLAG(sack, FLAG_APPLIED)) { /* readied sack becoming open */
437  CLEAR_FLAG(sack, FLAG_APPLIED);
439  "You open %s.",
440  name_sack);
441  SET_FLAG(sack, FLAG_APPLIED);
442  op->container = sack;
443  if (op->contr != NULL)
444  op->contr->socket.container_position = 0;
445 
446  if (set_object_face_other(sack))
448  else
449  esrv_update_item(UPD_FLAGS, op, sack);
450  esrv_send_inventory(op, sack);
451  } else {
452  object *left = NULL;
453 
454  if (sack->nrof > 1)
455  left = object_split(sack, sack->nrof-1, NULL, 1);
456 
457  CLEAR_FLAG(sack, FLAG_APPLIED);
459  "You readied %s.",
460  name_sack);
461  SET_FLAG(sack, FLAG_APPLIED);
462  esrv_update_item(UPD_FLAGS, op, sack);
463 
464  if (left) {
465  object_insert_in_ob(left, sack->env);
466  esrv_send_item(op, left);
467  }
468  }
469  }
470  return 1;
471 }
472 
484 void do_learn_spell(object *op, object *spell, int special_prayer) {
485  object *tmp;
486 
487  if (op->type != PLAYER) {
488  LOG(llevError, "BUG: do_learn_spell(): not a player\n");
489  return;
490  }
491 
492  /* Upgrade special prayers to normal prayers */
493  tmp = check_spell_known(op, spell->name);
494  if (tmp != NULL) {
495  if (special_prayer && !QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
496  LOG(llevError, "BUG: do_learn_spell(): spell already known, but not marked as startequip\n");
497  return;
498  }
499  return;
500  }
501 
502  play_sound_player_only(op->contr, SOUND_TYPE_SPELL, spell, 0, "learn");
503  tmp = object_new();
504  object_copy(spell, tmp);
506 
507  if (special_prayer)
509 
511  "Type 'bind cast %s to store the spell in a key.",
512  spell->name);
513 
514  esrv_add_spells(op->contr, tmp);
515 }
516 
525 void do_forget_spell(object *op, const char *spell) {
526  object *spob;
527 
528  if (op->type != PLAYER) {
529  LOG(llevError, "BUG: do_forget_spell(): not a player\n");
530  return;
531  }
532  spob = check_spell_known(op, spell);
533  if (spob == NULL) {
534  LOG(llevError, "BUG: do_forget_spell(): spell not known\n");
535  return;
536  }
537 
539  "You lose knowledge of %s.",
540  spell);
541  player_unready_range_ob(op->contr, spob);
542  esrv_remove_spell(op->contr, spob);
543  object_remove(spob);
544  object_free(spob, 0);
545 }
546 
557 static int apply_check_race_restrictions(object *who, object *item) {
558  char buf[MAX_BUF];
559  sstring restriction;
560 
561  if (who->type != PLAYER || QUERY_FLAG(who, FLAG_WIZ))
562  return 1;
563 
564  restriction = object_get_value(item, "race_restriction");
565  if (!restriction)
566  return 1;
567 
568  snprintf(buf, sizeof(buf), ":%s:", who->race);
569  buf[sizeof(buf)-1] = '\0';
570 
571  if (strstr(restriction, buf) != NULL)
572  return 1;
573 
574  query_name(item, buf, sizeof(buf));
575  draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_APPLY, MSG_TYPE_APPLY_PROHIBITION, "Somehow you can't seem to use the %s.", buf);
576 
577  return 0;
578 }
579 
597 int apply_manual(object *op, object *tmp, int aflag) {
598  tmp = HEAD(tmp);
599 
601  if (op->type == PLAYER) {
603  "You should pay for it first.");
604  return METHOD_SILENT_ERROR;
605  }
606  return 0; /* monsters just skip unpaid items */
607  }
608 
610  return METHOD_SILENT_ERROR;
611 
612  if (op->contr)
613  play_sound_player_only(op->contr, SOUND_TYPE_ITEM, tmp, 0, "apply");
614 
615  return ob_apply(tmp, op, aflag);
616 }
617 
637 int apply_by_living(object *pl, object *op, int aflag, int quiet) {
638  int tmp;
639 
640  if (op->env == NULL && (pl->move_type&MOVE_FLYING)) {
641  /* player is flying and applying object not in inventory */
642  if (!QUERY_FLAG(pl, FLAG_WIZ) && !(op->move_type&MOVE_FLYING)) {
644  "But you are floating high above the ground!");
645  return 0;
646  }
647  }
648 
649  /* Check for PLAYER to avoid a DM to disappear in a puff of smoke if
650  * applied.
651  */
652  if (op->type != PLAYER
654  && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
655  play_sound_map(SOUND_TYPE_ITEM, op, 0, "evaporate");
657  "The object disappears in a puff of smoke!");
659  "It must have been an illusion.");
660  object_remove(op);
661  object_free(op, 0);
662  return 1;
663  }
664 
665  tmp = apply_manual(pl, op, aflag);
666  if (!quiet) {
667  if (tmp == METHOD_UNHANDLED) {
668  char name[MAX_BUF];
669 
672  "I don't know how to apply the %s.",
673  name);
674  } else if (tmp == METHOD_ERROR)
676  "You must get it first!\n");
677  else if (tmp == METHOD_SILENT_ERROR)
678  return tmp;
679  }
680  if (tmp == METHOD_OK) {
681  if (op->anim_suffix != NULL)
682  apply_anim_suffix(pl, op->anim_suffix);
683  }
684  return tmp;
685 }
686 
695 void apply_by_living_below(object *pl) {
696  object *tmp;
697  int floors;
698 
699  if (pl->contr->transport && pl->contr->transport->type == TRANSPORT) {
700  ob_apply(pl->contr->transport, pl, 0);
701  return;
702  }
703 
704  /* If using a container, set the starting item to be the top
705  * item in the container. Otherwise, use the map.
706  */
707  tmp = pl->container != NULL ? pl->container->inv : pl->below;
708 
709  /* This is perhaps more complicated. However, I want to make sure that
710  * we don't use a corrupt pointer for the next object, so we get the
711  * next object in the stack before applying. This is can only be a
712  * problem if apply_by_living() has a bug in that it uses the object but
713  * does not return a proper value.
714  */
715  floors = 0;
718  floors++;
719  else if (floors > 0)
720  return; /* process only floor objects after first floor object */
721 
722  /* If it is visible, player can apply it. If it is applied by
723  * person moving on it, also activate. Added code to make it
724  * so that at least one of players movement types be that which
725  * the item needs.
726  */
727  if (!tmp->invisible || (tmp->move_on&pl->move_type)) {
728  if (apply_by_living(pl, tmp, 0, 1) == METHOD_OK)
729  return;
730  }
731  if (floors >= 2)
732  return; /* process at most two floor objects */
734 }
735 
751 static int unapply_special(object *who, object *op, int aflags) {
752  char name[MAX_BUF];
753 
754  if (op->type != LAMP)
757  switch (op->type) {
758  case WEAPON:
759  if (!(aflags&AP_NOPRINT))
761  "You unwield %s.",
762  name);
763  (void)change_abil(who, op);
765  who->current_weapon = NULL;
766  clear_skill(who);
767  break;
768 
769  case SKILL: /* allows objects to impart skills */
770  case SKILL_TOOL:
771  if (op != who->chosen_skill)
772  LOG(llevError, "BUG: unapply_special(): applied skill is not a chosen skill\n");
773  if (who->type == PLAYER) {
774  if (who->contr->shoottype == range_skill)
775  who->contr->shoottype = range_none;
776  if (!op->invisible) {
777  if (!(aflags&AP_NOPRINT))
779  "You stop using the %s.",
780  name);
781  } else {
782  if (!(aflags&AP_NOPRINT))
784  "You can no longer use the skill: %s.",
785  op->skill);
786  }
787  }
788  (void)change_abil(who, op);
789  who->chosen_skill = NULL;
791  break;
792 
793  case ARMOUR:
794  case HELMET:
795  case SHIELD:
796  case RING:
797  case BOOTS:
798  case GLOVES:
799  case AMULET:
800  case GIRDLE:
801  case BRACERS:
802  case CLOAK:
803  if (!(aflags&AP_NOPRINT))
805  "You unwear %s.",
806  name);
807  (void)change_abil(who, op);
808  break;
809 
810  case BOW:
811  case WAND:
812  case ROD:
813  clear_skill(who);
814  if (!(aflags&AP_NOPRINT))
816  "You unready %s.",
817  name);
818  if (who->type == PLAYER)
819  who->contr->shoottype = range_none;
820  else if (op->type == BOW)
822  else
824  break;
825 
826  case BUILDER:
827  if (!(aflags&AP_NOPRINT))
829  "You unready %s.",
830  name);
831  who->contr->shoottype = range_none;
832  who->contr->ranges[range_builder] = NULL;
833  break;
834 
835  default:
836  if (!(aflags&AP_NOPRINT))
838  "You unapply %s.",
839  name);
840  break;
841  }
842 
843  fix_object(who);
844 
845  if (!(aflags&AP_NO_MERGE)) {
846  object *tmp;
847 
848  tmp = object_merge(op, NULL);
849  if (who->type == PLAYER) {
850  if (tmp) { /* it was merged */
851  op = tmp;
852  }
854  }
855  }
856  return 0;
857 }
858 
878 static object *get_item_from_body_location(object *start, int loc) {
879  object *tmp;
880 
881  if (!start)
882  return NULL;
883 
884  tmp = start;
887  && tmp->body_info[loc]
888  && (!tmp->invisible || tmp->type == SKILL))
889  return tmp;
891  return NULL;
892 }
893 
915 static int unapply_for_ob(object *who, object *op, int aflags) {
916  int i;
917  object *tmp = NULL, *last;
918  char name[MAX_BUF];
919 
920  /* If we are applying a shield or weapon, unapply any equipped shield
921  * or weapons first - only allowed to use one weapon/shield at a time.
922  */
923  if (op->type == WEAPON || op->type == SHIELD) {
925  if (QUERY_FLAG(tmp, FLAG_APPLIED) && tmp->type == op->type) {
926  if (!(aflags&AP_IGNORE_CURSE)
927  && !(aflags&AP_PRINT)
929  /* In this case, we want to try and remove a
930  * cursed item. While we know it won't work, we
931  * want unapply_special to at least generate the
932  * message.
933  */
934  if (!(aflags&AP_NOPRINT)) {
937  "No matter how hard you try, you just can't remove %s.",
938  name);
939  }
940  return 1;
941  }
942 
943  if (aflags&AP_PRINT) {
946  name);
947  } else
948  unapply_special(who, tmp, aflags);
949  }
950  } FOR_INV_FINISH();
951  }
952 
953  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
954  /* this used up a slot that we need to free */
955  if (op->body_info[i]) {
956  last = who->inv;
957 
958  /* We do a while loop - may need to remove several items
959  * in order to free up enough slots.
960  */
961  while (who->body_used[i]+op->body_info[i] < 0) {
962  tmp = get_item_from_body_location(last, i);
963  if (!tmp)
964  return 1;
965 
966  /* If just printing, we don't care about cursed status */
967  if ((aflags&AP_IGNORE_CURSE)
968  || (aflags&AP_PRINT)
970  if (aflags&AP_PRINT) {
973  name);
974  } else
975  unapply_special(who, tmp, aflags);
976  } else {
977  /* Cursed item that we can't unequip - tell the player.
978  * Note this could be annoying if this is just one of a
979  * few, so it may not be critical (eg, putting on a
980  * ring and you have one cursed ring.)
981  */
982  if (!(aflags&AP_NOPRINT)) {
985  "The %s just won't come off",
986  name);
987  }
988  }
989  last = tmp->below;
990  }
991  /* if we got here, this slot is freed up - otherwise, if it
992  * wasn't freed up, the return in the !tmp would have
993  * kicked in.
994  */
995  } /* if op is using this body location */
996  } /* for body locations */
997  return 0;
998 }
999 
1016 int apply_can_apply_object(const object *who, const object *op) {
1017  int i, retval = 0;
1018  object *tmp = NULL, *ws = NULL;
1019 
1020  /* Players have 2 'arm's, so they could in theory equip 2 shields or
1021  * 2 weapons, but we don't want to let them do that. So if they are
1022  * trying to equip a weapon or shield, see if they already have one
1023  * in place and store that way.
1024  */
1025  if (op->type == WEAPON || op->type == SHIELD) {
1027  if (tmp != NULL) {
1028  retval = CAN_APPLY_UNAPPLY;
1029  ws = tmp;
1030  }
1031  }
1032 
1033  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1034  if (op->body_info[i]) {
1035  /* Item uses more slots than we have */
1036  if (FABS(op->body_info[i]) > who->body_info[i]) {
1037  /* Could return now for efficiently - rest of info
1038  * below isn't really needed.
1039  */
1040  retval |= CAN_APPLY_NEVER;
1041  } else if (who->body_used[i]+op->body_info[i] < 0) {
1042  /* in this case, equipping this would use more free
1043  * spots than we have.
1044  */
1045  object *tmp1;
1046 
1047  /* if we have an applied weapon/shield, and unapply
1048  * it would free enough slots to equip the new item,
1049  * then just set this can continue. We don't care
1050  * about the logic below - if you have shield equipped
1051  * and try to equip another shield, there is only one
1052  * choice. However, the check for the number of body
1053  * locations does take into the account cases where what
1054  * is being applied may be two handed for example.
1055  */
1056  if (ws) {
1057  if (who->body_used[i]-ws->body_info[i]+op->body_info[i] >= 0) {
1058  retval |= CAN_APPLY_UNAPPLY;
1059  continue;
1060  }
1061  }
1062 
1063  tmp1 = get_item_from_body_location(who->inv, i);
1064  if (!tmp1)
1065  retval |= CAN_APPLY_NEVER;
1066  else {
1067  /* need to unapply something. However, if this
1068  * something is different than we had found before,
1069  * it means they need to apply multiple objects
1070  */
1071  retval |= CAN_APPLY_UNAPPLY;
1072  if (!tmp)
1073  tmp = tmp1;
1074  else if (tmp != tmp1)
1075  retval |= CAN_APPLY_UNAPPLY_MULT;
1076  /* This object isn't using up all the slots, so
1077  * there must be another. If so, and if the new
1078  * item doesn't need all the slots, the player
1079  * then has a choice.
1080  */
1081  if (who->body_used[i]-tmp1->body_info[i] != who->body_info[i]
1082  && FABS(op->body_info[i]) < who->body_info[i])
1083  retval |= CAN_APPLY_UNAPPLY_CHOICE;
1084 
1085  /* Does unequipping 'tmp1' free up enough slots
1086  * for this to be equipped? If not, there must
1087  * be something else to unapply.
1088  */
1089  if (who->body_used[i]+op->body_info[i]-tmp1->body_info[i] < 0)
1090  retval |= CAN_APPLY_UNAPPLY_MULT;
1091  }
1092  } /* if not enough free slots */
1093  } /* if this object uses location i */
1094  } /* for i -> num_body_locations loop */
1095 
1096  /* Do checks for can_use_weapon/shield/armour. */
1098  retval |= CAN_APPLY_RESTRICTION;
1100  retval |= CAN_APPLY_RESTRICTION;
1102  retval |= CAN_APPLY_RESTRICTION;
1103 
1104  if (who->type != PLAYER) {
1105  if ((op->type == WAND || op->type == ROD)
1107  retval |= CAN_APPLY_RESTRICTION;
1108  if (op->type == BOW && !QUERY_FLAG(who, FLAG_USE_BOW))
1109  retval |= CAN_APPLY_RESTRICTION;
1110  if (op->type == RING && !QUERY_FLAG(who, FLAG_USE_RING))
1111  retval |= CAN_APPLY_RESTRICTION;
1112  }
1113  return retval;
1114 }
1115 
1131 int apply_check_weapon_power(const object *who, int improves) {
1132  return (who->level/5)+5 >= improves;
1133 }
1134 
1156 int apply_special(object *who, object *op, int aflags) {
1157  int basic_flag = aflags&AP_BASIC_FLAGS;
1158  object *tmp, *skop;
1159  char name_op[MAX_BUF];
1160 
1161  if (who == NULL) {
1162  LOG(llevError, "apply_special() from object without environment.\n");
1163  return 1;
1164  }
1165 
1166  if (op->env != who)
1167  return 1; /* op is not in inventory */
1168 
1169  /* trying to unequip op */
1170  if (QUERY_FLAG(op, FLAG_APPLIED)) {
1171  /* always apply, so no reason to unapply */
1172  if (basic_flag == AP_APPLY)
1173  return 0;
1174 
1175  if (!(aflags&AP_IGNORE_CURSE)
1177  if (!(aflags&AP_NOPRINT)) {
1178  query_name(op, name_op, MAX_BUF);
1180  "No matter how hard you try, you just can't remove %s.",
1181  name_op);
1182  }
1183  return 1;
1184  }
1185  return unapply_special(who, op, aflags);
1186  }
1187 
1188  if (basic_flag == AP_UNAPPLY)
1189  return 0;
1190 
1191  if (!apply_check_apply_restrictions(who, op, aflags))
1192  return 1;
1193 
1194  if (op->skill && op->type != SKILL && op->type != SKILL_TOOL) {
1195  skop = find_skill_by_name(who, op->skill);
1196  if (!skop) {
1197  if (!(aflags&AP_NOPRINT))
1199  "You need the %s skill to use this item!",
1200  op->skill);
1201  if (who->type == PLAYER)
1202  return 1;
1203 
1204  /* monsters do not care about missing skills */
1205  } else
1206  /* While experience will be credited properly, we want to
1207  * change the skill so that the dam and wc get updated
1208  */
1209  change_skill(who, skop, (aflags&AP_NOPRINT));
1210  } else
1211  skop = NULL;
1212 
1213  if (!apply_check_item_power(who, op, aflags))
1214  return 1;
1215 
1217  return 1;
1218 
1219  /* Ok. We are now at the state where we can apply the new object.
1220  * Note that we don't have the checks for can_use_...
1221  * below - that is already taken care of by apply_can_apply_object().
1222  */
1223 
1224  tmp = op->nrof <= 1 ? NULL : object_split(op, op->nrof-1, NULL, 0);
1225 
1226  switch (op->type) {
1227  case WEAPON:
1228  if (!apply_check_weapon_power(who, op->last_eat)) {
1229  if (!(aflags&AP_NOPRINT))
1231  "That weapon is too powerful for you to use. It would consume your soul!");
1232  if (tmp != NULL)
1234  return 1;
1235  }
1236 
1237  if (!apply_check_owner(who, op, aflags)) {
1238  if (tmp != NULL)
1240  return 1;
1241  }
1242 
1244 
1245  if (skop)
1246  change_skill(who, skop, 1);
1248 
1249  if (!(aflags&AP_NOPRINT)) {
1250  query_name(op, name_op, MAX_BUF);
1252  "You wield %s.",
1253  name_op);
1254  }
1255 
1256  (void)change_abil(who, op);
1257  break;
1258 
1259  case ARMOUR:
1260  case HELMET:
1261  case SHIELD:
1262  case BOOTS:
1263  case GLOVES:
1264  case GIRDLE:
1265  case BRACERS:
1266  case CLOAK:
1267  case RING:
1268  case AMULET:
1270  if (!(aflags&AP_NOPRINT)) {
1271  query_name(op, name_op, MAX_BUF);
1273  "You wear %s.",
1274  name_op);
1275  }
1276  (void)change_abil(who, op);
1277  break;
1278 
1279  /* this part is needed for skill-tools */
1280  case SKILL:
1281  case SKILL_TOOL:
1282  if (who->chosen_skill) {
1283  LOG(llevError, "BUG: apply_special(): can't apply two skills\n");
1284  return 1;
1285  }
1286 
1287  apply_update_ranged_skill(who, op, aflags);
1289  (void)change_abil(who, op);
1290  who->chosen_skill = op;
1292  break;
1293 
1294  case BOW:
1295  if (!apply_check_weapon_power(who, op->last_eat)) {
1296  if (!(aflags&AP_NOPRINT))
1298  "That weapon is too powerful for you to use. It would consume your soul!");
1299  if (tmp != NULL)
1301  return 1;
1302  }
1303 
1304  if (!apply_check_owner(who, op, aflags)) {
1305  if (tmp != NULL)
1307  return 1;
1308  }
1309  /*FALLTHROUGH*/
1310  case WAND:
1311  case ROD:
1312  /* check for skill, alter player status */
1314  if (skop)
1315  change_skill(who, skop, 0);
1316  if (!(aflags&AP_NOPRINT)) {
1317  query_name(op, name_op, MAX_BUF);
1319  "You ready %s.",
1320  name_op);
1321  }
1322  if (who->type == PLAYER) {
1323  if (op->type == BOW) {
1324  (void)change_abil(who, op);
1325  if (!(aflags&AP_NOPRINT)) {
1326  query_name(op, name_op, MAX_BUF);
1328  "You will now fire %s with %s.",
1329  op->race ? op->race : "nothing",
1330  name_op);
1331  }
1332  who->contr->shoottype = range_bow;
1333  } else
1334  who->contr->shoottype = range_misc;
1335  } else {
1336  if (op->type == BOW)
1338  else
1340  }
1341  break;
1342 
1343  case BUILDER:
1344  if (who->contr->ranges[range_builder])
1345  unapply_special(who, who->contr->ranges[range_builder], 0);
1346  who->contr->shoottype = range_builder;
1347  who->contr->ranges[range_builder] = op;
1348  if (!(aflags&AP_NOPRINT)) {
1349  query_name(op, name_op, MAX_BUF);
1351  "You ready your %s.",
1352  name_op);
1353  }
1354  break;
1355 
1356  default:
1357  query_name(op, name_op, MAX_BUF);
1359  "You apply %s.",
1360  name_op);
1361  break;
1362  } /* end of switch op->type */
1363 
1365 
1366  if (tmp != NULL)
1368 
1369  fix_object(who);
1370 
1371  /* We exclude spell casting objects. The fire code will set the
1372  * been applied flag when they are used - until that point,
1373  * you don't know anything about them.
1374  */
1375  if (who->type == PLAYER && op->type != WAND && op->type != ROD)
1377 
1379  if (who->type == PLAYER) {
1381  "Oops, it feels deadly cold!");
1383  }
1384  }
1385  if (who->type == PLAYER)
1387  return 0;
1388 }
1389 
1400 int apply_auto(object *op) {
1401  object *tmp;
1402 
1403  switch (op->type) {
1404  case SHOP_FLOOR:
1405  if (!HAS_RANDOM_ITEMS(op))
1406  return 0;
1407  do {
1408  int i;
1409 
1410  i = 10; /* let's give it 10 tries */
1411  while ((tmp = generate_treasure(op->randomitems, op->stats.exp ? (int)op->stats.exp : MAX(op->map->difficulty, 5))) == NULL
1412  && --i)
1413  ;
1414  if (tmp == NULL)
1415  return 0;
1418  tmp = NULL;
1419  }
1420  } while (!tmp);
1422  object_insert_in_map_at(tmp, op->map, NULL, 0, op->x, op->y);
1424  identify(tmp);
1425  return 1;
1426  break;
1427 
1428  case TREASURE:
1430  return 0;
1431  while (op->stats.hp-- > 0)
1432  create_treasure(op->randomitems, op, (op->map ? GT_ENVIRONMENT : 0) | (QUERY_FLAG(op, FLAG_BLESSED) ? GT_ONLY_GOOD : 0), op->stats.exp ? (int)op->stats.exp : op->map == NULL ? 14 : op->map->difficulty, 0);
1433 
1434  /* If we generated an object and put it in this object's
1435  * inventory, move it to the parent object as the current
1436  * object is about to disappear. An example of this item
1437  * is the random_ *stuff that is put inside other objects.
1438  */
1439  FOR_INV_PREPARE(op, tmp) {
1440  object_remove(tmp);
1441  if (op->env)
1442  object_insert_in_ob(tmp, op->env);
1443  else
1445  } FOR_INV_FINISH();
1446  object_remove(op);
1448  break;
1449  }
1450  return 0;
1451 }
1452 
1465 static void auto_apply_fix_inventory(mapstruct *m, object *tmp)
1466 {
1467  if (!tmp->inv)
1468  return;
1469  FOR_INV_PREPARE(tmp, invtmp) {
1470  if (invtmp->inv)
1471  auto_apply_fix_inventory(m,invtmp); // Recurse for containers in objects
1472  if (QUERY_FLAG(invtmp, FLAG_AUTO_APPLY))
1473  apply_auto(invtmp);
1474  else if (invtmp->type == TREASURE && HAS_RANDOM_ITEMS(invtmp)) {
1475  while (invtmp->stats.hp-- > 0)
1476  create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
1477  invtmp->randomitems = NULL;
1478  } else if (invtmp && invtmp->arch
1479  && invtmp->type != TREASURE
1480  && invtmp->type != SPELL
1481  && invtmp->type != CLASS
1482  && HAS_RANDOM_ITEMS(invtmp)) {
1483  create_treasure(invtmp->randomitems, invtmp, 0, m->difficulty, 0);
1484  /* Need to clear this so that we never try to
1485  * create treasure again for this object
1486  */
1487  invtmp->randomitems = NULL;
1488  }
1489  } FOR_INV_FINISH();
1490  /* This is really temporary - the code at the
1491  * bottom will also set randomitems to null.
1492  * The problem is there are bunches of maps/players
1493  * already out there with items that have spells
1494  * which haven't had the randomitems set
1495  * to null yet.
1496  * MSW 2004-05-13
1497  *
1498  * And if it's a spellbook, it's better to set
1499  * randomitems to NULL too, else you get two spells
1500  * in the book ^_-
1501  * Ryo 2004-08-16
1502  */
1503  if (tmp->type == WAND
1504  || tmp->type == ROD
1505  || tmp->type == SCROLL
1506  || tmp->type == FIREWALL
1507  || tmp->type == POTION
1508  || tmp->type == ALTAR
1509  || tmp->type == SPELLBOOK)
1510  tmp->randomitems = NULL;
1511 }
1512 
1524  int x, y;
1525 
1526  if (m == NULL)
1527  return;
1528 
1529  for (x = 0; x < MAP_WIDTH(m); x++)
1530  for (y = 0; y < MAP_HEIGHT(m); y++)
1531  FOR_MAP_PREPARE(m, x, y, tmp) {
1532  if (tmp->inv) {
1534  }
1536  apply_auto(tmp);
1537  else if ((tmp->type == TREASURE || tmp->type == CONTAINER)
1538  && HAS_RANDOM_ITEMS(tmp)) {
1539  while (tmp->stats.hp-- > 0)
1540  create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
1541  tmp->randomitems = NULL;
1542  } else if (tmp->type == TIMED_GATE) {
1543  object *head = HEAD(tmp);
1544 
1545  if (QUERY_FLAG(head, FLAG_IS_LINKED)) {
1546  tmp->speed = 0;
1548  }
1549  }
1550  /* This function can be called every time a map is loaded,
1551  * even when swapping back in. As such, we don't want to
1552  * create the treasure over and over again, so after we
1553  * generate the treasure, blank out randomitems so if it
1554  * is swapped in again, it won't make anything. This is a
1555  * problem for the above objects, because they have
1556  * counters which say how many times to make the treasure.
1557  */
1558  else if (tmp
1559  && tmp->arch
1560  && tmp->type != PLAYER
1561  && tmp->type != TREASURE
1562  && tmp->type != SPELL
1563  && tmp->type != PLAYER_CHANGER
1564  && tmp->type != CLASS
1565  && HAS_RANDOM_ITEMS(tmp)) {
1566  create_treasure(tmp->randomitems, tmp, 0, m->difficulty, 0);
1567  tmp->randomitems = NULL;
1568  }
1569 
1570  if (QUERY_FLAG(tmp, FLAG_MONSTER))
1572  } FOR_MAP_FINISH();
1573 
1574  for (x = 0; x < MAP_WIDTH(m); x++)
1575  for (y = 0; y < MAP_HEIGHT(m); y++)
1576  FOR_MAP_PREPARE(m, x, y, tmp) {
1577  if (tmp->above
1578  && (tmp->type == TRIGGER_BUTTON || tmp->type == TRIGGER_PEDESTAL))
1579  check_trigger(tmp, tmp->above);
1580  } FOR_MAP_FINISH();
1581 }
1582 
1597 void scroll_failure(object *op, int failure, int power) {
1598  if (abs(failure/4) > power)
1599  power = abs(failure/4); /* set minimum effect */
1600 
1601  if (failure <= -1 && failure > -15) {/* wonder */
1602  object *tmp;
1603 
1605  "Your spell warps!");
1607  cast_wonder(op, op, 0, tmp);
1608  if (op->stats.sp < 0)
1609  /* For some reason the sp can become negative here. */
1610  op->stats.sp = 0;
1612  return;
1613  }
1614 
1616  if (failure <= -35 && failure > -60) { /* confusion */
1618  "The magic recoils on you!");
1619  confuse_living(op, op, power);
1620  return;
1621  }
1622 
1623  if (failure <= -60 && failure > -70) {/* paralysis */
1625  "The magic recoils and paralyzes you!");
1626  paralyze_living(op, power);
1627  return;
1628  }
1629 
1630  if (failure <= -70 && failure > -80) {/* blind */
1632  "The magic recoils on you!");
1633  blind_living(op, op, power);
1634  return;
1635  }
1636 
1637  if (failure <= -80) {/* blast the immediate area */
1638  object *tmp;
1639 
1641  cast_magic_storm(op, tmp, power);
1643  "You unleash uncontrolled mana!");
1644  return;
1645  }
1646  }
1647  /* Either no spell failure on this server, or wrong values,
1648  * in any case let's punish.
1649  */
1651  "Your mana is drained!");
1652  op->stats.sp -= random_roll(0, power-1, op, PREFER_LOW);
1653  if (op->stats.sp < 0)
1654  op->stats.sp = 0;
1655 }
1656 
1668 void apply_changes_to_player(object *pl, object *change, int limit_stats) {
1669  int i, j;
1670  int excess_stat = 0; /* if the stat goes over the maximum
1671  * for the race, put the excess stat some
1672  * where else.
1673  */
1674 
1675  if (change->type != CLASS) return;
1676 
1677  /* the following code assigns stats up to the stat max
1678  * for the race, and if the stat max is exceeded,
1679  * tries to randomly reassign the excess stat
1680  */
1681  if (! (limit_stats & AC_PLAYER_STAT_NO_CHANGE)) {
1682  for (i = 0; i < NUM_STATS; i++) {
1683  int8_t stat = get_attr_value(&pl->contr->orig_stats, i);
1684  int race_bonus = get_attr_value(&pl->arch->clone.stats, i);
1685 
1686  stat += get_attr_value(&change->stats, i);
1687  if (limit_stats & AC_PLAYER_STAT_LIMIT) {
1688  if (stat > 20+race_bonus) {
1689  excess_stat++;
1690  stat = 20+race_bonus;
1691  } else if (stat < 1) {
1692  /* I didn't see any code here before to make sure minimum
1693  * stats were enforced - maybe it was just dumb
1694  * luck that one would not have a stat low enough that then
1695  * has a stat penalty for class that would bring it negative?
1696  * I imagine a negative stat would crash the server pretty
1697  * quickly - MSW, Sept 2010
1698  */
1699  excess_stat += stat;
1700  stat = 1;
1701  }
1702  }
1703  set_attr_value(&pl->contr->orig_stats, i, stat);
1704  }
1705 
1706  /* Maybe we should randomly deduct stats in this case?
1707  * It's will go away sometime soon in any case.
1708  */
1709  if (excess_stat < 0) excess_stat = 0;
1710 
1711  /* We don't put an explicit check for limit_stats here -
1712  * excess stat will never be 0 if limit_stats is not
1713  * true.
1714  */
1715  for (j = 0; excess_stat > 0 && j < 100; j++) {
1716  /* try 100 times to assign excess stats */
1717  int i = rndm(0, NUM_STATS-1);
1718  int stat = get_attr_value(&pl->contr->orig_stats, i);
1719  int race_bonus = get_attr_value(&pl->arch->clone.stats, i);
1720 
1721  if (i == CHARISMA) {
1722  continue; /* exclude cha from this */
1723  }
1724 
1725  if (stat < 20+race_bonus) {
1726  change_attr_value(&pl->contr->orig_stats, i, 1);
1727  excess_stat--;
1728  }
1729  }
1730  }
1731  /* Done with stat processing */
1732 
1733  /* insert the randomitems from the change's treasurelist into
1734  * the player ref: player.c
1735  */
1736  if (change->randomitems != NULL)
1737  give_initial_items(pl, change->randomitems);
1738 
1739 
1740  /* set up the face, for some races. */
1741 
1742  /* first, look for the force object banning changing the
1743  * face. Certain races never change face with class.
1744  */
1745  int has_noclassfacechange = (object_find_by_name(pl, "NOCLASSFACECHANGE") != NULL);
1746  const Animations *anim = NULL;
1747 
1748  if (change->anim_suffix) {
1749  char buf[MAX_BUF];
1750 
1751  snprintf(buf, MAX_BUF, "%s_%s", pl->animation->name, change->anim_suffix);
1753  if (anim) {
1754  pl->animation = anim;
1755  pl->anim_speed = -1;
1757  animate_object(pl, pl->facing);
1758  }
1759  }
1760  /* Check for anim == -1 so that we can override specific class faces for races.
1761  * This allows us to have custom class faces on the races that lack noclassfacechange
1762  *
1763  * Daniel Hawkins 2020-09-08
1764  */
1765  if ((!has_noclassfacechange) && anim == 0) {
1766  pl->animation = GET_ANIM(change);
1767  pl->face = change->face;
1768 
1769  if (QUERY_FLAG(change, FLAG_ANIMATE))
1771  else
1773  }
1774 
1775  /* Hard coding in class name is a horrible idea - lets
1776  * use the supported mechanism for this
1777  */
1778  if (object_present_in_ob_by_name(FORCE, "no weapon force", pl))
1780 
1781 }
1782 
1796 static int apply_check_apply_restrictions(object *who, object *op, int aflags) {
1797  int i;
1798 
1800  if (i == 0)
1801  return 1;
1802 
1803  /* Can't just apply this object. Lets see why not and what to do */
1804 
1805  if (i&CAN_APPLY_NEVER) {
1806  if (!(aflags&AP_NOPRINT)) {
1807  char name_op[MAX_BUF];
1808 
1809  query_name(op, name_op, MAX_BUF);
1811  "You don't have the body to use a %s",
1812  name_op);
1813  }
1814  return 0;
1815  }
1816 
1817  if (i&CAN_APPLY_RESTRICTION) {
1818  if (!(aflags&AP_NOPRINT)) {
1819  char name_op[MAX_BUF];
1820 
1821  query_name(op, name_op, MAX_BUF);
1823  "You have a prohibition against using a %s",
1824  name_op);
1825  }
1826  return 0;
1827  }
1828 
1829  if (who->type != PLAYER) {
1830  /* Some error, so don't try to equip something more */
1831  return !unapply_for_ob(who, op, aflags);
1832  }
1833 
1834  if (who->contr->unapply == unapply_never
1835  || (i&CAN_APPLY_UNAPPLY_CHOICE && who->contr->unapply == unapply_nochoice)) {
1836  if (!(aflags&AP_NOPRINT))
1838  "You need to unapply some item(s):");
1840  return 0;
1841  }
1842 
1843  if (who->contr->unapply == unapply_always
1844  || !(i&CAN_APPLY_UNAPPLY_CHOICE)) {
1845  return !unapply_for_ob(who, op, aflags);
1846  }
1847 
1848  return 1;
1849 }
1850 
1863 static int apply_check_item_power(const object *who, const object *op, int aflags) {
1864  if (who->type != PLAYER)
1865  return 1;
1866 
1867  if (op->item_power == 0
1868  || op->item_power+who->contr->item_power <= settings.item_power_factor*who->level)
1869  return 1;
1870 
1871  if (!(aflags&AP_NOPRINT))
1873  "Equipping that combined with other items would consume your soul!");
1874  return 0;
1875 }
1876 
1891 static int apply_check_personalized_blessings(object *who, const object *op) {
1892  const char *owner;
1893  const char *will;
1894  long item_will;
1895  long margin;
1896  const char *msg;
1897  int random_effect;
1898  int damage_percentile;
1899 
1901  return 1;
1902  }
1903 
1904  owner = object_get_value(op, "item_owner");
1905  if (owner == NULL || strcmp(owner, who->name) == 0)
1906  return 1;
1907 
1908  will = object_get_value(op, "item_willpower");
1909  item_will = will != NULL ? atol(will) : 0;
1910  if (item_will > who->stats.exp) {
1912  "This %s refuses to serve you - it keeps evading your hand !",
1913  op->name);
1914  return 0;
1915  }
1916 
1917  margin = item_will != 0 ? who->stats.exp/item_will : who->stats.exp;
1918  random_effect = random_roll(0, 100, who, 1)-margin*20;
1919  if (random_effect > 80) {
1920  msg = "You don't know why, but you have the feeling that the %s is angry at you !";
1921  damage_percentile = 60;
1922  } else if (random_effect > 60) {
1923  msg = "The %s seems to look at you nastily !";
1924  damage_percentile = 45;
1925  } else if (random_effect > 40) {
1926  msg = "You have the strange feeling that the %s is annoyed...";
1927  damage_percentile = 30;
1928  } else if (random_effect > 20) {
1929  msg = "The %s seems tired, or bored, in a way. Very strange !";
1930  damage_percentile = 15;
1931  } else if (random_effect > 0) {
1932  msg = "You hear the %s sighing !";
1933  damage_percentile = 0;
1934  } else {
1935  msg = NULL;
1936  damage_percentile = 0;
1937  }
1938  if (msg != NULL)
1940  msg, op->name);
1941  if (damage_percentile > 0) {
1942  int weapon_bite = (who->stats.hp*damage_percentile)/100;
1943  if (weapon_bite < 1)
1944  weapon_bite = 1;
1945  who->stats.hp -= weapon_bite;
1947  "You get a nasty bite in the hand !");
1948  }
1949 
1950  return 1;
1951 }
1952 
1967 static int apply_check_owner(const object *who, const object *op, int aflags) {
1968  const char *quotepos;
1969 
1970  if (op->level == 0)
1971  return 1;
1972 
1973  quotepos = strstr(op->name, "'");
1974  if (quotepos == NULL || strncmp(op->name, who->name, quotepos-op->name) == 0)
1975  return 1;
1976 
1977  if (!(aflags&AP_NOPRINT))
1979  "The weapon does not recognize you as its owner.");
1980  return 0;
1981 }
1982 
1993 static void apply_update_ranged_skill(const object *who, object *op, int aflags) {
1994  if (who->type != PLAYER) {
1995  return;
1996  }
1997 
1998  who->contr->shoottype = range_skill;
1999  who->contr->ranges[range_skill] = op;
2000  if (op->invisible) {
2001  if (!(aflags&AP_NOPRINT))
2003  "Readied skill: %s.",
2004  op->skill ? op->skill : op->name);
2005  } else {
2006  if (!(aflags&AP_NOPRINT)) {
2007  char name_op[MAX_BUF];
2008 
2009  query_name(op, name_op, MAX_BUF);
2011  "You ready %s.",
2012  name_op);
2014  "You can now use the skill: %s.",
2015  op->skill);
2016  }
2017  }
2018 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
paralyze_living
void paralyze_living(object *op, int dam)
Definition: attack.c:2353
CLASS
@ CLASS
Definition: object.h:138
FLAG_USE_BOW
#define FLAG_USE_BOW
Definition: define.h:293
obj::move_off
MoveType move_off
Definition: object.h:433
Face
Definition: face.h:14
HAS_RANDOM_ITEMS
#define HAS_RANDOM_ITEMS(op)
Definition: define.h:184
PLAYER
@ PLAYER
Definition: object.h:107
global.h
FREE_OBJ_NO_DESTROY_CALLBACK
#define FREE_OBJ_NO_DESTROY_CALLBACK
Definition: object.h:531
UPD_FACE
#define UPD_FACE
Definition: newclient.h:317
SOUND_TYPE_ITEM
#define SOUND_TYPE_ITEM
Definition: newclient.h:335
object_free
void object_free(object *ob, int flags)
Definition: object.c:1578
apply_check_item_power
static int apply_check_item_power(const object *who, const object *op, int aflags)
Definition: apply.c:1863
object_remove
void object_remove(object *op)
Definition: object.c:1819
FOR_MAP_FINISH
#define FOR_MAP_FINISH()
Definition: define.h:730
pl::transport
object * transport
Definition: player.h:213
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:13
obj::face
const Face * face
Definition: object.h:336
AP_APPLY
#define AP_APPLY
Definition: define.h:574
BOW
@ BOW
Definition: object.h:118
BRACERS
@ BRACERS
Definition: object.h:217
do_forget_spell
void do_forget_spell(object *op, const char *spell)
Definition: apply.c:525
apply_container
int apply_container(object *op, object *sack, int aflags)
Definition: apply.c:222
llevError
@ llevError
Definition: logger.h:11
FABS
#define FABS(x)
Definition: define.h:22
MOVE_ALL
#define MOVE_ALL
Definition: define.h:398
AP_NO_MERGE
#define AP_NO_MERGE
Definition: define.h:581
apply_auto
int apply_auto(object *op)
Definition: apply.c:1400
WAND
@ WAND
Definition: object.h:220
range_bow
@ range_bow
Definition: player.h:31
FLAG_USE_RING
#define FLAG_USE_RING
Definition: define.h:297
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
GLOVES
@ GLOVES
Definition: object.h:213
GIRDLE
@ GIRDLE
Definition: object.h:223
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
obj::map
struct mapdef * map
Definition: object.h:300
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
CAN_APPLY_NEVER
#define CAN_APPLY_NEVER
Definition: define.h:630
TRIGGER_PEDESTAL
@ TRIGGER_PEDESTAL
Definition: object.h:134
apply_check_weapon_power
int apply_check_weapon_power(const object *who, int improves)
Definition: apply.c:1131
confuse_living
void confuse_living(object *op, object *hitter, int dam)
Definition: attack.c:2266
clear_skill
void clear_skill(object *who)
Definition: skill_util.c:389
FALSE
#define FALSE
Definition: compat.h:14
object_new
object * object_new(void)
Definition: object.c:1255
esrv_send_inventory
void esrv_send_inventory(object *pl, object *op)
Definition: item.c:315
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:316
apply_update_ranged_skill
static void apply_update_ranged_skill(const object *who, object *op, int aflags)
Definition: apply.c:1993
SHOP_FLOOR
@ SHOP_FLOOR
Definition: object.h:183
METHOD_OK
#define METHOD_OK
Definition: ob_methods.h:15
pl
Definition: player.h:105
CAN_APPLY_RESTRICTION
#define CAN_APPLY_RESTRICTION
Definition: define.h:631
ARMOUR
@ ARMOUR
Definition: object.h:120
PREFER_LOW
#define PREFER_LOW
Definition: define.h:564
WEAPON
@ WEAPON
Definition: object.h:119
TIMED_GATE
@ TIMED_GATE
Definition: object.h:128
MSG_TYPE_APPLY_CURSED
#define MSG_TYPE_APPLY_CURSED
Definition: newclient.h:605
LOOSE_MANA
#define LOOSE_MANA
Definition: spells.h:162
GT_ONLY_GOOD
@ GT_ONLY_GOOD
Definition: treasure.h:34
range_none
@ range_none
Definition: player.h:30
CHARISMA
@ CHARISMA
Definition: living.h:15
AMULET
@ AMULET
Definition: object.h:139
play_sound_player_only
void play_sound_player_only(player *pl, int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:51
TREASURE
@ TREASURE
Definition: object.h:110
SKILL
@ SKILL
Definition: object.h:143
object_find_by_type_applied
object * object_find_by_type_applied(const object *who, int type)
Definition: object.c:4054
play_sound_map
void play_sound_map(int8_t sound_type, object *emitter, int dir, const char *action)
Definition: sounds.c:113
change_skill
int change_skill(object *who, object *new_skill, int flag)
Definition: skill_util.c:350
GET_ANIM
#define GET_ANIM(ob)
Definition: global.h:161
Ice.tmp
int tmp
Definition: Ice.py:207
FLAG_BLESSED
#define FLAG_BLESSED
Definition: define.h:369
NDI_NAVY
#define NDI_NAVY
Definition: newclient.h:244
TRANSPORT
@ TRANSPORT
Definition: object.h:108
UPD_NROF
#define UPD_NROF
Definition: newclient.h:321
should_director_abort
int should_director_abort(const object *op, const object *victim)
Definition: apply.c:68
unapply_always
@ unapply_always
Definition: player.h:78
obj::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:377
skills.h
TRIGGER_BUTTON
@ TRIGGER_BUTTON
Definition: object.h:132
esrv_add_spells
void esrv_add_spells(player *pl, object *spell)
Definition: request.c:1854
create_treasure
void create_treasure(treasurelist *t, object *op, int flag, int difficulty, int tries)
Definition: treasure.c:241
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: events.cpp:274
apply_check_personalized_blessings
static int apply_check_personalized_blessings(object *who, const object *op)
Definition: apply.c:1891
obj::randomitems
struct treasureliststruct * randomitems
Definition: object.h:390
MSG_TYPE_VICTIM
#define MSG_TYPE_VICTIM
Definition: newclient.h:415
MAX
#define MAX(x, y)
Definition: compat.h:24
obj::nrof
uint32_t nrof
Definition: object.h:337
ob_apply
method_ret ob_apply(object *op, object *applier, int aflags)
Definition: ob_methods.c:44
cast_magic_storm
void cast_magic_storm(object *op, object *tmp, int lvl)
Definition: spell_effect.c:46
settings
struct Settings settings
Definition: init.c:39
animate_object
void animate_object(object *op, int dir)
Definition: anim.c:43
range_builder
@ range_builder
Definition: player.h:36
esrv_send_item
void esrv_send_item(object *pl, object *op)
Definition: main.c:355
object_merge
object * object_merge(object *op, object *top)
Definition: object.c:2031
auto_apply_fix_inventory
static void auto_apply_fix_inventory(mapstruct *m, object *tmp)
Definition: apply.c:1465
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.c:4317
METHOD_UNHANDLED
#define METHOD_UNHANDLED
Definition: ob_methods.h:16
FLAG_IS_A_TEMPLATE
#define FLAG_IS_A_TEMPLATE
Definition: define.h:366
obj::slaying
sstring slaying
Definition: object.h:322
AP_NULL
#define AP_NULL
Definition: define.h:573
identify
object * identify(object *op)
Definition: item.c:1409
m
static event_registration m
Definition: citylife.cpp:427
autojail.who
who
Definition: autojail.py:3
CLOAK
@ CLOAK
Definition: object.h:204
give_initial_items
void give_initial_items(object *pl, treasurelist *items)
Definition: player.c:776
AP_PRINT
#define AP_PRINT
Definition: define.h:583
esrv_remove_spell
void esrv_remove_spell(player *pl, object *spell)
Definition: request.c:1717
HELMET
@ HELMET
Definition: object.h:136
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Definition: define.h:234
obj::name
sstring name
Definition: object.h:314
drop
void drop(object *op, object *tmp)
Definition: c_object.c:1168
object_copy
void object_copy(const object *src_ob, object *dest_ob)
Definition: object.c:1064
blind_living
void blind_living(object *op, object *hitter, int dam)
Definition: attack.c:2309
MSG_TYPE_APPLY_SUCCESS
#define MSG_TYPE_APPLY_SUCCESS
Definition: newclient.h:603
SPELL_WONDER
#define SPELL_WONDER
Definition: spells.h:163
scroll_failure
void scroll_failure(object *op, int failure, int power)
Definition: apply.c:1597
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:585
set_object_face_main
int set_object_face_main(object *op)
Definition: apply.c:146
FLAG_USE_RANGE
#define FLAG_USE_RANGE
Definition: define.h:292
POTION
@ POTION
Definition: object.h:111
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
Definition: define.h:320
BUILDER
@ BUILDER
Definition: object.h:246
apply_handle_yield
void apply_handle_yield(object *tmp)
Definition: apply.c:122
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:754
HEAD
#define HEAD(op)
Definition: object.h:593
ROD
@ ROD
Definition: object.h:109
CONTAINER
@ CONTAINER
Definition: object.h:231
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:377
AP_IGNORE_CURSE
#define AP_IGNORE_CURSE
Definition: define.h:582
navar-midane_pickup.msg
list msg
Definition: navar-midane_pickup.py:13
MOVE_FLYING
#define MOVE_FLYING
Definition: define.h:395
obj::carrying
int32_t carrying
Definition: object.h:372
apply_changes_to_player
void apply_changes_to_player(object *pl, object *change, int limit_stats)
Definition: apply.c:1668
obj::x
int16_t x
Definition: object.h:330
INS_NO_MERGE
#define INS_NO_MERGE
Definition: object.h:566
FLAG_DAMNED
#define FLAG_DAMNED
Definition: define.h:317
fix_object
void fix_object(object *op)
Definition: living.c:1126
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:315
get_item_from_body_location
static object * get_item_from_body_location(object *start, int loc)
Definition: apply.c:878
FLAG_USE_SHIELD
#define FLAG_USE_SHIELD
Definition: define.h:237
LAMP
@ LAMP
Definition: object.h:201
Settings::item_power_factor
float item_power_factor
Definition: global.h:298
obj::other_arch
struct archt * other_arch
Definition: object.h:418
apply_special
int apply_special(object *who, object *op, int aflags)
Definition: apply.c:1156
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
apply_check_apply_restrictions
static int apply_check_apply_restrictions(object *who, object *op, int aflags)
Definition: apply.c:1796
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Definition: object.h:570
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.c:4470
sstring
const typedef char * sstring
Definition: global.h:40
rndm
int rndm(int min, int max)
Definition: utils.c:162
tag_t
uint32_t tag_t
Definition: object.h:12
obj::env
struct obj * env
Definition: object.h:296
FLAG_USE_WEAPON
#define FLAG_USE_WEAPON
Definition: define.h:296
sproto.h
IS_SHIELD
#define IS_SHIELD(op)
Definition: define.h:170
find_key
object * find_key(object *pl, object *container, object *door)
Definition: player.c:2445
AC_PLAYER_STAT_NO_CHANGE
#define AC_PLAYER_STAT_NO_CHANGE
Definition: define.h:597
MSG_TYPE_VICTIM_WAS_HIT
#define MSG_TYPE_VICTIM_WAS_HIT
Definition: newclient.h:651
animate.anim
string anim
Definition: animate.py:20
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:750
mapdef
Definition: map.h:317
CAN_APPLY_UNAPPLY_MULT
#define CAN_APPLY_UNAPPLY_MULT
Definition: define.h:634
GT_ENVIRONMENT
@ GT_ENVIRONMENT
Definition: treasure.h:31
SOUND_TYPE_SPELL
#define SOUND_TYPE_SPELL
Definition: newclient.h:334
RING
@ RING
Definition: object.h:185
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:202
MAP_WIDTH
#define MAP_WIDTH(m)
Definition: map.h:78
MAX_BUF
#define MAX_BUF
Definition: define.h:35
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:281
IS_WEAPON
#define IS_WEAPON(op)
Definition: define.h:163
check_trigger
int check_trigger(object *op, object *cause)
Definition: button.c:518
monster_check_apply_all
void monster_check_apply_all(object *monster)
Definition: monster.c:1991
try_find_animation
Animations * try_find_animation(const char *name)
Definition: assets.cpp:300
random_roll
int random_roll(int min, int max, const object *op, int goodbad)
Definition: utils.c:42
Settings::spell_failure_effects
uint8_t spell_failure_effects
Definition: global.h:264
FOR_MAP_PREPARE
#define FOR_MAP_PREPARE(map_, mx_, my_, it_)
Definition: define.h:723
obj::y
int16_t y
Definition: object.h:330
MSG_TYPE_APPLY_BADBODY
#define MSG_TYPE_APPLY_BADBODY
Definition: newclient.h:607
range_misc
@ range_misc
Definition: player.h:33
transport_can_hold
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.c:54
FLAG_READY_SKILL
#define FLAG_READY_SKILL
Definition: define.h:333
FLAG_READY_BOW
#define FLAG_READY_BOW
Definition: define.h:299
animations_struct
Definition: face.h:25
sounds.h
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
obj::type
uint8_t type
Definition: object.h:343
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:262
CAN_APPLY_UNAPPLY
#define CAN_APPLY_UNAPPLY
Definition: define.h:633
spells.h
obj::stats
living stats
Definition: object.h:373
AP_OPEN
#define AP_OPEN
Definition: define.h:576
apply_by_living
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Definition: apply.c:637
archt::clone
object clone
Definition: object.h:473
unapply_for_ob
static int unapply_for_ob(object *who, object *op, int aflags)
Definition: apply.c:915
IS_ARMOR
#define IS_ARMOR(op)
Definition: define.h:166
unapply_nochoice
@ unapply_nochoice
Definition: player.h:76
apply_anim_suffix
void apply_anim_suffix(object *who, const char *suffix)
Definition: anim.c:149
FLAG_USE_ARMOUR
#define FLAG_USE_ARMOUR
Definition: define.h:295
item
Definition: item.py:1
apply_manual
int apply_manual(object *op, object *tmp, int aflag)
Definition: apply.c:597
reputation.victim
victim
Definition: reputation.py:14
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
FIREWALL
@ FIREWALL
Definition: object.h:168
PLAYER_CHANGER
@ PLAYER_CHANGER
Definition: object.h:162
check_spell_known
object * check_spell_known(object *op, const char *name)
Definition: spell_util.c:393
AC_PLAYER_STAT_LIMIT
#define AC_PLAYER_STAT_LIMIT
Definition: define.h:596
give.op
op
Definition: give.py:33
apply_by_living_below
void apply_by_living_below(object *pl)
Definition: apply.c:695
FLAG_AUTO_APPLY
#define FLAG_AUTO_APPLY
Definition: define.h:250
Settings::personalized_blessings
uint8_t personalized_blessings
Definition: global.h:307
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.c:360
SKILL_TOOL
@ SKILL_TOOL
Definition: object.h:189
CAN_APPLY_UNAPPLY_CHOICE
#define CAN_APPLY_UNAPPLY_CHOICE
Definition: define.h:635
diamondslots.y
y
Definition: diamondslots.py:16
FLAG_BEEN_APPLIED
#define FLAG_BEEN_APPLIED
Definition: define.h:323
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
buf
StringBuffer * buf
Definition: readable.c:1610
AP_NOPRINT
#define AP_NOPRINT
Definition: define.h:585
set_attr_value
void set_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:219
MAP_HEIGHT
#define MAP_HEIGHT(m)
Definition: map.h:80
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2833
cast_wonder
int cast_wonder(object *op, object *caster, int dir, object *spell_ob)
Definition: spell_effect.c:977
object_update_speed
void object_update_speed(object *op)
Definition: object.c:1330
obj::head
struct obj * head
Definition: object.h:299
obj::more
struct obj * more
Definition: object.h:298
obj::weight_limit
int32_t weight_limit
Definition: object.h:371
MSG_TYPE_APPLY_FAILURE
#define MSG_TYPE_APPLY_FAILURE
Definition: newclient.h:604
unapply_special
static int unapply_special(object *who, object *op, int aflags)
Definition: apply.c:751
object_present_in_ob_by_name
object * object_present_in_ob_by_name(int type, const char *str, const object *op)
Definition: object.c:3174
FLAG_ANIMATE
#define FLAG_ANIMATE
Definition: define.h:242
UPD_NAME
#define UPD_NAME
Definition: newclient.h:318
object_insert_in_map_at
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:2080
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:309
get_attr_value
int8_t get_attr_value(const living *stats, int attr)
Definition: living.c:314
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.c:1546
apply_auto_fix
void apply_auto_fix(mapstruct *m)
Definition: apply.c:1523
apply_can_apply_object
int apply_can_apply_object(const object *who, const object *op)
Definition: apply.c:1016
ALTAR
@ ALTAR
Definition: object.h:122
DOOR
@ DOOR
Definition: object.h:126
EVENT_CLOSE
#define EVENT_CLOSE
Definition: events.h:23
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
try_find_face
const Face * try_find_face(const char *name, const Face *error)
Definition: assets.cpp:312
set_object_face_other
static int set_object_face_other(object *op)
Definition: apply.c:173
AP_BASIC_FLAGS
#define AP_BASIC_FLAGS
Definition: define.h:578
FLAG_READY_RANGE
#define FLAG_READY_RANGE
Definition: define.h:298
METHOD_ERROR
#define METHOD_ERROR
Definition: ob_methods.h:17
generate_treasure
object * generate_treasure(treasurelist *t, int difficulty)
Definition: treasure.c:273
object_find_by_name
object * object_find_by_name(const object *who, const char *name)
Definition: object.c:3927
SCROLL
@ SCROLL
Definition: object.h:221
FLAG_IS_LINKED
#define FLAG_IS_LINKED
Definition: define.h:315
MSG_TYPE_APPLY_PROHIBITION
#define MSG_TYPE_APPLY_PROHIBITION
Definition: newclient.h:608
unapply_never
@ unapply_never
Definition: player.h:77
obj::anim_suffix
sstring anim_suffix
Definition: object.h:319
AP_UNAPPLY
#define AP_UNAPPLY
Definition: define.h:575
range_skill
@ range_skill
Definition: player.h:35
apply_check_owner
static int apply_check_owner(const object *who, const object *op, int aflags)
Definition: apply.c:1967
tod.h
BOOTS
@ BOOTS
Definition: object.h:212
apply_check_race_restrictions
static int apply_check_race_restrictions(object *who, object *item)
Definition: apply.c:557
TRUE
#define TRUE
Definition: compat.h:11
change_abil
int change_abil(object *op, object *tmp)
Definition: living.c:395
SPELL
@ SPELL
Definition: object.h:214
FLAG_READY_WEAPON
#define FLAG_READY_WEAPON
Definition: define.h:334
player_unready_range_ob
void player_unready_range_ob(player *pl, object *ob)
Definition: player.c:4421
SHIELD
@ SHIELD
Definition: object.h:135
MSG_TYPE_APPLY
#define MSG_TYPE_APPLY
Definition: newclient.h:408
FLAG_CURSED
#define FLAG_CURSED
Definition: define.h:316
MSG_TYPE_APPLY_ERROR
#define MSG_TYPE_APPLY_ERROR
Definition: newclient.h:601
living.h
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2613
SPELLBOOK
@ SPELLBOOK
Definition: object.h:203
NUM_STATS
@ NUM_STATS
Definition: living.h:18
change_attr_value
void change_attr_value(living *stats, int attr, int8_t value)
Definition: living.c:265
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
FORCE
@ FORCE
Definition: object.h:224
METHOD_SILENT_ERROR
#define METHOD_SILENT_ERROR
Definition: ob_methods.h:18
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:319
do_learn_spell
void do_learn_spell(object *op, object *spell, int special_prayer)
Definition: apply.c:484
pl::orig_stats
living orig_stats
Definition: player.h:166
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
banquet.floors
list floors
Definition: banquet.py:29
give.name
name
Definition: give.py:27
MSG_TYPE_APPLY_UNAPPLY
#define MSG_TYPE_APPLY_UNAPPLY
Definition: newclient.h:602