Crossfire Server, Trunk  R22047
c_object.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  */
19 #include "global.h"
20 
21 #include <ctype.h>
22 #include <math.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "living.h"
27 #include "loader.h"
28 #include "shop.h"
29 #include "skills.h"
30 #include "sproto.h"
31 
33 static const char *pickup_names[] = {
34  "debug", "inhibit", "stop", "food", "drink",
35  "valuables", "bow", "arrow", "helmet", "shield",
36  "armour", "boots", "gloves", "cloak", "key",
37  "missile", "melee", "magical", "potion", "spellbook",
38  "skillscroll", "readables", "magicdevice", "notcursed", "jewels",
39  "flesh", "container", NULL
40 };
41 
43 static const uint32_t pickup_modes[] = {
48 };
49 
58 static int get_pickup_mode_index(const char *name) {
59  int best = -1, len = strlen(name);
60  for (int mode = 0; pickup_names[mode]; mode++) {
61  if (!strcmp(pickup_names[mode], name)) {
62  return mode;
63  }
64  if (len < strlen(pickup_names[mode]) && strncmp(name, pickup_names[mode], len) == 0) {
65  if (best != -2) {
66  if (best != -1) {
67  best = -2;
68  } else {
69  best = mode;
70  }
71  }
72  }
73  }
74  return best != -2 ? best : -1;
75 }
76 
77 static void set_pickup_mode(const object *op, int i);
78 
79 /*
80  * Object id parsing functions
81  */
82 
100 static object *find_best_apply_object_match(object *start, object *pl, const char *params, int aflag) {
101  object *tmp, *best = NULL;
102  int match_val = 0, tmpmatch;
103 
104  tmp = start;
106  if (tmp->invisible)
107  continue;
108  if (aflag == AP_APPLY && QUERY_FLAG(tmp, FLAG_APPLIED))
109  continue;
110  if (aflag == AP_UNAPPLY && !QUERY_FLAG(tmp, FLAG_APPLIED))
111  continue;
112  tmpmatch = object_matches_string(pl, tmp, params);
113  if (tmpmatch > match_val) {
114  match_val = tmpmatch;
115  best = tmp;
116  }
118  return best;
119 }
120 
131 static object *find_best_object_match(object *pl, const char *params) {
132  return find_best_apply_object_match(pl->inv, pl, params, AP_NULL);
133 }
134 
143 void command_uskill(object *pl, const char *params) {
144  if (*params == '\0') {
146  "Usage: use_skill <skill name>");
147  return;
148  }
149  use_skill(pl, params);
150 }
151 
160 void command_rskill(object *pl, const char *params) {
161  object *skill;
162 
163  if (*params == '\0') {
165  "Usage: ready_skill <skill name>");
166  return;
167  }
168  skill = find_skill_by_name(pl, params);
169 
170  if (!skill) {
172  "You have no knowledge of the skill %s",
173  params);
174  return;
175  }
176  change_skill(pl, skill, 0);
177 }
178 
187 static void do_skill_by_number(object *op, int skill_subtype, const char *params,
188  const char *missing_message) {
189  object *skop = find_skill_by_number(op, skill_subtype);
190  if (skop) {
191  do_skill(op, op, skop, op->facing, *params == '\0' ? NULL : params);
192  return;
193  }
194 
196  missing_message);
197 }
198 
199 /* These functions (command_search, command_disarm) are really juse wrappers for
200  * things like 'use_skill ...'). In fact, they should really be obsoleted
201  * and replaced with those.
202  */
211 void command_search(object *op, const char *params) {
212  do_skill_by_number(op, SK_FIND_TRAPS, params, "You don't know how to search for unusual things.");
213 }
214 
223 void command_disarm(object *op, const char *params) {
224  do_skill_by_number(op, SK_DISARM_TRAPS, params, "You don't know how to disarm traps.");
225 }
226 
238 void command_throw(object *op, const char *params) {
239  do_skill_by_number(op, SK_THROWING, params, "You have no knowledge of the skill throwing.");
240 }
241 
250 void command_apply(object *op, const char *params) {
251  int aflag = 0;
252  object *inv = op->inv;
253  object *item;
254 
255  if (*params == '\0') {
257  return;
258  }
259 
260  while (*params == ' ')
261  params++;
262  if (!strncmp(params, "-a ", 3)) {
263  aflag = AP_APPLY;
264  params += 3;
265  }
266  if (!strncmp(params, "-u ", 3)) {
267  aflag = AP_UNAPPLY;
268  params += 3;
269  }
270  if (!strncmp(params, "-o ", 3)) {
271  aflag = AP_OPEN;
272  params += 3;
273  }
274  if (!strncmp(params, "-b ", 3)) {
275  params += 3;
276  if (op->container)
277  inv = op->container->inv;
278  else {
279  inv = op;
280  while (inv->above)
281  inv = inv->above;
282  }
283  }
284  while (*params == ' ')
285  params++;
286 
287  item = find_best_apply_object_match(inv, op, params, aflag);
288  if (item == NULL)
289  item = find_best_apply_object_match(inv, op, params, AP_NULL);
290  if (item) {
291  apply_by_living(op, item, aflag, 0);
292  } else
294  "Could not find any match to the %s.",
295  params);
296 }
297 
316 int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof) {
317  char name[MAX_BUF];
318  query_name(sack, name, MAX_BUF);
319 
320  if (!QUERY_FLAG(sack, FLAG_APPLIED)) {
322  "The %s is not active.",
323  name);
324  return 0;
325  }
326  if (sack == op) {
328  "You can't put the %s into itself.",
329  name);
330  return 0;
331  }
332  if (sack->race
333  && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type))) {
335  "You can put only %s into the %s.",
336  sack->race, name);
337  return 0;
338  }
339  if (op->type == SPECIAL_KEY && sack->slaying && op->slaying) {
341  "You can't put the key into %s.",
342  name);
343  return 0;
344  }
345  if (sack->weight_limit) {
346  int32_t new_weight;
347 
348  new_weight = sack->carrying+(nrof ? nrof : 1)
349  /* Most non-containers should have op->carrying == 0. Icecubes, however, will not,
350  * and we need to handle those.
351  * Daniel Hawkins 2021-01-21
352  */
353  *(op->weight+(op->type == CONTAINER ? op->carrying*op->stats.Str : op->carrying))
354  *(100-sack->stats.Str)/100;
355  if (new_weight > sack->weight_limit) {
357  "That won't fit in the %s!",
358  name);
359  return 0;
360  }
361  }
362  /* All other checks pass, must be OK */
363  return 1;
364 }
365 
378 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
379  /* buf needs to be big (more than 256 chars) because you can get
380  * very long item names.
381  */
382  char buf[HUGE_BUF], name[MAX_BUF];
383  object *env = tmp->env;
384  uint32_t weight, effective_weight_limit;
385  const int tmp_nrof = NROF(tmp);
386  tag_t tag;
387  mapstruct* map = tmp->map;
388  int16_t x = tmp->x, y = tmp->y;
389 
390  /* IF the player is flying & trying to take the item out of a container
391  * that is in his inventory, let him. tmp->env points to the container
392  * (sack, luggage, etc), tmp->env->env then points to the player (nested
393  * containers not allowed as of now)
394  */
395  if ((pl->move_type&MOVE_FLYING)
396  && !QUERY_FLAG(pl, FLAG_WIZ)
397  && object_get_player_container(tmp) != pl) {
399  "You are levitating, you can't reach the ground!");
400  return;
401  }
402  if (QUERY_FLAG(tmp, FLAG_NO_DROP))
403  return;
404 
405  if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
407  "The object disappears in a puff of smoke! It must have been an illusion.");
408  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
409  object_remove(tmp);
411  return;
412  }
413 
414  if (nrof > tmp_nrof || nrof == 0)
415  nrof = tmp_nrof;
416 
417  /* Figure out how much weight this object will add to the player */
418  weight = tmp->weight*nrof;
419  if (tmp->inv)
420  weight += tmp->carrying*(100-tmp->stats.Str)/100;
421 
422  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
423 
424  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
426  "That item is too heavy for you to pick up.");
427  return;
428  }
429 
431  SET_FLAG(tmp, FLAG_WAS_WIZ);
432 
433  if (nrof != tmp_nrof) {
434  char failure[MAX_BUF];
435 
436  tmp = object_split(tmp, nrof, failure, sizeof(failure));
437  if (!tmp) {
439  failure);
440  return;
441  }
442  } else {
443  /* If the object is in a container, send a delete to the client.
444  * - we are moving all the items from the container to elsewhere,
445  * so it needs to be deleted.
446  */
447  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
448  object_remove(tmp); /* Unlink it */
449  }
450  }
451  query_name(tmp, name, MAX_BUF);
452 
453  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
454  char *value = cost_str(shop_price_buy(tmp, pl));
455  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
456  free(value);
457  } else
458  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
459 
460  /* Now item is about to be picked. */
461  tag = tmp->count;
462  if (events_execute_object_event(tmp, EVENT_PICKUP, pl, op, NULL, SCRIPT_FIX_ALL) != 0) {
463  /* put item back, if it still exists */
464  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
465  if (env != NULL) {
466  object_insert_in_ob(tmp, env);
467  } else {
468  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
469  }
470  }
471  return;
472  }
473 
475  buf);
476 
477  tmp = object_insert_in_ob(tmp, op);
478 
479  /* All the stuff below deals with client/server code, and is only
480  * usable by players
481  */
482  if (pl->type != PLAYER)
483  return;
484 
485  /* Additional weight changes speed, etc */
486  fix_object(pl);
487 
488  /* These are needed to update the weight for the container we
489  * are putting the object in.
490  */
491  if (op != pl) {
492  esrv_update_item(UPD_WEIGHT, pl, op);
493  esrv_update_item(UPD_WEIGHT, pl, pl);
494  }
495 
496  /* Update the container the object was in */
497  if (env && env != pl && env != op)
498  esrv_update_item(UPD_WEIGHT, pl, env);
499 }
500 
509 void pick_up(object *op, object *alt) {
510 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
511  object *tmp = NULL, *tmp1;
512  mapstruct *tmp_map = NULL;
513  int count;
514 
515  /* Decide which object to pick. */
516  if (alt) {
517  if (!object_can_pick(op, alt)) {
519  "You can't pick up the %s.",
520  alt->name);
521  return;
522  }
523  tmp = alt;
524  } else {
525  if (op->below == NULL || !object_can_pick(op, op->below)) {
527  "There is nothing to pick up here.");
528  return;
529  }
530  tmp = op->below;
531  }
532 
533  /* it is possible that the object is a thrown object and is flying about.
534  * in that case, what we want to pick up is the payload. Objects
535  * that are thrown are encapsulated into a thrown object.
536  * stop_item() returns the payload (unlinked from map) and gets rid of the
537  * container object. If this object isn't picked up, we need to insert
538  * it back on the map.
539  * A bug here is that even attempting to pick up one of these objects will
540  * result in this logic being called even if player is unable to pick it
541  * up.
542  */
543 
544  tmp_map = tmp->map;
545  tmp1 = stop_item(tmp);
546  if (tmp1 == NULL)
547  return;
548 
549  /* If it is a thrown object, insert it back into the map here.
550  * makes life easier further along. Do no merge so pick up code
551  * behaves more sanely.
552  */
553  if (tmp1 != tmp) {
554  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
555  }
556 
557  if (tmp == NULL)
558  return;
559 
560  if (!object_can_pick(op, tmp))
561  return;
562 
563  /* Establish how many of the object we are picking up */
564  if (op->type == PLAYER) {
565  count = op->contr->count;
566  if (count == 0)
567  count = tmp->nrof;
568  } else
569  count = tmp->nrof;
570 
571  /* container is open, so use it */
572  if (op->container) {
573  alt = op->container;
574  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
575  return;
576  } else {
577  /* non container pickup. See if player has any
578  * active containers.
579  */
580  object *container = NULL;
581 
582  /* Look for any active containers that can hold this item.
583  * we cover two cases here - the perfect match case, where we
584  * break out of the loop, and the general case (have a container),
585  * Moved this into a single loop - reduces redundant code, is
586  * more efficient and easier to follow. MSW 2009-04-06
587  */
588  alt = op->inv;
590  if (alt->type == CONTAINER
591  && QUERY_FLAG(alt, FLAG_APPLIED)
592  && sack_can_hold(NULL, alt, tmp, count)) {
593  if (alt->race && alt->race == tmp->race) {
594  break; /* perfect match */
595  } else if (!container) {
596  container = alt;
597  }
598  }
600  /* Note container could be null, but no reason to check for it */
601  if (!alt)
602  alt = container;
603 
604  if (!alt)
605  alt = op; /* No free containers */
606  }
607  /* see if this object is already in this container. If so,
608  * move it to player inventory from this container.
609  */
610  if (tmp->env == alt) {
611  alt = op;
612  }
613 
614  /* Don't allow players to be put into containers. Instead,
615  * just put them in the players inventory.
616  */
617  if (tmp->type == CONTAINER && alt->type==CONTAINER) {
618  alt = op;
619  }
620 #ifdef PICKUP_DEBUG
621  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
622 #endif
623 
624  /* startequip items are not allowed to be put into containers
625  * Not sure why we have this limitation
626  */
627  if (op->type == PLAYER
628  && alt->type == CONTAINER
629  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
631  "This object cannot be put into containers!");
632  return;
633  }
634 
635  pick_up_object(op, alt, tmp, count);
636  if (op->type == PLAYER)
637  op->contr->count = 0;
638 }
639 
646 int object_matches_pickup_mode(const object *item, int mode) {
647  switch(mode) {
648  case PU_FOOD:
649  return item->type == FOOD;
650  case PU_DRINK:
651  return item->type == DRINK || (item->type == POISON && !QUERY_FLAG(item, FLAG_KNOWN_CURSED));
652  case PU_FLESH:
653  return item->type == FLESH;
654  case PU_POTION:
655  return item->type == POTION;
656  case PU_SPELLBOOK:
657  return item->type == SPELLBOOK;
658  case PU_SKILLSCROLL:
659  return item->type == SKILLSCROLL;
660  case PU_READABLES:
661  return item->type == BOOK || item->type == SCROLL;
662  case PU_MAGIC_DEVICE:
663  return item->type == WAND || item->type == ROD || item->type == WEAPON_IMPROVER || item->type == ARMOUR_IMPROVER || item->type == SKILL_TOOL;
664  case PU_MAGICAL:
666  case PU_VALUABLES:
667  return item->type == MONEY || item->type == GEM;
668  case PU_JEWELS:
669  return item->type == RING || item->type == AMULET;
670  case PU_BOW:
671  return item->type == BOW;
672  case PU_ARROW:
673  return item->type == ARROW;
674  case PU_ARMOUR:
675  return item->type == ARMOUR;
676  case PU_HELMET:
677  return item->type == HELMET;
678  case PU_SHIELD:
679  return item->type == SHIELD;
680  case PU_BOOTS:
681  return item->type == BOOTS;
682  case PU_GLOVES:
683  return item->type == GLOVES;
684  case PU_CLOAK:
685  return item->type == CLOAK;
686  case PU_MISSILEWEAPON:
687  return item->type == WEAPON && QUERY_FLAG(item, FLAG_IS_THROWN);
688  case PU_MELEEWEAPON:
689  return item->type == WEAPON;
690  case PU_KEY:
691  return item->type == KEY || item->type == SPECIAL_KEY;
692  case PU_CONTAINER:
693  return item->type == CONTAINER;
694  }
695  return 0;
696 }
697 
699 typedef struct {
700  union {
701  struct {
705  };
706  char name[100];
708  };
709  int missed;
711 
719 typedef int (*item_matcher)(object *who, matcher_params *params, object *item);
720 
728 static int matcher_all(object *who, matcher_params *params, object *item) {
729  (void)who;
730  (void)params;
731  (void)item;
732  return 1;
733 }
734 
742 static int matcher_number(object *who, matcher_params *params, object *item) {
743  if (params->item_must_be_pickable == 0 || object_can_pick(who, item)) {
744  params->item_number++;
745  }
746  if (params->item_to_pick == params->item_number) {
747  /* Since we don't always increase item_number, multiple items may have the same index,
748  including unpickable ones, so to avoid failure messages just ensure no other item can be picked. */
749  params->item_to_pick = 0;
750  return 1;
751  }
752  return 0;
753 }
754 
762 static int matcher_name(object *who, matcher_params *params, object *item) {
763  int ival = object_matches_string(who, item, params->name);
764  if (ival > 0) {
765  if (ival <= 2 && !object_can_pick(who, item)) {
766  if (!QUERY_FLAG(item, FLAG_IS_FLOOR))/* don't count floor tiles */
767  params->missed++;
768  return 0;
769  }
770  return 1;
771  }
772  return 0;
773 }
774 
782 static int matcher_pickup_type(object *who, matcher_params *params, object *item) {
783  (void)who;
784  return object_matches_pickup_mode(item, params->pickup_type);
785 }
786 
794 static item_matcher make_matcher(object *who, const char *params, matcher_params *mp) {
795  memset(mp, 0, sizeof(*mp));
796  if (params[0] == '\0') {
797  mp->item_to_pick = 1;
798  mp->item_must_be_pickable = 1;
799  return &matcher_number;
800  }
801  if (params[0] == '#') {
802  mp->item_to_pick = atoi(params + 1);
803  if (mp->item_to_pick == 0) {
805  return NULL;
806  }
807  return &matcher_number;
808  }
809  if (params[0] == '*') {
810  if (params[1] == '\0') {
811  return &matcher_all;
812  }
813  int idx = get_pickup_mode_index(params + 1);
814  if (idx == -1) {
815  draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, "Invalid items %s", params + 1);
816  return NULL;
817  }
818  mp->pickup_type = pickup_modes[idx];
819  return &matcher_pickup_type;
820  }
821  strncpy(mp->name, params, sizeof(mp->name) - 1);
822  return &matcher_name;
823 }
824 
833 void command_take(object *op, const char *params) {
834  object *tmp;
835  int did_one = 0;
836 
837  if (op->container)
838  tmp = op->container->inv;
839  else {
840  tmp = op->above;
841  if (tmp)
842  while (tmp->above) {
843  tmp = tmp->above;
844  }
845  if (!tmp)
846  tmp = op->below;
847  }
848 
849  if (tmp == NULL) {
851  "Nothing to take!");
852  return;
853  }
854 
855  matcher_params mp;
856  item_matcher matcher = make_matcher(op, params, &mp);
857  if (!matcher) {
858  return; // Player already informed of failure.
859  }
860 
862 
864  if (tmp->invisible) {
865  continue;
866  }
867  if ((*matcher)(op, &mp, tmp)) {
868  pick_up(op, tmp);
869  did_one = 1;
870  }
872 
873  /* Nothing picked up, check if unable to pick or nothing to pick. */
874  if (params[0] == '\0' && !did_one) {
875  int found = 0;
876  FOR_BELOW_PREPARE(op, tmp)
877  if (!tmp->invisible) {
879  "You can't pick up a %s.",
880  tmp->name ? tmp->name : "null");
881  found = 1;
882  break;
883  }
885  if (!found)
887  "There is nothing to pick up.");
888  }
889 
890  if (mp.missed == 1)
892  "You were unable to take one of the items.");
893  else if (mp.missed > 1)
895  "You were unable to take %d of the items.",
896  mp.missed);
897 
898  /* Now update player and send information. */
900  fix_object(op);
901  if (op->type == PLAYER) {
902  op->contr->count = 0;
903  esrv_update_item(UPD_WEIGHT, op, op);
904  }
905 }
906 
925 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
926  object *sack2, *orig = sack;
927  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
928 
929  if (sack == tmp)
930  return; /* Can't put an object in itself */
931  query_name(sack, name_sack, MAX_BUF);
932  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
934  "The %s is not a container.",
935  name_sack);
936  return;
937  }
938  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
939  query_name(tmp, name_tmp, MAX_BUF);
941  "You cannot put the %s in the %s.",
942  name_tmp, name_sack);
943  return;
944  }
945  if (tmp->type == CONTAINER) {
946  if (tmp->inv) {
947  if (tmp->slaying)
948  return;
949  /* Eneq(@csd.uu.se): If the object to be dropped is a container
950  * and does not require a key to be opened,
951  * we instead move the contents of that container into the active
952  * container, this is only done if the object has something in it.
953  * If object is container but need a key, just don't do anything
954  */
955  sack2 = tmp;
956  query_name(tmp, name_tmp, MAX_BUF);
958  "You move the items from %s into %s.",
959  name_tmp, name_sack);
960 
961  FOR_INV_PREPARE(tmp, tmp2) {
962  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
963  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
964  put_object_in_sack(op, sack, tmp2, 0);
965  } else {
968  "Your %s fills up.",
969  name_sack);
970  break;
971  }
972  } FOR_INV_FINISH();
973  esrv_update_item(UPD_WEIGHT, op, sack2);
974  return;
975  } else {
976  query_name(tmp, name_tmp, MAX_BUF);
978  "You can not put a %s into a %s",
979  name_tmp,
980  name_sack);
981  return;
982  }
983  }
984 
985  /* Don't worry about this for containers - our caller should have
986  * already checked this.
987  */
988  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
989  return;
990 
991  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
992  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
993  return;
994  }
995 
996  /* we want to put some portion of the item into the container */
997  if (nrof && tmp->nrof != nrof) {
998  char failure[MAX_BUF];
999 
1000  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1001 
1002  if (!tmp) {
1004  failure);
1005  return;
1006  }
1007  } else
1008  object_remove(tmp);
1009 
1010  if (sack->nrof > 1) {
1011  orig = object_split(sack, sack->nrof-1, NULL, 0);
1012  set_object_face_main(orig);
1013  CLEAR_FLAG(orig, FLAG_APPLIED);
1014  if (sack->env) {
1015  object_insert_in_ob(orig, sack->env);
1016  } else {
1017  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
1018  orig->move_off = 0;
1019  }
1020  }
1021 
1022  query_name(tmp, name_tmp, MAX_BUF);
1024  "You put the %s in %s.",
1025  name_tmp, name_sack);
1026 
1027  object_insert_in_ob(tmp, sack);
1028  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1029  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1030  /* in object.c */
1031 
1032  /* If a transport, need to update all the players in the transport
1033  * the view of what is in it.
1034  */
1035  if (sack->type == TRANSPORT) {
1036  FOR_INV_PREPARE(sack, tmp)
1037  if (tmp->type == PLAYER)
1038  tmp->contr->socket.update_look = 1;
1039  FOR_INV_FINISH();
1040  } else {
1041  /* update the sacks weight */
1042  esrv_update_item(UPD_WEIGHT, op, sack);
1043  }
1044 }
1045 
1061 object *drop_object(object *op, object *tmp, uint32_t nrof) {
1062  tag_t tmp_tag;
1063 
1064  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1065  return NULL;
1066  }
1067 
1068  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1069  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
1070  return NULL; /* can't unapply it */
1071  }
1072 
1073  if (events_execute_object_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1074  return NULL;
1075 
1076  /* ensure the plugin didn't destroy the object */
1077  if (QUERY_FLAG(tmp, FLAG_REMOVED))
1078  return NULL;
1079 
1080  /* We are only dropping some of the items. We split the current objec
1081  * off
1082  */
1083  if (nrof && tmp->nrof != nrof) {
1084  char failure[MAX_BUF];
1085 
1086  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1087  if (!tmp) {
1089  failure);
1090  return NULL;
1091  }
1092  } else
1093  object_remove(tmp);
1094 
1095  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
1096  char name[MAX_BUF];
1097 
1098  query_name(tmp, name, MAX_BUF);
1100  "You drop the %s. The gods who lent it to you retrieve it.",
1101  name);
1103 
1104  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1105  fix_object(op);
1106 
1107  return NULL;
1108  }
1109 
1110  /* If SAVE_INTERVAL is commented out, we never want to save
1111  * the player here.
1112  */
1113 #ifdef SAVE_INTERVAL
1114  /* I'm not sure why there is a value check - since the save
1115  * is done every SAVE_INTERVAL seconds, why care the value
1116  * of what he is dropping?
1117  */
1118  if (op->type == PLAYER
1119  && !QUERY_FLAG(tmp, FLAG_UNPAID)
1120  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
1121  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
1122  save_player(op, 1);
1123  op->contr->last_save_time = time(NULL);
1124  }
1125 #endif /* SAVE_INTERVAL */
1126 
1127 
1128  tmp_tag = tmp->count;
1129  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
1130  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
1131  sell_item(tmp, op);
1132  }
1133 
1134  /* Call this before we update the various windows/players. At least
1135  * that we, we know the weight is correct.
1136  */
1137  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
1138  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1139  /* in object.c */
1140 
1141  /* Need to update weight of player */
1142  if (op->type == PLAYER)
1143  esrv_update_item(UPD_WEIGHT, op, op);
1144  }
1145  return tmp;
1146 }
1147 
1156 void drop(object *op, object *tmp) {
1157  /* Hopeful fix for disappearing objects when dropping from a container -
1158  * somehow, players get an invisible object in the container, and the
1159  * old logic would skip over invisible objects - works fine for the
1160  * playes inventory, but drop inventory wants to use the next value.
1161  */
1162  if (tmp->invisible) {
1163  /* if the following is the case, it must be in an container. */
1164  if (tmp->env && tmp->env->type != PLAYER) {
1165  /* Just toss the object - probably shouldn't be hanging
1166  * around anyways
1167  */
1168  object_remove(tmp);
1170  return;
1171  } else {
1173  if (!tmp->invisible)
1174  break;
1176  }
1177  }
1178 
1179  if (tmp == NULL) {
1181  "You don't have anything to drop.");
1182  return;
1183  }
1184  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1186  "This item is locked");
1187  return;
1188  }
1189  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1190  return;
1191  }
1192 
1193  if (op->container) {
1194  if (op->type == PLAYER) {
1195  put_object_in_sack(op, op->container, tmp, op->contr->count);
1196  } else {
1197  put_object_in_sack(op, op->container, tmp, 0);
1198  };
1199  } else {
1200  if (op->type == PLAYER) {
1201  drop_object(op, tmp, op->contr->count);
1202  } else {
1203  drop_object(op, tmp, 0);
1204  };
1205  }
1206  if (op->type == PLAYER)
1207  op->contr->count = 0;
1208 }
1209 
1218 void command_dropall(object *op, const char *params) {
1219  int count = 0;
1220 
1221  if (op->inv == NULL) {
1222  draw_ext_info(NDI_UNIQUE, 0, op,
1224  "Nothing to drop!");
1225  return;
1226  }
1227 
1228  if (op->contr)
1229  count = op->contr->count;
1230 
1231  /* Set this so we don't call it for _every_ object that
1232  * is dropped.
1233  */
1235 
1236  /*
1237  * This is the default. Drops everything not locked or considered
1238  * not something that should be dropped.
1239  * Care must be taken that the next item pointer is not to money as
1240  * the drop() routine will do unknown things to it when dropping
1241  * in a shop. --Tero.Pelander@utu.fi
1242  */
1243  if (*params == '\0') {
1244  FOR_INV_PREPARE(op, curinv) {
1245  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1246  && curinv->type != MONEY
1247  && curinv->type != FOOD
1248  && curinv->type != KEY
1249  && curinv->type != SPECIAL_KEY
1250  && curinv->type != GEM
1251  && !curinv->invisible
1252  && (curinv->type != CONTAINER || op->container != curinv)) {
1253  drop(op, curinv);
1254  if (op->contr)
1255  op->contr->count = count;
1256  }
1257  } FOR_INV_FINISH();
1258  } else if (strcmp(params, "weapons") == 0) {
1259  FOR_INV_PREPARE(op, curinv) {
1260  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1261  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1262  drop(op, curinv);
1263  if (op->contr)
1264  op->contr->count = count;
1265  }
1266  } FOR_INV_FINISH();
1267  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1268  FOR_INV_PREPARE(op, curinv) {
1269  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1270  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1271  drop(op, curinv);
1272  if (op->contr)
1273  op->contr->count = count;
1274  }
1275  } FOR_INV_FINISH();
1276  } else if (strcmp(params, "food") == 0) {
1277  FOR_INV_PREPARE(op, curinv) {
1278  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1279  && (curinv->type == FOOD || curinv->type == DRINK)) {
1280  drop(op, curinv);
1281  if (op->contr)
1282  op->contr->count = count;
1283  }
1284  } FOR_INV_FINISH();
1285  } else if (strcmp(params, "flesh") == 0) {
1286  FOR_INV_PREPARE(op, curinv) {
1287  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1288  && (curinv->type == FLESH)) {
1289  drop(op, curinv);
1290  if (op->contr)
1291  op->contr->count = count;
1292  }
1293  } FOR_INV_FINISH();
1294  } else if (strcmp(params, "misc") == 0) {
1295  FOR_INV_PREPARE(op, curinv) {
1296  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1297  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1298  switch (curinv->type) {
1299  case BOOK:
1300  case SPELLBOOK:
1301  case GIRDLE:
1302  case AMULET:
1303  case RING:
1304  case CLOAK:
1305  case BOOTS:
1306  case GLOVES:
1307  case BRACERS:
1308  case SCROLL:
1309  case ARMOUR_IMPROVER:
1310  case WEAPON_IMPROVER:
1311  case WAND:
1312  case ROD:
1313  case POTION:
1314  drop(op, curinv);
1315  if (op->contr)
1316  op->contr->count = count;
1317  break;
1318 
1319  default:
1320  break;
1321  }
1322  }
1323  } FOR_INV_FINISH();
1324  }
1325  op->contr->socket.update_look = 1;
1327  /* call it now, once */
1328  fix_object(op);
1329  /* Need to update weight of player. Likewise, only do it once */
1330  if (op->type == PLAYER)
1331  esrv_update_item(UPD_WEIGHT, op, op);
1332 }
1333 
1342 void command_drop(object *op, const char *params) {
1343  int did_one = 0;
1344  int ival = 0;
1345  int missed = 0;
1346 
1347  if (*params == '\0') {
1349  "Drop what?");
1350  return;
1351  }
1352 
1353  matcher_params mp;
1354  item_matcher matcher = make_matcher(op, params, &mp);
1355  if (!matcher) {
1356  return;
1357  }
1358 
1360 
1361  FOR_INV_PREPARE(op, tmp) {
1362  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1363  continue;
1364  if ((*matcher)(op, &mp, tmp)) {
1365  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1366  missed++;
1367  } else {
1368  drop(op, tmp);
1369  }
1370  did_one = 1;
1371  }
1372  } FOR_INV_FINISH();
1373  if (!did_one)
1375  "Nothing to drop.");
1376  if (missed == 1)
1378  "One item couldn't be dropped because it was locked.");
1379  else if (missed > 1)
1381  "%d items couldn't be dropped because they were locked.",
1382  missed);
1383 
1384  /* Now update player and send information. */
1386  fix_object(op);
1387  if (op->type == PLAYER) {
1388  op->contr->count = 0;
1389  esrv_update_item(UPD_WEIGHT, op, op);
1390  }
1391 }
1392 
1401 static void empty_container(object *container, object *pl) {
1402  int left = 0;
1403  char name[MAX_BUF];
1404 
1405  if (!container->inv)
1406  return;
1407 
1408  FOR_INV_PREPARE(container, inv) {
1409  object *next;
1410 
1411  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1412  /* you can have locked items in container. */
1413  left++;
1414  continue;
1415  }
1416  next = inv->below;
1417  drop(pl, inv);
1418  if (inv->below == next)
1419  /* item couldn't be dropped for some reason. */
1420  left++;
1421  } FOR_INV_FINISH();
1422  esrv_update_item(UPD_WEIGHT, pl, container);
1423 
1424  query_name(container, name, sizeof(name));
1425  if (left)
1426  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1427  else
1428  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s.", name);
1429 }
1430 
1439 void command_empty(object *op, const char *params) {
1440  object *container;
1441 
1442  if (*params == '\0') {
1444  "Empty what?");
1445  return;
1446  }
1447 
1448  if (strcmp(params, "all") == 0) {
1449  FOR_INV_PREPARE(op, inv)
1450  if (inv->type == CONTAINER)
1451  empty_container(inv, op);
1452  FOR_INV_FINISH();
1453  return;
1454  }
1455 
1456  container = find_best_object_match(op, params);
1457  if (!container) {
1459  "No such item.");
1460  return;
1461  }
1462  if (container->type != CONTAINER) {
1464  "This is not a container!");
1465  return;
1466  }
1467  empty_container(container, op);
1468 }
1469 
1478 void command_examine(object *op, const char *params) {
1479  if (*params == '\0') {
1480  FOR_BELOW_PREPARE(op, tmp)
1481  if (LOOK_OBJ(tmp)) {
1482  examine(op, tmp);
1483  break;
1484  }
1485  FOR_BELOW_FINISH();
1486  } else {
1487  object *tmp = find_best_object_match(op, params);
1488 
1489  if (tmp)
1490  examine(op, tmp);
1491  else
1493  "Could not find an object that matches %s",
1494  params);
1495  }
1496 }
1497 
1509 object *find_marked_object(object *op) {
1510  if (!op || !op->contr || !op->contr->mark)
1511  return NULL;
1512 
1513  /* This may seem like overkill, but we need to make sure that they
1514  * player hasn't dropped the item. We use count on the off chance that
1515  * an item got reincarnated at some point.
1516  */
1517  /*
1518  FOR_INV_PREPARE(op, tmp) {
1519  if (tmp->invisible)
1520  continue;
1521  if (tmp == op->contr->mark) {
1522  if (tmp->count == op->contr->mark_count)
1523  return tmp;
1524  else {
1525  op->contr->mark = NULL;
1526  op->contr->mark_count = 0;
1527  return NULL;
1528  }
1529  }
1530  } FOR_INV_FINISH();
1531  */
1532  /* Try a different way of doing this
1533  * We check the environment of the marked object
1534  * to make sure it is still in the player's inventory.
1535  * In addition, we ensure there is the correct tag for that item.
1536  *
1537  * Daniel Hawkins 2018-10-23
1538  */
1539  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1540  return op->contr->mark;
1541  // Otherwise reset the mark, since it is no longer valid.
1542  op->contr->mark = NULL;
1543  op->contr->mark_count = 0;
1544  return NULL;
1545 }
1546 
1556 void command_mark(object *op, const char *params) {
1557  char name[MAX_BUF];
1558 
1559  if (!op->contr)
1560  return;
1561  if (*params == '\0') {
1562  object *mark = find_marked_object(op);
1563  if (!mark)
1565  "You have no marked object.");
1566  else {
1567  query_name(mark, name, MAX_BUF);
1569  "%s is marked.",
1570  name);
1571  }
1572  } else {
1573  object *mark1 = find_best_object_match(op, params);
1574 
1575  if (!mark1) {
1577  "Could not find an object that matches %s",
1578  params);
1579  return;
1580  } else {
1581  op->contr->mark = mark1;
1582  op->contr->mark_count = mark1->count;
1583  query_name(mark1, name, MAX_BUF);
1585  "Marked item %s",
1586  name);
1587  return;
1588  }
1589  }
1590  /*shouldnt get here */
1591 }
1592 
1603 void examine_monster(object *op, object *tmp, int level) {
1604  object *mon = HEAD(tmp), *probe;
1605 
1606  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1608  "It is an undead force.");
1609  if (mon->level > op->level)
1611  "It is likely more powerful than you.");
1612  else if (mon->level < op->level)
1614  "It is likely less powerful than you.");
1615  else
1617  "It is probably as powerful as you.");
1618 
1619  if (mon->attacktype&AT_ACID)
1621  "You smell an acrid odor.");
1622 
1623  /* Anyone know why this used to use the clone value instead of the
1624  * maxhp field? This seems that it should give more accurate results.
1625  */
1626  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1627  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1628  case 0:
1630  "It is critically wounded.");
1631  break;
1632 
1633  case 1:
1635  "It is in a bad shape.");
1636  break;
1637 
1638  case 2:
1640  "It is hurt.");
1641  break;
1642 
1643  case 3:
1645  "It is somewhat hurt.");
1646  break;
1647 
1648  default:
1650  "It is in excellent shape.");
1651  break;
1652  }
1653  if (object_present_in_ob(POISONING, mon) != NULL)
1655  "It looks very ill.");
1656 
1657  if (level < 10)
1658  return;
1659  knowledge_show_monster_detail(op, mon->arch->name);
1660 
1661  if (level < 15)
1662  return;
1663 
1664  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1665  if (probe != NULL && probe->level > level)
1666  return;
1667 
1668  if (probe == NULL) {
1670  free_string(probe->name);
1671  probe->name = add_string("probe_force");
1674  object_insert_in_ob(probe, mon);
1675  fix_object(mon);
1676  }
1677  probe->level = level;
1678  if (level / 10 > probe->duration)
1679  probe->duration = level / 10;
1680 }
1681 
1691 void examine(object *op, object *tmp) {
1692  char buf[VERY_BIG_BUF];
1693  int in_shop;
1694  int i, exp = 0, conn;
1695 
1696  /* we use this to track how far along we got with trying to identify an item,
1697  * so that we can give the appropriate message to the player */
1698  int id_attempted = 0;
1699  char prefix[MAX_BUF] = "That is";
1700  const typedata *tmptype;
1701  object *skill;
1702 
1703  buf[0] = '\0';
1704 
1705  if (tmp == NULL || tmp->type == CLOSE_CON)
1706  return;
1707  tmptype = get_typedata(tmp->type);
1708  if (!tmptype) {
1709  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid", tmp->count, tmp->type);
1710  return;
1711  }
1712  /* first of all check whether this is an item we need to identify, and identify it as best we can.*/
1713  if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
1714  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1715  skill = find_skill_by_number(op, SK_DET_MAGIC);
1716  if (skill && (object_can_pick(op, tmp))) {
1717  exp = detect_magic_on_item(op, tmp, skill);
1718  if (exp) {
1719  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1721  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1722  }
1723  }
1724  skill = find_skill_by_number(op, SK_DET_CURSE);
1725  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1726  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1727  exp = detect_curse_on_item(op, tmp, skill);
1728  if (exp) {
1729  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1731  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1732  }
1733  }
1734  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1735 
1736  id_attempted = 1;
1737  skill = find_skill_by_number(op, tmptype->identifyskill);
1738  if (skill) {
1739  id_attempted = 2;
1740 
1741  /* identify_object_with_skill() may merge tmp with another
1742  * object, so once that happens, we really can not do
1743  * any further processing with tmp. It would be possible
1744  * to modify identify_object_with_skill() to return
1745  * the merged object, but it is currently set to return
1746  * exp, so it would have to do it via modifying the
1747  * passed in value, but many other consumers would
1748  * need to be modified for that.
1749  */
1750  exp = identify_object_with_skill(tmp, op, skill, 1);
1751  if (exp) {
1752  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1753  return;
1754  }
1755  }
1756  if(!exp) {
1757  /* The primary id skill didn't work, let's try the secondary one */
1758  skill = find_skill_by_number(op, tmptype->identifyskill2);
1759  if (skill) {
1760  /* if we've reached here, then the first skill will have been attempted
1761  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1762  * that now, and try with the secondary ID skill, if it fails, then the
1763  * flag will be reset anyway, if it succeeds, it won't matter.*/
1765  id_attempted = 2;
1766  exp = identify_object_with_skill(tmp, op, skill, 1);
1767  if (exp) {
1768  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1769  return;
1770  }
1771  }
1772  }
1773  }
1774  }
1775  if (!exp) {
1776  /* if we did get exp we'll already have propulated prefix */
1777  if (tmptype->identifyskill || tmptype->identifyskill2) {
1778  switch (id_attempted) {
1779  case 1:
1780  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1781  break;
1782  case 2:
1783  snprintf(prefix, MAX_BUF, "You fail to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1784  break;
1785  default:
1786  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1787  }
1788  } else snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1789  }
1790  /* now we need to get the rest of the object description */
1791  ob_describe(tmp, op, 1, buf, sizeof(buf));
1792 
1794  "%s %s", prefix, buf);
1795  buf[0] = '\0';
1796  if (tmp->custom_name) {
1798  "You name it %s",
1799  tmp->custom_name);
1800  }
1801 
1802  switch (tmp->type) {
1803  case SKILLSCROLL:
1804  case SKILL_TOOL:
1805  // Embedded skills are stored as an archetype name and don't get reified
1806  // until the player actually reads/equips the object, so we need to
1807  // handle it differently from spells, which are stored in the inv.
1808  if (!tmp->skill) break; // Blank skill scroll, somehow.
1809  archetype *skill = get_archetype_by_skill_name(tmp->skill, SKILL);
1810  if (!skill) {
1811  // Skill name doesn't correspond to any actual skill.
1813  "Unfortunately the scroll is damaged and unreadable.");
1814  break;
1815  }
1816  // Only print the flavor text once we have identified.
1817  if (is_identified(tmp) && skill->clone.msg) {
1819  stringbuffer_append_string(sb, skill->clone.msg);
1821  char *const fluff = stringbuffer_finish(sb);
1822  // SPELL_INFO is not a perfect match here, but it should display in the
1823  // same manner as the spell descriptions below and there's no SKILL_INFO
1824  // message type.
1826  free(fluff);
1827  }
1828  break;
1829 
1830  case SPELLBOOK:
1831  case SCROLL:
1832  case WAND:
1833  case ROD:
1834  case POTION:
1835  // Only print the flavor text once we have identified.
1836  if (is_identified(tmp) && tmp->inv && tmp->inv->msg) {
1837  // If the embedded spell has a msg, display it here so that the
1838  // player knows what it does before they actually read/use the item.
1839  // Strip trailing newlines so that the output of examine() is
1840  // contiguous.
1841  // TODO: It might be better to strip the newlines in object_set_msg
1842  // and append them at print time, rather than ensuring that the msg
1843  // is newline-terminated and stripping off the newlines when we don't
1844  // want them; C string handling makes the latter a lot less convenient.
1846  stringbuffer_append_string(sb, tmp->inv->msg);
1848  char *const fluff = stringbuffer_finish(sb);
1850  free(fluff);
1851  }
1852  if (tmp->type == WAND && is_identified(tmp)) {
1853  snprintf(buf, sizeof(buf), "It has %d charges left.", tmp->stats.food);
1854  }
1855  break;
1856 
1857  case BOOK:
1858  if (tmp->msg != NULL)
1859  snprintf(buf, sizeof(buf), "Something is written in it.");
1860  break;
1861 
1862  case CONTAINER:
1863  if (tmp->race != NULL) {
1864  if (tmp->weight_limit && tmp->stats.Str < 100)
1865  snprintf(buf, sizeof(buf), "It can hold only %s and its weight limit is %.1f kg.", tmp->race, tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
1866  else
1867  snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
1868  } else
1869  if (tmp->weight_limit && tmp->stats.Str < 100)
1870  snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
1871  break;
1872  }
1873 
1874  if (buf[0] != '\0')
1876  buf);
1877 
1878  // TODO: combine with weight and properly pluralize, so you get:
1879  // It is made of stone and weighs 15.0 kg.
1880  // They are made of paper and weigh 3 kg.
1881  if (tmp->materialname != NULL && !tmp->msg) {
1883  "It is made of: %s.",
1884  tmp->materialname);
1885  }
1886  /* Where to wear this item */
1887  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1888  if (tmp->body_info[i]) {
1889  if (op->body_info[i]) {
1890  if (tmp->body_info[i] < -1) {
1892  "%s %s (%d)", tmp->nrof > 1 ? "They go" : "It goes",
1893  body_locations[i].use_name, -tmp->body_info[i]);
1894  } else {
1896  "%s %s", tmp->nrof > 1 ? "They go" : "It goes",
1897  body_locations[i].use_name);
1898  }
1899  } else {
1901  "%s %s", tmp->nrof > 1 ? "They go" : "It goes",
1902  body_locations[i].nonuse_name);
1903  }
1904  }
1905  }
1906 
1907  if (tmp->weight) {
1908  snprintf(buf, sizeof(buf), tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", tmp->weight*((float)(tmp->nrof ? tmp->nrof : 1)/1000.0));
1910  buf);
1911  }
1912 
1913  in_shop = shop_contains(op);
1914 
1915  if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
1916  char *value = cost_approx_str(tmp, op);
1917  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
1918  free(value);
1920  buf);
1921  if (in_shop) {
1922  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1923  value = cost_str(shop_price_buy(tmp, op));
1924  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
1925  free(value);
1926  } else {
1927  value = cost_str(shop_price_sell(tmp, op));
1928  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
1929  free(value);
1930  }
1932  buf);
1933  }
1934  }
1935 
1936  if (QUERY_FLAG(tmp, FLAG_MONSTER))
1937  examine_monster(op, tmp, 0);
1938 
1939  /* Is this item buildable? */
1940  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
1942  "This is a buildable item.");
1943  if (QUERY_FLAG(tmp, FLAG_IS_LINKED)){
1944  conn = get_button_value(tmp);
1945  if (conn) {
1946  FOR_INV_PREPARE(op, tmp_inv) {
1947  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
1948  && strcmp(tmp_inv->slaying, op->map->path) == 0
1949  && tmp_inv->msg != NULL
1950  && tmp_inv->path_attuned == (uint32_t) conn) {
1951 
1953  MSG_TYPE_COMMAND_EXAMINE, "Connected with: %s",
1954  tmp_inv->msg);
1955 
1956  break;
1957  }
1958  } FOR_INV_FINISH();
1959  }
1960  }
1961  }
1962 
1963  /* Does the object have a message? Don't show message for all object
1964  * types - especially if the first entry is a match
1965  */
1966  if (tmp->msg
1967  && tmp->type != EXIT
1968  && tmp->type != BOOK
1969  && tmp->type != CORPSE
1970  && !tmp->move_on
1971  && strncasecmp(tmp->msg, "@match", 6)) {
1972  /* This is just a hack so when identifying the items, we print
1973  * out the extra message. Do this only for "identifiable types", e.g.
1974  * we don't want to print this message when the player looks at a
1975  * locked door (where msg is used to store the message they get when
1976  * trying to force it open).
1977  *
1978  * Also, don't print the message for the object unless it has been identified
1979  * -- SilverNexus 2015-05-20
1980  */
1981  if (is_identifiable_type(tmp) && is_identified(tmp)) {
1983  "The object has a story:");
1984 
1986  tmp->msg);
1987  }
1988  }
1990  " "); /* Blank line */
1991 
1992  if (is_identified(tmp)) {
1994  }
1995 }
1996 
2005 void inventory(object *op, object *inv) {
2006  const char *in;
2007  int items = 0, length;
2008  char weight[MAX_BUF], name[MAX_BUF];
2009 
2010  if (inv == NULL && op == NULL) {
2012  "Inventory of what object?");
2013  return;
2014  }
2015  FOR_INV_PREPARE(inv ? inv : op, tmp)
2016  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
2017  || !op || QUERY_FLAG(op, FLAG_WIZ))
2018  items++;
2019  FOR_INV_FINISH();
2020  if (inv == NULL) { /* player's inventory */
2021  if (items == 0) {
2023  "You carry nothing.");
2024  return;
2025  } else {
2026  length = 28;
2027  in = "";
2029  "Inventory:");
2030  }
2031  } else {
2032  if (items == 0)
2033  return;
2034  else {
2035  length = 28;
2036  in = " ";
2037  }
2038  }
2039  FOR_INV_PREPARE(inv ? inv : op, tmp) {
2040  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
2041  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
2042  continue;
2043  query_weight(tmp, weight, MAX_BUF);
2044  query_name(tmp, name, MAX_BUF);
2045  if (!op || QUERY_FLAG(op, FLAG_WIZ))
2047  "[fixed]%s- %-*.*s (%5d) %-8s",
2048  in, length, length, name, tmp->count, weight);
2049  else
2051  "[fixed]%s- %-*.*s %-8s",
2052  in, length+8, length+8, name, weight);
2053  } FOR_INV_FINISH();
2054  if (!inv && op) {
2055  query_weight(op, weight, MAX_BUF);
2057  "[fixed]%-*s %-8s",
2058  41, "Total weight :", weight);
2059  }
2060 }
2061 
2070 static void display_new_pickup(const object *op, int old) {
2071  int i = op->contr->mode;
2072 
2073  esrv_send_pickup(op->contr);
2074 
2075  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
2076  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
2078  "Pickup is %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
2079  }
2080  return;
2081  }
2082 
2084  "%d NEWMODE",
2085  i&PU_NEWMODE ? 1 : 0);
2087  "%d DEBUG",
2088  i&PU_DEBUG ? 1 : 0);
2090  "%d INHIBIT",
2091  i&PU_INHIBIT ? 1 : 0);
2093  "%d STOP",
2094  i&PU_STOP ? 1 : 0);
2095 
2097  "%d <= x pickup weight/value RATIO (0==off)",
2098  (i&PU_RATIO)*5);
2099 
2101  "%d FOOD",
2102  i&PU_FOOD ? 1 : 0);
2104  "%d DRINK",
2105  i&PU_DRINK ? 1 : 0);
2107  "%d VALUABLES",
2108  i&PU_VALUABLES ? 1 : 0);
2109 
2111  "%d BOW",
2112  i&PU_BOW ? 1 : 0);
2114  "%d ARROW",
2115  i&PU_ARROW ? 1 : 0);
2116 
2118  "%d HELMET",
2119  i&PU_HELMET ? 1 : 0);
2121  "%d SHIELD",
2122  i&PU_SHIELD ? 1 : 0);
2124  "%d ARMOUR",
2125  i&PU_ARMOUR ? 1 : 0);
2126 
2128  "%d BOOTS",
2129  i&PU_BOOTS ? 1 : 0);
2131  "%d GLOVES",
2132  i&PU_GLOVES ? 1 : 0);
2134  "%d CLOAK",
2135  i&PU_CLOAK ? 1 : 0);
2137  "%d KEY",
2138  i&PU_KEY ? 1 : 0);
2139 
2141  "%d MISSILEWEAPON",
2142  i&PU_MISSILEWEAPON ? 1 : 0);
2144  "%d MELEEWEAPON",
2145  i&PU_MELEEWEAPON ? 1 : 0);
2147  "%d MAGICAL",
2148  i&PU_MAGICAL ? 1 : 0);
2150  "%d POTION",
2151  i&PU_POTION ? 1 : 0);
2152 
2154  "%d SPELLBOOK",
2155  i&PU_SPELLBOOK ? 1 : 0);
2157  "%d SKILLSCROLL",
2158  i&PU_SKILLSCROLL ? 1 : 0);
2160  "%d READABLES",
2161  i&PU_READABLES ? 1 : 0);
2163  "%d MAGICDEVICE",
2164  i&PU_MAGIC_DEVICE ? 1 : 0);
2165 
2167  "%d NOT CURSED",
2168  i&PU_NOT_CURSED ? 1 : 0);
2169 
2171  "%d JEWELS",
2172  i&PU_JEWELS ? 1 : 0);
2173 
2175  "%d FLESH",
2176  i&PU_FLESH ? 1 : 0);
2177 
2179  "%d CONTAINER",
2180  i&PU_CONTAINER ? 1 : 0);
2181 
2183  "");
2184 }
2185 
2195 void command_pickup(object *op, const char *params) {
2196  uint32_t i;
2197 
2198  if (*params == '\0') {
2199  /* if the new mode is used, just print the settings */
2200  if (op->contr->mode&PU_NEWMODE) {
2201  display_new_pickup(op, op->contr->mode);
2202  return;
2203  }
2204  if (1)
2205  LOG(llevDebug, "command_pickup: !params\n");
2206  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
2207  return;
2208  }
2209 
2210  while (*params == ' ')
2211  params++;
2212 
2213  if (*params == '+' || *params == '-' || *params == '!') {
2214  int index = get_pickup_mode_index(params + 1);
2215 
2216  if (index != -1) {
2217  int old = op->contr->mode;
2218  i = op->contr->mode;
2219  if (!(i&PU_NEWMODE))
2220  i = PU_NEWMODE;
2221  if (*params == '+')
2222  i = i|pickup_modes[index];
2223  else if (*params == '-')
2224  i = i&~pickup_modes[index];
2225  else {
2226  if (i&pickup_modes[index])
2227  i = i&~pickup_modes[index];
2228  else
2229  i = i|pickup_modes[index];
2230  }
2231  op->contr->mode = i;
2232  display_new_pickup(op, old);
2233  return;
2234  }
2236  "Pickup: invalid item %s\n",
2237  params);
2238  return;
2239  }
2240 
2241  if (sscanf(params, "%u", &i) != 1) {
2242  if (1)
2243  LOG(llevDebug, "command_pickup: params==NULL\n");
2245  "Usage: pickup <0-7> or <value_density> .");
2246  return;
2247  }
2248  set_pickup_mode(op, i);
2249  display_new_pickup(op, op->contr->mode);
2250 }
2251 
2260 static void set_pickup_mode(const object *op, int i) {
2261  op->contr->mode = i;
2262  switch (op->contr->mode) {
2263  case 0:
2265  "Mode: Don't pick up.");
2266  break;
2267 
2268  case 1:
2270  "Mode: Pick up one item.");
2271  break;
2272 
2273  case 2:
2275  "Mode: Pick up one item and stop.");
2276  break;
2277 
2278  case 3:
2280  "Mode: Stop before picking up.");
2281  break;
2282 
2283  case 4:
2285  "Mode: Pick up all items.");
2286  break;
2287 
2288  case 5:
2290  "Mode: Pick up all items and stop.");
2291  break;
2292 
2293  case 6:
2295  "Mode: Pick up all magic items.");
2296  break;
2297 
2298  case 7:
2300  "Mode: Pick up all coins and gems");
2301  break;
2302  }
2303 }
2304 
2313 void command_search_items(object *op, const char *params) {
2314  if (settings.search_items == FALSE)
2315  return;
2316 
2317  if (!params || *params == '\0') {
2318  if (op->contr->search_str[0] == '\0') {
2320  "Example: search magic+1 "
2321  "Would automatically pick up all "
2322  "items containing the word 'magic+1'.");
2323  return;
2324  }
2325  op->contr->search_str[0] = '\0';
2327  "Search mode turned off.");
2328  fix_object(op);
2329  return;
2330  }
2331  if ((int)strlen(params) >= MAX_BUF) {
2333  "Search string too long.");
2334  return;
2335  }
2336  strcpy(op->contr->search_str, params);
2338  "Searching for '%s'.",
2339  op->contr->search_str);
2340  fix_object(op);
2341 }
2342 
2358 void command_rename_item(object *op, const char *params) {
2359  char buf[VERY_BIG_BUF], name[MAX_BUF];
2360  tag_t itemnumber;
2361  object *item = NULL;
2362  object *tmp;
2363  char *closebrace;
2364  size_t counter;
2365 
2366  if (*params != '\0') {
2367  /* Let's skip white spaces */
2368  while (' ' == *params)
2369  params++;
2370 
2371  /* Checking the first part */
2372  itemnumber = atoi(params);
2373  if (itemnumber != 0) {
2374  int found = 0;
2375  FOR_INV_PREPARE(op, item)
2376  if (item->count == itemnumber && !item->invisible) {
2377  found = 1;
2378  break;
2379  }
2380  FOR_INV_FINISH();
2381  if (!found) {
2383  "Tried to rename an invalid item.");
2384  return;
2385  }
2386  while (isdigit(*params) || ' ' == *params)
2387  params++;
2388  } else if ('<' == *params) {
2389  /* Got old name, let's get it & find appropriate matching item */
2390  closebrace = strchr(params, '>');
2391  if (!closebrace) {
2393  "Syntax error!");
2394  return;
2395  }
2396  /* Sanity check for buffer overruns */
2397  if (closebrace-params > 127) {
2399  "Old name too long (up to 127 characters allowed)!");
2400  return;
2401  }
2402  /* Copy the old name */
2403  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2404 
2405  /* Find best matching item */
2406  item = find_best_object_match(op, buf);
2407  if (!item) {
2409  "Could not find a matching item to rename.");
2410  return;
2411  }
2412 
2413  /* Now need to move pointer to just after > */
2414  params = closebrace+1;
2415  while (' ' == *params)
2416  params++;
2417  } else {
2418  /* Use marked item */
2419  item = find_marked_object(op);
2420  if (!item) {
2422  "No marked item to rename.");
2423  return;
2424  }
2425  }
2426 
2427  /* Now let's find the new name */
2428  if (!strncmp(params, "to ", 3)) {
2429  params += 3;
2430  while (' ' == *params)
2431  params++;
2432  if ('<' != *params) {
2434  "Syntax error, expecting < at start of new name!");
2435  return;
2436  }
2437  closebrace = strchr(params+1, '>');
2438  if (!closebrace) {
2440  "Syntax error, expecting > at end of new name!");
2441  return;
2442  }
2443 
2444  /* Sanity check for buffer overruns */
2445  if (closebrace-params > 127) {
2447  "New name too long (up to 127 characters allowed)!");
2448  return;
2449  }
2450 
2451  /* Copy the new name */
2452  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2453 
2454  /* Let's check it for weird characters */
2455  for (counter = 0; counter < strlen(buf); counter++) {
2456  if (isalnum(buf[counter]))
2457  continue;
2458  if (' ' == buf[counter])
2459  continue;
2460  if ('\'' == buf[counter])
2461  continue;
2462  if ('+' == buf[counter])
2463  continue;
2464  if ('_' == buf[counter])
2465  continue;
2466  if ('-' == buf[counter])
2467  continue;
2468 
2469  /* If we come here, then the name contains an invalid character...
2470  * tell the player & exit
2471  */
2473  "Invalid new name!");
2474  return;
2475  }
2476  } else {
2477  /* If param contains something, then syntax error... */
2478  if (strlen(params)) {
2480  "Syntax error, expected 'to <' after old name!");
2481  return;
2482  }
2483  /* New name is empty */
2484  buf[0] = '\0';
2485  }
2486  } else {
2487  /* Last case: *params=='\0' */
2488  item = find_marked_object(op);
2489  if (!item) {
2491  "No marked item to rename.");
2492  return;
2493  }
2494  buf[0] = '\0';
2495  }
2496 
2497  /* Coming here, everything is fine... */
2498  if (!strlen(buf)) {
2499  /* Clear custom name */
2500  if (item->custom_name == NULL) {
2502  "This item has no custom name.");
2503  return;
2504  }
2505 
2506  FREE_AND_CLEAR_STR(item->custom_name);
2507  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2509  "You stop calling your %s with weird names.",
2510  name);
2511  } else {
2512  if (item->custom_name != NULL && strcmp(item->custom_name, buf) == 0) {
2513  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2515  "You keep calling your %s %s.",
2516  name, buf);
2517  return;
2518  }
2519 
2520  /* Set custom name */
2521  FREE_AND_COPY(item->custom_name, buf);
2522 
2523  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2525  "Your %s will now be called %s.",
2526  name, buf);
2527  }
2528 
2529  tmp = object_merge(item, NULL);
2530  if (tmp == NULL) {
2531  /* object was not merged - if it was, object_merge() handles updating for us. */
2532  esrv_update_item(UPD_NAME, op, item);
2533  }
2534 }
2535 
2544 void command_lock_item(object *op, const char *params) {
2545  object *item;
2546  object *tmp;
2547  char name[HUGE_BUF];
2548 
2549  if (*params == '\0' || strlen(params) == 0) {
2551  "Lock what item?");
2552  return;
2553  }
2554 
2555  item = find_best_object_match(op, params);
2556  if (!item) {
2558  "Can't find any matching item.");
2559  return;
2560  }
2561 
2562  query_short_name(item, name, HUGE_BUF);
2563  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2565  "Unlocked %s.", name);
2566  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2567  } else {
2569  "Locked %s.", name);
2570  SET_FLAG(item, FLAG_INV_LOCKED);
2571  }
2572 
2573  tmp = object_merge(item, NULL);
2574  if (tmp == NULL) {
2575  /* object was not merged, if it was object_merge() handles updates for us */
2576  esrv_update_item(UPD_FLAGS, op, item);
2577  }
2578 }
2579 
2587 void command_use(object *op, const char *params) {
2588  char *with, copy[MAX_BUF];
2589  object *first, *second/*, *add*/;
2590  /*archetype *arch;*/
2591  /*int count;*/
2592  /*sstring data;*/
2593  recipe *transformation;
2594 
2595  if (!IS_PLAYER(op))
2596  return;
2597 
2598  strlcpy(copy, params, sizeof(copy));
2599  with = strstr(copy, " with ");
2600  if (!with) {
2601  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2602  return;
2603  }
2604 
2605  with[0] = '\0';
2606  with = with+strlen(" with ");
2607 
2608  first = find_best_object_match(op, copy);
2609  if (!first) {
2610  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2611  return;
2612  }
2613  second = find_best_object_match(op, with);
2614  if (!second) {
2615  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2616  return;
2617  }
2618 
2619  transformation = NULL;
2620  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2622  if (transformation->ingred_count != 1)
2623  continue;
2624 
2625 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2626  if (strcmp(second->name, transformation->ingred->name) == 0) {
2628  object *generated = create_archetype(transformation->arch_name[0]);
2629  if (transformation->yield)
2630  generated->nrof = transformation->yield;
2631  object_insert_in_ob(generated, op);
2632  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2634  return;
2635  }
2636  }
2637  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2638  return;
2639 
2640  /*
2641  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2642  data = object_get_value(second, copy);
2643  if (!data) {
2644  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2645  data = object_get_value(second, copy);
2646  if (!data) {
2647  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2648  data = object_get_value(second, copy);
2649  if (!data) {
2650  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2651  return 1;
2652  }
2653  }
2654  }
2655 
2656  while (data != NULL) {
2657  if (strncmp(data, "add ", 4) == 0) {
2658  data += 4;
2659  if (isdigit(*data)) {
2660  count = atol(data);
2661  data = strchr(data, ' ')+1;
2662  } else
2663  count = 1;
2664  with = strchr(data, ' ');
2665  if (!with) {
2666  strncpy(copy, data, sizeof(copy));
2667  data = NULL;
2668  } else {
2669  *with = '\0';
2670  strncpy(copy, data, sizeof(copy));
2671  data += strlen(copy)+1;
2672  }
2673  arch = find_archetype(copy);
2674  if (!arch) {
2675  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2676  return 1;
2677  }
2678  add = object_create_arch(arch);
2679  add->nrof = count;
2680  object_insert_in_ob(add, op);
2681  } else if (strncmp(data, "remove $", 8) == 0) {
2682  data += 8;
2683  if (*data == '1') {
2684  if (first)
2685  first = object_decrease_nrof_by_one(first);
2686  data += 2;
2687  } else if (*data == '2') {
2688  if (second)
2689  second = object_decrease_nrof_by_one(second);
2690  data += 2;
2691  } else {
2692  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2693  return 1;
2694  }
2695  } else {
2696  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2697  return 1;
2698  }
2699  }
2700 
2701  return 1;
2702  */
2703 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:313
#define AP_UNAPPLY
Definition: define.h:612
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.c:3898
void apply_by_living_below(object *pl)
Definition: apply.c:695
void sell_item(object *op, object *pl)
Definition: shop.c:967
static object * find_best_object_match(object *pl, const char *params)
Definition: c_object.c:131
#define FLAG_NO_DROP
Definition: define.h:289
Definition: player.h:92
int apply_special(object *who, object *op, int aflags)
Definition: apply.c:1156
#define FLAG_IS_FLOOR
Definition: define.h:303
#define FLAG_UNPAID
Definition: define.h:236
static void do_skill_by_number(object *op, int skill_subtype, const char *params, const char *missing_message)
Definition: c_object.c:187
#define MSG_TYPE_COMMAND_INVENTORY
Definition: newclient.h:513
#define FLAG_IS_LINKED
Definition: define.h:316
int change_skill(object *who, object *new_skill, int flag)
Definition: skill_util.c:350
void command_search_items(object *op, const char *params)
Definition: c_object.c:2313
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.c:925
void pick_up(object *op, object *alt)
Definition: c_object.c:509
bool shop_contains(object *ob)
Definition: shop.c:1291
uint8_t max_stat
Definition: global.h:324
int item_must_be_pickable
Definition: c_object.c:704
#define PU_CONTAINER
Definition: define.h:143
int(* item_matcher)(object *who, matcher_params *params, object *item)
Definition: c_object.c:719
#define SET_FLAG(xyz, p)
Definition: define.h:223
#define PU_DEBUG
Definition: define.h:108
int identifyskill
Definition: define.h:93
StringBuffer * buf
Definition: readable.c:1591
void command_lock_item(object *op, const char *params)
Definition: c_object.c:2544
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:511
void command_take(object *op, const char *params)
Definition: c_object.c:833
#define PU_STOP
Definition: define.h:110
void stringbuffer_trim_whitespace(StringBuffer *sb)
Definition: stringbuffer.c:166
#define PU_SHIELD
Definition: define.h:122
int yield
Definition: recipe.h:21
object * mon
Definition: comet_perf.c:75
int identify_object_with_skill(object *tmp, object *pl, object *skill, int print_on_success)
Definition: skills.c:808
#define MSG_TYPE_SPELL
Definition: newclient.h:387
#define FLAG_NO_FIX_PLAYER
Definition: define.h:277
int save_player(object *op, int flag)
Definition: login.c:212
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
void inventory(object *op, object *inv)
Definition: c_object.c:2005
void free_string(sstring str)
Definition: shstr.c:280
#define PU_KEY
Definition: define.h:128
#define HUGE_BUF
Definition: define.h:37
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:512
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.c:340
#define MSG_TYPE_SPELL_INFO
Definition: newclient.h:634
#define NDI_BLUE
Definition: newclient.h:226
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:680
linked_char * ingred
Definition: recipe.h:22
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Definition: recipe.c:729
void command_throw(object *op, const char *params)
Definition: c_object.c:238
void query_weight(const object *op, char *buf, size_t size)
Definition: item.c:410
#define MSG_TYPE_SKILL_MISSING
Definition: newclient.h:582
#define PU_FLESH
Definition: define.h:142
#define PU_FOOD
Definition: define.h:115
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
Definition: item.c:54
object * stop_item(object *op)
Definition: time.c:452
#define FALSE
Definition: compat.h:11
uint32_t get_weight_limit(int stat)
Definition: living.c:2360
static const char * pickup_names[]
Definition: c_object.c:33
static void pick_up_object(object *pl, object *op, object *tmp, int nrof)
Definition: c_object.c:378
#define SCRIPT_FIX_ALL
Definition: global.h:370
#define AP_APPLY
Definition: define.h:611
#define PU_NEWMODE
Definition: define.h:111
void command_dropall(object *op, const char *params)
Definition: c_object.c:1218
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:308
void command_rskill(object *pl, const char *params)
Definition: c_object.c:160
#define PU_MISSILEWEAPON
Definition: define.h:130
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:791
#define PU_CLOAK
Definition: define.h:127
#define MIN(x, y)
Definition: compat.h:17
void command_empty(object *op, const char *params)
Definition: c_object.c:1439
#define FLAG_REMOVED
Definition: define.h:232
void command_rename_item(object *op, const char *params)
Definition: c_object.c:2358
#define FLAG_KNOWN_MAGICAL
Definition: define.h:320
int ingred_count
Definition: recipe.h:23
const typedata * get_typedata(int itemtype)
Definition: item.c:318
#define FLAG_UNDEAD
Definition: define.h:270
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Definition: spell_effect.c:707
#define AP_OPEN
Definition: define.h:613
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Definition: knowledge.c:1359
void object_free_drop_inventory(object *ob)
Definition: object.c:1316
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1849
void command_examine(object *op, const char *params)
Definition: c_object.c:1478
#define MSG_TYPE_COMMAND
Definition: newclient.h:379
#define PU_BOOTS
Definition: define.h:125
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Definition: apply.c:637
void examine(object *op, object *tmp)
Definition: c_object.c:1691
void command_search(object *op, const char *params)
Definition: c_object.c:211
int is_identified(const object *op)
Definition: item.c:1316
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Definition: skills.c:701
char ** arch_name
Definition: recipe.h:13
uint64_t shop_price_buy(const object *obj, object *who)
Definition: shop.c:186
int object_can_pick(const object *who, const object *item)
Definition: object.c:3657
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2602
char * cost_approx_str(const object *obj, object *who)
Definition: shop.c:414
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:510
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:509
#define EVENT_DROP
Definition: events.h:26
#define PU_SKILLSCROLL
Definition: define.h:136
signed short int16_t
Definition: win32.h:160
uint8_t search_items
Definition: global.h:266
int item_to_pick
Definition: c_object.c:702
object * create_archetype(const char *name)
Definition: arch.cpp:281
#define PU_ARROW
Definition: define.h:120
static int matcher_all(object *who, matcher_params *params, object *item)
Definition: c_object.c:728
#define snprintf
Definition: win32.h:46
static int get_pickup_mode_index(const char *name)
Definition: c_object.c:58
#define FLAG_IDENTIFIED
Definition: define.h:261
#define FOR_INV_FINISH()
Definition: define.h:714
#define MOVE_FLYING
Definition: define.h:410
void command_drop(object *op, const char *params)
Definition: c_object.c:1342
static const uint32_t pickup_modes[]
Definition: c_object.c:43
#define FLAG_PROBE
Definition: define.h:257
#define PU_INHIBIT
Definition: define.h:109
#define PU_BOW
Definition: define.h:118
#define AP_NULL
Definition: define.h:610
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.c:2900
static int matcher_number(object *who, matcher_params *params, object *item)
Definition: c_object.c:742
#define PU_RATIO
Definition: define.h:113
static int matcher_pickup_type(object *who, matcher_params *params, object *item)
Definition: c_object.c:782
char * cost_str(uint64_t cost)
Definition: shop.c:410
#define UPD_FLAGS
Definition: newclient.h:290
void command_apply(object *op, const char *params)
Definition: c_object.c:250
#define FLAG_IS_CAULDRON
Definition: define.h:339
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.c:422
int object_matches_pickup_mode(const object *item, int mode)
Definition: c_object.c:646
uint8_t real_wiz
Definition: global.h:270
#define PU_DRINK
Definition: define.h:116
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:2110
static void empty_container(object *container, object *pl)
Definition: c_object.c:1401
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:198
#define UPD_WEIGHT
Definition: newclient.h:291
void knowledge_show_monster_detail(object *op, const char *name)
Definition: knowledge.c:1553
static void set_pickup_mode(const object *op, int i)
Definition: c_object.c:2260
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define EVENT_PICKUP
Definition: events.h:27
#define FLAG_WIZ
Definition: define.h:231
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.c:2166
static int matcher_name(object *who, matcher_params *params, object *item)
Definition: c_object.c:762
#define MAX_BUF
Definition: define.h:35
#define PU_READABLES
Definition: define.h:137
archetype * get_archetype_by_skill_name(const char *skill, int type)
Definition: arch.cpp:82
int strncasecmp(const char *s1, const char *s2, int n)
uint64_t shop_price_sell(const object *obj, object *who)
Definition: shop.c:243
#define FLAG_IS_THROWN
Definition: define.h:249
int identifyskill2
Definition: define.h:94
static item_matcher make_matcher(object *who, const char *params, matcher_params *mp)
Definition: c_object.c:794
#define FLAG_KNOWN_CURSED
Definition: define.h:321
void command_pickup(object *op, const char *params)
Definition: c_object.c:2195
unsigned int uint32_t
Definition: win32.h:162
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Definition: ob_methods.c:91
#define AP_NO_MERGE
Definition: define.h:618
int set_object_face_main(object *op)
Definition: apply.c:146
const char * name
Definition: global.h:87
#define PU_MELEEWEAPON
Definition: define.h:131
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Definition: c_object.c:316
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2382
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Definition: skills.c:750
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:28
char name[100]
Definition: c_object.c:706
#define VERY_BIG_BUF
Definition: define.h:36
#define FREE_AND_COPY(sv, nv)
Definition: global.h:204
int get_button_value(const object *button)
Definition: button.c:749
void command_use(object *op, const char *params)
Definition: c_object.c:2587
#define FLAG_IS_BUILDABLE
Definition: define.h:376
struct Settings settings
Definition: init.c:39
static void display_new_pickup(const object *op, int old)
Definition: c_object.c:2070
#define MSG_TYPE_COMMAND_INFO
Definition: newclient.h:506
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.c:54
#define FLAG_APPLIED
Definition: define.h:235
object * object_merge(object *op, object *top)
Definition: object.c:1800
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:508
#define PU_SPELLBOOK
Definition: define.h:135
object * object_get_player_container(object *op)
Definition: object.c:377
signed int int32_t
Definition: win32.h:159
#define UPD_NAME
Definition: newclient.h:293
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.c:4334
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:787
#define FLAG_STARTEQUIP
Definition: define.h:268
void command_disarm(object *op, const char *params)
Definition: c_object.c:223
#define FORCE_NAME
Definition: spells.h:169
#define PU_VALUABLES
Definition: define.h:117
#define PU_MAGICAL
Definition: define.h:132
sstring add_string(const char *str)
Definition: shstr.c:124
#define PU_JEWELS
Definition: define.h:141
#define FLAG_MONSTER
Definition: define.h:245
void esrv_send_pickup(player *pl)
Definition: request.c:1664
#define MSG_TYPE_SKILL
Definition: newclient.h:383
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: events.cpp:259
#define NDI_UNIQUE
Definition: newclient.h:245
static object * find_best_apply_object_match(object *start, object *pl, const char *params, int aflag)
Definition: c_object.c:100
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
#define PU_GLOVES
Definition: define.h:126
#define FLAG_WAS_WIZ
Definition: define.h:234
object * find_marked_object(object *op)
Definition: c_object.c:1509
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:583
#define PU_ARMOUR
Definition: define.h:123
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.c:1061
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:741
#define SK_SUBTRACT_SKILL_EXP
Definition: skills.h:81
object * find_skill_by_number(object *who, int skillno)
Definition: main.c:349
Definition: map.h:326
int use_skill(object *op, const char *string)
Definition: skill_util.c:955
int is_identifiable_type(const object *op)
Definition: item.c:1292
#define FLAG_NO_PICK
Definition: define.h:239
#define PU_POTION
Definition: define.h:133
#define FLAG_NO_SKILL_IDENT
Definition: define.h:336
#define PU_HELMET
Definition: define.h:121
#define AT_ACID
Definition: attack.h:82
void command_uskill(object *pl, const char *params)
Definition: c_object.c:143
#define FLAG_INV_LOCKED
Definition: define.h:330
void fix_object(object *op)
Definition: living.c:1124
#define PU_NOT_CURSED
Definition: define.h:140
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:202
int level
Definition: readable.c:1589
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:370
#define FOR_BELOW_FINISH()
Definition: define.h:748
void command_mark(object *op, const char *params)
Definition: c_object.c:1556
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:707
void object_remove(object *op)
Definition: object.c:1588
void examine_monster(object *op, object *tmp, int level)
Definition: c_object.c:1603
#define PU_MAGIC_DEVICE
Definition: define.h:138
#define FLAG_FREED
Definition: define.h:233
void drop(object *op, object *tmp)
Definition: c_object.c:1156