Crossfire Server, Trunk  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 
317 int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof) {
318  char name[MAX_BUF];
319  query_name(sack, name, MAX_BUF);
320 
321  if (!QUERY_FLAG(sack, FLAG_APPLIED)) {
323  "The %s is not active.",
324  name);
325  return 0;
326  }
327  if (sack == op) {
329  "You can't put the %s into itself.",
330  name);
331  return 0;
332  }
333  if (sack->race
334  && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type))) {
336  "You can put only %s into the %s.",
337  sack->race, name);
338  return 0;
339  }
340  if (op->type == SPECIAL_KEY && sack->slaying && op->slaying) {
342  "You can't put the key into %s.",
343  name);
344  return 0;
345  }
346  if (sack->weight_limit) {
347  int32_t new_weight;
348 
349  new_weight = sack->carrying+(nrof ? nrof : 1)
350  /* Most non-containers should have op->carrying == 0. Icecubes, however, will not,
351  * and we need to handle those.
352  * Neila Hawkins 2021-01-21
353  */
354  *(op->weight+(op->type == CONTAINER ? op->carrying*op->stats.Str : op->carrying))
355  *(100-sack->stats.Str)/100;
356  if (new_weight > sack->weight_limit) {
358  "That won't fit in the %s!",
359  name);
360  return 0;
361  }
362  }
363  /* All other checks pass, must be OK */
364  return 1;
365 }
366 
379 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
380  /* buf needs to be big (more than 256 chars) because you can get
381  * very long item names.
382  */
383  char buf[HUGE_BUF], name[MAX_BUF];
384  object *env = tmp->env;
385  uint32_t weight, effective_weight_limit;
386  const int tmp_nrof = NROF(tmp);
387  tag_t tag;
388  mapstruct* map = tmp->map;
389  int16_t x = tmp->x, y = tmp->y;
390 
391  /* IF the player is flying & trying to take the item out of a container
392  * that is in his inventory, let him. tmp->env points to the container
393  * (sack, luggage, etc), tmp->env->env then points to the player (nested
394  * containers not allowed as of now)
395  */
396  if ((pl->move_type&MOVE_FLYING)
397  && !QUERY_FLAG(pl, FLAG_WIZ)
398  && object_get_player_container(tmp) != pl) {
400  "You are levitating, you can't reach the ground!");
401  return;
402  }
403  if (QUERY_FLAG(tmp, FLAG_NO_DROP))
404  return;
405 
406  if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
408  "The object disappears in a puff of smoke! It must have been an illusion.");
409  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
410  object_remove(tmp);
412  return;
413  }
414 
415  if (nrof > tmp_nrof || nrof == 0)
416  nrof = tmp_nrof;
417 
418  /* Figure out how much weight this object will add to the player */
419  weight = tmp->weight*nrof;
420  if (tmp->inv)
421  weight += tmp->carrying*(100-tmp->stats.Str)/100;
422 
423  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
424 
425  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
427  "That item is too heavy for you to pick up.");
428  return;
429  }
430 
432  SET_FLAG(tmp, FLAG_WAS_WIZ);
433 
434  if (nrof != tmp_nrof) {
435  char failure[MAX_BUF];
436 
437  tmp = object_split(tmp, nrof, failure, sizeof(failure));
438  if (!tmp) {
440  failure);
441  return;
442  }
443  } else {
444  /* If the object is in a container, send a delete to the client.
445  * - we are moving all the items from the container to elsewhere,
446  * so it needs to be deleted.
447  */
448  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
449  object_remove(tmp); /* Unlink it */
450  }
451  }
452  query_name(tmp, name, MAX_BUF);
453 
454  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
455  char *value = cost_str(shop_price_buy(tmp, pl));
456  if (op == pl) {
457  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
458  } else {
459  snprintf(buf, sizeof(buf), "%s will cost you %s. You place it in your %s.", name, value, op->name);
460  }
461  free(value);
462  } else {
463  if (op == pl) {
464  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
465  } else {
466  snprintf(buf, sizeof(buf), "You pick up the %s and put it in your %s.", name, op->name);
467  }
468  }
469 
470  /* Now item is about to be picked. */
471  tag = tmp->count;
472  if (events_execute_object_event(tmp, EVENT_PICKUP, pl, op, NULL, SCRIPT_FIX_ALL) != 0) {
473  /* put item back, if it still exists */
474  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
475  if (env != NULL) {
476  object_insert_in_ob(tmp, env);
477  } else {
478  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
479  }
480  }
481  return;
482  }
483 
485  buf);
486 
487  object_insert_in_ob(tmp, op);
488 
489  /* All the stuff below deals with client/server code, and is only
490  * usable by players
491  */
492  if (pl->type != PLAYER)
493  return;
494 
495  /* Additional weight changes speed, etc */
496  fix_object(pl);
497 
498  /* These are needed to update the weight for the container we
499  * are putting the object in.
500  */
501  if (op != pl) {
502  esrv_update_item(UPD_WEIGHT, pl, op);
503  esrv_update_item(UPD_WEIGHT, pl, pl);
504  }
505 
506  /* Update the container the object was in */
507  if (env && env != pl && env != op)
509 }
510 
519 void pick_up(object *op, object *alt) {
520 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
521  object *tmp = NULL, *tmp1;
522  mapstruct *tmp_map = NULL;
523  int count;
524 
525  /* Decide which object to pick. */
526  if (alt) {
527  if (!object_can_pick(op, alt)) {
529  "You can't pick up the %s.",
530  alt->name);
531  return;
532  }
533  tmp = alt;
534  } else {
535  if (op->below == NULL || !object_can_pick(op, op->below)) {
537  "There is nothing to pick up here.");
538  return;
539  }
540  tmp = op->below;
541  }
542 
543  /* it is possible that the object is a thrown object and is flying about.
544  * in that case, what we want to pick up is the payload. Objects
545  * that are thrown are encapsulated into a thrown object.
546  * stop_item() returns the payload (unlinked from map) and gets rid of the
547  * container object. If this object isn't picked up, we need to insert
548  * it back on the map.
549  * A bug here is that even attempting to pick up one of these objects will
550  * result in this logic being called even if player is unable to pick it
551  * up.
552  */
553 
554  tmp_map = tmp->map;
555  tmp1 = stop_item(tmp);
556  if (tmp1 == NULL)
557  return;
558 
559  /* If it is a thrown object, insert it back into the map here.
560  * makes life easier further along. Do no merge so pick up code
561  * behaves more sanely.
562  */
563  if (tmp1 != tmp) {
564  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
565  }
566 
567  if (tmp == NULL)
568  return;
569 
570  if (!object_can_pick(op, tmp))
571  return;
572 
573  /* Establish how many of the object we are picking up */
574  if (op->type == PLAYER) {
575  count = op->contr->count;
576  if (count == 0)
577  count = tmp->nrof;
578  } else
579  count = tmp->nrof;
580 
581  /* container is open, so use it */
582  if (op->container) {
583  alt = op->container;
584  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
585  return;
586  } else {
587  /* non container pickup. See if player has any
588  * active containers.
589  */
590  object *container = NULL;
591 
592  /* Look for any active containers that can hold this item.
593  * we cover two cases here - the perfect match case, where we
594  * break out of the loop, and the general case (have a container),
595  * Moved this into a single loop - reduces redundant code, is
596  * more efficient and easier to follow. MSW 2009-04-06
597  */
598  alt = op->inv;
600  if (alt->type == CONTAINER
601  && QUERY_FLAG(alt, FLAG_APPLIED)
602  && sack_can_hold(NULL, alt, tmp, count)) {
603  if (alt->race && alt->race == tmp->race) {
604  break; /* perfect match */
605  } else if (!container) {
606  container = alt;
607  }
608  }
610  /* Note container could be null, but no reason to check for it */
611  if (!alt)
612  alt = container;
613 
614  if (!alt)
615  alt = op; /* No free containers */
616  }
617  /* see if this object is already in this container. If so,
618  * move it to player inventory from this container.
619  */
620  if (tmp->env == alt) {
621  alt = op;
622  }
623 
624  /* Don't allow players to be put into containers. Instead,
625  * just put them in the players inventory.
626  */
627  if ((tmp->type == CONTAINER || tmp->type == MIMIC) && alt->type==CONTAINER) {
628  alt = op;
629  }
630 #ifdef PICKUP_DEBUG
631  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
632 #endif
633 
634  /* startequip items are not allowed to be put into containers
635  * Not sure why we have this limitation
636  */
637  if (op->type == PLAYER
638  && alt->type == CONTAINER
639  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
641  "This object cannot be put into containers!");
642  return;
643  }
644 
645  pick_up_object(op, alt, tmp, count);
646  if (op->type == PLAYER)
647  op->contr->count = 0;
648 }
649 
656 int object_matches_pickup_mode(const object *item, int mode) {
657  switch(mode) {
658  case PU_FOOD:
659  return item->type == FOOD;
660  case PU_DRINK:
661  return item->type == DRINK || (item->type == POISON && !QUERY_FLAG(item, FLAG_KNOWN_CURSED));
662  case PU_FLESH:
663  return item->type == FLESH;
664  case PU_POTION:
665  return item->type == POTION;
666  case PU_SPELLBOOK:
667  return item->type == SPELLBOOK;
668  case PU_SKILLSCROLL:
669  return item->type == SKILLSCROLL;
670  case PU_READABLES:
671  return item->type == BOOK || item->type == SCROLL;
672  case PU_MAGIC_DEVICE:
673  return item->type == WAND || item->type == ROD || item->type == WEAPON_IMPROVER || item->type == ARMOUR_IMPROVER || item->type == SKILL_TOOL;
674  case PU_MAGICAL:
676  case PU_VALUABLES:
677  return item->type == MONEY || item->type == GEM;
678  case PU_JEWELS:
679  return item->type == RING || item->type == AMULET;
680  case PU_BOW:
681  return item->type == BOW;
682  case PU_ARROW:
683  return item->type == ARROW;
684  case PU_ARMOUR:
685  return item->type == ARMOUR;
686  case PU_HELMET:
687  return item->type == HELMET;
688  case PU_SHIELD:
689  return item->type == SHIELD;
690  case PU_BOOTS:
691  return item->type == BOOTS;
692  case PU_GLOVES:
693  return item->type == GLOVES;
694  case PU_CLOAK:
695  return item->type == CLOAK;
696  case PU_MISSILEWEAPON:
697  return item->type == WEAPON && QUERY_FLAG(item, FLAG_IS_THROWN);
698  case PU_MELEEWEAPON:
699  return item->type == WEAPON;
700  case PU_KEY:
701  return item->type == KEY || item->type == SPECIAL_KEY;
702  case PU_CONTAINER:
703  return item->type == CONTAINER;
704  case PU_CURSED:
705  return QUERY_FLAG(item, FLAG_KNOWN_CURSED);
706  }
707  return 0;
708 }
709 
712  union {
713  struct {
717  };
718  char name[MAX_BUF];
720  };
721  int missed;
722 };
723 
731 typedef int (*item_matcher)(object *who, matcher_params *params, object *item);
732 
740 static int matcher_all(object *who, matcher_params *params, object *item) {
741  (void)who;
742  (void)params;
743  (void)item;
744  return 1;
745 }
746 
754 static int matcher_number(object *who, matcher_params *params, object *item) {
755  if (params->item_must_be_pickable == 0 || object_can_pick(who, item)) {
756  params->item_number++;
757  }
758  if (params->item_to_pick == params->item_number) {
759  /* Since we don't always increase item_number, multiple items may have the same index,
760  including unpickable ones, so to avoid failure messages just ensure no other item can be picked. */
761  params->item_to_pick = 0;
762  return 1;
763  }
764  return 0;
765 }
766 
774 static int matcher_name(object *who, matcher_params *params, object *item) {
775  int ival = object_matches_string(who, item, params->name);
776  if (ival > 0) {
777  if (ival <= 2 && !object_can_pick(who, item)) {
778  if (!QUERY_FLAG(item, FLAG_IS_FLOOR))/* don't count floor tiles */
779  params->missed++;
780  return 0;
781  }
782  return 1;
783  }
784  return 0;
785 }
786 
794 static int matcher_pickup_type(object *who, matcher_params *params, object *item) {
795  (void)who;
796  return object_matches_pickup_mode(item, params->pickup_type);
797 }
798 
806 static item_matcher make_matcher(object *who, const char *params, matcher_params *mp) {
807  memset(mp, 0, sizeof(*mp));
808  if (params[0] == '\0') {
809  mp->item_to_pick = 1;
810  mp->item_must_be_pickable = 1;
811  return &matcher_number;
812  }
813  if (params[0] == '#') {
814  mp->item_to_pick = atoi(params + 1);
815  if (mp->item_to_pick == 0) {
817  return NULL;
818  }
819  return &matcher_number;
820  }
821  if (params[0] == '*') {
822  if (params[1] == '\0') {
823  return &matcher_all;
824  }
825  int idx = get_pickup_mode_index(params + 1);
826  if (idx == -1) {
827  draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, "Invalid items %s", params + 1);
828  return NULL;
829  }
830  mp->pickup_type = pickup_modes[idx];
831  return &matcher_pickup_type;
832  }
833  strncpy(mp->name, params, sizeof(mp->name) - 1);
834  return &matcher_name;
835 }
836 
845 void command_take(object *op, const char *params) {
846  object *tmp;
847  int did_one = 0;
848 
849  if (op->container)
850  tmp = op->container->inv;
851  else {
852  tmp = op->above;
853  if (tmp)
854  while (tmp->above) {
855  tmp = tmp->above;
856  }
857  if (!tmp)
858  tmp = op->below;
859  }
860 
861  if (tmp == NULL) {
863  "Nothing to take!");
864  return;
865  }
866 
867  matcher_params mp;
868  item_matcher matcher = make_matcher(op, params, &mp);
869  if (!matcher) {
870  return; // Player already informed of failure.
871  }
872 
874 
876  if (tmp->invisible) {
877  continue;
878  }
879  if ((*matcher)(op, &mp, tmp)) {
880  pick_up(op, tmp);
881  did_one = 1;
882  }
884 
885  /* Nothing picked up, check if unable to pick or nothing to pick. */
886  if (params[0] == '\0' && !did_one) {
887  int found = 0;
888  FOR_BELOW_PREPARE(op, tmp)
889  if (!tmp->invisible) {
891  "You can't pick up a %s.",
892  tmp->name ? tmp->name : "null");
893  found = 1;
894  break;
895  }
897  if (!found)
899  "There is nothing to pick up.");
900  }
901 
902  if (mp.missed == 1)
904  "You were unable to take one of the items.");
905  else if (mp.missed > 1)
907  "You were unable to take %d of the items.",
908  mp.missed);
909 
910  /* Now update player and send information. */
912  fix_object(op);
913  if (op->type == PLAYER) {
914  op->contr->count = 0;
915  esrv_update_item(UPD_WEIGHT, op, op);
916  }
917 }
918 
937 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
938  object *sack2, *orig = sack;
939  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
940 
941  if (sack == tmp)
942  return; /* Can't put an object in itself */
943  query_name(sack, name_sack, MAX_BUF);
944  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
946  "The %s is not a container.",
947  name_sack);
948  return;
949  }
950  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
951  query_name(tmp, name_tmp, MAX_BUF);
953  "You cannot put the %s in the %s.",
954  name_tmp, name_sack);
955  return;
956  }
957  if (tmp->type == CONTAINER) {
958  if (tmp->inv) {
959  if (tmp->slaying)
960  return;
961  /* Eneq(@csd.uu.se): If the object to be dropped is a container
962  * and does not require a key to be opened,
963  * we instead move the contents of that container into the active
964  * container, this is only done if the object has something in it.
965  * If object is container but need a key, just don't do anything
966  */
967  sack2 = tmp;
968  query_name(tmp, name_tmp, MAX_BUF);
970  "You move the items from %s into %s.",
971  name_tmp, name_sack);
972 
973  FOR_INV_PREPARE(tmp, tmp2) {
974  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
975  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
976  put_object_in_sack(op, sack, tmp2, 0);
977  } else {
980  "Your %s fills up.",
981  name_sack);
982  break;
983  }
984  } FOR_INV_FINISH();
985  esrv_update_item(UPD_WEIGHT, op, sack2);
986  return;
987  } else {
988  query_name(tmp, name_tmp, MAX_BUF);
990  "You can not put a %s into a %s",
991  name_tmp,
992  name_sack);
993  return;
994  }
995  }
996 
997  /* Don't worry about this for containers - our caller should have
998  * already checked this.
999  */
1000  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
1001  return;
1002 
1003  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1004  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
1005  return;
1006  }
1007 
1008  /* we want to put some portion of the item into the container */
1009  if (nrof && tmp->nrof != nrof) {
1010  char failure[MAX_BUF];
1011 
1012  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1013 
1014  if (!tmp) {
1016  failure);
1017  return;
1018  }
1019  } else
1020  object_remove(tmp);
1021 
1022  if (sack->nrof > 1) {
1023  orig = object_split(sack, sack->nrof-1, NULL, 0);
1024  set_object_face_main(orig);
1025  CLEAR_FLAG(orig, FLAG_APPLIED);
1026  if (sack->env) {
1027  object_insert_in_ob(orig, sack->env);
1028  } else {
1029  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
1030  orig->move_off = 0;
1031  }
1032  }
1033 
1034  query_name(tmp, name_tmp, MAX_BUF);
1036  "You put the %s in %s.",
1037  name_tmp, name_sack);
1038 
1039  object_insert_in_ob(tmp, sack);
1040  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1041  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1042  /* in object.c */
1043 
1044  /* If a transport, need to update all the players in the transport
1045  * the view of what is in it.
1046  */
1047  if (sack->type == TRANSPORT) {
1048  FOR_INV_PREPARE(sack, tmp)
1049  if (tmp->type == PLAYER)
1050  tmp->contr->socket->update_look = 1;
1051  FOR_INV_FINISH();
1052  } else {
1053  /* update the sacks weight */
1054  esrv_update_item(UPD_WEIGHT, op, sack);
1055  }
1056 }
1057 
1073 object *drop_object(object *op, object *tmp, uint32_t nrof) {
1074  tag_t tmp_tag;
1075 
1076  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1077  return NULL;
1078  }
1079 
1080  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1081  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
1082  return NULL; /* can't unapply it */
1083  }
1084 
1085  if (events_execute_object_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1086  return NULL;
1087 
1088  /* ensure the plugin didn't destroy the object */
1089  if (QUERY_FLAG(tmp, FLAG_REMOVED))
1090  return NULL;
1091 
1092  /* We are only dropping some of the items. We split the current objec
1093  * off
1094  */
1095  if (nrof && tmp->nrof != nrof) {
1096  char failure[MAX_BUF];
1097 
1098  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1099  if (!tmp) {
1101  failure);
1102  return NULL;
1103  }
1104  } else
1105  object_remove(tmp);
1106 
1107  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
1108  char name[MAX_BUF];
1109 
1110  query_name(tmp, name, MAX_BUF);
1112  "You drop the %s. The gods who lent it to you retrieve it.",
1113  name);
1115 
1116  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1117  fix_object(op);
1118 
1119  return NULL;
1120  }
1121 
1122  /* If SAVE_INTERVAL is commented out, we never want to save
1123  * the player here.
1124  */
1125 #ifdef SAVE_INTERVAL
1126  /* I'm not sure why there is a value check - since the save
1127  * is done every SAVE_INTERVAL seconds, why care the value
1128  * of what he is dropping?
1129  */
1130  if (op->type == PLAYER
1131  && !QUERY_FLAG(tmp, FLAG_UNPAID)
1132  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
1133  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
1134  save_player(op, 1);
1135  op->contr->last_save_time = time(NULL);
1136  }
1137 #endif /* SAVE_INTERVAL */
1138 
1139 
1140  tmp_tag = tmp->count;
1141  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
1142  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
1143  sell_item(tmp, op);
1144  }
1145 
1146  /* Call this before we update the various windows/players. At least
1147  * that we, we know the weight is correct.
1148  */
1149  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
1150  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1151  /* in object.c */
1152 
1153  /* Need to update weight of player */
1154  if (op->type == PLAYER)
1155  esrv_update_item(UPD_WEIGHT, op, op);
1156  }
1157  return tmp;
1158 }
1159 
1168 void drop(object *op, object *tmp) {
1169  /* Hopeful fix for disappearing objects when dropping from a container -
1170  * somehow, players get an invisible object in the container, and the
1171  * old logic would skip over invisible objects - works fine for the
1172  * playes inventory, but drop inventory wants to use the next value.
1173  */
1174  if (tmp->invisible) {
1175  /* if the following is the case, it must be in an container. */
1176  if (tmp->env && tmp->env->type != PLAYER) {
1177  /* Just toss the object - probably shouldn't be hanging
1178  * around anyways
1179  */
1180  object_remove(tmp);
1182  return;
1183  } else {
1185  if (!tmp->invisible)
1186  break;
1188  }
1189  }
1190 
1191  if (tmp == NULL) {
1193  "You don't have anything to drop.");
1194  return;
1195  }
1196  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1198  "This item is locked");
1199  return;
1200  }
1201  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1202  return;
1203  }
1204 
1205  if (op->container) {
1206  if (op->type == PLAYER) {
1207  put_object_in_sack(op, op->container, tmp, op->contr->count);
1208  } else {
1209  put_object_in_sack(op, op->container, tmp, 0);
1210  };
1211  } else {
1212  if (op->type == PLAYER) {
1213  drop_object(op, tmp, op->contr->count);
1214  } else {
1215  drop_object(op, tmp, 0);
1216  };
1217  }
1218  if (op->type == PLAYER)
1219  op->contr->count = 0;
1220 }
1221 
1230 void command_dropall(object *op, const char *params) {
1231  int count = 0;
1232 
1233  if (op->inv == NULL) {
1234  draw_ext_info(NDI_UNIQUE, 0, op,
1236  "Nothing to drop!");
1237  return;
1238  }
1239 
1240  if (op->contr)
1241  count = op->contr->count;
1242 
1243  /* Set this so we don't call it for _every_ object that
1244  * is dropped.
1245  */
1247 
1248  /*
1249  * This is the default. Drops everything not locked or considered
1250  * not something that should be dropped.
1251  * Care must be taken that the next item pointer is not to money as
1252  * the drop() routine will do unknown things to it when dropping
1253  * in a shop. --Tero.Pelander@utu.fi
1254  */
1255  if (*params == '\0') {
1256  FOR_INV_PREPARE(op, curinv) {
1257  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1258  && curinv->type != MONEY
1259  && curinv->type != FOOD
1260  && curinv->type != KEY
1261  && curinv->type != SPECIAL_KEY
1262  && curinv->type != GEM
1263  && !curinv->invisible
1264  && (curinv->type != CONTAINER || op->container != curinv)) {
1265  drop(op, curinv);
1266  if (op->contr)
1267  op->contr->count = count;
1268  }
1269  } FOR_INV_FINISH();
1270  } else if (strcmp(params, "weapons") == 0) {
1271  FOR_INV_PREPARE(op, curinv) {
1272  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1273  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1274  drop(op, curinv);
1275  if (op->contr)
1276  op->contr->count = count;
1277  }
1278  } FOR_INV_FINISH();
1279  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1280  FOR_INV_PREPARE(op, curinv) {
1281  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1282  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1283  drop(op, curinv);
1284  if (op->contr)
1285  op->contr->count = count;
1286  }
1287  } FOR_INV_FINISH();
1288  } else if (strcmp(params, "food") == 0) {
1289  FOR_INV_PREPARE(op, curinv) {
1290  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1291  && (curinv->type == FOOD || curinv->type == DRINK)) {
1292  drop(op, curinv);
1293  if (op->contr)
1294  op->contr->count = count;
1295  }
1296  } FOR_INV_FINISH();
1297  } else if (strcmp(params, "flesh") == 0) {
1298  FOR_INV_PREPARE(op, curinv) {
1299  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1300  && (curinv->type == FLESH)) {
1301  drop(op, curinv);
1302  if (op->contr)
1303  op->contr->count = count;
1304  }
1305  } FOR_INV_FINISH();
1306  } else if (strcmp(params, "misc") == 0) {
1307  FOR_INV_PREPARE(op, curinv) {
1308  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1309  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1310  switch (curinv->type) {
1311  case BOOK:
1312  case SPELLBOOK:
1313  case GIRDLE:
1314  case AMULET:
1315  case RING:
1316  case CLOAK:
1317  case BOOTS:
1318  case GLOVES:
1319  case BRACERS:
1320  case SCROLL:
1321  case ARMOUR_IMPROVER:
1322  case WEAPON_IMPROVER:
1323  case WAND:
1324  case ROD:
1325  case POTION:
1326  drop(op, curinv);
1327  if (op->contr)
1328  op->contr->count = count;
1329  break;
1330 
1331  default:
1332  break;
1333  }
1334  }
1335  } FOR_INV_FINISH();
1336  }
1337  op->contr->socket->update_look = 1;
1339  /* call it now, once */
1340  fix_object(op);
1341  /* Need to update weight of player. Likewise, only do it once */
1342  if (op->type == PLAYER)
1343  esrv_update_item(UPD_WEIGHT, op, op);
1344 }
1345 
1354 void command_drop(object *op, const char *params) {
1355  int did_one = 0;
1356  int missed = 0;
1357 
1358  if (*params == '\0') {
1360  "Drop what?");
1361  return;
1362  }
1363 
1364  matcher_params mp;
1365  item_matcher matcher = make_matcher(op, params, &mp);
1366  if (!matcher) {
1367  return;
1368  }
1369 
1371 
1372  FOR_INV_PREPARE(op, tmp) {
1373  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1374  continue;
1375  if ((*matcher)(op, &mp, tmp)) {
1376  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1377  missed++;
1378  } else {
1379  drop(op, tmp);
1380  }
1381  did_one = 1;
1382  }
1383  } FOR_INV_FINISH();
1384  if (!did_one)
1386  "Nothing to drop.");
1387  if (missed == 1)
1389  "One item couldn't be dropped because it was locked.");
1390  else if (missed > 1)
1392  "%d items couldn't be dropped because they were locked.",
1393  missed);
1394 
1395  /* Now update player and send information. */
1397  fix_object(op);
1398  if (op->type == PLAYER) {
1399  op->contr->count = 0;
1400  esrv_update_item(UPD_WEIGHT, op, op);
1401  }
1402 }
1403 
1412 static void empty_container(object *container, object *pl) {
1413  int left = 0;
1414  char name[MAX_BUF];
1415 
1416  if (!container->inv)
1417  return;
1418 
1419  FOR_INV_PREPARE(container, inv) {
1420  object *next;
1421 
1422  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1423  /* you can have locked items in container. */
1424  left++;
1425  continue;
1426  }
1427  next = inv->below;
1428  drop(pl, inv);
1429  if (inv->below == next)
1430  /* item couldn't be dropped for some reason. */
1431  left++;
1432  } FOR_INV_FINISH();
1433  esrv_update_item(UPD_WEIGHT, pl, container);
1434 
1435  query_name(container, name, sizeof(name));
1436  if (left)
1437  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1438  else
1440 }
1441 
1450 void command_empty(object *op, const char *params) {
1451  object *container;
1452 
1453  if (*params == '\0') {
1455  "Empty what?");
1456  return;
1457  }
1458 
1459  if (strcmp(params, "all") == 0) {
1460  FOR_INV_PREPARE(op, inv)
1461  if (inv->type == CONTAINER)
1462  empty_container(inv, op);
1463  FOR_INV_FINISH();
1464  return;
1465  }
1466 
1467  container = find_best_object_match(op, params);
1468  if (!container) {
1470  "No such item.");
1471  return;
1472  }
1473  if (container->type != CONTAINER) {
1475  "This is not a container!");
1476  return;
1477  }
1478  empty_container(container, op);
1479 }
1480 
1489 void command_examine(object *op, const char *params) {
1490  if (*params == '\0') {
1491  FOR_BELOW_PREPARE(op, tmp)
1492  if (LOOK_OBJ(tmp)) {
1493  examine(op, tmp);
1494  break;
1495  }
1496  FOR_BELOW_FINISH();
1497  } else {
1498  object *tmp = find_best_object_match(op, params);
1499 
1500  if (tmp)
1501  examine(op, tmp);
1502  else
1504  "Could not find an object that matches %s",
1505  params);
1506  }
1507 }
1508 
1520 object *find_marked_object(object *op) {
1521  if (!op || !op->contr || !op->contr->mark)
1522  return NULL;
1523 
1524  /* This may seem like overkill, but we need to make sure that they
1525  * player hasn't dropped the item. We use count on the off chance that
1526  * an item got reincarnated at some point.
1527  */
1528  /*
1529  FOR_INV_PREPARE(op, tmp) {
1530  if (tmp->invisible)
1531  continue;
1532  if (tmp == op->contr->mark) {
1533  if (tmp->count == op->contr->mark_count)
1534  return tmp;
1535  else {
1536  op->contr->mark = NULL;
1537  op->contr->mark_count = 0;
1538  return NULL;
1539  }
1540  }
1541  } FOR_INV_FINISH();
1542  */
1543  /* Try a different way of doing this
1544  * We check the environment of the marked object
1545  * to make sure it is still in the player's inventory.
1546  * In addition, we ensure there is the correct tag for that item.
1547  *
1548  * Neila Hawkins 2018-10-23
1549  */
1550  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1551  return op->contr->mark;
1552  // Otherwise reset the mark, since it is no longer valid.
1553  op->contr->mark = NULL;
1554  op->contr->mark_count = 0;
1555  return NULL;
1556 }
1557 
1567 void command_mark(object *op, const char *params) {
1568  char name[MAX_BUF];
1569 
1570  if (!op->contr)
1571  return;
1572  if (*params == '\0') {
1573  object *mark = find_marked_object(op);
1574  if (!mark)
1576  "You have no marked object.");
1577  else {
1578  query_name(mark, name, MAX_BUF);
1580  "%s is marked.",
1581  name);
1582  }
1583  } else {
1584  object *mark1 = find_best_object_match(op, params);
1585 
1586  if (!mark1) {
1588  "Could not find an object that matches %s",
1589  params);
1590  return;
1591  } else {
1592  op->contr->mark = mark1;
1593  op->contr->mark_count = mark1->count;
1594  query_name(mark1, name, MAX_BUF);
1596  "Marked item %s",
1597  name);
1598  return;
1599  }
1600  }
1601  /*shouldnt get here */
1602 }
1603 
1614 void examine_monster(object *op, object *tmp, int level) {
1615  object *mon = HEAD(tmp), *probe;
1616 
1617  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1619  "It is an undead force.");
1620  if (mon->level > op->level)
1622  "It is likely more powerful than you.");
1623  else if (mon->level < op->level)
1625  "It is likely less powerful than you.");
1626  else
1628  "It is probably as powerful as you.");
1629 
1630  if (mon->attacktype&AT_ACID)
1632  "You smell an acrid odor.");
1633 
1634  /* Anyone know why this used to use the clone value instead of the
1635  * maxhp field? This seems that it should give more accurate results.
1636  */
1637  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1638  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1639  case 0:
1641  "It is critically wounded.");
1642  break;
1643 
1644  case 1:
1646  "It is in a bad shape.");
1647  break;
1648 
1649  case 2:
1651  "It is hurt.");
1652  break;
1653 
1654  case 3:
1656  "It is somewhat hurt.");
1657  break;
1658 
1659  default:
1661  "It is in excellent shape.");
1662  break;
1663  }
1664  if (object_present_in_ob(POISONING, mon) != NULL)
1666  "It looks very ill.");
1667 
1668  if (level < 10)
1669  return;
1670  knowledge_add_probe_monster(op, mon);
1671 
1672  if (level < 15)
1673  return;
1674 
1675  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1676  if (probe != NULL && probe->level > level)
1677  return;
1678 
1679  if (probe == NULL) {
1681  free_string(probe->name);
1682  probe->name = add_string("probe_force");
1685  object_insert_in_ob(probe, mon);
1686  fix_object(mon);
1687  }
1688  probe->level = level;
1689  if (level / 10 > probe->duration)
1690  probe->duration = level / 10;
1691 }
1692 
1694  EX_ID_ABORT, // Not safe to continue
1695  EX_ID_NO_SKILL, // Player lacks the requisite skill(s)
1696  EX_ID_FAILED // Player has the skill but failed their ID roll
1697 };
1698 
1710 ex_autoid_result examine_autoidentify(object *op, object *tmp) {
1711  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1712  int exp = 0;
1713  object *skill = find_skill_by_number(op, SK_DET_MAGIC);
1714  if (skill && (object_can_pick(op, tmp))) {
1715  exp = detect_magic_on_item(op, tmp, skill);
1716  if (exp) {
1717  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1719  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1720  }
1721  }
1722 
1724  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1725  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1726  exp = detect_curse_on_item(op, tmp, skill);
1727  if (exp) {
1728  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1730  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1731  }
1732  }
1733 
1734  const typedata *tmptype = get_typedata(tmp->type);
1735  if (!tmptype) {
1736  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid\n", tmp->count, tmp->type);
1737  return EX_ID_ABORT;
1738  }
1739 
1740  bool have_skill = false;
1741  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1742  skill = find_skill_by_number(op, tmptype->identifyskill);
1743  if (skill) {
1744  /* identify_object_with_skill() may merge tmp with another
1745  * object, so once that happens, we really can not do
1746  * any further processing with tmp. It would be possible
1747  * to modify identify_object_with_skill() to return
1748  * the merged object, but it is currently set to return
1749  * exp, so it would have to do it via modifying the
1750  * passed in value, but many other consumers would
1751  * need to be modified for that.
1752  */
1753  exp = identify_object_with_skill(tmp, op, skill, 1);
1754  if (exp) {
1755  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1756  return EX_ID_ABORT;
1757  }
1758  }
1759 
1760  /* The primary id skill didn't work, let's try the secondary one */
1761  skill = find_skill_by_number(op, tmptype->identifyskill2);
1762  if (skill) {
1763  /* if we've reached here, then the first skill will have been attempted
1764  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1765  * that now, and try with the secondary ID skill, if it fails, then the
1766  * flag will be reset anyway, if it succeeds, it won't matter.*/
1768  exp = identify_object_with_skill(tmp, op, skill, 1);
1769  if (exp) {
1770  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1771  return EX_ID_ABORT;
1772  }
1773  }
1774  }
1775  return have_skill ? EX_ID_FAILED : EX_ID_NO_SKILL;
1776 }
1777 
1786 void examine_weight_and_material(object *op, object *tmp) {
1787  bool pl = tmp->nrof > 1;
1788  float weight = (tmp->nrof ? tmp->nrof : 1) * ((float)tmp->weight/1000.0);
1789 
1790  if (tmp->materialname && weight) {
1792  "%s made of %s and %s %3.3f kg.",
1793  pl ? "They are" : "It is", tmp->materialname,
1794  pl ? "weigh" : "weighs", weight);
1795  } else if (tmp->materialname) {
1797  "%s made of %s.", pl ? "They are" : "It is", tmp->materialname);
1798  } else if (weight) {
1800  "%s %3.3f kg.", pl ? "They weigh" : "it weighs", weight);
1801  }
1802 }
1803 
1812 void examine_wand_charge_level(object *op, object *tmp) {
1813  if (!is_identified(tmp)) return;
1814  const char *desc;
1815  if (tmp->stats.food <= 0) {
1816  desc = "It is completely depleted.";
1817  } else if (tmp->stats.food <= 2) {
1818  desc = "It is nearly depleted.";
1819  } else if (tmp->stats.food <= 4) {
1820  desc = "It is very low on power.";
1821  } else if (tmp->stats.food <= 8) {
1822  desc = "It is low on power.";
1823  } else if (tmp->stats.food <= 16) {
1824  desc = "It is well charged.";
1825  } else if (tmp->stats.food <= 32) {
1826  desc = "It is fully charged.";
1827  } else {
1828  desc = "It is overflowing with power.";
1829  }
1831 }
1832 
1841 void examine_rod_charge_level(object *op, object *tmp) {
1842  if (!is_identified(tmp)) return;
1843  if (!tmp->inv) // rod has no spell
1844  return;
1845  const int castings = tmp->stats.hp/SP_level_spellpoint_cost(tmp, tmp->inv, SPELL_HIGHEST);
1846  const char *desc;
1847  /* Rods get less precise information than wands/staves as part of balancing
1848  out their reusability -- in particular, you can't tell if a rod is *almost*
1849  out of shots or *completely* out of shots without trying it. */
1850  if (castings <= 1) {
1851  desc = "It is nearly depleted.";
1852  } else if (castings <= 3) {
1853  desc = "It hums with power.";
1854  } else {
1855  desc = "It crackles with power.";
1856  }
1858 }
1859 
1873 bool examine_fluff(object *op, object *tmp, bool output) {
1874  /* No message for stuff the player hasn't IDed. */
1875  if (!is_identifiable_type(tmp) || !is_identified(tmp)) {
1876  return false;
1877  }
1878 
1879  // We use stringbuffer throughout this function so that we can use
1880  // trim_whitespace to conveniently strip trailing newlines, ensuring that
1881  // the output of examine is contiguous.
1882  // TODO: It might be better to strip the newlines in object_set_msg
1883  // and append them at print time, rather than ensuring that the msg
1884  // is newline-terminated and stripping off the newlines when we don't
1885  // want them; C string handling makes the latter a lot less convenient.
1886  if (tmp->msg && strncasecmp(tmp->msg, "@match", 6)) {
1887  if (!output) return true;
1889  stringbuffer_append_string(sb, tmp->msg);
1891  char *const msg = stringbuffer_finish(sb);
1893  free(msg);
1894  }
1895 
1896  switch (tmp->type) {
1897  /* Stuff with embedded skills. */
1898  case SKILLSCROLL:
1899  case SKILL_TOOL:
1900  {
1901  // Embedded skills are stored as an archetype name and don't get reified
1902  // until the player actually reads/equips the object, so we need to turn
1903  // the name into an actual archetype and then read the msg out of that.
1904  if (!tmp->skill) break; // Blank skill scroll, somehow.
1906  if (!skill) {
1907  if (!output) break; // Still need to check for lore later.
1908  // Skill name doesn't correspond to any actual skill.
1910  "Unfortunately, it is damaged beyond %s.",
1911  (tmp->type == SKILLSCROLL) ? "comprehension" : "repair");
1912  break;
1913  }
1914  if (skill->clone.msg) {
1915  if (!output) return true;
1917  "%s lets you %s a skill:",
1918  tmp->nrof > 1 ? "These objects" : "This object",
1919  (tmp->type == SKILLSCROLL) ? "learn" : "use");
1920 
1922  stringbuffer_append_string(sb, skill->clone.msg);
1924  char *const fluff = stringbuffer_finish(sb);
1925  // SPELL_INFO is not a perfect match here, but it should display in the
1926  // same manner as the spell descriptions below and there's no SKILL_INFO
1927  // message type.
1929  free(fluff);
1930  }
1931  break;
1932  }
1933 
1934  /* Stuff with embedded spells. */
1935  case SPELLBOOK:
1936  case SCROLL:
1937  case WAND:
1938  case ROD:
1939  case POTION:
1940  {
1941  if (tmp->inv && tmp->inv->msg) {
1942  if (!output) return true;
1944  "%s holds%s a spell:",
1945  tmp->nrof > 1 ? "These objects" : "This object",
1946  tmp->type == SPELLBOOK ? " knowledge of" : "");
1947 
1949  stringbuffer_append_string(sb, tmp->inv->msg);
1951  char *const fluff = stringbuffer_finish(sb);
1953  free(fluff);
1954  }
1955  }
1956  }
1957 
1958  if (tmp->lore) {
1959  if (!output) return true;
1961  "%s a story:", tmp->nrof > 1 ? "These objects have" : "This object has");
1963  stringbuffer_append_string(sb, tmp->lore);
1965  char *const msg = stringbuffer_finish(sb);
1967  free(msg);
1968  }
1969 
1970  // If we get this far in output=false mode, we didn't hit any of the earlier
1971  // escape hatches and thus have nothing to output. In normal use we'll hit
1972  // this regardless and assume we output something.
1973  return output;
1974 }
1975 
1985 void examine(object *op, object *tmp) {
1986  if (tmp == NULL || tmp->type == CLOSE_CON)
1987  return;
1988 
1989  /* If the player has examined this twice in a row, do a more detailed
1990  examine. last_examined shouldn't get set unless we already know that
1991  examine_fluff() will do something interesting. */
1992  if (op->contr->last_examined == tmp->count) {
1993  op->contr->last_examined = 0;
1995  "You examine the %s more closely.", tmp->nrof > 1 ? tmp->name_pl : tmp->name);
1996  examine_fluff(op, tmp, true);
1998  " "); /* Blank line */
1999  return;
2000  }
2001 
2002  int i;
2003  char prefix[MAX_BUF] = "";
2004  char buf[VERY_BIG_BUF] = "";
2005  if (is_identified(tmp)) {
2006  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof<=1 ? "That is" : "Those are");
2007  } else {
2008  switch(examine_autoidentify(op, tmp)) {
2009  case EX_ID_NO_SKILL:
2010  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:",
2011  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
2012  break;
2013  case EX_ID_FAILED:
2014  snprintf(prefix, MAX_BUF, "You fail to understand %s:",
2015  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
2016  break;
2017  case EX_ID_ABORT:
2018  default:
2019  /* Item may have been merged with something else, not safe to proceed. */
2020  return;
2021  }
2022  }
2023 
2024  /* now we need to get the rest of the object description */
2025  ob_describe(tmp, op, 1, buf, sizeof(buf));
2026 
2028  "%s %s", prefix, buf);
2029  buf[0] = '\0';
2030  sstring custom_name = object_get_value(tmp, CUSTOM_NAME_FIELD);
2031  if (custom_name) {
2033  "You name it %s",
2034  custom_name);
2035  }
2036 
2037  switch (tmp->type) {
2038  case WAND:
2039  examine_wand_charge_level(op, tmp);
2040  break;
2041 
2042  case ROD:
2043  examine_rod_charge_level(op, tmp);
2044  break;
2045 
2046  case BOOK:
2047  if (tmp->msg != NULL)
2048  snprintf(buf, sizeof(buf), "Something is written in it.");
2049  break;
2050 
2051  case CONTAINER:
2052  if (tmp->race != NULL) {
2053  if (tmp->weight_limit && tmp->stats.Str < 100)
2054  snprintf(buf, sizeof(buf), "It can hold only %s and its weight limit is %.1f kg.", tmp->race, tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
2055  else
2056  snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
2057  } else
2058  if (tmp->weight_limit && tmp->stats.Str < 100)
2059  snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
2060  break;
2061  }
2062 
2063  if (buf[0] != '\0')
2065  buf);
2066 
2067  examine_weight_and_material(op, tmp);
2068 
2069  /* Where to wear this item */
2070  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
2071  if (tmp->body_info[i]) {
2072  if (op->body_info[i]) {
2073  if (tmp->body_info[i] < -1) {
2075  "%s %s (%d).", tmp->nrof > 1 ? "They go" : "It goes",
2076  body_locations[i].use_name, -tmp->body_info[i]);
2077  } else {
2079  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2081  }
2082  } else {
2084  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2086  }
2087  }
2088  }
2089 
2090  int in_shop = shop_contains(op);
2091 
2092  if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2093  char *value = cost_approx_str(tmp, op);
2094  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
2095  free(value);
2097  buf);
2098  if (in_shop) {
2099  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
2100  value = cost_str(shop_price_buy(tmp, op));
2101  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
2102  free(value);
2103  } else {
2104  value = cost_str(shop_price_sell(tmp, op));
2105  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
2106  free(value);
2107  }
2109  buf);
2110  }
2111  }
2112 
2113  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2114  examine_monster(op, tmp, 0);
2115 
2116  /* Is this item buildable? */
2117  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
2118  int conn;
2119  bool has_link = false;
2120  if (QUERY_FLAG(tmp, FLAG_IS_LINKED) && (conn = get_button_value(tmp))) {
2121  FOR_INV_PREPARE(op, tmp_inv) {
2122  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
2123  && strcmp(tmp_inv->slaying, op->map->path) == 0
2124  && tmp_inv->msg != NULL
2125  && tmp_inv->path_attuned == (uint32_t) conn) {
2126 
2127  has_link = true;
2130  "This is a buildable item, connected with: %s",
2131  tmp_inv->msg);
2132  break;
2133  }
2134  } FOR_INV_FINISH();
2135  }
2136  if (!has_link) {
2138  "This is a buildable item.");
2139  }
2140  }
2141 
2142  /* Does it have fluff text? */
2143  if (examine_fluff(op, tmp, false)) {
2144  op->contr->last_examined = tmp->count;
2146  "Examine again for more details.");
2147  } else {
2148  op->contr->last_examined = 0;
2149  }
2150 
2152  " "); /* Blank line */
2153 
2154  if (is_identified(tmp)) {
2156  }
2157 }
2158 
2167 void inventory(object *op, object *inv) {
2168  const char *in;
2169  int items = 0, length;
2170  char weight[MAX_BUF], name[MAX_BUF];
2171 
2172  if (inv == NULL && op == NULL) {
2174  "Inventory of what object?");
2175  return;
2176  }
2177  FOR_INV_PREPARE(inv ? inv : op, tmp)
2178  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
2179  || !op || QUERY_FLAG(op, FLAG_WIZ))
2180  items++;
2181  FOR_INV_FINISH();
2182  if (inv == NULL) { /* player's inventory */
2183  if (items == 0) {
2185  "You carry nothing.");
2186  return;
2187  } else {
2188  length = 28;
2189  in = "";
2191  "Inventory:");
2192  }
2193  } else {
2194  if (items == 0)
2195  return;
2196  else {
2197  length = 28;
2198  in = " ";
2199  }
2200  }
2201  FOR_INV_PREPARE(inv ? inv : op, tmp) {
2202  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
2203  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
2204  continue;
2205  query_weight(tmp, weight, MAX_BUF);
2206  query_name(tmp, name, MAX_BUF);
2207  if (!op || QUERY_FLAG(op, FLAG_WIZ))
2209  "[fixed]%s- %-*.*s (%5d) %-8s",
2210  in, length, length, name, tmp->count, weight);
2211  else
2213  "[fixed]%s- %-*.*s %-8s",
2214  in, length+8, length+8, name, weight);
2215  } FOR_INV_FINISH();
2216  if (!inv && op) {
2217  query_weight(op, weight, MAX_BUF);
2219  "[fixed]%-*s %-8s",
2220  41, "Total weight :", weight);
2221  }
2222 }
2223 
2232 static void display_new_pickup(const object *op, int old) {
2233  int i = op->contr->mode;
2234 
2235  esrv_send_pickup(op->contr);
2236 
2237  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
2238  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
2240  "Pickup is now %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
2241  }
2242  return;
2243  }
2244 
2246  "%d NEWMODE",
2247  i&PU_NEWMODE ? 1 : 0);
2249  "%d DEBUG",
2250  i&PU_DEBUG ? 1 : 0);
2252  "%d INHIBIT",
2253  i&PU_INHIBIT ? 1 : 0);
2255  "%d STOP",
2256  i&PU_STOP ? 1 : 0);
2257 
2259  "%d <= x pickup weight/value RATIO (0==off)",
2260  (i&PU_RATIO)*5);
2261 
2263  "%d FOOD",
2264  i&PU_FOOD ? 1 : 0);
2266  "%d DRINK",
2267  i&PU_DRINK ? 1 : 0);
2269  "%d VALUABLES",
2270  i&PU_VALUABLES ? 1 : 0);
2271 
2273  "%d BOW",
2274  i&PU_BOW ? 1 : 0);
2276  "%d ARROW",
2277  i&PU_ARROW ? 1 : 0);
2278 
2280  "%d HELMET",
2281  i&PU_HELMET ? 1 : 0);
2283  "%d SHIELD",
2284  i&PU_SHIELD ? 1 : 0);
2286  "%d ARMOUR",
2287  i&PU_ARMOUR ? 1 : 0);
2288 
2290  "%d BOOTS",
2291  i&PU_BOOTS ? 1 : 0);
2293  "%d GLOVES",
2294  i&PU_GLOVES ? 1 : 0);
2296  "%d CLOAK",
2297  i&PU_CLOAK ? 1 : 0);
2299  "%d KEY",
2300  i&PU_KEY ? 1 : 0);
2301 
2303  "%d MISSILEWEAPON",
2304  i&PU_MISSILEWEAPON ? 1 : 0);
2306  "%d MELEEWEAPON",
2307  i&PU_MELEEWEAPON ? 1 : 0);
2309  "%d MAGICAL",
2310  i&PU_MAGICAL ? 1 : 0);
2312  "%d POTION",
2313  i&PU_POTION ? 1 : 0);
2314 
2316  "%d SPELLBOOK",
2317  i&PU_SPELLBOOK ? 1 : 0);
2319  "%d SKILLSCROLL",
2320  i&PU_SKILLSCROLL ? 1 : 0);
2322  "%d READABLES",
2323  i&PU_READABLES ? 1 : 0);
2325  "%d MAGICDEVICE",
2326  i&PU_MAGIC_DEVICE ? 1 : 0);
2327 
2329  "%d NOT CURSED",
2330  i&PU_NOT_CURSED ? 1 : 0);
2331 
2333  "%d JEWELS",
2334  i&PU_JEWELS ? 1 : 0);
2335 
2337  "%d FLESH",
2338  i&PU_FLESH ? 1 : 0);
2339 
2341  "%d CONTAINER",
2342  i&PU_CONTAINER ? 1 : 0);
2343 
2345  "%d CURSED",
2346  i&PU_CURSED ? 1 : 0);
2347 
2349  "");
2350 }
2351 
2361 void command_pickup(object *op, const char *params) {
2362  uint32_t i;
2363 
2364  if (*params == '\0') {
2365  /* if the new mode is used, just print the settings */
2366  if (op->contr->mode&PU_NEWMODE) {
2367  display_new_pickup(op, op->contr->mode);
2368  return;
2369  }
2370  if (1)
2371  LOG(llevDebug, "command_pickup: !params\n");
2372  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
2373  return;
2374  }
2375 
2376  while (*params == ' ')
2377  params++;
2378 
2379  if (*params == '+' || *params == '-' || *params == '!') {
2380  int index = get_pickup_mode_index(params + 1);
2381 
2382  if (index != -1) {
2383  int old = op->contr->mode;
2384  i = op->contr->mode;
2385  if (!(i&PU_NEWMODE))
2386  i = PU_NEWMODE;
2387  if (*params == '+')
2388  i = i|pickup_modes[index];
2389  else if (*params == '-')
2390  i = i&~pickup_modes[index];
2391  else {
2392  if (i&pickup_modes[index])
2393  i = i&~pickup_modes[index];
2394  else
2395  i = i|pickup_modes[index];
2396  }
2397  op->contr->mode = i;
2398  display_new_pickup(op, old);
2399  return;
2400  }
2402  "Pickup: invalid item %s\n",
2403  params);
2404  return;
2405  }
2406 
2407  if (sscanf(params, "%u", &i) != 1) {
2408  if (1)
2409  LOG(llevDebug, "command_pickup: params==NULL\n");
2411  "Usage: pickup <0-7> or <value_density> .");
2412  return;
2413  }
2414  set_pickup_mode(op, i);
2415  display_new_pickup(op, op->contr->mode);
2416 }
2417 
2426 static void set_pickup_mode(const object *op, int i) {
2427  op->contr->mode = i;
2428  switch (op->contr->mode) {
2429  case 0:
2431  "Mode: Don't pick up.");
2432  break;
2433 
2434  case 1:
2436  "Mode: Pick up one item.");
2437  break;
2438 
2439  case 2:
2441  "Mode: Pick up one item and stop.");
2442  break;
2443 
2444  case 3:
2446  "Mode: Stop before picking up.");
2447  break;
2448 
2449  case 4:
2451  "Mode: Pick up all items.");
2452  break;
2453 
2454  case 5:
2456  "Mode: Pick up all items and stop.");
2457  break;
2458 
2459  case 6:
2461  "Mode: Pick up all magic items.");
2462  break;
2463 
2464  case 7:
2466  "Mode: Pick up all coins and gems");
2467  break;
2468  }
2469 }
2470 
2479 void command_search_items(object *op, const char *params) {
2480  if (settings.search_items == FALSE)
2481  return;
2482 
2483  if (!params || *params == '\0') {
2484  if (op->contr->search_str[0] == '\0') {
2486  "Example: search magic+1 "
2487  "Would automatically pick up all "
2488  "items containing the word 'magic+1'.");
2489  return;
2490  }
2491  op->contr->search_str[0] = '\0';
2493  "Search mode turned off.");
2494  fix_object(op);
2495  return;
2496  }
2497  if ((int)strlen(params) >= MAX_BUF) {
2499  "Search string too long.");
2500  return;
2501  }
2502  strcpy(op->contr->search_str, params);
2504  "Searching for '%s'.",
2505  op->contr->search_str);
2506  fix_object(op);
2507 }
2508 
2524 void command_rename_item(object *op, const char *params) {
2525  char buf[VERY_BIG_BUF], name[MAX_BUF];
2526  tag_t itemnumber;
2527  object *item = NULL;
2528  object *tmp;
2529  const char *closebrace;
2530  size_t counter;
2531 
2532  if (*params != '\0') {
2533  /* Let's skip white spaces */
2534  while (' ' == *params)
2535  params++;
2536 
2537  /* Checking the first part */
2538  itemnumber = atoi(params);
2539  if (itemnumber != 0) {
2540  FOR_INV_PREPARE(op, inv)
2541  if (inv->count == itemnumber && !inv->invisible) {
2542  item = inv;
2543  break;
2544  }
2545  FOR_INV_FINISH();
2546  if (!item) {
2548  "Tried to rename an invalid item.");
2549  return;
2550  }
2551  while (isdigit(*params) || ' ' == *params)
2552  params++;
2553  } else if ('<' == *params) {
2554  /* Got old name, let's get it & find appropriate matching item */
2555  closebrace = strchr(params, '>');
2556  if (!closebrace) {
2558  "Syntax error!");
2559  return;
2560  }
2561  /* Sanity check for buffer overruns */
2562  if (closebrace-params > 127) {
2564  "Old name too long (up to 127 characters allowed)!");
2565  return;
2566  }
2567  /* Copy the old name */
2568  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2569 
2570  /* Find best matching item */
2571  item = find_best_object_match(op, buf);
2572  if (!item) {
2574  "Could not find a matching item to rename.");
2575  return;
2576  }
2577 
2578  /* Now need to move pointer to just after > */
2579  params = closebrace+1;
2580  while (' ' == *params)
2581  params++;
2582  } else {
2583  /* Use marked item */
2584  item = find_marked_object(op);
2585  if (!item) {
2587  "No marked item to rename.");
2588  return;
2589  }
2590  }
2591 
2592  /* Now let's find the new name */
2593  if (!strncmp(params, "to ", 3)) {
2594  params += 3;
2595  while (' ' == *params)
2596  params++;
2597  if ('<' != *params) {
2599  "Syntax error, expecting < at start of new name!");
2600  return;
2601  }
2602  closebrace = strchr(params+1, '>');
2603  if (!closebrace) {
2605  "Syntax error, expecting > at end of new name!");
2606  return;
2607  }
2608 
2609  /* Sanity check for buffer overruns */
2610  if (closebrace-params > 127) {
2612  "New name too long (up to 127 characters allowed)!");
2613  return;
2614  }
2615 
2616  /* Copy the new name */
2617  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2618 
2619  /* Let's check it for weird characters */
2620  for (counter = 0; counter < strlen(buf); counter++) {
2621  if (isalnum(buf[counter]))
2622  continue;
2623  if (' ' == buf[counter])
2624  continue;
2625  if ('\'' == buf[counter])
2626  continue;
2627  if ('+' == buf[counter])
2628  continue;
2629  if ('_' == buf[counter])
2630  continue;
2631  if ('-' == buf[counter])
2632  continue;
2633 
2634  /* If we come here, then the name contains an invalid character...
2635  * tell the player & exit
2636  */
2638  "Invalid new name!");
2639  return;
2640  }
2641  } else {
2642  /* If param contains something, then syntax error... */
2643  if (strlen(params)) {
2645  "Syntax error, expected 'to <' after old name!");
2646  return;
2647  }
2648  /* New name is empty */
2649  buf[0] = '\0';
2650  }
2651  } else {
2652  /* Last case: *params=='\0' */
2653  item = find_marked_object(op);
2654  if (!item) {
2656  "No marked item to rename.");
2657  return;
2658  }
2659  buf[0] = '\0';
2660  }
2661 
2662  /* Coming here, everything is fine... */
2663  if (!strlen(buf)) {
2664  /* Clear custom name */
2665  if (object_get_value(item, CUSTOM_NAME_FIELD) == NULL) {
2667  "This item has no custom name.");
2668  return;
2669  }
2670 
2671  object_set_value(item, CUSTOM_NAME_FIELD, NULL, 0);
2672  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2674  "You stop calling your %s with weird names.",
2675  name);
2676  } else {
2677  sstring custom_name = object_get_value(item, CUSTOM_NAME_FIELD);
2678  if (custom_name != NULL && strcmp(custom_name, buf) == 0) {
2679  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2681  "You keep calling your %s %s.",
2682  name, buf);
2683  return;
2684  }
2685 
2686  /* Set custom name */
2688 
2689  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2691  "Your %s will now be called %s.",
2692  name, buf);
2693  }
2694 
2695  tmp = object_merge(item, NULL);
2696  if (tmp == NULL) {
2697  /* object was not merged - if it was, object_merge() handles updating for us. */
2698  esrv_update_item(UPD_NAME, op, item);
2699  }
2700 }
2701 
2710 void command_lock_item(object *op, const char *params) {
2711  object *item;
2712  object *tmp;
2713  char name[HUGE_BUF];
2714 
2715  if (*params == '\0' || strlen(params) == 0) {
2717  "Lock what item?");
2718  return;
2719  }
2720 
2721  item = find_best_object_match(op, params);
2722  if (!item) {
2724  "Can't find any matching item.");
2725  return;
2726  }
2727 
2728  query_short_name(item, name, HUGE_BUF);
2729  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2731  "Unlocked %s.", name);
2732  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2733  } else {
2735  "Locked %s.", name);
2736  SET_FLAG(item, FLAG_INV_LOCKED);
2737  }
2738 
2739  tmp = object_merge(item, NULL);
2740  if (tmp == NULL) {
2741  /* object was not merged, if it was object_merge() handles updates for us */
2742  esrv_update_item(UPD_FLAGS, op, item);
2743  }
2744 }
2745 
2753 void command_use(object *op, const char *params) {
2754  char *with, copy[MAX_BUF];
2755  object *first, *second/*, *add*/;
2756  /*archetype *arch;*/
2757  /*int count;*/
2758  /*sstring data;*/
2759  recipe *transformation;
2760 
2761  if (!IS_PLAYER(op))
2762  return;
2763 
2764  strlcpy(copy, params, sizeof(copy));
2765  with = strstr(copy, " with ");
2766  if (!with) {
2767  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2768  return;
2769  }
2770 
2771  with[0] = '\0';
2772  with = with+strlen(" with ");
2773 
2774  first = find_best_object_match(op, copy);
2775  if (!first) {
2776  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2777  return;
2778  }
2779  second = find_best_object_match(op, with);
2780  if (!second) {
2781  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2782  return;
2783  }
2784 
2785  transformation = NULL;
2786  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2788  if (transformation->ingred_count != 1)
2789  continue;
2790 
2791 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2792  if (strcmp(second->name, transformation->ingred->name) == 0) {
2794  object *generated = create_archetype(transformation->arch_name[0]);
2795  if (transformation->yield)
2796  generated->nrof = transformation->yield;
2797  object_insert_in_ob(generated, op);
2798  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2800  return;
2801  }
2802  }
2803  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2804  return;
2805 
2806  /*
2807  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2808  data = object_get_value(second, copy);
2809  if (!data) {
2810  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2811  data = object_get_value(second, copy);
2812  if (!data) {
2813  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2814  data = object_get_value(second, copy);
2815  if (!data) {
2816  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2817  return 1;
2818  }
2819  }
2820  }
2821 
2822  while (data != NULL) {
2823  if (strncmp(data, "add ", 4) == 0) {
2824  data += 4;
2825  if (isdigit(*data)) {
2826  count = atol(data);
2827  data = strchr(data, ' ')+1;
2828  } else
2829  count = 1;
2830  with = strchr(data, ' ');
2831  if (!with) {
2832  strncpy(copy, data, sizeof(copy));
2833  data = NULL;
2834  } else {
2835  *with = '\0';
2836  strncpy(copy, data, sizeof(copy));
2837  data += strlen(copy)+1;
2838  }
2839  arch = find_archetype(copy);
2840  if (!arch) {
2841  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2842  return 1;
2843  }
2844  add = object_create_arch(arch);
2845  add->nrof = count;
2846  object_insert_in_ob(add, op);
2847  } else if (strncmp(data, "remove $", 8) == 0) {
2848  data += 8;
2849  if (*data == '1') {
2850  if (first)
2851  first = object_decrease_nrof_by_one(first);
2852  data += 2;
2853  } else if (*data == '2') {
2854  if (second)
2855  second = object_decrease_nrof_by_one(second);
2856  data += 2;
2857  } else {
2858  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2859  return 1;
2860  }
2861  } else {
2862  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2863  return 1;
2864  }
2865  }
2866 
2867  return 1;
2868  */
2869 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
drop
void drop(object *op, object *tmp)
Drop an item, either on the floor or in a container.
Definition: c_object.cpp:1168
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:323
find_recipe_for_tool
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Find a recipe for a specified tool.
Definition: recipe.cpp:894
do_skill
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:431
MIMIC
@ MIMIC
Definition: object.h:254
PLAYER
@ PLAYER
Definition: object.h:112
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
global.h
settings
struct Settings settings
Server settings.
Definition: init.cpp:139
living::maxhp
int16_t maxhp
Max hit points.
Definition: living.h:41
matcher_pickup_type
static int matcher_pickup_type(object *who, matcher_params *params, object *item)
Check if an item matches a pickup type.
Definition: c_object.cpp:794
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:15
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:533
AP_APPLY
#define AP_APPLY
Item is to be applied.
Definition: define.h:568
BOW
@ BOW
Definition: object.h:123
BRACERS
@ BRACERS
Definition: object.h:222
CLOSE_CON
@ CLOSE_CON
Eneq((at)csd.uu.se): Id for close_container archetype.
Definition: object.h:234
llevError
@ llevError
Error, serious thing.
Definition: logger.h:11
ARMOUR_IMPROVER
@ ARMOUR_IMPROVER
Definition: object.h:237
command_search
void command_search(object *op, const char *params)
'search' command.
Definition: c_object.cpp:212
find_skill_by_number
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
AP_NO_MERGE
#define AP_NO_MERGE
Don't try to merge object after (un)applying it.
Definition: define.h:575
WAND
@ WAND
Definition: object.h:225
player::mode
uint32_t mode
Mode of player for pickup.
Definition: player.h:123
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:58
FLAG_UNDEAD
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
FLESH
@ FLESH
animal 'body parts' -b.t.
Definition: object.h:192
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
PU_ARROW
#define PU_ARROW
Definition: define.h:120
GLOVES
@ GLOVES
Definition: object.h:218
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
GIRDLE
@ GIRDLE
Definition: object.h:228
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:410
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
KEY
@ KEY
Definition: object.h:132
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
command_rename_item
void command_rename_item(object *op, const char *params)
Changing the custom name of an item.
Definition: c_object.cpp:2524
recipe::yield
int yield
Maximum number of items produced by the recipe.
Definition: recipe.h:21
object_merge
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:2051
player::mark_count
uint32_t mark_count
Count of marked object.
Definition: player.h:212
examine_monster
void examine_monster(object *op, object *tmp, int level)
Player examine a monster.
Definition: c_object.cpp:1614
FALSE
#define FALSE
Definition: compat.h:14
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:424
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:57
examine
void examine(object *op, object *tmp)
Player examines some object.
Definition: c_object.cpp:1985
SK_DET_MAGIC
@ SK_DET_MAGIC
Detect magic.
Definition: skills.h:30
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:319
FLAG_IS_BUILDABLE
#define FLAG_IS_BUILDABLE
Can build on item.
Definition: define.h:367
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:698
GEM
@ GEM
Definition: object.h:172
object::invisible
int16_t invisible
How much longer the object will be invis.
Definition: object.h:370
detect_curse_on_item
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Runs a 'detect curse' check on a given item.
Definition: skills.cpp:703
object::x
int16_t x
Definition: object.h:335
command_rskill
void command_rskill(object *pl, const char *params)
'ready_skill' command.
Definition: c_object.cpp:161
shop_price_buy
uint64_t shop_price_buy(const object *obj, object *who)
Adjust the value of an item to be bought based on the player's bargaining skill and charisma.
Definition: shop.cpp:190
ARMOUR
@ ARMOUR
Definition: object.h:125
SK_DISARM_TRAPS
@ SK_DISARM_TRAPS
Disarm traps.
Definition: skills.h:46
command_use
void command_use(object *op, const char *params)
Try to use an item on another.
Definition: c_object.cpp:2753
PU_FOOD
#define PU_FOOD
Definition: define.h:115
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:305
WEAPON
@ WEAPON
Definition: object.h:124
typedata::identifyskill
int identifyskill
Skill used to identify this object class.
Definition: define.h:93
esrv_send_pickup
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1835
PU_BOW
#define PU_BOW
Definition: define.h:118
command_uskill
void command_uskill(object *pl, const char *params)
'use_skill' command.
Definition: c_object.cpp:144
PU_MAGIC_DEVICE
#define PU_MAGIC_DEVICE
Definition: define.h:138
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
AMULET
@ AMULET
Definition: object.h:144
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
matcher_name
static int matcher_name(object *who, matcher_params *params, object *item)
Check if an item matches a string.
Definition: c_object.cpp:774
MIN
#define MIN(x, y)
Definition: compat.h:21
in
same as sound ncom command like but with extra the client want tick commands so it knows animation timing the client wants to be informed of pickup mode changes Mode will be sent when the player successfully logs in
Definition: protocol.txt:408
SKILL
@ SKILL
Also see SKILL_TOOL (74) below.
Definition: object.h:148
examine_wand_charge_level
void examine_wand_charge_level(object *op, object *tmp)
Output charge information for a wand or staff.
Definition: c_object.cpp:1812
object::count
tag_t count
Unique object number for this object.
Definition: object.h:307
change_skill
int change_skill(object *who, object *new_skill, int flag)
This changes the object's skill to new_skill.
Definition: skill_util.cpp:359
MSG_TYPE_COMMAND_EXAMINE
#define MSG_TYPE_COMMAND_EXAMINE
Player examining something.
Definition: newclient.h:535
fix_object
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.cpp:1132
command_mark
void command_mark(object *op, const char *params)
'mark' command, to mark an item for some effects (enchant armor, ...).
Definition: c_object.cpp:1567
command_pickup
void command_pickup(object *op, const char *params)
'pickup' command.
Definition: c_object.cpp:2361
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
recipe::arch_name
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
TRANSPORT
@ TRANSPORT
see doc/Developers/objects
Definition: object.h:113
PU_FLESH
#define PU_FLESH
Definition: define.h:142
PU_READABLES
#define PU_READABLES
Definition: define.h:137
skills.h
PU_POTION
#define PU_POTION
Definition: define.h:133
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can't use command.
Definition: newclient.h:532
matcher_params::item_to_pick
int item_to_pick
Index of the item to pick, 1-based.
Definition: c_object.cpp:714
FLAG_PROBE
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:257
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:329
MSG_TYPE_SPELL_INFO
#define MSG_TYPE_SPELL_INFO
random info about spell, not related to failure/success
Definition: newclient.h:642
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
object_get_value
const char * object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4346
apply_by_living_below
void apply_by_living_below(object *pl)
Attempt to apply the object 'below' the player.
Definition: apply.cpp:695
ex_autoid_result
ex_autoid_result
Definition: c_object.cpp:1693
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
NDI_BLUE
#define NDI_BLUE
Actually, it is Dodger Blue.
Definition: newclient.h:250
object::level
int16_t level
Level of creature or object.
Definition: object.h:361
events_execute_object_event
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:308
buf
StringBuffer * buf
Definition: readable.cpp:1565
object_insert_in_ob
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:2857
object::above
object * above
Pointer to the object stacked above this one.
Definition: object.h:296
HUGE_BUF
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
set_pickup_mode
static void set_pickup_mode(const object *op, int i)
Sets the 'old' pickup mode.
Definition: c_object.cpp:2426
POISONING
@ POISONING
Definition: object.h:223
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:407
command_drop
void command_drop(object *op, const char *params)
'drop' command.
Definition: c_object.cpp:1354
body_locations_struct::nonuse_name
const char * nonuse_name
Name to describe objects we can't use.
Definition: object.h:25
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:239
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:302
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:705
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
socket_struct::update_look
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:104
command_empty
void command_empty(object *op, const char *params)
'empty' command.
Definition: c_object.cpp:1450
object_matches_pickup_mode
int object_matches_pickup_mode(const object *item, int mode)
Checks if an item matches a specific pickup mode.
Definition: c_object.cpp:656
object::carrying
int32_t carrying
How much weight this object contains.
Definition: object.h:377
LOOK_OBJ
#define LOOK_OBJ(ob)
This returns TRUE if the object is something that should be displayed in the look window.
Definition: object.h:521
AP_NULL
#define AP_NULL
Nothing specific.
Definition: define.h:567
PU_GLOVES
#define PU_GLOVES
Definition: define.h:126
typedata
Link an object type with skill needed to identify, and general name.
Definition: define.h:89
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
CLOAK
@ CLOAK
Definition: object.h:209
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Deallocate the string buffer instance and return the string.
Definition: stringbuffer.cpp:76
get_button_value
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.cpp:749
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1560
put_object_in_sack
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:937
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
NROF
static uint32_t NROF(const object *const ob)
Returns ob->nrof, unless it is 0, in which case return 1.
Definition: object.h:625
HELMET
@ HELMET
Definition: object.h:141
use_skill
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:964
matcher_all
static int matcher_all(object *who, matcher_params *params, object *item)
Function allowing all objects.
Definition: c_object.cpp:740
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
POISON
@ POISON
Definition: object.h:118
PU_RATIO
#define PU_RATIO
Definition: define.h:113
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
linked_char::name
const char * name
Definition: global.h:99
PU_KEY
#define PU_KEY
Definition: define.h:128
command_throw
void command_throw(object *op, const char *params)
'throw' command.
Definition: c_object.cpp:239
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:323
EVENT_PICKUP
#define EVENT_PICKUP
Object picked up.
Definition: events.h:28
matcher_params::pickup_type
int pickup_type
Value in Pickup modes to match against.
Definition: c_object.cpp:719
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:588
matcher_params::name
char name[MAX_BUF]
Name to match for.
Definition: c_object.cpp:718
POTION
@ POTION
Definition: object.h:116
body_locations_struct::use_name
const char * use_name
Name used when describing an item we can use.
Definition: object.h:24
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:320
output
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended it will issue a classical message output
Definition: media-tags.txt:36
examine_weight_and_material
void examine_weight_and_material(object *op, object *tmp)
Output weight and material information for an examined object.
Definition: c_object.cpp:1786
EVENT_DROP
#define EVENT_DROP
Object dropped on the floor.
Definition: events.h:27
matcher_number
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:754
SK_DET_CURSE
@ SK_DET_CURSE
Detect curse.
Definition: skills.h:33
set_object_face_main
int set_object_face_main(object *op)
Makes an object's face the main face, which is supposed to be the "closed" one.
Definition: apply.cpp:146
MSG_TYPE_COMMAND_INFO
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:529
object::weight_limit
int32_t weight_limit
Weight-limit of object.
Definition: object.h:376
add_string
sstring add_string(const char *str)
This will add 'str' to the hash table.
Definition: shstr.cpp:124
knowledge_add_probe_monster
void knowledge_add_probe_monster(object *op, object *mon)
Display monster details, then add to a player's knowledge if not already.
Definition: knowledge.cpp:1528
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:748
HEAD
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:607
player_can_find
bool player_can_find(object *op, object *ob)
Return true if player 'op' can see object 'op' for purpose of locating items for partial item matchin...
Definition: item.cpp:590
pick_up_object
static void pick_up_object(object *pl, object *op, object *tmp, int nrof)
Try to pick up some item.
Definition: c_object.cpp:379
transport_can_hold
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,...
Definition: apply.cpp:54
ROD
@ ROD
Definition: object.h:114
CONTAINER
@ CONTAINER
Definition: object.h:236
object::below
object * below
Pointer to the object stacked below this one.
Definition: object.h:295
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:436
object_find_by_type_and_name
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:4108
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn't contain any information about object...
Definition: item.cpp:513
PU_STOP
#define PU_STOP
Definition: define.h:110
PU_VALUABLES
#define PU_VALUABLES
Definition: define.h:117
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:387
object::value
int32_t value
How much money it is worth (or contains)
Definition: object.h:360
is_identified
int is_identified(const object *op)
Return true if the item is identified, either because it is of a type that doesn't ever need identifi...
Definition: item.cpp:1353
ob_describe
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Returns the description of an object, as seen by the given observer.
Definition: ob_methods.cpp:91
SPECIAL_KEY
@ SPECIAL_KEY
Definition: object.h:129
empty_container
static void empty_container(object *container, object *pl)
Put all contents of the container on the ground below the player or in opened container,...
Definition: c_object.cpp:1412
MOVE_FLYING
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:395
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:580
SKILLSCROLL
@ SKILLSCROLL
can add a skill to player's inventory -bt.
Definition: object.h:239
object::materialname
sstring materialname
Specific material name.
Definition: object.h:356
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:318
NDI_GOLD
#define NDI_GOLD
Definition: newclient.h:257
command_dropall
void command_dropall(object *op, const char *params)
Command to drop all items that have not been locked.
Definition: c_object.cpp:1230
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:671
identify_object_with_skill
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:810
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:584
living::food
int32_t food
How much food in stomach.
Definition: living.h:48
MSG_TYPE_SKILL_MISSING
#define MSG_TYPE_SKILL_MISSING
Don't have the skill.
Definition: newclient.h:590
PU_SPELLBOOK
#define PU_SPELLBOOK
Definition: define.h:135
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.cpp:2179
matcher_params
Matching parameters.
Definition: c_object.cpp:711
knowledge_item_can_be_used_alchemy
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
tag_t
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:14
body_locations
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
The ordering of this is actually doesn't make a difference However, for ease of use,...
Definition: item.cpp:55
archetype
The archetype structure is a set of rules on how to generate and manipulate objects which point to ar...
Definition: object.h:483
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.cpp:4574
PU_MELEEWEAPON
#define PU_MELEEWEAPON
Definition: define.h:131
sproto.h
ARROW
@ ARROW
Definition: object.h:122
make_matcher
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:806
FLAG_NO_DROP
#define FLAG_NO_DROP
Object can't be dropped.
Definition: define.h:288
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:95
PU_MAGICAL
#define PU_MAGICAL
Definition: define.h:132
FOR_OB_AND_BELOW_PREPARE
#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:744
MSG_TYPE_SPELL
#define MSG_TYPE_SPELL
Spell related info.
Definition: newclient.h:414
BOOK
@ BOOK
Definition: object.h:119
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Scales the spellpoint cost of a spell by it's increased effectiveness.
Definition: spell_util.cpp:236
object::race
sstring race
Human, goblin, dragon, etc.
Definition: object.h:326
object::facing
int8_t facing
Object is oriented/facing that way.
Definition: object.h:345
find_best_apply_object_match
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
RING
@ RING
Definition: object.h:190
detect_magic_on_item
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Runs a 'detect magic' check on a given item.
Definition: skills.cpp:752
PU_HELMET
#define PU_HELMET
Definition: define.h:121
weight
TIPS on SURVIVING Crossfire is populated with a wealth of different monsters These monsters can have varying immunities and attack types In some of them can be quite a bit smarter than others It will be important for new players to learn the abilities of different monsters and learn just how much it will take to kill them This section discusses how monsters can interact with players Most monsters in the game are out to mindlessly kill and destroy the players These monsters will help boost a player s after he kills them When fighting a large amount of monsters in a single attempt to find a narrower hallway so that you are not being attacked from all sides Charging into a room full of Beholders for instance would not be open the door and fight them one at a time For there are several maps designed for them Find these areas and clear them out All throughout these a player can find signs and books which they can read by stepping onto them and hitting A to apply the book sign These messages will help the player to learn the system One more always keep an eye on your food If your food drops to your character will soon so BE CAREFUL ! NPCs Non Player Character are special monsters which have intelligence Players may be able to interact with these monsters to help solve puzzles and find items of interest To speak with a monster you suspect to be a simply move to an adjacent square to them and push the double ie Enter your and press< Return > You can also use say if you feel like typing a little extra Other NPCs may not speak to but display intelligence with their movement Some monsters can be and may attack the nearest of your enemies Others can be in that they follow you around and help you in your quest to kill enemies and find treasure SPECIAL ITEMS There are many special items which can be found in of these the most important may be the signs all a player must do is apply the handle In the case of the player must move items over the button to hold it down Some of the larger buttons may need very large items to be moved onto before they can be activated Gates and locked but be for you could fall down into a pit full of ghosts or dragons and not be able to get back out Break away sometimes it may be worth a player s time to test the walls of a map for secret doors Fire such as missile weapons and spells you will notice them going up in smoke ! So be careful not to destroy valuable items Spellbooks sometimes a player can learn the other times they cannot There are many different types of books and scrolls out there Improve item have lower weight
Definition: survival-guide.txt:100
object_insert_in_map_at
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:2100
command_search_items
void command_search_items(object *op, const char *params)
'search-items' command.
Definition: c_object.cpp:2479
inventory
void inventory(object *op, object *inv)
Prints object's inventory.
Definition: c_object.cpp:2167
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
find_skill_by_name
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:211
recipe::ingred_count
int ingred_count
Number of items in ingred.
Definition: recipe.h:23
env
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2222
pick_up
void pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.cpp:519
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
do_skill_by_number
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
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
object_insert_in_map
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:2361
sack_can_hold
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: c_object.cpp:317
create_archetype
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
object_present_in_ob
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:3168
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2373
object::weight
int32_t weight
Attributes of the object.
Definition: object.h:375
free_string
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.cpp:280
command_disarm
void command_disarm(object *op, const char *params)
'disarm' command.
Definition: c_object.cpp:224
IS_PLAYER
static bool IS_PLAYER(object *op)
Definition: object.h:609
StringBuffer
A buffer that will be expanded as content is added to it.
Definition: stringbuffer.cpp:25
matcher_params::item_must_be_pickable
int item_must_be_pickable
If non zero, then the item number is increased only if the item is pickable.
Definition: c_object.cpp:716
probe
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Try to get information about a living thing.
Definition: spell_effect.cpp:699
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
recipe
One alchemy recipe.
Definition: recipe.h:10
player::search_str
char search_str[MAX_BUF]
Item we are looking for.
Definition: player.h:211
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:534
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:319
pickup_modes
static const uint32_t pickup_modes[]
Value in Pickup modes associated with pickup_names.
Definition: c_object.cpp:43
find_best_object_match
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
player::mark
object * mark
Marked object.
Definition: player.h:213
get_pickup_mode_index
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
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
MSG_TYPE_COMMAND_INVENTORY
#define MSG_TYPE_COMMAND_INVENTORY
Inventory listing.
Definition: newclient.h:536
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
object::lore
sstring lore
Obscure information about this object, to get put into books and the like.
Definition: object.h:332
NDI_UNIQUE
#define NDI_UNIQUE
Print immediately, don't buffer.
Definition: newclient.h:265
object::slaying
sstring slaying
Which race to do double damage to.
Definition: object.h:327
item_matcher
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:731
query_weight
void query_weight(const object *op, char *buf, size_t size)
Formats the item's weight.
Definition: item.cpp:415
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
PU_CLOAK
#define PU_CLOAK
Definition: define.h:127
AP_OPEN
#define AP_OPEN
Item is a container to be fully opened.
Definition: define.h:570
cost_approx_str
char * cost_approx_str(const object *obj, object *who)
Return a textual cost approximation in a newly-allocated string.
Definition: shop.cpp:369
object_can_pick
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.cpp:3867
stringbuffer_trim_whitespace
void stringbuffer_trim_whitespace(StringBuffer *sb)
Trim trailing whitespace from a stringbuffer.
Definition: stringbuffer.cpp:222
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
cost_str
char * cost_str(uint64_t cost)
Definition: shop.cpp:365
is_identifiable_type
int is_identifiable_type(const object *op)
Return true if this item's type is one that cares about whether or not it's been identified – e....
Definition: item.cpp:1329
mapstruct
This is a game-map.
Definition: map.h:315
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:301
sstring
const typedef char * sstring
Definition: sstring.h:2
command_apply
void command_apply(object *op, const char *params)
'apply' command.
Definition: c_object.cpp:251
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:329
shop.h
object_split
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:2637
command_examine
void command_examine(object *op, const char *params)
'examine' command.
Definition: c_object.cpp:1489
PU_ARMOUR
#define PU_ARMOUR
Definition: define.h:123
examine_fluff
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:1873
apply_by_living
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Living thing is applying an object.
Definition: apply.cpp:637
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:359
Settings::max_stat
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:326
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
PU_NEWMODE
#define PU_NEWMODE
Definition: define.h:111
SKILL_TOOL
@ SKILL_TOOL
Allows the use of a skill.
Definition: object.h:194
FLAG_NO_FIX_PLAYER
#define FLAG_NO_FIX_PLAYER
fix_object() won't be called
Definition: define.h:277
find_marked_object
object * find_marked_object(object *op)
Return the object the player has marked with the 'mark' command below.
Definition: c_object.cpp:1520
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
SK_SUBTRACT_SKILL_EXP
#define SK_SUBTRACT_SKILL_EXP
Used when removing exp.
Definition: skills.h:81
apply_special
int apply_special(object *who, object *op, int aflags)
Apply an object.
Definition: apply.cpp:1156
display_new_pickup
static void display_new_pickup(const object *op, int old)
Utility function to display the pickup mode for a player.
Definition: c_object.cpp:2232
level
int level
Definition: readable.cpp:1563
typedata::identifyskill2
int identifyskill2
Second skill used to identify this object class.
Definition: define.h:94
player::count
uint32_t count
Any numbers typed before a command.
Definition: player.h:122
object::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:382
player::last_examined
tag_t last_examined
Tag of most recently 'examined object.
Definition: player.h:165
UPD_NAME
#define UPD_NAME
Definition: newclient.h:321
AT_ACID
#define AT_ACID
Definition: attack.h:82
loader.h
save_player
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:230
Settings::real_wiz
uint8_t real_wiz
Use mud-like wizards.
Definition: global.h:273
stop_item
object * stop_item(object *op)
An item (ARROW or such) stops moving.
Definition: time.cpp:455
FOOD
@ FOOD
Definition: object.h:117
object::container
object * container
Current container being used.
Definition: object.h:299
skill
skill
Definition: arch-handbook.txt:585
object_remove
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:1833
recipe::ingred
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
drop_object
object * drop_object(object *op, object *tmp, uint32_t nrof)
Try to drop an object on the floor.
Definition: c_object.cpp:1073
EX_ID_FAILED
@ EX_ID_FAILED
Definition: c_object.cpp:1696
object::move_off
MoveType move_off
Move types affected moving off this space.
Definition: object.h:440
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:236
examine_rod_charge_level
void examine_rod_charge_level(object *op, object *tmp)
Output charge information for a rod.
Definition: c_object.cpp:1841
DRINK
@ DRINK
Definition: object.h:162
sell_item
void sell_item(object *op, object *pl)
Player is selling an item.
Definition: shop.cpp:968
VERY_BIG_BUF
#define VERY_BIG_BUF
Definition: define.h:36
PU_CURSED
#define PU_CURSED
Definition: define.h:144
command_lock_item
void command_lock_item(object *op, const char *params)
Alternate way to lock/unlock items (command line).
Definition: c_object.cpp:2710
WEAPON_IMPROVER
@ WEAPON_IMPROVER
Definition: object.h:238
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:484
SCROLL
@ SCROLL
Definition: object.h:226
FLAG_IS_LINKED
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:315
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:107
matcher_params::missed
int missed
How many items were missed when matching.
Definition: c_object.cpp:721
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:689
Settings::search_items
uint8_t search_items
Search_items command.
Definition: global.h:269
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
object_set_value
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:4499
AP_UNAPPLY
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:569
SK_FIND_TRAPS
@ SK_FIND_TRAPS
Find traps.
Definition: skills.h:34
PU_DRINK
#define PU_DRINK
Definition: define.h:116
command_take
void command_take(object *op, const char *params)
This takes (picks up) an item.
Definition: c_object.cpp:845
BOOTS
@ BOOTS
Definition: object.h:217
shop_contains
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: shop.cpp:1300
pickup_names
static const char * pickup_names[]
Valid names for pickup types.
Definition: c_object.cpp:33
FLAG_IS_CAULDRON
#define FLAG_IS_CAULDRON
container can make alchemical stuff
Definition: define.h:338
matcher_params::item_number
int item_number
Index of the checked item, 1-based.
Definition: c_object.cpp:715
PU_SHIELD
#define PU_SHIELD
Definition: define.h:122
EX_ID_NO_SKILL
@ EX_ID_NO_SKILL
Definition: c_object.cpp:1695
SHIELD
@ SHIELD
Definition: object.h:140
object::attacktype
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
FLAG_NO_SKILL_IDENT
#define FLAG_NO_SKILL_IDENT
If set, item cannot be identified w/ a skill.
Definition: define.h:335
object_get_player_container
object * object_get_player_container(object *op)
Finds the player carrying an object.
Definition: object.cpp:607
living.h
FLAG_IS_THROWN
#define FLAG_IS_THROWN
Object is designed to be thrown.
Definition: define.h:249
SK_THROWING
@ SK_THROWING
Throwing.
Definition: skills.h:44
EX_ID_ABORT
@ EX_ID_ABORT
Definition: c_object.cpp:1694
SPELLBOOK
@ SPELLBOOK
Definition: object.h:208
CUSTOM_NAME_FIELD
#define CUSTOM_NAME_FIELD
Key in an object for the player-assigned custom name.
Definition: object.h:98
shop_price_sell
uint64_t shop_price_sell(const object *obj, object *who)
Adjust the value of an item to be sold based on the player's bargaining skill and charisma.
Definition: shop.cpp:211
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:664
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
FORCE
@ FORCE
Definition: object.h:229
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:13
MONEY
@ MONEY
Definition: object.h:142
examine_autoidentify
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:1710
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
living::Str
int8_t Str
Definition: living.h:36
PU_DEBUG
#define PU_DEBUG
Definition: define.h:108
get_archetype_by_skill_name
archetype * get_archetype_by_skill_name(const char *skill, int type)
Retrieves an archetype by skill name and type.
Definition: arch.cpp:78
PU_SKILLSCROLL
#define PU_SKILLSCROLL
Definition: define.h:136