Crossfire Server  1.75.0
c_object.cpp
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", "cursed", 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;
60  size_t len = strlen(name);
61  for (size_t mode = 0; pickup_names[mode]; mode++) {
62  if (!strcmp(pickup_names[mode], name)) {
63  return mode;
64  }
65  if (len < strlen(pickup_names[mode]) && strncmp(name, pickup_names[mode], len) == 0) {
66  if (best != -2) {
67  if (best != -1) {
68  best = -2;
69  } else {
70  best = mode;
71  }
72  }
73  }
74  }
75  return best != -2 ? best : -1;
76 }
77 
78 static void set_pickup_mode(const object *op, int i);
79 
80 /*
81  * Object id parsing functions
82  */
83 
101 static object *find_best_apply_object_match(object *start, object *pl, const char *params, int aflag) {
102  object *tmp, *best = NULL;
103  int match_val = 0, tmpmatch;
104 
105  tmp = start;
107  if (!player_can_find(pl, tmp))
108  continue;
109  if (aflag == AP_APPLY && QUERY_FLAG(tmp, FLAG_APPLIED))
110  continue;
111  if (aflag == AP_UNAPPLY && !QUERY_FLAG(tmp, FLAG_APPLIED))
112  continue;
113  tmpmatch = object_matches_string(pl, tmp, params);
114  if (tmpmatch > match_val) {
115  match_val = tmpmatch;
116  best = tmp;
117  }
119  return best;
120 }
121 
132 static object *find_best_object_match(object *pl, const char *params) {
133  return find_best_apply_object_match(pl->inv, pl, params, AP_NULL);
134 }
135 
144 void command_uskill(object *pl, const char *params) {
145  if (*params == '\0') {
147  "Usage: use_skill <skill name>");
148  return;
149  }
150  use_skill(pl, params);
151 }
152 
161 void command_rskill(object *pl, const char *params) {
162  object *skill;
163 
164  if (*params == '\0') {
166  "Usage: ready_skill <skill name>");
167  return;
168  }
169  skill = find_skill_by_name(pl, params);
170 
171  if (!skill) {
173  "You have no knowledge of the skill %s",
174  params);
175  return;
176  }
177  change_skill(pl, skill, 0);
178 }
179 
188 static void do_skill_by_number(object *op, int skill_subtype, const char *params,
189  const char *missing_message) {
190  object *skop = find_skill_by_number(op, skill_subtype);
191  if (skop) {
192  do_skill(op, op, skop, op->facing, *params == '\0' ? NULL : params);
193  return;
194  }
195 
197  missing_message);
198 }
199 
200 /* These functions (command_search, command_disarm) are really juse wrappers for
201  * things like 'use_skill ...'). In fact, they should really be obsoleted
202  * and replaced with those.
203  */
212 void command_search(object *op, const char *params) {
213  do_skill_by_number(op, SK_FIND_TRAPS, params, "You don't know how to search for unusual things.");
214 }
215 
224 void command_disarm(object *op, const char *params) {
225  do_skill_by_number(op, SK_DISARM_TRAPS, params, "You don't know how to disarm traps.");
226 }
227 
239 void command_throw(object *op, const char *params) {
240  do_skill_by_number(op, SK_THROWING, params, "You have no knowledge of the skill throwing.");
241 }
242 
251 void command_apply(object *op, const char *params) {
252  int aflag = 0;
253  object *inv = op->inv;
254  object *item;
255 
256  if (*params == '\0') {
258  return;
259  }
260 
261  while (*params == ' ')
262  params++;
263  if (!strncmp(params, "-a ", 3)) {
264  aflag = AP_APPLY;
265  params += 3;
266  }
267  if (!strncmp(params, "-u ", 3)) {
268  aflag = AP_UNAPPLY;
269  params += 3;
270  }
271  if (!strncmp(params, "-o ", 3)) {
272  aflag = AP_OPEN;
273  params += 3;
274  }
275  if (!strncmp(params, "-b ", 3)) {
276  params += 3;
277  if (op->container)
278  inv = op->container->inv;
279  else {
280  inv = op;
281  while (inv->above)
282  inv = inv->above;
283  }
284  }
285  while (*params == ' ')
286  params++;
287 
288  item = find_best_apply_object_match(inv, op, params, aflag);
289  if (item == NULL)
290  item = find_best_apply_object_match(inv, op, params, AP_NULL);
291  if (item) {
292  apply_by_living(op, item, aflag, 0);
293  } else
295  "Could not find any match to the %s.",
296  params);
297 }
298 
302 bool csv_contains(std::string list, std::string item, std::string delim) {
303  size_t pos;
304  while (true) {
305  pos = list.find(delim);
306  auto match = list.substr(0, pos);
307  if (item == match)
308  return true;
309 
310  if (pos == std::string::npos)
311  return false;
312  list.erase(0, pos + 1);
313  }
314  return false;
315 }
316 
329 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
330  /* buf needs to be big (more than 256 chars) because you can get
331  * very long item names.
332  */
333  char buf[HUGE_BUF], name[MAX_BUF];
334  object *env = tmp->env;
335  uint32_t weight, effective_weight_limit;
336  const int tmp_nrof = NROF(tmp);
337  tag_t tag;
338  mapstruct* map = tmp->map;
339  int16_t x = tmp->x, y = tmp->y;
340 
341  /* IF the player is flying & trying to take the item out of a container
342  * that is in his inventory, let him. tmp->env points to the container
343  * (sack, luggage, etc), tmp->env->env then points to the player (nested
344  * containers not allowed as of now)
345  */
346  if ((pl->move_type&MOVE_FLYING)
347  && !QUERY_FLAG(pl, FLAG_WIZ)
348  && object_get_player_container(tmp) != pl) {
350  "You are levitating, you can't reach the ground!");
351  return;
352  }
353  if (QUERY_FLAG(tmp, FLAG_NO_DROP))
354  return;
355 
356  if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
358  "The object disappears in a puff of smoke! It must have been an illusion.");
359  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
360  object_remove(tmp);
362  return;
363  }
364 
365  if (nrof > tmp_nrof || nrof == 0)
366  nrof = tmp_nrof;
367 
368  /* Figure out how much weight this object will add to the player */
369  weight = tmp->weight*nrof;
370  if (tmp->inv)
371  weight += tmp->carrying*(100-tmp->stats.Str)/100;
372 
373  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
374 
375  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
377  "That item is too heavy for you to pick up.");
378  return;
379  }
380 
382  SET_FLAG(tmp, FLAG_WAS_WIZ);
383 
384  if (nrof != tmp_nrof) {
385  char failure[MAX_BUF];
386 
387  tmp = object_split(tmp, nrof, failure, sizeof(failure));
388  if (!tmp) {
390  failure);
391  return;
392  }
393  } else {
394  /* If the object is in a container, send a delete to the client.
395  * - we are moving all the items from the container to elsewhere,
396  * so it needs to be deleted.
397  */
398  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
399  object_remove(tmp); /* Unlink it */
400  }
401  }
402  query_name(tmp, name, MAX_BUF);
403 
404  if (pl->type == PLAYER && QUERY_FLAG(tmp, FLAG_UNPAID)) {
405  char *value = cost_str(shop_price_buy(tmp, pl));
406  if (op == pl) {
407  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
408  } else {
409  snprintf(buf, sizeof(buf), "%s will cost you %s. You place it in your %s.", name, value, op->name);
410  }
411  free(value);
412  } else {
413  if (op == pl) {
414  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
415  } else {
416  snprintf(buf, sizeof(buf), "You pick up the %s and put it in your %s.", name, op->name);
417  }
418  }
419 
420  /* Now item is about to be picked. */
421  tag = tmp->count;
422  if (events_execute_object_event(tmp, EVENT_PICKUP, pl, op, NULL, SCRIPT_FIX_ALL) != 0) {
423  /* put item back, if it still exists */
424  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
425  if (env != NULL) {
426  object_insert_in_ob(tmp, env);
427  } else {
428  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
429  }
430  }
431  return;
432  }
433 
435  buf);
436 
437  object_insert_in_ob(tmp, op);
438 
439  /* All the stuff below deals with client/server code, and is only
440  * usable by players
441  */
442  if (pl->type != PLAYER)
443  return;
444 
445  /* Additional weight changes speed, etc */
446  fix_object(pl);
447 
448  /* These are needed to update the weight for the container we
449  * are putting the object in.
450  */
451  if (op != pl) {
452  esrv_update_item(UPD_WEIGHT, pl, op);
453  esrv_update_item(UPD_WEIGHT, pl, pl);
454  }
455 
456  /* Update the container the object was in */
457  if (env && env != pl && env != op)
458  esrv_update_item(UPD_WEIGHT, pl, env);
459 }
460 
470 bool pick_up(object *op, object *alt) {
471 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
472  object *tmp = NULL, *tmp1;
473  mapstruct *tmp_map = NULL;
474  int count;
475 
476  /* Decide which object to pick. */
477  if (alt) {
478  if (!object_can_pick(op, alt)) {
480  "You can't pick up the %s.",
481  alt->name);
482  return false;
483  }
484  tmp = alt;
485  } else {
486  if (op->below == NULL || !object_can_pick(op, op->below)) {
488  "There is nothing to pick up here.");
489  return false;
490  }
491  tmp = op->below;
492  }
493 
494  /* it is possible that the object is a thrown object and is flying about.
495  * in that case, what we want to pick up is the payload. Objects
496  * that are thrown are encapsulated into a thrown object.
497  * stop_item() returns the payload (unlinked from map) and gets rid of the
498  * container object. If this object isn't picked up, we need to insert
499  * it back on the map.
500  * A bug here is that even attempting to pick up one of these objects will
501  * result in this logic being called even if player is unable to pick it
502  * up.
503  */
504 
505  tmp_map = tmp->map;
506  tmp1 = stop_item(tmp);
507  if (tmp1 == NULL)
508  return false;
509 
510  /* If it is a thrown object, insert it back into the map here.
511  * makes life easier further along. Do no merge so pick up code
512  * behaves more sanely.
513  */
514  if (tmp1 != tmp) {
515  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
516  }
517 
518  if (tmp == NULL)
519  return false;
520 
521  if (!object_can_pick(op, tmp))
522  return false;
523 
524  /* Establish how many of the object we are picking up */
525  if (op->type == PLAYER) {
526  count = op->contr->count;
527  if (count == 0)
528  count = tmp->nrof;
529  } else
530  count = tmp->nrof;
531 
532  /* container is open, so use it */
533  if (op->container) {
534  alt = op->container;
535  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
536  return false;
537  } else {
538  /* non container pickup. See if player has any
539  * active containers.
540  */
541  object *container = NULL;
542 
543  /* Look for any active containers that can hold this item.
544  * we cover two cases here - the perfect match case, where we
545  * break out of the loop, and the general case (have a container),
546  * Moved this into a single loop - reduces redundant code, is
547  * more efficient and easier to follow. MSW 2009-04-06
548  */
549  alt = op->inv;
551  if (alt->type == CONTAINER
552  && QUERY_FLAG(alt, FLAG_APPLIED)
553  && sack_can_hold(NULL, alt, tmp, count)) {
554  if (alt->race && alt->race == tmp->race) {
555  break; /* perfect match */
556  } else if (!container) {
557  container = alt;
558  }
559  }
561  /* Note container could be null, but no reason to check for it */
562  if (!alt)
563  alt = container;
564 
565  if (!alt)
566  alt = op; /* No free containers */
567  }
568  /* see if this object is already in this container. If so,
569  * move it to player inventory from this container.
570  */
571  if (tmp->env == alt) {
572  alt = op;
573  }
574 
575  /* Don't allow players to be put into containers. Instead,
576  * just put them in the players inventory.
577  */
578  if ((tmp->type == CONTAINER || tmp->type == MIMIC) && alt->type==CONTAINER) {
579  alt = op;
580  }
581 #ifdef PICKUP_DEBUG
582  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
583 #endif
584 
585  /* startequip items are not allowed to be put into containers
586  * Not sure why we have this limitation
587  */
588  if (op->type == PLAYER
589  && alt->type == CONTAINER
590  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
592  "This object cannot be put into containers!");
593  return false;
594  }
595 
596  pick_up_object(op, alt, tmp, count);
597  if (op->type == PLAYER)
598  op->contr->count = 0;
599  return true;
600 }
601 
608 int object_matches_pickup_mode(const object *item, int mode) {
609  switch(mode) {
610  case PU_FOOD:
611  return item->type == FOOD;
612  case PU_DRINK:
613  return item->type == DRINK || (item->type == POISON && !QUERY_FLAG(item, FLAG_KNOWN_CURSED));
614  case PU_FLESH:
615  return item->type == FLESH;
616  case PU_POTION:
617  return item->type == POTION;
618  case PU_SPELLBOOK:
619  return item->type == SPELLBOOK;
620  case PU_SKILLSCROLL:
621  return item->type == SKILLSCROLL;
622  case PU_READABLES:
623  return item->type == BOOK || item->type == SCROLL;
624  case PU_MAGIC_DEVICE:
625  return item->type == WAND || item->type == ROD || item->type == WEAPON_IMPROVER || item->type == ARMOUR_IMPROVER || item->type == SKILL_TOOL;
626  case PU_MAGICAL:
628  case PU_VALUABLES:
629  return item->type == MONEY || item->type == GEM;
630  case PU_JEWELS:
631  return item->type == RING || item->type == AMULET;
632  case PU_BOW:
633  return item->type == BOW;
634  case PU_ARROW:
635  return item->type == ARROW;
636  case PU_ARMOUR:
637  return item->type == ARMOUR;
638  case PU_HELMET:
639  return item->type == HELMET;
640  case PU_SHIELD:
641  return item->type == SHIELD;
642  case PU_BOOTS:
643  return item->type == BOOTS;
644  case PU_GLOVES:
645  return item->type == GLOVES;
646  case PU_CLOAK:
647  return item->type == CLOAK;
648  case PU_MISSILEWEAPON:
649  return item->type == WEAPON && QUERY_FLAG(item, FLAG_IS_THROWN);
650  case PU_MELEEWEAPON:
651  return item->type == WEAPON;
652  case PU_KEY:
653  return item->type == KEY || item->type == SPECIAL_KEY;
654  case PU_CONTAINER:
655  return item->type == CONTAINER;
656  case PU_CURSED:
657  return QUERY_FLAG(item, FLAG_KNOWN_CURSED);
658  }
659  return 0;
660 }
661 
664  union {
665  struct {
669  };
670  char name[MAX_BUF];
672  };
673  int missed;
674 };
675 
683 typedef int (*item_matcher)(object *who, matcher_params *params, object *item);
684 
692 static int matcher_all(object *who, matcher_params *params, object *item) {
693  (void)who;
694  (void)params;
695  (void)item;
696  return 1;
697 }
698 
706 static int matcher_number(object *who, matcher_params *params, object *item) {
707  if (params->item_must_be_pickable == 0 || object_can_pick(who, item)) {
708  params->item_number++;
709  }
710  if (params->item_to_pick == params->item_number) {
711  /* Since we don't always increase item_number, multiple items may have the same index,
712  including unpickable ones, so to avoid failure messages just ensure no other item can be picked. */
713  params->item_to_pick = 0;
714  return 1;
715  }
716  return 0;
717 }
718 
726 static int matcher_name(object *who, matcher_params *params, object *item) {
727  int ival = object_matches_string(who, item, params->name);
728  if (ival > 0) {
729  if (ival <= 2 && !object_can_pick(who, item)) {
730  if (!QUERY_FLAG(item, FLAG_IS_FLOOR))/* don't count floor tiles */
731  params->missed++;
732  return 0;
733  }
734  return 1;
735  }
736  return 0;
737 }
738 
746 static int matcher_pickup_type(object *who, matcher_params *params, object *item) {
747  (void)who;
748  return object_matches_pickup_mode(item, params->pickup_type);
749 }
750 
758 static item_matcher make_matcher(object *who, const char *params, matcher_params *mp) {
759  memset(mp, 0, sizeof(*mp));
760  if (params[0] == '\0') {
761  mp->item_to_pick = 1;
762  mp->item_must_be_pickable = 1;
763  return &matcher_number;
764  }
765  if (params[0] == '#') {
766  mp->item_to_pick = atoi(params + 1);
767  if (mp->item_to_pick == 0) {
769  return NULL;
770  }
771  return &matcher_number;
772  }
773  if (params[0] == '*') {
774  if (params[1] == '\0') {
775  return &matcher_all;
776  }
777  int idx = get_pickup_mode_index(params + 1);
778  if (idx == -1) {
779  draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, "Invalid items %s", params + 1);
780  return NULL;
781  }
782  mp->pickup_type = pickup_modes[idx];
783  return &matcher_pickup_type;
784  }
785  strncpy(mp->name, params, sizeof(mp->name) - 1);
786  return &matcher_name;
787 }
788 
797 void command_take(object *op, const char *params) {
798  object *tmp;
799  int did_one = 0;
800 
801  if (op->container)
802  tmp = op->container->inv;
803  else {
804  tmp = op->above;
805  if (tmp)
806  while (tmp->above) {
807  tmp = tmp->above;
808  }
809  if (!tmp)
810  tmp = op->below;
811  }
812 
813  if (tmp == NULL) {
815  "Nothing to take!");
816  return;
817  }
818 
819  matcher_params mp;
820  item_matcher matcher = make_matcher(op, params, &mp);
821  if (!matcher) {
822  return; // Player already informed of failure.
823  }
824 
826 
828  if (tmp->invisible) {
829  continue;
830  }
831  if ((*matcher)(op, &mp, tmp)) {
832  pick_up(op, tmp);
833  did_one = 1;
834  }
836 
837  /* Nothing picked up, check if unable to pick or nothing to pick. */
838  if (params[0] == '\0' && !did_one) {
839  int found = 0;
840  FOR_BELOW_PREPARE(op, tmp)
841  if (!tmp->invisible) {
843  "You can't pick up a %s.",
844  tmp->name ? tmp->name : "null");
845  found = 1;
846  break;
847  }
849  if (!found)
851  "There is nothing to pick up.");
852  }
853 
854  if (mp.missed == 1)
856  "You were unable to take one of the items.");
857  else if (mp.missed > 1)
859  "You were unable to take %d of the items.",
860  mp.missed);
861 
862  /* Now update player and send information. */
864  fix_object(op);
865  if (op->type == PLAYER) {
866  op->contr->count = 0;
867  esrv_update_item(UPD_WEIGHT, op, op);
868  }
869 }
870 
889 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
890  object *sack2, *orig = sack;
891  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
892 
893  if (sack == tmp)
894  return; /* Can't put an object in itself */
895  query_name(sack, name_sack, MAX_BUF);
896  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
898  "The %s is not a container.",
899  name_sack);
900  return;
901  }
902  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
903  query_name(tmp, name_tmp, MAX_BUF);
905  "You cannot put the %s in the %s.",
906  name_tmp, name_sack);
907  return;
908  }
909  if (tmp->type == CONTAINER) {
910  if (tmp->inv) {
911  if (tmp->slaying)
912  return;
913  /* Eneq(@csd.uu.se): If the object to be dropped is a container
914  * and does not require a key to be opened,
915  * we instead move the contents of that container into the active
916  * container, this is only done if the object has something in it.
917  * If object is container but need a key, just don't do anything
918  */
919  sack2 = tmp;
920  query_name(tmp, name_tmp, MAX_BUF);
922  "You move the items from %s into %s.",
923  name_tmp, name_sack);
924 
925  FOR_INV_PREPARE(tmp, tmp2) {
926  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
927  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
928  put_object_in_sack(op, sack, tmp2, 0);
929  } else {
932  "Your %s fills up.",
933  name_sack);
934  break;
935  }
936  } FOR_INV_FINISH();
937  esrv_update_item(UPD_WEIGHT, op, sack2);
938  return;
939  } else {
940  query_name(tmp, name_tmp, MAX_BUF);
942  "You can not put a %s into a %s",
943  name_tmp,
944  name_sack);
945  return;
946  }
947  }
948 
949  /* Don't worry about this for containers - our caller should have
950  * already checked this.
951  */
952  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
953  return;
954 
955  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
956  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
957  return;
958  }
959 
960  /* we want to put some portion of the item into the container */
961  if (nrof && tmp->nrof != nrof) {
962  char failure[MAX_BUF];
963 
964  tmp = object_split(tmp, nrof, failure, sizeof(failure));
965 
966  if (!tmp) {
968  failure);
969  return;
970  }
971  } else
972  object_remove(tmp);
973 
974  if (sack->nrof > 1) {
975  orig = object_split(sack, sack->nrof-1, NULL, 0);
976  set_object_face_main(orig);
977  CLEAR_FLAG(orig, FLAG_APPLIED);
978  if (sack->env) {
979  object_insert_in_ob(orig, sack->env);
980  } else {
981  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
982  orig->move_off = 0;
983  }
984  }
985 
986  query_name(tmp, name_tmp, MAX_BUF);
988  "You put the %s in %s.",
989  name_tmp, name_sack);
990 
991  object_insert_in_ob(tmp, sack);
992  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
993  fix_object(op); /* This is overkill, fix_player() is called somewhere */
994  /* in object.c */
995 
996  /* If a transport, need to update all the players in the transport
997  * the view of what is in it.
998  */
999  if (sack->type == TRANSPORT) {
1000  FOR_INV_PREPARE(sack, tmp)
1001  if (tmp->type == PLAYER)
1002  tmp->contr->socket->update_look = 1;
1003  FOR_INV_FINISH();
1004  } else {
1005  /* update the sacks weight */
1006  esrv_update_item(UPD_WEIGHT, op, sack);
1007  }
1008 }
1009 
1025 object *drop_object(object *op, object *tmp, uint32_t nrof) {
1026  tag_t tmp_tag;
1027 
1028  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1029  return NULL;
1030  }
1031 
1032  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1033  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
1034  return NULL; /* can't unapply it */
1035  }
1036 
1037  if (events_execute_object_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1038  return NULL;
1039 
1040  /* ensure the plugin didn't destroy the object */
1041  if (QUERY_FLAG(tmp, FLAG_REMOVED))
1042  return NULL;
1043 
1044  /* We are only dropping some of the items. We split the current objec
1045  * off
1046  */
1047  if (nrof && tmp->nrof != nrof) {
1048  char failure[MAX_BUF];
1049 
1050  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1051  if (!tmp) {
1053  failure);
1054  return NULL;
1055  }
1056  } else
1057  object_remove(tmp);
1058 
1059  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
1060  char name[MAX_BUF];
1061 
1062  query_name(tmp, name, MAX_BUF);
1064  "You drop the %s. The gods who lent it to you retrieve it.",
1065  name);
1067 
1068  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1069  fix_object(op);
1070 
1071  return NULL;
1072  }
1073 
1074  /* If SAVE_INTERVAL is commented out, we never want to save
1075  * the player here.
1076  */
1077 #ifdef SAVE_INTERVAL
1078  /* I'm not sure why there is a value check - since the save
1079  * is done every SAVE_INTERVAL seconds, why care the value
1080  * of what he is dropping?
1081  */
1082  if (op->type == PLAYER
1083  && !QUERY_FLAG(tmp, FLAG_UNPAID)
1084  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
1085  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
1086  save_player(op, 1);
1087  op->contr->last_save_time = time(NULL);
1088  }
1089 #endif /* SAVE_INTERVAL */
1090 
1091 
1092  tmp_tag = tmp->count;
1093  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
1094  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
1095  sell_item(tmp, op);
1096  }
1097 
1098  /* Call this before we update the various windows/players. At least
1099  * that we, we know the weight is correct.
1100  */
1101  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
1102  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1103  /* in object.c */
1104 
1105  /* Need to update weight of player */
1106  if (op->type == PLAYER)
1107  esrv_update_item(UPD_WEIGHT, op, op);
1108  }
1109  return tmp;
1110 }
1111 
1120 void drop(object *op, object *tmp) {
1121  /* Hopeful fix for disappearing objects when dropping from a container -
1122  * somehow, players get an invisible object in the container, and the
1123  * old logic would skip over invisible objects - works fine for the
1124  * playes inventory, but drop inventory wants to use the next value.
1125  */
1126  if (tmp->invisible) {
1127  /* if the following is the case, it must be in an container. */
1128  if (tmp->env && tmp->env->type != PLAYER) {
1129  /* Just toss the object - probably shouldn't be hanging
1130  * around anyways
1131  */
1132  object_remove(tmp);
1134  return;
1135  } else {
1137  if (!tmp->invisible)
1138  break;
1140  }
1141  }
1142 
1143  if (tmp == NULL) {
1145  "You don't have anything to drop.");
1146  return;
1147  }
1148  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1150  "This item is locked");
1151  return;
1152  }
1153  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1154  return;
1155  }
1156 
1157  if (op->container) {
1158  if (op->type == PLAYER) {
1159  put_object_in_sack(op, op->container, tmp, op->contr->count);
1160  } else {
1161  put_object_in_sack(op, op->container, tmp, 0);
1162  };
1163  } else {
1164  if (op->type == PLAYER) {
1165  drop_object(op, tmp, op->contr->count);
1166  } else {
1167  drop_object(op, tmp, 0);
1168  };
1169  }
1170  if (op->type == PLAYER)
1171  op->contr->count = 0;
1172 }
1173 
1182 void command_dropall(object *op, const char *params) {
1183  int count = 0;
1184 
1185  if (op->inv == NULL) {
1186  draw_ext_info(NDI_UNIQUE, 0, op,
1188  "Nothing to drop!");
1189  return;
1190  }
1191 
1192  if (op->contr)
1193  count = op->contr->count;
1194 
1195  /* Set this so we don't call it for _every_ object that
1196  * is dropped.
1197  */
1199 
1200  /*
1201  * This is the default. Drops everything not locked or considered
1202  * not something that should be dropped.
1203  * Care must be taken that the next item pointer is not to money as
1204  * the drop() routine will do unknown things to it when dropping
1205  * in a shop. --Tero.Pelander@utu.fi
1206  */
1207  if (*params == '\0') {
1208  FOR_INV_PREPARE(op, curinv) {
1209  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1210  && curinv->type != MONEY
1211  && curinv->type != FOOD
1212  && curinv->type != KEY
1213  && curinv->type != SPECIAL_KEY
1214  && curinv->type != GEM
1215  && !curinv->invisible
1216  && (curinv->type != CONTAINER || op->container != curinv)) {
1217  drop(op, curinv);
1218  if (op->contr)
1219  op->contr->count = count;
1220  }
1221  } FOR_INV_FINISH();
1222  } else if (strcmp(params, "weapons") == 0) {
1223  FOR_INV_PREPARE(op, curinv) {
1224  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1225  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1226  drop(op, curinv);
1227  if (op->contr)
1228  op->contr->count = count;
1229  }
1230  } FOR_INV_FINISH();
1231  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1232  FOR_INV_PREPARE(op, curinv) {
1233  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1234  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1235  drop(op, curinv);
1236  if (op->contr)
1237  op->contr->count = count;
1238  }
1239  } FOR_INV_FINISH();
1240  } else if (strcmp(params, "food") == 0) {
1241  FOR_INV_PREPARE(op, curinv) {
1242  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1243  && (curinv->type == FOOD || curinv->type == DRINK)) {
1244  drop(op, curinv);
1245  if (op->contr)
1246  op->contr->count = count;
1247  }
1248  } FOR_INV_FINISH();
1249  } else if (strcmp(params, "flesh") == 0) {
1250  FOR_INV_PREPARE(op, curinv) {
1251  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1252  && (curinv->type == FLESH)) {
1253  drop(op, curinv);
1254  if (op->contr)
1255  op->contr->count = count;
1256  }
1257  } FOR_INV_FINISH();
1258  } else if (strcmp(params, "misc") == 0) {
1259  FOR_INV_PREPARE(op, curinv) {
1260  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1261  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1262  switch (curinv->type) {
1263  case BOOK:
1264  case SPELLBOOK:
1265  case GIRDLE:
1266  case AMULET:
1267  case RING:
1268  case CLOAK:
1269  case BOOTS:
1270  case GLOVES:
1271  case BRACERS:
1272  case SCROLL:
1273  case ARMOUR_IMPROVER:
1274  case WEAPON_IMPROVER:
1275  case WAND:
1276  case ROD:
1277  case POTION:
1278  drop(op, curinv);
1279  if (op->contr)
1280  op->contr->count = count;
1281  break;
1282 
1283  default:
1284  break;
1285  }
1286  }
1287  } FOR_INV_FINISH();
1288  }
1289  op->contr->socket->update_look = 1;
1291  /* call it now, once */
1292  fix_object(op);
1293  /* Need to update weight of player. Likewise, only do it once */
1294  if (op->type == PLAYER)
1295  esrv_update_item(UPD_WEIGHT, op, op);
1296 }
1297 
1306 void command_drop(object *op, const char *params) {
1307  int did_one = 0;
1308  int missed = 0;
1309 
1310  if (*params == '\0') {
1312  "Drop what?");
1313  return;
1314  }
1315 
1316  matcher_params mp;
1317  item_matcher matcher = make_matcher(op, params, &mp);
1318  if (!matcher) {
1319  return;
1320  }
1321 
1323 
1324  FOR_INV_PREPARE(op, tmp) {
1325  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1326  continue;
1327  if ((*matcher)(op, &mp, tmp)) {
1328  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1329  missed++;
1330  } else {
1331  drop(op, tmp);
1332  }
1333  did_one = 1;
1334  }
1335  } FOR_INV_FINISH();
1336  if (!did_one)
1338  "Nothing to drop.");
1339  if (missed == 1)
1341  "One item couldn't be dropped because it was locked.");
1342  else if (missed > 1)
1344  "%d items couldn't be dropped because they were locked.",
1345  missed);
1346 
1347  /* Now update player and send information. */
1349  fix_object(op);
1350  if (op->type == PLAYER) {
1351  op->contr->count = 0;
1352  esrv_update_item(UPD_WEIGHT, op, op);
1353  }
1354 }
1355 
1364 static void empty_container(object *container, object *pl) {
1365  int left = 0;
1366  char name[MAX_BUF];
1367 
1368  if (!container->inv)
1369  return;
1370 
1371  FOR_INV_PREPARE(container, inv) {
1372  object *next;
1373 
1374  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1375  /* you can have locked items in container. */
1376  left++;
1377  continue;
1378  }
1379  next = inv->below;
1380  drop(pl, inv);
1381  if (inv->below == next)
1382  /* item couldn't be dropped for some reason. */
1383  left++;
1384  } FOR_INV_FINISH();
1385  esrv_update_item(UPD_WEIGHT, pl, container);
1386 
1387  query_name(container, name, sizeof(name));
1388  if (left)
1389  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1390  else
1391  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s.", name);
1392 }
1393 
1402 void command_empty(object *op, const char *params) {
1403  object *container;
1404 
1405  if (*params == '\0') {
1407  "Empty what?");
1408  return;
1409  }
1410 
1411  if (strcmp(params, "all") == 0) {
1412  FOR_INV_PREPARE(op, inv)
1413  if (inv->type == CONTAINER)
1414  empty_container(inv, op);
1415  FOR_INV_FINISH();
1416  return;
1417  }
1418 
1419  container = find_best_object_match(op, params);
1420  if (!container) {
1422  "No such item.");
1423  return;
1424  }
1425  if (container->type != CONTAINER) {
1427  "This is not a container!");
1428  return;
1429  }
1430  empty_container(container, op);
1431 }
1432 
1441 void command_examine(object *op, const char *params) {
1442  if (*params == '\0') {
1443  FOR_BELOW_PREPARE(op, tmp)
1444  if (LOOK_OBJ(tmp)) {
1445  examine(op, tmp);
1446  break;
1447  }
1448  FOR_BELOW_FINISH();
1449  } else {
1450  object *tmp = find_best_object_match(op, params);
1451 
1452  if (tmp)
1453  examine(op, tmp);
1454  else
1456  "Could not find an object that matches %s",
1457  params);
1458  }
1459 }
1460 
1472 object *find_marked_object(object *op) {
1473  if (!op || !op->contr || !op->contr->mark)
1474  return NULL;
1475 
1476  /* This may seem like overkill, but we need to make sure that they
1477  * player hasn't dropped the item. We use count on the off chance that
1478  * an item got reincarnated at some point.
1479  */
1480  /*
1481  FOR_INV_PREPARE(op, tmp) {
1482  if (tmp->invisible)
1483  continue;
1484  if (tmp == op->contr->mark) {
1485  if (tmp->count == op->contr->mark_count)
1486  return tmp;
1487  else {
1488  op->contr->mark = NULL;
1489  op->contr->mark_count = 0;
1490  return NULL;
1491  }
1492  }
1493  } FOR_INV_FINISH();
1494  */
1495  /* Try a different way of doing this
1496  * We check the environment of the marked object
1497  * to make sure it is still in the player's inventory.
1498  * In addition, we ensure there is the correct tag for that item.
1499  *
1500  * Neila Hawkins 2018-10-23
1501  */
1502  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1503  return op->contr->mark;
1504  // Otherwise reset the mark, since it is no longer valid.
1505  op->contr->mark = NULL;
1506  op->contr->mark_count = 0;
1507  return NULL;
1508 }
1509 
1519 void command_mark(object *op, const char *params) {
1520  char name[MAX_BUF];
1521 
1522  if (!op->contr)
1523  return;
1524  if (*params == '\0') {
1525  object *mark = find_marked_object(op);
1526  if (!mark)
1528  "You have no marked object.");
1529  else {
1530  query_name(mark, name, MAX_BUF);
1532  "%s is marked.",
1533  name);
1534  }
1535  } else {
1536  object *mark1 = find_best_object_match(op, params);
1537 
1538  if (!mark1) {
1540  "Could not find an object that matches %s",
1541  params);
1542  return;
1543  } else {
1544  op->contr->mark = mark1;
1545  op->contr->mark_count = mark1->count;
1546  query_name(mark1, name, MAX_BUF);
1548  "Marked item %s",
1549  name);
1550  return;
1551  }
1552  }
1553  /*shouldnt get here */
1554 }
1555 
1566 void examine_monster(object *op, object *tmp, int level) {
1567  object *mon = HEAD(tmp), *probe;
1568 
1569  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1571  "It is an undead force.");
1572  if (mon->level > op->level)
1574  "It is likely more powerful than you.");
1575  else if (mon->level < op->level)
1577  "It is likely less powerful than you.");
1578  else
1580  "It is probably as powerful as you.");
1581 
1582  if (mon->attacktype&AT_ACID)
1584  "You smell an acrid odor.");
1585 
1586  /* Anyone know why this used to use the clone value instead of the
1587  * maxhp field? This seems that it should give more accurate results.
1588  */
1589  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1590  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1591  case 0:
1593  "It is critically wounded.");
1594  break;
1595 
1596  case 1:
1598  "It is in a bad shape.");
1599  break;
1600 
1601  case 2:
1603  "It is hurt.");
1604  break;
1605 
1606  case 3:
1608  "It is somewhat hurt.");
1609  break;
1610 
1611  default:
1613  "It is in excellent shape.");
1614  break;
1615  }
1616  if (object_present_in_ob(POISONING, mon) != NULL)
1618  "It looks very ill.");
1619 
1620  if (level < 10)
1621  return;
1622  knowledge_add_probe_monster(op, mon);
1623 
1624  if (level < 15)
1625  return;
1626 
1627  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1628  if (probe != NULL && probe->level > level)
1629  return;
1630 
1631  if (probe == NULL) {
1633  free_string(probe->name);
1634  probe->name = add_string("probe_force");
1637  object_insert_in_ob(probe, mon);
1638  fix_object(mon);
1639  }
1640  probe->level = level;
1641  if (level / 10 > probe->duration)
1642  probe->duration = level / 10;
1643 }
1644 
1646  EX_ID_ABORT, // Not safe to continue
1647  EX_ID_NO_SKILL, // Player lacks the requisite skill(s)
1648  EX_ID_FAILED // Player has the skill but failed their ID roll
1649 };
1650 
1662 ex_autoid_result examine_autoidentify(object *op, object *tmp) {
1663  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1664  int exp = 0;
1665  object *skill = find_skill_by_number(op, SK_DET_MAGIC);
1666  if (skill && (object_can_pick(op, tmp))) {
1667  exp = detect_magic_on_item(op, tmp, skill);
1668  if (exp) {
1669  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1671  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1672  }
1673  }
1674 
1675  skill = find_skill_by_number(op, SK_DET_CURSE);
1676  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1677  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1678  exp = detect_curse_on_item(op, tmp, skill);
1679  if (exp) {
1680  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1682  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1683  }
1684  }
1685 
1686  const typedata *tmptype = get_typedata(tmp->type);
1687  if (!tmptype) {
1688  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid\n", tmp->count, tmp->type);
1689  return EX_ID_ABORT;
1690  }
1691 
1692  bool have_skill = false;
1693  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1694  skill = find_skill_by_number(op, tmptype->identifyskill);
1695  if (skill) {
1696  /* identify_object_with_skill() may merge tmp with another
1697  * object, so once that happens, we really can not do
1698  * any further processing with tmp. It would be possible
1699  * to modify identify_object_with_skill() to return
1700  * the merged object, but it is currently set to return
1701  * exp, so it would have to do it via modifying the
1702  * passed in value, but many other consumers would
1703  * need to be modified for that.
1704  */
1705  exp = identify_object_with_skill(tmp, op, skill, 1);
1706  if (exp) {
1707  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1708  return EX_ID_ABORT;
1709  }
1710  }
1711 
1712  /* The primary id skill didn't work, let's try the secondary one */
1713  skill = find_skill_by_number(op, tmptype->identifyskill2);
1714  if (skill) {
1715  /* if we've reached here, then the first skill will have been attempted
1716  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1717  * that now, and try with the secondary ID skill, if it fails, then the
1718  * flag will be reset anyway, if it succeeds, it won't matter.*/
1720  exp = identify_object_with_skill(tmp, op, skill, 1);
1721  if (exp) {
1722  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1723  return EX_ID_ABORT;
1724  }
1725  }
1726  }
1727  return have_skill ? EX_ID_FAILED : EX_ID_NO_SKILL;
1728 }
1729 
1738 void examine_weight_and_material(object *op, object *tmp) {
1739  bool pl = tmp->nrof > 1;
1740  float weight = (tmp->nrof ? tmp->nrof : 1) * ((float)tmp->weight/1000.0);
1741 
1742  if (tmp->materialname && weight) {
1744  "%s made of %s and %s %3.3f kg.",
1745  pl ? "They are" : "It is", tmp->materialname,
1746  pl ? "weigh" : "weighs", weight);
1747  } else if (tmp->materialname) {
1749  "%s made of %s.", pl ? "They are" : "It is", tmp->materialname);
1750  } else if (weight) {
1752  "%s %3.3f kg.", pl ? "They weigh" : "it weighs", weight);
1753  }
1754 }
1755 
1764 void examine_wand_charge_level(object *op, object *tmp) {
1765  if (!is_identified(tmp)) return;
1766  const char *desc;
1767  if (tmp->stats.food <= 0) {
1768  desc = "It is completely depleted.";
1769  } else if (tmp->stats.food <= 2) {
1770  desc = "It is nearly depleted.";
1771  } else if (tmp->stats.food <= 4) {
1772  desc = "It is very low on power.";
1773  } else if (tmp->stats.food <= 8) {
1774  desc = "It is low on power.";
1775  } else if (tmp->stats.food <= 16) {
1776  desc = "It is well charged.";
1777  } else if (tmp->stats.food <= 32) {
1778  desc = "It is fully charged.";
1779  } else {
1780  desc = "It is overflowing with power.";
1781  }
1783 }
1784 
1793 void examine_rod_charge_level(object *op, object *tmp) {
1794  if (!is_identified(tmp)) return;
1795  if (!tmp->inv) // rod has no spell
1796  return;
1797  const int castings = tmp->stats.hp/SP_level_spellpoint_cost(tmp, tmp->inv, SPELL_HIGHEST);
1798  const char *desc;
1799  /* Rods get less precise information than wands/staves as part of balancing
1800  out their reusability -- in particular, you can't tell if a rod is *almost*
1801  out of shots or *completely* out of shots without trying it. */
1802  if (castings <= 1) {
1803  desc = "It is nearly depleted.";
1804  } else if (castings <= 3) {
1805  desc = "It hums with power.";
1806  } else {
1807  desc = "It crackles with power.";
1808  }
1810 }
1811 
1825 bool examine_fluff(object *op, object *tmp, bool output) {
1826  /* No message for stuff the player hasn't IDed. */
1827  if (!is_identified(tmp)) {
1828  return false;
1829  }
1830 
1831  // We use stringbuffer throughout this function so that we can use
1832  // trim_whitespace to conveniently strip trailing newlines, ensuring that
1833  // the output of examine is contiguous.
1834  // TODO: It might be better to strip the newlines in object_set_msg
1835  // and append them at print time, rather than ensuring that the msg
1836  // is newline-terminated and stripping off the newlines when we don't
1837  // want them; C string handling makes the latter a lot less convenient.
1838  if (tmp->msg && strncasecmp(tmp->msg, "@match", 6)) {
1839  if (!output) return true;
1841  stringbuffer_append_string(sb, tmp->msg);
1843  char *const msg = stringbuffer_finish(sb);
1845  free(msg);
1846  }
1847 
1848  switch (tmp->type) {
1849  /* Stuff with embedded skills. */
1850  case SKILLSCROLL:
1851  case SKILL_TOOL:
1852  {
1853  // Embedded skills are stored as an archetype name and don't get reified
1854  // until the player actually reads/equips the object, so we need to turn
1855  // the name into an actual archetype and then read the msg out of that.
1856  if (!tmp->skill) break; // Blank skill scroll, somehow.
1858  if (!skill) {
1859  if (!output) break; // Still need to check for lore later.
1860  // Skill name doesn't correspond to any actual skill.
1862  "Unfortunately, it is damaged beyond %s.",
1863  (tmp->type == SKILLSCROLL) ? "comprehension" : "repair");
1864  break;
1865  }
1866  if (skill->clone.msg) {
1867  if (!output) return true;
1869  "%s lets you %s a skill:",
1870  tmp->nrof > 1 ? "These objects" : "This object",
1871  (tmp->type == SKILLSCROLL) ? "learn" : "use");
1872 
1874  stringbuffer_append_string(sb, skill->clone.msg);
1876  char *const fluff = stringbuffer_finish(sb);
1877  // SPELL_INFO is not a perfect match here, but it should display in the
1878  // same manner as the spell descriptions below and there's no SKILL_INFO
1879  // message type.
1881  free(fluff);
1882  }
1883  break;
1884  }
1885 
1886  /* Stuff with embedded spells. */
1887  case SPELLBOOK:
1888  case SCROLL:
1889  case WAND:
1890  case ROD:
1891  case POTION:
1892  {
1893  if (tmp->inv && tmp->inv->msg) {
1894  if (!output) return true;
1896  "%s holds%s a spell:",
1897  tmp->nrof > 1 ? "These objects" : "This object",
1898  tmp->type == SPELLBOOK ? " knowledge of" : "");
1899 
1901  stringbuffer_append_string(sb, tmp->inv->msg);
1903  char *const fluff = stringbuffer_finish(sb);
1905  free(fluff);
1906  }
1907  }
1908  }
1909 
1910  if (tmp->lore) {
1911  if (!output) return true;
1913  "%s a story:", tmp->nrof > 1 ? "These objects have" : "This object has");
1915  stringbuffer_append_string(sb, tmp->lore);
1917  char *const msg = stringbuffer_finish(sb);
1919  free(msg);
1920  }
1921 
1922  // If we get this far in output=false mode, we didn't hit any of the earlier
1923  // escape hatches and thus have nothing to output. In normal use we'll hit
1924  // this regardless and assume we output something.
1925  return output;
1926 }
1927 
1937 void examine(object *op, object *tmp) {
1938  if (tmp == NULL || tmp->type == CLOSE_CON)
1939  return;
1940 
1941  /* If the player has examined this twice in a row, do a more detailed
1942  examine. last_examined shouldn't get set unless we already know that
1943  examine_fluff() will do something interesting. */
1944  if (op->contr->last_examined == tmp->count) {
1945  op->contr->last_examined = 0;
1947  "You examine the %s more closely.", tmp->nrof > 1 ? tmp->name_pl : tmp->name);
1948  examine_fluff(op, tmp, true);
1950  " "); /* Blank line */
1951  return;
1952  }
1953 
1954  int i;
1955  char prefix[MAX_BUF] = "";
1956  char buf[VERY_BIG_BUF] = "";
1957  if (is_identified(tmp)) {
1958  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof<=1 ? "That is" : "Those are");
1959  } else {
1960  switch(examine_autoidentify(op, tmp)) {
1961  case EX_ID_NO_SKILL:
1962  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:",
1963  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
1964  break;
1965  case EX_ID_FAILED:
1966  snprintf(prefix, MAX_BUF, "You fail to understand %s:",
1967  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
1968  break;
1969  case EX_ID_ABORT:
1970  default:
1971  /* Item may have been merged with something else, not safe to proceed. */
1972  return;
1973  }
1974  }
1975 
1976  /* now we need to get the rest of the object description */
1977  ob_describe(tmp, op, 1, buf, sizeof(buf));
1978 
1980  "%s %s", prefix, buf);
1981  buf[0] = '\0';
1982  sstring custom_name = object_get_value(tmp, CUSTOM_NAME_FIELD);
1983  if (custom_name) {
1985  "You name it %s",
1986  custom_name);
1987  }
1988 
1989  method_ret ret = ob_examine(tmp, op, 1, buf, sizeof(buf));
1990  if (ret == METHOD_UNHANDLED) {
1991  switch (tmp->type) {
1992  case WAND:
1993  examine_wand_charge_level(op, tmp);
1994  break;
1995 
1996  case ROD:
1997  examine_rod_charge_level(op, tmp);
1998  break;
1999 
2000  case BOOK:
2001  if (tmp->msg != NULL)
2002  snprintf(buf, sizeof(buf), "Something is written in it.");
2003  break;
2004  }
2005  }
2006 
2007  if (buf[0] != '\0')
2009  buf);
2010 
2011  examine_weight_and_material(op, tmp);
2012 
2013  /* Where to wear this item */
2014  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
2015  if (tmp->body_info[i]) {
2016  if (op->body_info[i]) {
2017  if (tmp->body_info[i] < -1) {
2019  "%s %s (%d).", tmp->nrof > 1 ? "They go" : "It goes",
2020  body_locations[i].use_name, -tmp->body_info[i]);
2021  } else {
2023  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2025  }
2026  } else {
2028  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2030  }
2031  }
2032  }
2033 
2034  int in_shop = shop_contains(op);
2035 
2036  if (!QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2037  char *value = cost_approx_str(tmp, op);
2038  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
2039  free(value);
2041  buf);
2042  if (in_shop) {
2043  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
2044  if (object_value_set(tmp, "pshop_owner")) {
2045  const char *seller = object_get_value(tmp, "pshop_owner");
2046  snprintf(buf, sizeof(buf), "%s is selling this item.", seller);
2048  }
2049 
2050  value = cost_str(shop_price_buy(tmp, op));
2051  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
2052  free(value);
2053  } else {
2054  value = cost_str(shop_price_sell(tmp, op));
2055  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
2056  free(value);
2057  }
2059  buf);
2060  }
2061  }
2062 
2063  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2064  examine_monster(op, tmp, 0);
2065 
2066  /* Is this item buildable? */
2067  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
2068  int conn;
2069  bool has_link = false;
2070  if (QUERY_FLAG(tmp, FLAG_IS_LINKED) && (conn = get_button_value(tmp))) {
2071  FOR_INV_PREPARE(op, tmp_inv) {
2072  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
2073  && strcmp(tmp_inv->slaying, op->map->path) == 0
2074  && tmp_inv->msg != NULL
2075  && tmp_inv->path_attuned == (uint32_t) conn) {
2076 
2077  has_link = true;
2080  "This is a buildable item, connected with: %s",
2081  tmp_inv->msg);
2082  break;
2083  }
2084  } FOR_INV_FINISH();
2085  }
2086  if (!has_link) {
2088  "This is a buildable item.");
2089  }
2090  }
2091 
2092  /* Does it have fluff text? */
2093  if (examine_fluff(op, tmp, false)) {
2094  op->contr->last_examined = tmp->count;
2096  "Examine again for more details.");
2097  } else {
2098  op->contr->last_examined = 0;
2099  }
2100 
2102  " "); /* Blank line */
2103 
2104  if (is_identified(tmp)) {
2106  }
2107 }
2108 
2117 void inventory(object *op, object *inv) {
2118  const char *in;
2119  int items = 0, length;
2120  char weight[MAX_BUF], name[MAX_BUF];
2121 
2122  if (inv == NULL && op == NULL) {
2124  "Inventory of what object?");
2125  return;
2126  }
2127  FOR_INV_PREPARE(inv ? inv : op, tmp)
2128  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
2129  || !op || QUERY_FLAG(op, FLAG_WIZ))
2130  items++;
2131  FOR_INV_FINISH();
2132  if (inv == NULL) { /* player's inventory */
2133  if (items == 0) {
2135  "You carry nothing.");
2136  return;
2137  } else {
2138  length = 28;
2139  in = "";
2141  "Inventory:");
2142  }
2143  } else {
2144  if (items == 0)
2145  return;
2146  else {
2147  length = 28;
2148  in = " ";
2149  }
2150  }
2151  FOR_INV_PREPARE(inv ? inv : op, tmp) {
2152  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
2153  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
2154  continue;
2155  query_weight(tmp, weight, MAX_BUF);
2156  query_name(tmp, name, MAX_BUF);
2157  if (!op || QUERY_FLAG(op, FLAG_WIZ))
2159  "[fixed]%s- %-*.*s (%5d) %-8s",
2160  in, length, length, name, tmp->count, weight);
2161  else
2163  "[fixed]%s- %-*.*s %-8s",
2164  in, length+8, length+8, name, weight);
2165  } FOR_INV_FINISH();
2166  if (!inv && op) {
2167  query_weight(op, weight, MAX_BUF);
2169  "[fixed]%-*s %-8s",
2170  41, "Total weight :", weight);
2171  }
2172 }
2173 
2182 static void display_new_pickup(const object *op, int old) {
2183  int i = op->contr->mode;
2184 
2185  esrv_send_pickup(op->contr);
2186 
2187  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
2188  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
2190  "Pickup is now %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
2191  }
2192  return;
2193  }
2194 
2196  "%d NEWMODE",
2197  i&PU_NEWMODE ? 1 : 0);
2199  "%d DEBUG",
2200  i&PU_DEBUG ? 1 : 0);
2202  "%d INHIBIT",
2203  i&PU_INHIBIT ? 1 : 0);
2205  "%d STOP",
2206  i&PU_STOP ? 1 : 0);
2207 
2209  "%d <= x pickup weight/value RATIO (0==off)",
2210  (i&PU_RATIO)*5);
2211 
2213  "%d FOOD",
2214  i&PU_FOOD ? 1 : 0);
2216  "%d DRINK",
2217  i&PU_DRINK ? 1 : 0);
2219  "%d VALUABLES",
2220  i&PU_VALUABLES ? 1 : 0);
2221 
2223  "%d BOW",
2224  i&PU_BOW ? 1 : 0);
2226  "%d ARROW",
2227  i&PU_ARROW ? 1 : 0);
2228 
2230  "%d HELMET",
2231  i&PU_HELMET ? 1 : 0);
2233  "%d SHIELD",
2234  i&PU_SHIELD ? 1 : 0);
2236  "%d ARMOUR",
2237  i&PU_ARMOUR ? 1 : 0);
2238 
2240  "%d BOOTS",
2241  i&PU_BOOTS ? 1 : 0);
2243  "%d GLOVES",
2244  i&PU_GLOVES ? 1 : 0);
2246  "%d CLOAK",
2247  i&PU_CLOAK ? 1 : 0);
2249  "%d KEY",
2250  i&PU_KEY ? 1 : 0);
2251 
2253  "%d MISSILEWEAPON",
2254  i&PU_MISSILEWEAPON ? 1 : 0);
2256  "%d MELEEWEAPON",
2257  i&PU_MELEEWEAPON ? 1 : 0);
2259  "%d MAGICAL",
2260  i&PU_MAGICAL ? 1 : 0);
2262  "%d POTION",
2263  i&PU_POTION ? 1 : 0);
2264 
2266  "%d SPELLBOOK",
2267  i&PU_SPELLBOOK ? 1 : 0);
2269  "%d SKILLSCROLL",
2270  i&PU_SKILLSCROLL ? 1 : 0);
2272  "%d READABLES",
2273  i&PU_READABLES ? 1 : 0);
2275  "%d MAGICDEVICE",
2276  i&PU_MAGIC_DEVICE ? 1 : 0);
2277 
2279  "%d NOT CURSED",
2280  i&PU_NOT_CURSED ? 1 : 0);
2281 
2283  "%d JEWELS",
2284  i&PU_JEWELS ? 1 : 0);
2285 
2287  "%d FLESH",
2288  i&PU_FLESH ? 1 : 0);
2289 
2291  "%d CONTAINER",
2292  i&PU_CONTAINER ? 1 : 0);
2293 
2295  "%d CURSED",
2296  i&PU_CURSED ? 1 : 0);
2297 
2299  "");
2300 }
2301 
2311 void command_pickup(object *op, const char *params) {
2312  uint32_t i;
2313 
2314  if (*params == '\0') {
2315  /* if the new mode is used, just print the settings */
2316  if (op->contr->mode&PU_NEWMODE) {
2317  display_new_pickup(op, op->contr->mode);
2318  return;
2319  }
2320  if (1)
2321  LOG(llevDebug, "command_pickup: !params\n");
2322  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
2323  return;
2324  }
2325 
2326  while (*params == ' ')
2327  params++;
2328 
2329  if (*params == '+' || *params == '-' || *params == '!') {
2330  int index = get_pickup_mode_index(params + 1);
2331 
2332  if (index != -1) {
2333  int old = op->contr->mode;
2334  i = op->contr->mode;
2335  if (!(i&PU_NEWMODE))
2336  i = PU_NEWMODE;
2337  if (*params == '+')
2338  i = i|pickup_modes[index];
2339  else if (*params == '-')
2340  i = i&~pickup_modes[index];
2341  else {
2342  if (i&pickup_modes[index])
2343  i = i&~pickup_modes[index];
2344  else
2345  i = i|pickup_modes[index];
2346  }
2347  op->contr->mode = i;
2348  display_new_pickup(op, old);
2349  return;
2350  }
2352  "Pickup: invalid item %s\n",
2353  params);
2354  return;
2355  }
2356 
2357  if (sscanf(params, "%u", &i) != 1) {
2358  if (1)
2359  LOG(llevDebug, "command_pickup: params==NULL\n");
2361  "Usage: pickup <0-7> or <value_density> .");
2362  return;
2363  }
2364  set_pickup_mode(op, i);
2365  display_new_pickup(op, op->contr->mode);
2366 }
2367 
2376 static void set_pickup_mode(const object *op, int i) {
2377  op->contr->mode = i;
2378  switch (op->contr->mode) {
2379  case 0:
2381  "Mode: Don't pick up.");
2382  break;
2383 
2384  case 1:
2386  "Mode: Pick up one item.");
2387  break;
2388 
2389  case 2:
2391  "Mode: Pick up one item and stop.");
2392  break;
2393 
2394  case 3:
2396  "Mode: Stop before picking up.");
2397  break;
2398 
2399  case 4:
2401  "Mode: Pick up all items.");
2402  break;
2403 
2404  case 5:
2406  "Mode: Pick up all items and stop.");
2407  break;
2408 
2409  case 6:
2411  "Mode: Pick up all magic items.");
2412  break;
2413 
2414  case 7:
2416  "Mode: Pick up all coins and gems");
2417  break;
2418  }
2419 }
2420 
2429 void command_search_items(object *op, const char *params) {
2430  if (settings.search_items == FALSE)
2431  return;
2432 
2433  if (!params || *params == '\0') {
2434  if (op->contr->search_str[0] == '\0') {
2436  "Example: search magic+1 "
2437  "Would automatically pick up all "
2438  "items containing the word 'magic+1'.");
2439  return;
2440  }
2441  op->contr->search_str[0] = '\0';
2443  "Search mode turned off.");
2444  fix_object(op);
2445  return;
2446  }
2447  if ((int)strlen(params) >= MAX_BUF) {
2449  "Search string too long.");
2450  return;
2451  }
2452  strcpy(op->contr->search_str, params);
2454  "Searching for '%s'.",
2455  op->contr->search_str);
2456  fix_object(op);
2457 }
2458 
2474 void command_rename_item(object *op, const char *params) {
2475  char buf[VERY_BIG_BUF], name[MAX_BUF];
2476  tag_t itemnumber;
2477  object *item = NULL;
2478  object *tmp;
2479  const char *closebrace;
2480  size_t counter;
2481 
2482  if (*params != '\0') {
2483  /* Let's skip white spaces */
2484  while (' ' == *params)
2485  params++;
2486 
2487  /* Checking the first part */
2488  itemnumber = atoi(params);
2489  if (itemnumber != 0) {
2490  FOR_INV_PREPARE(op, inv)
2491  if (inv->count == itemnumber && !inv->invisible) {
2492  item = inv;
2493  break;
2494  }
2495  FOR_INV_FINISH();
2496  if (!item) {
2498  "Tried to rename an invalid item.");
2499  return;
2500  }
2501  while (isdigit(*params) || ' ' == *params)
2502  params++;
2503  } else if ('<' == *params) {
2504  /* Got old name, let's get it & find appropriate matching item */
2505  closebrace = strchr(params, '>');
2506  if (!closebrace) {
2508  "Syntax error!");
2509  return;
2510  }
2511  /* Sanity check for buffer overruns */
2512  if (closebrace-params > 127) {
2514  "Old name too long (up to 127 characters allowed)!");
2515  return;
2516  }
2517  /* Copy the old name */
2518  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2519 
2520  /* Find best matching item */
2521  item = find_best_object_match(op, buf);
2522  if (!item) {
2524  "Could not find a matching item to rename.");
2525  return;
2526  }
2527 
2528  /* Now need to move pointer to just after > */
2529  params = closebrace+1;
2530  while (' ' == *params)
2531  params++;
2532  } else {
2533  /* Use marked item */
2534  item = find_marked_object(op);
2535  if (!item) {
2537  "No marked item to rename.");
2538  return;
2539  }
2540  }
2541 
2542  /* Now let's find the new name */
2543  if (!strncmp(params, "to ", 3)) {
2544  params += 3;
2545  while (' ' == *params)
2546  params++;
2547  if ('<' != *params) {
2549  "Syntax error, expecting < at start of new name!");
2550  return;
2551  }
2552  closebrace = strchr(params+1, '>');
2553  if (!closebrace) {
2555  "Syntax error, expecting > at end of new name!");
2556  return;
2557  }
2558 
2559  /* Sanity check for buffer overruns */
2560  if (closebrace-params > 127) {
2562  "New name too long (up to 127 characters allowed)!");
2563  return;
2564  }
2565 
2566  /* Copy the new name */
2567  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2568 
2569  /* Let's check it for weird characters */
2570  for (counter = 0; counter < strlen(buf); counter++) {
2571  if (isalnum(buf[counter]))
2572  continue;
2573  if (' ' == buf[counter])
2574  continue;
2575  if ('\'' == buf[counter])
2576  continue;
2577  if ('+' == buf[counter])
2578  continue;
2579  if ('_' == buf[counter])
2580  continue;
2581  if ('-' == buf[counter])
2582  continue;
2583 
2584  /* If we come here, then the name contains an invalid character...
2585  * tell the player & exit
2586  */
2588  "Invalid new name!");
2589  return;
2590  }
2591  } else {
2592  /* If param contains something, then syntax error... */
2593  if (strlen(params)) {
2595  "Syntax error, expected 'to <' after old name!");
2596  return;
2597  }
2598  /* New name is empty */
2599  buf[0] = '\0';
2600  }
2601  } else {
2602  /* Last case: *params=='\0' */
2603  item = find_marked_object(op);
2604  if (!item) {
2606  "No marked item to rename.");
2607  return;
2608  }
2609  buf[0] = '\0';
2610  }
2611 
2612  /* Coming here, everything is fine... */
2613  if (!strlen(buf)) {
2614  /* Clear custom name */
2615  if (object_get_value(item, CUSTOM_NAME_FIELD) == NULL) {
2617  "This item has no custom name.");
2618  return;
2619  }
2620 
2621  object_set_value(item, CUSTOM_NAME_FIELD, NULL, 0);
2622  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2624  "You stop calling your %s with weird names.",
2625  name);
2626  } else {
2627  sstring custom_name = object_get_value(item, CUSTOM_NAME_FIELD);
2628  if (custom_name != NULL && strcmp(custom_name, buf) == 0) {
2629  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2631  "You keep calling your %s %s.",
2632  name, buf);
2633  return;
2634  }
2635 
2636  /* Set custom name */
2637  object_set_value(item, CUSTOM_NAME_FIELD, buf, 1);
2638 
2639  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2641  "Your %s will now be called %s.",
2642  name, buf);
2643  }
2644 
2645  tmp = object_merge(item, NULL);
2646  if (tmp == NULL) {
2647  /* object was not merged - if it was, object_merge() handles updating for us. */
2648  esrv_update_item(UPD_NAME, op, item);
2649  }
2650 }
2651 
2660 void command_lock_item(object *op, const char *params) {
2661  object *item;
2662  object *tmp;
2663  char name[HUGE_BUF];
2664 
2665  if (*params == '\0' || strlen(params) == 0) {
2667  "Lock what item?");
2668  return;
2669  }
2670 
2671  item = find_best_object_match(op, params);
2672  if (!item) {
2674  "Can't find any matching item.");
2675  return;
2676  }
2677 
2678  query_short_name(item, name, HUGE_BUF);
2679  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2681  "Unlocked %s.", name);
2682  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2683  } else {
2685  "Locked %s.", name);
2686  SET_FLAG(item, FLAG_INV_LOCKED);
2687  }
2688 
2689  tmp = object_merge(item, NULL);
2690  if (tmp == NULL) {
2691  /* object was not merged, if it was object_merge() handles updates for us */
2692  esrv_update_item(UPD_FLAGS, op, item);
2693  }
2694 }
2695 
2703 void command_use(object *op, const char *params) {
2704  char *with, copy[MAX_BUF];
2705  object *first, *second/*, *add*/;
2706  /*archetype *arch;*/
2707  /*int count;*/
2708  /*sstring data;*/
2709  recipe *transformation;
2710 
2711  if (!IS_PLAYER(op))
2712  return;
2713 
2714  strlcpy(copy, params, sizeof(copy));
2715  with = strstr(copy, " with ");
2716  if (!with) {
2717  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2718  return;
2719  }
2720 
2721  with[0] = '\0';
2722  with = with+strlen(" with ");
2723 
2724  first = find_best_object_match(op, copy);
2725  if (!first) {
2726  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2727  return;
2728  }
2729  second = find_best_object_match(op, with);
2730  if (!second) {
2731  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2732  return;
2733  }
2734 
2735  transformation = NULL;
2736  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2738  if (transformation->ingred_count != 1)
2739  continue;
2740 
2741 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2742  if (strcmp(second->name, transformation->ingred->name) == 0) {
2744  object *generated = create_archetype(transformation->arch_name[0]);
2745  if (transformation->yield)
2746  generated->nrof = transformation->yield;
2747  object_insert_in_ob(generated, op);
2748  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2750  return;
2751  }
2752  }
2753  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2754  return;
2755 
2756  /*
2757  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2758  data = object_get_value(second, copy);
2759  if (!data) {
2760  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2761  data = object_get_value(second, copy);
2762  if (!data) {
2763  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2764  data = object_get_value(second, copy);
2765  if (!data) {
2766  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2767  return 1;
2768  }
2769  }
2770  }
2771 
2772  while (data != NULL) {
2773  if (strncmp(data, "add ", 4) == 0) {
2774  data += 4;
2775  if (isdigit(*data)) {
2776  count = atol(data);
2777  data = strchr(data, ' ')+1;
2778  } else
2779  count = 1;
2780  with = strchr(data, ' ');
2781  if (!with) {
2782  strncpy(copy, data, sizeof(copy));
2783  data = NULL;
2784  } else {
2785  *with = '\0';
2786  strncpy(copy, data, sizeof(copy));
2787  data += strlen(copy)+1;
2788  }
2789  arch = find_archetype(copy);
2790  if (!arch) {
2791  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2792  return 1;
2793  }
2794  add = object_create_arch(arch);
2795  add->nrof = count;
2796  object_insert_in_ob(add, op);
2797  } else if (strncmp(data, "remove $", 8) == 0) {
2798  data += 8;
2799  if (*data == '1') {
2800  if (first)
2801  first = object_decrease_nrof_by_one(first);
2802  data += 2;
2803  } else if (*data == '2') {
2804  if (second)
2805  second = object_decrease_nrof_by_one(second);
2806  data += 2;
2807  } else {
2808  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2809  return 1;
2810  }
2811  } else {
2812  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2813  return 1;
2814  }
2815  }
2816 
2817  return 1;
2818  */
2819 }
Error, serious thing.
Definition: logger.h:11
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:596
void apply_by_living_below(object *pl)
Attempt to apply the object &#39;below&#39; the player.
Definition: apply.cpp:357
void sell_item(object *op, object *pl)
Player is selling an item.
Definition: shop.cpp:909
#define FLAG_NO_DROP
Object can&#39;t be dropped.
Definition: define.h:276
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:15
int apply_special(object *who, object *op, int aflags)
Apply an object.
Definition: apply.cpp:818
void command_throw(object *op, const char *params)
&#39;throw&#39; command.
Definition: c_object.cpp:239
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:223
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
#define MSG_TYPE_COMMAND_INVENTORY
Inventory listing.
Definition: newclient.h:554
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:303
see doc/Developers/objects
Definition: object.h:113
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:586
int change_skill(object *who, object *new_skill, int flag)
This changes the object&#39;s skill to new_skill.
Definition: skill_util.cpp:357
See Key.
Definition: object.h:132
See Ring.
Definition: object.h:190
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:325
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
int item_must_be_pickable
If non zero, then the item number is increased only if the item is pickable.
Definition: c_object.cpp:668
#define FLAG_IS_BUILDABLE
Can build on item.
Definition: define.h:363
bool player_can_find(object *op, object *ob)
Return true if player &#39;op&#39; can see object &#39;op&#39; for purpose of locating items for partial item matchin...
Definition: item.cpp:590
#define PU_CONTAINER
Definition: define.h:143
Eneq((at)csd.uu.se): Id for close_container archetype.
Definition: object.h:234
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
object_split(ob,nr) splits up ob into two parts.
Definition: object.cpp:2622
static int matcher_all(object *who, matcher_params *params, object *item)
Function allowing all objects.
Definition: c_object.cpp:692
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
See Bracers.
Definition: object.h:222
#define PU_DEBUG
Definition: define.h:108
See Scroll.
Definition: object.h:226
int identifyskill
Skill used to identify this object class.
Definition: define.h:93
static int matcher_number(object *who, matcher_params *params, object *item)
Check if an item is the one at the desired position.
Definition: c_object.cpp:706
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Find a recipe for a specified tool.
Definition: recipe.cpp:897
const typedata * get_typedata(int itemtype)
Definition: item.cpp:328
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:552
static item_matcher make_matcher(object *who, const char *params, matcher_params *mp)
Parse parameters and sets up an item matcher based on them.
Definition: c_object.cpp:758
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
See Cloak.
Definition: object.h:209
See Food.
Definition: object.h:117
#define EVENT_PICKUP
Object picked up.
Definition: events.h:36
#define PU_STOP
Definition: define.h:110
See Projectile.
Definition: object.h:122
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:290
#define PU_SHIELD
Definition: define.h:122
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.cpp:1818
int identify_object_with_skill(object *tmp, object *pl, object *skill, int print_on_success)
Helper function for do_skill_ident, so that we can loop over inventory AND objects on the ground conv...
Definition: skills.cpp:819
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:428
#define FLAG_NO_FIX_PLAYER
fix_object() won&#39;t be called
Definition: define.h:264
#define LOOK_OBJ(ob)
This returns TRUE if the object is something that should be displayed in the look window...
Definition: object.h:521
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:239
bool csv_contains(std::string list, std::string item, std::string delim)
Split list by comma, then see if item matches anything in the list.
Definition: c_object.cpp:302
int level
Definition: readable.cpp:1561
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
#define PU_KEY
Definition: define.h:128
uint32_t count
Any numbers typed before a command.
Definition: player.h:124
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
object * drop_object(object *op, object *tmp, uint32_t nrof)
Try to drop an object on the floor.
Definition: c_object.cpp:1025
#define MSG_TYPE_COMMAND_EXAMINE
Player examining something.
Definition: newclient.h:553
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
See Spellbook.
Definition: object.h:208
See Money.
Definition: object.h:142
void examine_wand_charge_level(object *op, object *tmp)
Output charge information for a wand or staff.
Definition: c_object.cpp:1764
#define MSG_TYPE_SPELL_INFO
random info about spell, not related to failure/success
Definition: newclient.h:675
sstring slaying
Which race to do double damage to.
Definition: object.h:327
#define NDI_BLUE
Actually, it is Dodger Blue.
Definition: newclient.h:251
static uint32_t NROF(const object *const ob)
Returns ob->nrof, unless it is 0, in which case return 1.
Definition: object.h:627
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
char name[MAX_BUF]
Name to match for.
Definition: c_object.cpp:670
void stringbuffer_trim_whitespace(StringBuffer *sb)
Trim trailing whitespace from a stringbuffer.
object * above
Pointer to the object stacked above this one.
Definition: object.h:296
Detect curse.
Definition: skills.h:33
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it&#39;s increased effectiveness.
Definition: spell_util.cpp:236
See Weapon.
Definition: object.h:124
method_ret ob_examine(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Get examine text for OP as seen by OBSERVER.
Definition: ob_methods.cpp:113
See Helmet.
Definition: object.h:141
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
#define MSG_TYPE_SKILL_MISSING
Don&#39;t have the skill.
Definition: newclient.h:623
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Check if an item op can be put into a sack.
Definition: container.cpp:66
See Rod.
Definition: object.h:114
int16_t y
Position in the map for this object.
Definition: object.h:335
uint32_t mode
Mode of player for pickup.
Definition: player.h:125
void drop(object *op, object *tmp)
Drop an item, either on the floor or in a container.
Definition: c_object.cpp:1120
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2373
static int matcher_pickup_type(object *who, matcher_params *params, object *item)
Check if an item matches a pickup type.
Definition: c_object.cpp:746
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
See Drink.
Definition: object.h:162
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
See Girdle.
Definition: object.h:228
#define PU_FLESH
Definition: define.h:142
#define PU_FOOD
Definition: define.h:115
object * stop_item(object *op)
An item (ARROW or such) stops moving.
Definition: time.cpp:455
See Amulet.
Definition: object.h:144
Definition: object.h:254
#define FALSE
Definition: compat.h:14
int16_t x
Definition: object.h:335
void inventory(object *op, object *inv)
Prints object&#39;s inventory.
Definition: c_object.cpp:2117
animal &#39;body parts&#39; -b.t.
Definition: object.h:192
Global type definitions and header inclusions.
Link an object type with skill needed to identify, and general name.
Definition: define.h:89
See Boots.
Definition: object.h:217
#define AP_APPLY
Item is to be applied.
Definition: define.h:595
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
#define PU_NEWMODE
Definition: define.h:111
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:308
#define PU_MISSILEWEAPON
Definition: define.h:130
See Wand & Staff.
Definition: object.h:225
void command_apply(object *op, const char *params)
&#39;apply&#39; command.
Definition: c_object.cpp:251
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:777
#define PU_CLOAK
Definition: define.h:127
#define MIN(x, y)
Definition: compat.h:21
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
int32_t weight
Attributes of the object.
Definition: object.h:375
void command_dropall(object *op, const char *params)
Command to drop all items that have not been locked.
Definition: c_object.cpp:1182
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:307
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
bool pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.cpp:470
char method_ret
Define some standard return values for callbacks which don&#39;t need to return any other results...
Definition: ob_methods.h:14
Allows the use of a skill.
Definition: object.h:194
Throwing.
Definition: skills.h:44
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:257
void examine_weight_and_material(object *op, object *tmp)
Output weight and material information for an examined object.
Definition: c_object.cpp:1738
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Try to get information about a living thing.
#define AP_OPEN
Item is a container to be fully opened.
Definition: define.h:597
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:294
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Displays known alchemy recipes an item can be used in.
Definition: knowledge.cpp:1334
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:108
int16_t level
Level of creature or object.
Definition: object.h:361
One alchemy recipe.
Definition: recipe.h:10
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.cpp:4559
int(* item_matcher)(object *who, matcher_params *params, object *item)
Prototype for a function checking if an object matches some parameters.
Definition: c_object.cpp:683
Matching parameters.
Definition: c_object.cpp:663
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:420
#define PU_BOOTS
Definition: define.h:125
See Shooting Weapon.
Definition: object.h:123
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Living thing is applying an object.
Definition: apply.cpp:299
void query_weight(const object *op, char *buf, size_t size)
Formats the item&#39;s weight.
Definition: item.cpp:420
Disarm traps.
Definition: skills.h:46
#define PU_CURSED
Definition: define.h:144
See Book.
Definition: object.h:119
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Runs a &#39;detect curse&#39; check on a given item.
Definition: skills.cpp:712
uint64_t shop_price_buy(const object *obj, object *who)
Adjust the value of an item to be bought based on the player&#39;s bargaining skill and charisma...
Definition: shop.cpp:128
sstring materialname
Specific material name.
Definition: object.h:356
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
This function inserts the object in the two-way linked list which represents what is on a map...
Definition: object.cpp:2346
char * cost_approx_str(const object *obj, object *who)
Return a textual cost approximation in a newly-allocated string.
Definition: shop.cpp:312
void command_examine(object *op, const char *params)
&#39;examine&#39; command.
Definition: c_object.cpp:1441
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:551
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:550
Defines for loader.l / loader.c.
#define PU_SKILLSCROLL
Definition: define.h:136
uint8_t search_items
Search_items command.
Definition: global.h:268
int32_t carrying
How much weight this object contains.
Definition: object.h:377
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Returns the description (short item name) of an object, as seen by the given observer.
Definition: ob_methods.cpp:92
int item_to_pick
Index of the item to pick, 1-based.
Definition: c_object.cpp:666
See Special Key.
Definition: object.h:129
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:360
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.cpp:276
static bool IS_PLAYER(object *op)
Definition: object.h:611
object * env
Pointer to the object which is the environment.
Definition: object.h:301
#define SET_FLAG(xyz, p)
Definition: define.h:384
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
tag_t last_examined
Tag of most recently &#39;examined object.
Definition: player.h:167
#define QUERY_FLAG(xyz, p)
Definition: define.h:386
#define PU_ARROW
Definition: define.h:120
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.cpp:1545
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:700
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:401
socket_struct * socket
Socket information for this player.
Definition: player.h:109
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
static int matcher_name(object *who, matcher_params *params, object *item)
Check if an item matches a string.
Definition: c_object.cpp:726
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
This is a game-map.
Definition: map.h:320
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:244
#define PU_INHIBIT
Definition: define.h:109
#define PU_BOW
Definition: define.h:118
#define AP_NULL
Nothing specific.
Definition: define.h:594
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
int yield
Maximum number of items produced by the recipe.
Definition: recipe.h:21
static void do_skill_by_number(object *op, int skill_subtype, const char *params, const char *missing_message)
Attempt to use a skill from its subtype.
Definition: c_object.cpp:188
#define PU_RATIO
Definition: define.h:113
int item_number
Index of the checked item, 1-based.
Definition: c_object.cpp:667
void examine(object *op, object *tmp)
Player examines some object.
Definition: c_object.cpp:1937
char * cost_str(uint64_t cost)
Definition: shop.cpp:308
Detect magic.
Definition: skills.h:30
int is_identified(const object *op)
Return true if the item is identified, either because it is of a type that doesn&#39;t ever need identifi...
Definition: item.cpp:1357
#define UPD_FLAGS
Definition: newclient.h:331
uint32_t mark_count
Count of marked object.
Definition: player.h:214
#define FLAG_IS_CAULDRON
container can make alchemical stuff
Definition: define.h:326
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Main skills use function-similar in scope to cast_spell().
Definition: skill_util.cpp:443
uint8_t real_wiz
Use mud-like wizards.
Definition: global.h:272
See Potion.
Definition: object.h:116
#define PU_DRINK
Definition: define.h:116
Find traps.
Definition: skills.h:34
struct Settings settings
Global settings.
Definition: init.cpp:139
sstring lore
Obscure information about this object, to get put into books and the like.
Definition: object.h:332
object * object_present_in_ob(uint8_t type, const object *op)
Searches for any objects with a matching type variable in the inventory of the given object...
Definition: object.cpp:3153
void examine_rod_charge_level(object *op, object *tmp)
Output charge information for a rod.
Definition: c_object.cpp:1793
const char * use_name
Name used when describing an item we can use.
Definition: object.h:24
#define UPD_WEIGHT
Definition: newclient.h:332
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
void command_rskill(object *pl, const char *params)
&#39;ready_skill&#39; command.
Definition: c_object.cpp:161
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:609
int object_matches_pickup_mode(const object *item, int mode)
Checks if an item matches a specific pickup mode.
Definition: c_object.cpp:608
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
living stats
Str, Con, Dex, etc.
Definition: object.h:378
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
#define METHOD_UNHANDLED
Definition: ob_methods.h:16
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
#define PU_READABLES
Definition: define.h:137
const char * nonuse_name
Name to describe objects we can&#39;t use.
Definition: object.h:25
archetype * get_archetype_by_skill_name(const char *skill, int type)
Retrieves an archetype by skill name and type.
Definition: arch.cpp:78
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
can add a skill to player&#39;s inventory -bt.
Definition: object.h:239
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
Skill-related defines, including subtypes.
uint64_t shop_price_sell(const object *obj, object *who)
Adjust the value of an item to be sold based on the player&#39;s bargaining skill and charisma...
Definition: shop.cpp:154
ex_autoid_result
Definition: c_object.cpp:1645
object * mark
Marked object.
Definition: player.h:215
bool examine_fluff(object *op, object *tmp, bool output)
Emit the "fluff", the non-mechanical flavour text, for a given item.
Definition: c_object.cpp:1825
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.cpp:3852
See Container.
Definition: object.h:236
#define FLAG_IS_THROWN
Object is designed to be thrown.
Definition: define.h:236
static const char * pickup_names[]
Valid names for pickup types.
Definition: c_object.cpp:33
int identifyskill2
Second skill used to identify this object class.
Definition: define.h:94
void command_search(object *op, const char *params)
&#39;search&#39; command.
Definition: c_object.cpp:212
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: map.cpp:2763
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Find object in inventory by type and name.
Definition: object.cpp:4093
void knowledge_add_probe_monster(object *op, object *mon)
Display monster details, then add to a player&#39;s knowledge if not already.
Definition: knowledge.cpp:1528
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:308
object * object_merge(object *op, object *top)
This function goes through all objects below and including top, and merges op to the first matching o...
Definition: object.cpp:2036
ex_autoid_result examine_autoidentify(object *op, object *tmp)
When the player examines an unidentified object, try to ID it if they have the requisite skills...
Definition: c_object.cpp:1662
See Player.
Definition: object.h:112
See Poison Food.
Definition: object.h:118
#define AP_NO_MERGE
Don&#39;t try to merge object after (un)applying it.
Definition: define.h:602
See Shield.
Definition: object.h:140
static int get_pickup_mode_index(const char *name)
Return the pickup index in pickup_names and pickup_modes associated with the specified name...
Definition: c_object.cpp:58
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:382
const char * name
Definition: global.h:99
sstring name_pl
The plural name of the object.
Definition: object.h:323
#define PU_MELEEWEAPON
Definition: define.h:131
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:692
void command_disarm(object *op, const char *params)
&#39;disarm&#39; command.
Definition: c_object.cpp:224
#define INS_NO_MERGE
Don&#39;t try to merge with other items.
Definition: object.h:582
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Runs a &#39;detect magic&#39; check on a given item.
Definition: skills.cpp:761
object * container
Current container being used.
Definition: object.h:299
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
#define VERY_BIG_BUF
Definition: define.h:36
static void set_pickup_mode(const object *op, int i)
Sets the &#39;old&#39; pickup mode.
Definition: c_object.cpp:2376
Also see SKILL_TOOL (74) below.
Definition: object.h:148
void command_empty(object *op, const char *params)
&#39;empty&#39; command.
Definition: c_object.cpp:1402
void examine_monster(object *op, object *tmp, int level)
Player examine a monster.
Definition: c_object.cpp:1566
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
sstring name
The name of the object, obviously...
Definition: object.h:319
#define SCRIPT_FIX_ALL
Definition: global.h:380
Only for debugging purposes.
Definition: logger.h:13
uint32_t nrof
Number of objects.
Definition: object.h:342
sstring name
Usually monster-name/combination.
Definition: treasure.h:86
MoveType move_off
Move types affected moving off this space.
Definition: object.h:440
void command_use(object *op, const char *params)
Try to use an item on another.
Definition: c_object.cpp:2703
static object * find_best_object_match(object *pl, const char *params)
Shortcut to find_best_apply_object_match(pl->inv, pl, params, AF_NULL);.
Definition: c_object.cpp:132
int set_object_face_main(object *op)
Makes an object&#39;s face the main face, which is supposed to be the "closed" one.
Definition: container.cpp:127
#define SPELL_HIGHEST
Definition: spells.h:60
void command_drop(object *op, const char *params)
&#39;drop&#39; command.
Definition: c_object.cpp:1306
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:547
#define CLEAR_FLAG(xyz, p)
Definition: define.h:385
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
static void empty_container(object *container, object *pl)
Put all contents of the container on the ground below the player or in opened container, except locked items.
Definition: c_object.cpp:1364
char search_str[MAX_BUF]
Item we are looking for.
Definition: player.h:213
int transport_can_hold(const object *transport, const object *op, int nrof)
Can transport hold object op? This is a pretty trivial function, but in the future, possible transport may have more restrictions or weight reduction like containers.
Definition: apply.cpp:54
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
#define PU_SPELLBOOK
Definition: define.h:135
#define UPD_NAME
Definition: newclient.h:334
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
The ordering of this is actually doesn&#39;t make a difference However, for ease of use, new entries should go at the end so those people that debug the code that get used to something being in the location 4 don&#39;t get confused.
Definition: item.cpp:56
int object_set_value(object *op, const char *key, const char *value, int add_key)
Updates the key in op to value.
Definition: object.cpp:4484
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:773
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:255
#define FORCE_NAME
Definition: spells.h:169
void command_take(object *op, const char *params)
This takes (picks up) an item.
Definition: c_object.cpp:797
#define PU_VALUABLES
Definition: define.h:117
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.cpp:749
void command_rename_item(object *op, const char *params)
Changing the custom name of an item.
Definition: c_object.cpp:2474
#define PU_MAGICAL
Definition: define.h:132
static object * find_best_apply_object_match(object *start, object *pl, const char *params, int aflag)
Search from start and through below for what matches best with params.
Definition: c_object.cpp:101
object * find_marked_object(object *op)
Return the object the player has marked with the &#39;mark&#39; command below.
Definition: c_object.cpp:1472
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
#define PU_JEWELS
Definition: define.h:141
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1880
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:424
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Execute an event on the specified object.
Definition: events.cpp:309
int pickup_type
Value in Pickup modes to match against.
Definition: c_object.cpp:671
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:270
See Gloves.
Definition: object.h:218
#define PU_GLOVES
Definition: define.h:126
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:221
int32_t food
How much food in stomach.
Definition: living.h:48
StringBuffer * buf
Definition: readable.cpp:1563
Structure containing object statistics.
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Something tries to put an object into another.
Definition: c_object.cpp:889
void command_search_items(object *op, const char *params)
&#39;search-items&#39; command.
Definition: c_object.cpp:2429
static void pick_up_object(object *pl, object *op, object *tmp, int nrof)
Try to pick up some item.
Definition: c_object.cpp:329
A buffer that will be expanded as content is added to it.
int16_t maxhp
Max hit points.
Definition: living.h:41
#define PU_ARMOUR
Definition: define.h:123
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:727
#define SK_SUBTRACT_SKILL_EXP
Used when removing exp.
Definition: skills.h:81
object * object_get_player_container(object *op)
Finds the player carrying an object.
Definition: object.cpp:592
object * find_skill_by_number(object *who, int skillno)
This returns the first skill pointer of the given subtype (the one that accumulates exp...
Definition: main.cpp:375
const char * sstring
Definition: sstring.h:2
int missed
How many items were missed when matching.
Definition: c_object.cpp:673
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.cpp:2085
void command_uskill(object *pl, const char *params)
&#39;use_skill&#39; command.
Definition: c_object.cpp:144
int use_skill(object *op, const char *string)
Similar to invoke command, it executes the skill in the direction that the user is facing...
Definition: skill_util.cpp:988
int ingred_count
Number of items in ingred.
Definition: recipe.h:23
See Jewel.
Definition: object.h:172
tag_t count
Unique object number for this object.
Definition: object.h:307
void command_lock_item(object *op, const char *params)
Alternate way to lock/unlock items (command line).
Definition: c_object.cpp:2660
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:226
#define PU_POTION
Definition: define.h:133
#define FLAG_NO_SKILL_IDENT
If set, item cannot be identified w/ a skill.
Definition: define.h:323
#define NDI_GOLD
Definition: newclient.h:259
See Breastplate Armor.
Definition: object.h:125
void command_mark(object *op, const char *params)
&#39;mark&#39; command, to mark an item for some effects (enchant armor, ...).
Definition: c_object.cpp:1519
#define PU_HELMET
Definition: define.h:121
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn&#39;t contain any information about object...
Definition: item.cpp:518
#define AT_ACID
Random equipped item might corrode when hit (64)
Definition: attack.h:84
static void display_new_pickup(const object *op, int old)
Utility function to display the pickup mode for a player.
Definition: c_object.cpp:2182
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:317
#define PU_NOT_CURSED
Definition: define.h:140
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: skill_util.cpp:209
object clone
An object from which to do object_copy()
Definition: object.h:487
void command_pickup(object *op, const char *params)
&#39;pickup&#39; command.
Definition: c_object.cpp:2311
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:734
#define CUSTOM_NAME_FIELD
Key in an object for the player-assigned custom name.
Definition: object.h:98
int8_t Str
Use
Definition: living.h:36
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:693
#define EVENT_DROP
Object dropped on the floor.
Definition: events.h:35
int16_t hp
Hit Points.
Definition: living.h:40
static const uint32_t pickup_modes[]
Value in Pickup modes associated with pickup_names.
Definition: c_object.cpp:43
#define PU_MAGIC_DEVICE
Definition: define.h:138
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
Definition: object.h:229