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 (pl->type == PLAYER && 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 
520 bool pick_up(object *op, object *alt) {
521 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
522  object *tmp = NULL, *tmp1;
523  mapstruct *tmp_map = NULL;
524  int count;
525 
526  /* Decide which object to pick. */
527  if (alt) {
528  if (!object_can_pick(op, alt)) {
530  "You can't pick up the %s.",
531  alt->name);
532  return false;
533  }
534  tmp = alt;
535  } else {
536  if (op->below == NULL || !object_can_pick(op, op->below)) {
538  "There is nothing to pick up here.");
539  return false;
540  }
541  tmp = op->below;
542  }
543 
544  /* it is possible that the object is a thrown object and is flying about.
545  * in that case, what we want to pick up is the payload. Objects
546  * that are thrown are encapsulated into a thrown object.
547  * stop_item() returns the payload (unlinked from map) and gets rid of the
548  * container object. If this object isn't picked up, we need to insert
549  * it back on the map.
550  * A bug here is that even attempting to pick up one of these objects will
551  * result in this logic being called even if player is unable to pick it
552  * up.
553  */
554 
555  tmp_map = tmp->map;
556  tmp1 = stop_item(tmp);
557  if (tmp1 == NULL)
558  return false;
559 
560  /* If it is a thrown object, insert it back into the map here.
561  * makes life easier further along. Do no merge so pick up code
562  * behaves more sanely.
563  */
564  if (tmp1 != tmp) {
565  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
566  }
567 
568  if (tmp == NULL)
569  return false;
570 
571  if (!object_can_pick(op, tmp))
572  return false;
573 
574  /* Establish how many of the object we are picking up */
575  if (op->type == PLAYER) {
576  count = op->contr->count;
577  if (count == 0)
578  count = tmp->nrof;
579  } else
580  count = tmp->nrof;
581 
582  /* container is open, so use it */
583  if (op->container) {
584  alt = op->container;
585  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
586  return false;
587  } else {
588  /* non container pickup. See if player has any
589  * active containers.
590  */
591  object *container = NULL;
592 
593  /* Look for any active containers that can hold this item.
594  * we cover two cases here - the perfect match case, where we
595  * break out of the loop, and the general case (have a container),
596  * Moved this into a single loop - reduces redundant code, is
597  * more efficient and easier to follow. MSW 2009-04-06
598  */
599  alt = op->inv;
601  if (alt->type == CONTAINER
602  && QUERY_FLAG(alt, FLAG_APPLIED)
603  && sack_can_hold(NULL, alt, tmp, count)) {
604  if (alt->race && alt->race == tmp->race) {
605  break; /* perfect match */
606  } else if (!container) {
607  container = alt;
608  }
609  }
611  /* Note container could be null, but no reason to check for it */
612  if (!alt)
613  alt = container;
614 
615  if (!alt)
616  alt = op; /* No free containers */
617  }
618  /* see if this object is already in this container. If so,
619  * move it to player inventory from this container.
620  */
621  if (tmp->env == alt) {
622  alt = op;
623  }
624 
625  /* Don't allow players to be put into containers. Instead,
626  * just put them in the players inventory.
627  */
628  if ((tmp->type == CONTAINER || tmp->type == MIMIC) && alt->type==CONTAINER) {
629  alt = op;
630  }
631 #ifdef PICKUP_DEBUG
632  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
633 #endif
634 
635  /* startequip items are not allowed to be put into containers
636  * Not sure why we have this limitation
637  */
638  if (op->type == PLAYER
639  && alt->type == CONTAINER
640  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
642  "This object cannot be put into containers!");
643  return false;
644  }
645 
646  pick_up_object(op, alt, tmp, count);
647  if (op->type == PLAYER)
648  op->contr->count = 0;
649  return true;
650 }
651 
658 int object_matches_pickup_mode(const object *item, int mode) {
659  switch(mode) {
660  case PU_FOOD:
661  return item->type == FOOD;
662  case PU_DRINK:
663  return item->type == DRINK || (item->type == POISON && !QUERY_FLAG(item, FLAG_KNOWN_CURSED));
664  case PU_FLESH:
665  return item->type == FLESH;
666  case PU_POTION:
667  return item->type == POTION;
668  case PU_SPELLBOOK:
669  return item->type == SPELLBOOK;
670  case PU_SKILLSCROLL:
671  return item->type == SKILLSCROLL;
672  case PU_READABLES:
673  return item->type == BOOK || item->type == SCROLL;
674  case PU_MAGIC_DEVICE:
675  return item->type == WAND || item->type == ROD || item->type == WEAPON_IMPROVER || item->type == ARMOUR_IMPROVER || item->type == SKILL_TOOL;
676  case PU_MAGICAL:
678  case PU_VALUABLES:
679  return item->type == MONEY || item->type == GEM;
680  case PU_JEWELS:
681  return item->type == RING || item->type == AMULET;
682  case PU_BOW:
683  return item->type == BOW;
684  case PU_ARROW:
685  return item->type == ARROW;
686  case PU_ARMOUR:
687  return item->type == ARMOUR;
688  case PU_HELMET:
689  return item->type == HELMET;
690  case PU_SHIELD:
691  return item->type == SHIELD;
692  case PU_BOOTS:
693  return item->type == BOOTS;
694  case PU_GLOVES:
695  return item->type == GLOVES;
696  case PU_CLOAK:
697  return item->type == CLOAK;
698  case PU_MISSILEWEAPON:
699  return item->type == WEAPON && QUERY_FLAG(item, FLAG_IS_THROWN);
700  case PU_MELEEWEAPON:
701  return item->type == WEAPON;
702  case PU_KEY:
703  return item->type == KEY || item->type == SPECIAL_KEY;
704  case PU_CONTAINER:
705  return item->type == CONTAINER;
706  case PU_CURSED:
707  return QUERY_FLAG(item, FLAG_KNOWN_CURSED);
708  }
709  return 0;
710 }
711 
714  union {
715  struct {
719  };
720  char name[MAX_BUF];
722  };
723  int missed;
724 };
725 
733 typedef int (*item_matcher)(object *who, matcher_params *params, object *item);
734 
742 static int matcher_all(object *who, matcher_params *params, object *item) {
743  (void)who;
744  (void)params;
745  (void)item;
746  return 1;
747 }
748 
756 static int matcher_number(object *who, matcher_params *params, object *item) {
757  if (params->item_must_be_pickable == 0 || object_can_pick(who, item)) {
758  params->item_number++;
759  }
760  if (params->item_to_pick == params->item_number) {
761  /* Since we don't always increase item_number, multiple items may have the same index,
762  including unpickable ones, so to avoid failure messages just ensure no other item can be picked. */
763  params->item_to_pick = 0;
764  return 1;
765  }
766  return 0;
767 }
768 
776 static int matcher_name(object *who, matcher_params *params, object *item) {
777  int ival = object_matches_string(who, item, params->name);
778  if (ival > 0) {
779  if (ival <= 2 && !object_can_pick(who, item)) {
780  if (!QUERY_FLAG(item, FLAG_IS_FLOOR))/* don't count floor tiles */
781  params->missed++;
782  return 0;
783  }
784  return 1;
785  }
786  return 0;
787 }
788 
796 static int matcher_pickup_type(object *who, matcher_params *params, object *item) {
797  (void)who;
798  return object_matches_pickup_mode(item, params->pickup_type);
799 }
800 
808 static item_matcher make_matcher(object *who, const char *params, matcher_params *mp) {
809  memset(mp, 0, sizeof(*mp));
810  if (params[0] == '\0') {
811  mp->item_to_pick = 1;
812  mp->item_must_be_pickable = 1;
813  return &matcher_number;
814  }
815  if (params[0] == '#') {
816  mp->item_to_pick = atoi(params + 1);
817  if (mp->item_to_pick == 0) {
819  return NULL;
820  }
821  return &matcher_number;
822  }
823  if (params[0] == '*') {
824  if (params[1] == '\0') {
825  return &matcher_all;
826  }
827  int idx = get_pickup_mode_index(params + 1);
828  if (idx == -1) {
829  draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, "Invalid items %s", params + 1);
830  return NULL;
831  }
832  mp->pickup_type = pickup_modes[idx];
833  return &matcher_pickup_type;
834  }
835  strncpy(mp->name, params, sizeof(mp->name) - 1);
836  return &matcher_name;
837 }
838 
847 void command_take(object *op, const char *params) {
848  object *tmp;
849  int did_one = 0;
850 
851  if (op->container)
852  tmp = op->container->inv;
853  else {
854  tmp = op->above;
855  if (tmp)
856  while (tmp->above) {
857  tmp = tmp->above;
858  }
859  if (!tmp)
860  tmp = op->below;
861  }
862 
863  if (tmp == NULL) {
865  "Nothing to take!");
866  return;
867  }
868 
869  matcher_params mp;
870  item_matcher matcher = make_matcher(op, params, &mp);
871  if (!matcher) {
872  return; // Player already informed of failure.
873  }
874 
876 
878  if (tmp->invisible) {
879  continue;
880  }
881  if ((*matcher)(op, &mp, tmp)) {
882  pick_up(op, tmp);
883  did_one = 1;
884  }
886 
887  /* Nothing picked up, check if unable to pick or nothing to pick. */
888  if (params[0] == '\0' && !did_one) {
889  int found = 0;
890  FOR_BELOW_PREPARE(op, tmp)
891  if (!tmp->invisible) {
893  "You can't pick up a %s.",
894  tmp->name ? tmp->name : "null");
895  found = 1;
896  break;
897  }
899  if (!found)
901  "There is nothing to pick up.");
902  }
903 
904  if (mp.missed == 1)
906  "You were unable to take one of the items.");
907  else if (mp.missed > 1)
909  "You were unable to take %d of the items.",
910  mp.missed);
911 
912  /* Now update player and send information. */
914  fix_object(op);
915  if (op->type == PLAYER) {
916  op->contr->count = 0;
917  esrv_update_item(UPD_WEIGHT, op, op);
918  }
919 }
920 
939 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
940  object *sack2, *orig = sack;
941  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
942 
943  if (sack == tmp)
944  return; /* Can't put an object in itself */
945  query_name(sack, name_sack, MAX_BUF);
946  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
948  "The %s is not a container.",
949  name_sack);
950  return;
951  }
952  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
953  query_name(tmp, name_tmp, MAX_BUF);
955  "You cannot put the %s in the %s.",
956  name_tmp, name_sack);
957  return;
958  }
959  if (tmp->type == CONTAINER) {
960  if (tmp->inv) {
961  if (tmp->slaying)
962  return;
963  /* Eneq(@csd.uu.se): If the object to be dropped is a container
964  * and does not require a key to be opened,
965  * we instead move the contents of that container into the active
966  * container, this is only done if the object has something in it.
967  * If object is container but need a key, just don't do anything
968  */
969  sack2 = tmp;
970  query_name(tmp, name_tmp, MAX_BUF);
972  "You move the items from %s into %s.",
973  name_tmp, name_sack);
974 
975  FOR_INV_PREPARE(tmp, tmp2) {
976  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
977  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
978  put_object_in_sack(op, sack, tmp2, 0);
979  } else {
982  "Your %s fills up.",
983  name_sack);
984  break;
985  }
986  } FOR_INV_FINISH();
987  esrv_update_item(UPD_WEIGHT, op, sack2);
988  return;
989  } else {
990  query_name(tmp, name_tmp, MAX_BUF);
992  "You can not put a %s into a %s",
993  name_tmp,
994  name_sack);
995  return;
996  }
997  }
998 
999  /* Don't worry about this for containers - our caller should have
1000  * already checked this.
1001  */
1002  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
1003  return;
1004 
1005  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1006  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
1007  return;
1008  }
1009 
1010  /* we want to put some portion of the item into the container */
1011  if (nrof && tmp->nrof != nrof) {
1012  char failure[MAX_BUF];
1013 
1014  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1015 
1016  if (!tmp) {
1018  failure);
1019  return;
1020  }
1021  } else
1022  object_remove(tmp);
1023 
1024  if (sack->nrof > 1) {
1025  orig = object_split(sack, sack->nrof-1, NULL, 0);
1026  set_object_face_main(orig);
1027  CLEAR_FLAG(orig, FLAG_APPLIED);
1028  if (sack->env) {
1029  object_insert_in_ob(orig, sack->env);
1030  } else {
1031  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
1032  orig->move_off = 0;
1033  }
1034  }
1035 
1036  query_name(tmp, name_tmp, MAX_BUF);
1038  "You put the %s in %s.",
1039  name_tmp, name_sack);
1040 
1041  object_insert_in_ob(tmp, sack);
1042  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1043  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1044  /* in object.c */
1045 
1046  /* If a transport, need to update all the players in the transport
1047  * the view of what is in it.
1048  */
1049  if (sack->type == TRANSPORT) {
1050  FOR_INV_PREPARE(sack, tmp)
1051  if (tmp->type == PLAYER)
1052  tmp->contr->socket->update_look = 1;
1053  FOR_INV_FINISH();
1054  } else {
1055  /* update the sacks weight */
1056  esrv_update_item(UPD_WEIGHT, op, sack);
1057  }
1058 }
1059 
1075 object *drop_object(object *op, object *tmp, uint32_t nrof) {
1076  tag_t tmp_tag;
1077 
1078  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1079  return NULL;
1080  }
1081 
1082  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1083  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
1084  return NULL; /* can't unapply it */
1085  }
1086 
1087  if (events_execute_object_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1088  return NULL;
1089 
1090  /* ensure the plugin didn't destroy the object */
1091  if (QUERY_FLAG(tmp, FLAG_REMOVED))
1092  return NULL;
1093 
1094  /* We are only dropping some of the items. We split the current objec
1095  * off
1096  */
1097  if (nrof && tmp->nrof != nrof) {
1098  char failure[MAX_BUF];
1099 
1100  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1101  if (!tmp) {
1103  failure);
1104  return NULL;
1105  }
1106  } else
1107  object_remove(tmp);
1108 
1109  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
1110  char name[MAX_BUF];
1111 
1112  query_name(tmp, name, MAX_BUF);
1114  "You drop the %s. The gods who lent it to you retrieve it.",
1115  name);
1117 
1118  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1119  fix_object(op);
1120 
1121  return NULL;
1122  }
1123 
1124  /* If SAVE_INTERVAL is commented out, we never want to save
1125  * the player here.
1126  */
1127 #ifdef SAVE_INTERVAL
1128  /* I'm not sure why there is a value check - since the save
1129  * is done every SAVE_INTERVAL seconds, why care the value
1130  * of what he is dropping?
1131  */
1132  if (op->type == PLAYER
1133  && !QUERY_FLAG(tmp, FLAG_UNPAID)
1134  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
1135  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
1136  save_player(op, 1);
1137  op->contr->last_save_time = time(NULL);
1138  }
1139 #endif /* SAVE_INTERVAL */
1140 
1141 
1142  tmp_tag = tmp->count;
1143  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
1144  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
1145  sell_item(tmp, op);
1146  }
1147 
1148  /* Call this before we update the various windows/players. At least
1149  * that we, we know the weight is correct.
1150  */
1151  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
1152  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1153  /* in object.c */
1154 
1155  /* Need to update weight of player */
1156  if (op->type == PLAYER)
1157  esrv_update_item(UPD_WEIGHT, op, op);
1158  }
1159  return tmp;
1160 }
1161 
1170 void drop(object *op, object *tmp) {
1171  /* Hopeful fix for disappearing objects when dropping from a container -
1172  * somehow, players get an invisible object in the container, and the
1173  * old logic would skip over invisible objects - works fine for the
1174  * playes inventory, but drop inventory wants to use the next value.
1175  */
1176  if (tmp->invisible) {
1177  /* if the following is the case, it must be in an container. */
1178  if (tmp->env && tmp->env->type != PLAYER) {
1179  /* Just toss the object - probably shouldn't be hanging
1180  * around anyways
1181  */
1182  object_remove(tmp);
1184  return;
1185  } else {
1187  if (!tmp->invisible)
1188  break;
1190  }
1191  }
1192 
1193  if (tmp == NULL) {
1195  "You don't have anything to drop.");
1196  return;
1197  }
1198  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1200  "This item is locked");
1201  return;
1202  }
1203  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1204  return;
1205  }
1206 
1207  if (op->container) {
1208  if (op->type == PLAYER) {
1209  put_object_in_sack(op, op->container, tmp, op->contr->count);
1210  } else {
1211  put_object_in_sack(op, op->container, tmp, 0);
1212  };
1213  } else {
1214  if (op->type == PLAYER) {
1215  drop_object(op, tmp, op->contr->count);
1216  } else {
1217  drop_object(op, tmp, 0);
1218  };
1219  }
1220  if (op->type == PLAYER)
1221  op->contr->count = 0;
1222 }
1223 
1232 void command_dropall(object *op, const char *params) {
1233  int count = 0;
1234 
1235  if (op->inv == NULL) {
1236  draw_ext_info(NDI_UNIQUE, 0, op,
1238  "Nothing to drop!");
1239  return;
1240  }
1241 
1242  if (op->contr)
1243  count = op->contr->count;
1244 
1245  /* Set this so we don't call it for _every_ object that
1246  * is dropped.
1247  */
1249 
1250  /*
1251  * This is the default. Drops everything not locked or considered
1252  * not something that should be dropped.
1253  * Care must be taken that the next item pointer is not to money as
1254  * the drop() routine will do unknown things to it when dropping
1255  * in a shop. --Tero.Pelander@utu.fi
1256  */
1257  if (*params == '\0') {
1258  FOR_INV_PREPARE(op, curinv) {
1259  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1260  && curinv->type != MONEY
1261  && curinv->type != FOOD
1262  && curinv->type != KEY
1263  && curinv->type != SPECIAL_KEY
1264  && curinv->type != GEM
1265  && !curinv->invisible
1266  && (curinv->type != CONTAINER || op->container != curinv)) {
1267  drop(op, curinv);
1268  if (op->contr)
1269  op->contr->count = count;
1270  }
1271  } FOR_INV_FINISH();
1272  } else if (strcmp(params, "weapons") == 0) {
1273  FOR_INV_PREPARE(op, curinv) {
1274  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1275  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1276  drop(op, curinv);
1277  if (op->contr)
1278  op->contr->count = count;
1279  }
1280  } FOR_INV_FINISH();
1281  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1282  FOR_INV_PREPARE(op, curinv) {
1283  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1284  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1285  drop(op, curinv);
1286  if (op->contr)
1287  op->contr->count = count;
1288  }
1289  } FOR_INV_FINISH();
1290  } else if (strcmp(params, "food") == 0) {
1291  FOR_INV_PREPARE(op, curinv) {
1292  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1293  && (curinv->type == FOOD || curinv->type == DRINK)) {
1294  drop(op, curinv);
1295  if (op->contr)
1296  op->contr->count = count;
1297  }
1298  } FOR_INV_FINISH();
1299  } else if (strcmp(params, "flesh") == 0) {
1300  FOR_INV_PREPARE(op, curinv) {
1301  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1302  && (curinv->type == FLESH)) {
1303  drop(op, curinv);
1304  if (op->contr)
1305  op->contr->count = count;
1306  }
1307  } FOR_INV_FINISH();
1308  } else if (strcmp(params, "misc") == 0) {
1309  FOR_INV_PREPARE(op, curinv) {
1310  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1311  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1312  switch (curinv->type) {
1313  case BOOK:
1314  case SPELLBOOK:
1315  case GIRDLE:
1316  case AMULET:
1317  case RING:
1318  case CLOAK:
1319  case BOOTS:
1320  case GLOVES:
1321  case BRACERS:
1322  case SCROLL:
1323  case ARMOUR_IMPROVER:
1324  case WEAPON_IMPROVER:
1325  case WAND:
1326  case ROD:
1327  case POTION:
1328  drop(op, curinv);
1329  if (op->contr)
1330  op->contr->count = count;
1331  break;
1332 
1333  default:
1334  break;
1335  }
1336  }
1337  } FOR_INV_FINISH();
1338  }
1339  op->contr->socket->update_look = 1;
1341  /* call it now, once */
1342  fix_object(op);
1343  /* Need to update weight of player. Likewise, only do it once */
1344  if (op->type == PLAYER)
1345  esrv_update_item(UPD_WEIGHT, op, op);
1346 }
1347 
1356 void command_drop(object *op, const char *params) {
1357  int did_one = 0;
1358  int missed = 0;
1359 
1360  if (*params == '\0') {
1362  "Drop what?");
1363  return;
1364  }
1365 
1366  matcher_params mp;
1367  item_matcher matcher = make_matcher(op, params, &mp);
1368  if (!matcher) {
1369  return;
1370  }
1371 
1373 
1374  FOR_INV_PREPARE(op, tmp) {
1375  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1376  continue;
1377  if ((*matcher)(op, &mp, tmp)) {
1378  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1379  missed++;
1380  } else {
1381  drop(op, tmp);
1382  }
1383  did_one = 1;
1384  }
1385  } FOR_INV_FINISH();
1386  if (!did_one)
1388  "Nothing to drop.");
1389  if (missed == 1)
1391  "One item couldn't be dropped because it was locked.");
1392  else if (missed > 1)
1394  "%d items couldn't be dropped because they were locked.",
1395  missed);
1396 
1397  /* Now update player and send information. */
1399  fix_object(op);
1400  if (op->type == PLAYER) {
1401  op->contr->count = 0;
1402  esrv_update_item(UPD_WEIGHT, op, op);
1403  }
1404 }
1405 
1414 static void empty_container(object *container, object *pl) {
1415  int left = 0;
1416  char name[MAX_BUF];
1417 
1418  if (!container->inv)
1419  return;
1420 
1421  FOR_INV_PREPARE(container, inv) {
1422  object *next;
1423 
1424  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1425  /* you can have locked items in container. */
1426  left++;
1427  continue;
1428  }
1429  next = inv->below;
1430  drop(pl, inv);
1431  if (inv->below == next)
1432  /* item couldn't be dropped for some reason. */
1433  left++;
1434  } FOR_INV_FINISH();
1435  esrv_update_item(UPD_WEIGHT, pl, container);
1436 
1437  query_name(container, name, sizeof(name));
1438  if (left)
1439  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1440  else
1442 }
1443 
1452 void command_empty(object *op, const char *params) {
1453  object *container;
1454 
1455  if (*params == '\0') {
1457  "Empty what?");
1458  return;
1459  }
1460 
1461  if (strcmp(params, "all") == 0) {
1462  FOR_INV_PREPARE(op, inv)
1463  if (inv->type == CONTAINER)
1464  empty_container(inv, op);
1465  FOR_INV_FINISH();
1466  return;
1467  }
1468 
1469  container = find_best_object_match(op, params);
1470  if (!container) {
1472  "No such item.");
1473  return;
1474  }
1475  if (container->type != CONTAINER) {
1477  "This is not a container!");
1478  return;
1479  }
1480  empty_container(container, op);
1481 }
1482 
1491 void command_examine(object *op, const char *params) {
1492  if (*params == '\0') {
1493  FOR_BELOW_PREPARE(op, tmp)
1494  if (LOOK_OBJ(tmp)) {
1495  examine(op, tmp);
1496  break;
1497  }
1498  FOR_BELOW_FINISH();
1499  } else {
1500  object *tmp = find_best_object_match(op, params);
1501 
1502  if (tmp)
1503  examine(op, tmp);
1504  else
1506  "Could not find an object that matches %s",
1507  params);
1508  }
1509 }
1510 
1522 object *find_marked_object(object *op) {
1523  if (!op || !op->contr || !op->contr->mark)
1524  return NULL;
1525 
1526  /* This may seem like overkill, but we need to make sure that they
1527  * player hasn't dropped the item. We use count on the off chance that
1528  * an item got reincarnated at some point.
1529  */
1530  /*
1531  FOR_INV_PREPARE(op, tmp) {
1532  if (tmp->invisible)
1533  continue;
1534  if (tmp == op->contr->mark) {
1535  if (tmp->count == op->contr->mark_count)
1536  return tmp;
1537  else {
1538  op->contr->mark = NULL;
1539  op->contr->mark_count = 0;
1540  return NULL;
1541  }
1542  }
1543  } FOR_INV_FINISH();
1544  */
1545  /* Try a different way of doing this
1546  * We check the environment of the marked object
1547  * to make sure it is still in the player's inventory.
1548  * In addition, we ensure there is the correct tag for that item.
1549  *
1550  * Neila Hawkins 2018-10-23
1551  */
1552  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1553  return op->contr->mark;
1554  // Otherwise reset the mark, since it is no longer valid.
1555  op->contr->mark = NULL;
1556  op->contr->mark_count = 0;
1557  return NULL;
1558 }
1559 
1569 void command_mark(object *op, const char *params) {
1570  char name[MAX_BUF];
1571 
1572  if (!op->contr)
1573  return;
1574  if (*params == '\0') {
1575  object *mark = find_marked_object(op);
1576  if (!mark)
1578  "You have no marked object.");
1579  else {
1580  query_name(mark, name, MAX_BUF);
1582  "%s is marked.",
1583  name);
1584  }
1585  } else {
1586  object *mark1 = find_best_object_match(op, params);
1587 
1588  if (!mark1) {
1590  "Could not find an object that matches %s",
1591  params);
1592  return;
1593  } else {
1594  op->contr->mark = mark1;
1595  op->contr->mark_count = mark1->count;
1596  query_name(mark1, name, MAX_BUF);
1598  "Marked item %s",
1599  name);
1600  return;
1601  }
1602  }
1603  /*shouldnt get here */
1604 }
1605 
1616 void examine_monster(object *op, object *tmp, int level) {
1617  object *mon = HEAD(tmp), *probe;
1618 
1619  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1621  "It is an undead force.");
1622  if (mon->level > op->level)
1624  "It is likely more powerful than you.");
1625  else if (mon->level < op->level)
1627  "It is likely less powerful than you.");
1628  else
1630  "It is probably as powerful as you.");
1631 
1632  if (mon->attacktype&AT_ACID)
1634  "You smell an acrid odor.");
1635 
1636  /* Anyone know why this used to use the clone value instead of the
1637  * maxhp field? This seems that it should give more accurate results.
1638  */
1639  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1640  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1641  case 0:
1643  "It is critically wounded.");
1644  break;
1645 
1646  case 1:
1648  "It is in a bad shape.");
1649  break;
1650 
1651  case 2:
1653  "It is hurt.");
1654  break;
1655 
1656  case 3:
1658  "It is somewhat hurt.");
1659  break;
1660 
1661  default:
1663  "It is in excellent shape.");
1664  break;
1665  }
1666  if (object_present_in_ob(POISONING, mon) != NULL)
1668  "It looks very ill.");
1669 
1670  if (level < 10)
1671  return;
1672  knowledge_add_probe_monster(op, mon);
1673 
1674  if (level < 15)
1675  return;
1676 
1677  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1678  if (probe != NULL && probe->level > level)
1679  return;
1680 
1681  if (probe == NULL) {
1683  free_string(probe->name);
1684  probe->name = add_string("probe_force");
1687  object_insert_in_ob(probe, mon);
1688  fix_object(mon);
1689  }
1690  probe->level = level;
1691  if (level / 10 > probe->duration)
1692  probe->duration = level / 10;
1693 }
1694 
1696  EX_ID_ABORT, // Not safe to continue
1697  EX_ID_NO_SKILL, // Player lacks the requisite skill(s)
1698  EX_ID_FAILED // Player has the skill but failed their ID roll
1699 };
1700 
1712 ex_autoid_result examine_autoidentify(object *op, object *tmp) {
1713  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1714  int exp = 0;
1715  object *skill = find_skill_by_number(op, SK_DET_MAGIC);
1716  if (skill && (object_can_pick(op, tmp))) {
1717  exp = detect_magic_on_item(op, tmp, skill);
1718  if (exp) {
1719  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1721  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1722  }
1723  }
1724 
1726  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1727  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1728  exp = detect_curse_on_item(op, tmp, skill);
1729  if (exp) {
1730  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1732  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1733  }
1734  }
1735 
1736  const typedata *tmptype = get_typedata(tmp->type);
1737  if (!tmptype) {
1738  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid\n", tmp->count, tmp->type);
1739  return EX_ID_ABORT;
1740  }
1741 
1742  bool have_skill = false;
1743  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1744  skill = find_skill_by_number(op, tmptype->identifyskill);
1745  if (skill) {
1746  /* identify_object_with_skill() may merge tmp with another
1747  * object, so once that happens, we really can not do
1748  * any further processing with tmp. It would be possible
1749  * to modify identify_object_with_skill() to return
1750  * the merged object, but it is currently set to return
1751  * exp, so it would have to do it via modifying the
1752  * passed in value, but many other consumers would
1753  * need to be modified for that.
1754  */
1755  exp = identify_object_with_skill(tmp, op, skill, 1);
1756  if (exp) {
1757  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1758  return EX_ID_ABORT;
1759  }
1760  }
1761 
1762  /* The primary id skill didn't work, let's try the secondary one */
1763  skill = find_skill_by_number(op, tmptype->identifyskill2);
1764  if (skill) {
1765  /* if we've reached here, then the first skill will have been attempted
1766  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1767  * that now, and try with the secondary ID skill, if it fails, then the
1768  * flag will be reset anyway, if it succeeds, it won't matter.*/
1770  exp = identify_object_with_skill(tmp, op, skill, 1);
1771  if (exp) {
1772  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1773  return EX_ID_ABORT;
1774  }
1775  }
1776  }
1777  return have_skill ? EX_ID_FAILED : EX_ID_NO_SKILL;
1778 }
1779 
1788 void examine_weight_and_material(object *op, object *tmp) {
1789  bool pl = tmp->nrof > 1;
1790  float weight = (tmp->nrof ? tmp->nrof : 1) * ((float)tmp->weight/1000.0);
1791 
1792  if (tmp->materialname && weight) {
1794  "%s made of %s and %s %3.3f kg.",
1795  pl ? "They are" : "It is", tmp->materialname,
1796  pl ? "weigh" : "weighs", weight);
1797  } else if (tmp->materialname) {
1799  "%s made of %s.", pl ? "They are" : "It is", tmp->materialname);
1800  } else if (weight) {
1802  "%s %3.3f kg.", pl ? "They weigh" : "it weighs", weight);
1803  }
1804 }
1805 
1814 void examine_wand_charge_level(object *op, object *tmp) {
1815  if (!is_identified(tmp)) return;
1816  const char *desc;
1817  if (tmp->stats.food <= 0) {
1818  desc = "It is completely depleted.";
1819  } else if (tmp->stats.food <= 2) {
1820  desc = "It is nearly depleted.";
1821  } else if (tmp->stats.food <= 4) {
1822  desc = "It is very low on power.";
1823  } else if (tmp->stats.food <= 8) {
1824  desc = "It is low on power.";
1825  } else if (tmp->stats.food <= 16) {
1826  desc = "It is well charged.";
1827  } else if (tmp->stats.food <= 32) {
1828  desc = "It is fully charged.";
1829  } else {
1830  desc = "It is overflowing with power.";
1831  }
1833 }
1834 
1843 void examine_rod_charge_level(object *op, object *tmp) {
1844  if (!is_identified(tmp)) return;
1845  if (!tmp->inv) // rod has no spell
1846  return;
1847  const int castings = tmp->stats.hp/SP_level_spellpoint_cost(tmp, tmp->inv, SPELL_HIGHEST);
1848  const char *desc;
1849  /* Rods get less precise information than wands/staves as part of balancing
1850  out their reusability -- in particular, you can't tell if a rod is *almost*
1851  out of shots or *completely* out of shots without trying it. */
1852  if (castings <= 1) {
1853  desc = "It is nearly depleted.";
1854  } else if (castings <= 3) {
1855  desc = "It hums with power.";
1856  } else {
1857  desc = "It crackles with power.";
1858  }
1860 }
1861 
1875 bool examine_fluff(object *op, object *tmp, bool output) {
1876  /* No message for stuff the player hasn't IDed. */
1877  if (!is_identifiable_type(tmp) || !is_identified(tmp)) {
1878  return false;
1879  }
1880 
1881  // We use stringbuffer throughout this function so that we can use
1882  // trim_whitespace to conveniently strip trailing newlines, ensuring that
1883  // the output of examine is contiguous.
1884  // TODO: It might be better to strip the newlines in object_set_msg
1885  // and append them at print time, rather than ensuring that the msg
1886  // is newline-terminated and stripping off the newlines when we don't
1887  // want them; C string handling makes the latter a lot less convenient.
1888  if (tmp->msg && strncasecmp(tmp->msg, "@match", 6)) {
1889  if (!output) return true;
1891  stringbuffer_append_string(sb, tmp->msg);
1893  char *const msg = stringbuffer_finish(sb);
1895  free(msg);
1896  }
1897 
1898  switch (tmp->type) {
1899  /* Stuff with embedded skills. */
1900  case SKILLSCROLL:
1901  case SKILL_TOOL:
1902  {
1903  // Embedded skills are stored as an archetype name and don't get reified
1904  // until the player actually reads/equips the object, so we need to turn
1905  // the name into an actual archetype and then read the msg out of that.
1906  if (!tmp->skill) break; // Blank skill scroll, somehow.
1908  if (!skill) {
1909  if (!output) break; // Still need to check for lore later.
1910  // Skill name doesn't correspond to any actual skill.
1912  "Unfortunately, it is damaged beyond %s.",
1913  (tmp->type == SKILLSCROLL) ? "comprehension" : "repair");
1914  break;
1915  }
1916  if (skill->clone.msg) {
1917  if (!output) return true;
1919  "%s lets you %s a skill:",
1920  tmp->nrof > 1 ? "These objects" : "This object",
1921  (tmp->type == SKILLSCROLL) ? "learn" : "use");
1922 
1924  stringbuffer_append_string(sb, skill->clone.msg);
1926  char *const fluff = stringbuffer_finish(sb);
1927  // SPELL_INFO is not a perfect match here, but it should display in the
1928  // same manner as the spell descriptions below and there's no SKILL_INFO
1929  // message type.
1931  free(fluff);
1932  }
1933  break;
1934  }
1935 
1936  /* Stuff with embedded spells. */
1937  case SPELLBOOK:
1938  case SCROLL:
1939  case WAND:
1940  case ROD:
1941  case POTION:
1942  {
1943  if (tmp->inv && tmp->inv->msg) {
1944  if (!output) return true;
1946  "%s holds%s a spell:",
1947  tmp->nrof > 1 ? "These objects" : "This object",
1948  tmp->type == SPELLBOOK ? " knowledge of" : "");
1949 
1951  stringbuffer_append_string(sb, tmp->inv->msg);
1953  char *const fluff = stringbuffer_finish(sb);
1955  free(fluff);
1956  }
1957  }
1958  }
1959 
1960  if (tmp->lore) {
1961  if (!output) return true;
1963  "%s a story:", tmp->nrof > 1 ? "These objects have" : "This object has");
1965  stringbuffer_append_string(sb, tmp->lore);
1967  char *const msg = stringbuffer_finish(sb);
1969  free(msg);
1970  }
1971 
1972  // If we get this far in output=false mode, we didn't hit any of the earlier
1973  // escape hatches and thus have nothing to output. In normal use we'll hit
1974  // this regardless and assume we output something.
1975  return output;
1976 }
1977 
1987 void examine(object *op, object *tmp) {
1988  if (tmp == NULL || tmp->type == CLOSE_CON)
1989  return;
1990 
1991  /* If the player has examined this twice in a row, do a more detailed
1992  examine. last_examined shouldn't get set unless we already know that
1993  examine_fluff() will do something interesting. */
1994  if (op->contr->last_examined == tmp->count) {
1995  op->contr->last_examined = 0;
1997  "You examine the %s more closely.", tmp->nrof > 1 ? tmp->name_pl : tmp->name);
1998  examine_fluff(op, tmp, true);
2000  " "); /* Blank line */
2001  return;
2002  }
2003 
2004  int i;
2005  char prefix[MAX_BUF] = "";
2006  char buf[VERY_BIG_BUF] = "";
2007  if (is_identified(tmp)) {
2008  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof<=1 ? "That is" : "Those are");
2009  } else {
2010  switch(examine_autoidentify(op, tmp)) {
2011  case EX_ID_NO_SKILL:
2012  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:",
2013  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
2014  break;
2015  case EX_ID_FAILED:
2016  snprintf(prefix, MAX_BUF, "You fail to understand %s:",
2017  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
2018  break;
2019  case EX_ID_ABORT:
2020  default:
2021  /* Item may have been merged with something else, not safe to proceed. */
2022  return;
2023  }
2024  }
2025 
2026  /* now we need to get the rest of the object description */
2027  ob_describe(tmp, op, 1, buf, sizeof(buf));
2028 
2030  "%s %s", prefix, buf);
2031  buf[0] = '\0';
2032  sstring custom_name = object_get_value(tmp, CUSTOM_NAME_FIELD);
2033  if (custom_name) {
2035  "You name it %s",
2036  custom_name);
2037  }
2038 
2039  switch (tmp->type) {
2040  case WAND:
2041  examine_wand_charge_level(op, tmp);
2042  break;
2043 
2044  case ROD:
2045  examine_rod_charge_level(op, tmp);
2046  break;
2047 
2048  case BOOK:
2049  if (tmp->msg != NULL)
2050  snprintf(buf, sizeof(buf), "Something is written in it.");
2051  break;
2052 
2053  case CONTAINER:
2054  if (tmp->race != NULL) {
2055  if (tmp->weight_limit && tmp->stats.Str < 100)
2056  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)));
2057  else
2058  snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
2059  } else
2060  if (tmp->weight_limit && tmp->stats.Str < 100)
2061  snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
2062  break;
2063  }
2064 
2065  if (buf[0] != '\0')
2067  buf);
2068 
2069  examine_weight_and_material(op, tmp);
2070 
2071  /* Where to wear this item */
2072  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
2073  if (tmp->body_info[i]) {
2074  if (op->body_info[i]) {
2075  if (tmp->body_info[i] < -1) {
2077  "%s %s (%d).", tmp->nrof > 1 ? "They go" : "It goes",
2078  body_locations[i].use_name, -tmp->body_info[i]);
2079  } else {
2081  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2083  }
2084  } else {
2086  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2088  }
2089  }
2090  }
2091 
2092  int in_shop = shop_contains(op);
2093 
2094  if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2095  char *value = cost_approx_str(tmp, op);
2096  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
2097  free(value);
2099  buf);
2100  if (in_shop) {
2101  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
2102  if (object_value_set(tmp, "pshop_owner")) {
2103  const char *seller = object_get_value(tmp, "pshop_owner");
2104  snprintf(buf, sizeof(buf), "%s is selling this item.", seller);
2106  }
2107 
2108  value = cost_str(shop_price_buy(tmp, op));
2109  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
2110  free(value);
2111  } else {
2112  value = cost_str(shop_price_sell(tmp, op));
2113  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
2114  free(value);
2115  }
2117  buf);
2118  }
2119  }
2120 
2121  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2122  examine_monster(op, tmp, 0);
2123 
2124  /* Is this item buildable? */
2125  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
2126  int conn;
2127  bool has_link = false;
2128  if (QUERY_FLAG(tmp, FLAG_IS_LINKED) && (conn = get_button_value(tmp))) {
2129  FOR_INV_PREPARE(op, tmp_inv) {
2130  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
2131  && strcmp(tmp_inv->slaying, op->map->path) == 0
2132  && tmp_inv->msg != NULL
2133  && tmp_inv->path_attuned == (uint32_t) conn) {
2134 
2135  has_link = true;
2138  "This is a buildable item, connected with: %s",
2139  tmp_inv->msg);
2140  break;
2141  }
2142  } FOR_INV_FINISH();
2143  }
2144  if (!has_link) {
2146  "This is a buildable item.");
2147  }
2148  }
2149 
2150  /* Does it have fluff text? */
2151  if (examine_fluff(op, tmp, false)) {
2152  op->contr->last_examined = tmp->count;
2154  "Examine again for more details.");
2155  } else {
2156  op->contr->last_examined = 0;
2157  }
2158 
2160  " "); /* Blank line */
2161 
2162  if (is_identified(tmp)) {
2164  }
2165 }
2166 
2175 void inventory(object *op, object *inv) {
2176  const char *in;
2177  int items = 0, length;
2178  char weight[MAX_BUF], name[MAX_BUF];
2179 
2180  if (inv == NULL && op == NULL) {
2182  "Inventory of what object?");
2183  return;
2184  }
2185  FOR_INV_PREPARE(inv ? inv : op, tmp)
2186  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
2187  || !op || QUERY_FLAG(op, FLAG_WIZ))
2188  items++;
2189  FOR_INV_FINISH();
2190  if (inv == NULL) { /* player's inventory */
2191  if (items == 0) {
2193  "You carry nothing.");
2194  return;
2195  } else {
2196  length = 28;
2197  in = "";
2199  "Inventory:");
2200  }
2201  } else {
2202  if (items == 0)
2203  return;
2204  else {
2205  length = 28;
2206  in = " ";
2207  }
2208  }
2209  FOR_INV_PREPARE(inv ? inv : op, tmp) {
2210  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
2211  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
2212  continue;
2213  query_weight(tmp, weight, MAX_BUF);
2214  query_name(tmp, name, MAX_BUF);
2215  if (!op || QUERY_FLAG(op, FLAG_WIZ))
2217  "[fixed]%s- %-*.*s (%5d) %-8s",
2218  in, length, length, name, tmp->count, weight);
2219  else
2221  "[fixed]%s- %-*.*s %-8s",
2222  in, length+8, length+8, name, weight);
2223  } FOR_INV_FINISH();
2224  if (!inv && op) {
2225  query_weight(op, weight, MAX_BUF);
2227  "[fixed]%-*s %-8s",
2228  41, "Total weight :", weight);
2229  }
2230 }
2231 
2240 static void display_new_pickup(const object *op, int old) {
2241  int i = op->contr->mode;
2242 
2243  esrv_send_pickup(op->contr);
2244 
2245  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
2246  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
2248  "Pickup is now %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
2249  }
2250  return;
2251  }
2252 
2254  "%d NEWMODE",
2255  i&PU_NEWMODE ? 1 : 0);
2257  "%d DEBUG",
2258  i&PU_DEBUG ? 1 : 0);
2260  "%d INHIBIT",
2261  i&PU_INHIBIT ? 1 : 0);
2263  "%d STOP",
2264  i&PU_STOP ? 1 : 0);
2265 
2267  "%d <= x pickup weight/value RATIO (0==off)",
2268  (i&PU_RATIO)*5);
2269 
2271  "%d FOOD",
2272  i&PU_FOOD ? 1 : 0);
2274  "%d DRINK",
2275  i&PU_DRINK ? 1 : 0);
2277  "%d VALUABLES",
2278  i&PU_VALUABLES ? 1 : 0);
2279 
2281  "%d BOW",
2282  i&PU_BOW ? 1 : 0);
2284  "%d ARROW",
2285  i&PU_ARROW ? 1 : 0);
2286 
2288  "%d HELMET",
2289  i&PU_HELMET ? 1 : 0);
2291  "%d SHIELD",
2292  i&PU_SHIELD ? 1 : 0);
2294  "%d ARMOUR",
2295  i&PU_ARMOUR ? 1 : 0);
2296 
2298  "%d BOOTS",
2299  i&PU_BOOTS ? 1 : 0);
2301  "%d GLOVES",
2302  i&PU_GLOVES ? 1 : 0);
2304  "%d CLOAK",
2305  i&PU_CLOAK ? 1 : 0);
2307  "%d KEY",
2308  i&PU_KEY ? 1 : 0);
2309 
2311  "%d MISSILEWEAPON",
2312  i&PU_MISSILEWEAPON ? 1 : 0);
2314  "%d MELEEWEAPON",
2315  i&PU_MELEEWEAPON ? 1 : 0);
2317  "%d MAGICAL",
2318  i&PU_MAGICAL ? 1 : 0);
2320  "%d POTION",
2321  i&PU_POTION ? 1 : 0);
2322 
2324  "%d SPELLBOOK",
2325  i&PU_SPELLBOOK ? 1 : 0);
2327  "%d SKILLSCROLL",
2328  i&PU_SKILLSCROLL ? 1 : 0);
2330  "%d READABLES",
2331  i&PU_READABLES ? 1 : 0);
2333  "%d MAGICDEVICE",
2334  i&PU_MAGIC_DEVICE ? 1 : 0);
2335 
2337  "%d NOT CURSED",
2338  i&PU_NOT_CURSED ? 1 : 0);
2339 
2341  "%d JEWELS",
2342  i&PU_JEWELS ? 1 : 0);
2343 
2345  "%d FLESH",
2346  i&PU_FLESH ? 1 : 0);
2347 
2349  "%d CONTAINER",
2350  i&PU_CONTAINER ? 1 : 0);
2351 
2353  "%d CURSED",
2354  i&PU_CURSED ? 1 : 0);
2355 
2357  "");
2358 }
2359 
2369 void command_pickup(object *op, const char *params) {
2370  uint32_t i;
2371 
2372  if (*params == '\0') {
2373  /* if the new mode is used, just print the settings */
2374  if (op->contr->mode&PU_NEWMODE) {
2375  display_new_pickup(op, op->contr->mode);
2376  return;
2377  }
2378  if (1)
2379  LOG(llevDebug, "command_pickup: !params\n");
2380  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
2381  return;
2382  }
2383 
2384  while (*params == ' ')
2385  params++;
2386 
2387  if (*params == '+' || *params == '-' || *params == '!') {
2388  int index = get_pickup_mode_index(params + 1);
2389 
2390  if (index != -1) {
2391  int old = op->contr->mode;
2392  i = op->contr->mode;
2393  if (!(i&PU_NEWMODE))
2394  i = PU_NEWMODE;
2395  if (*params == '+')
2396  i = i|pickup_modes[index];
2397  else if (*params == '-')
2398  i = i&~pickup_modes[index];
2399  else {
2400  if (i&pickup_modes[index])
2401  i = i&~pickup_modes[index];
2402  else
2403  i = i|pickup_modes[index];
2404  }
2405  op->contr->mode = i;
2406  display_new_pickup(op, old);
2407  return;
2408  }
2410  "Pickup: invalid item %s\n",
2411  params);
2412  return;
2413  }
2414 
2415  if (sscanf(params, "%u", &i) != 1) {
2416  if (1)
2417  LOG(llevDebug, "command_pickup: params==NULL\n");
2419  "Usage: pickup <0-7> or <value_density> .");
2420  return;
2421  }
2422  set_pickup_mode(op, i);
2423  display_new_pickup(op, op->contr->mode);
2424 }
2425 
2434 static void set_pickup_mode(const object *op, int i) {
2435  op->contr->mode = i;
2436  switch (op->contr->mode) {
2437  case 0:
2439  "Mode: Don't pick up.");
2440  break;
2441 
2442  case 1:
2444  "Mode: Pick up one item.");
2445  break;
2446 
2447  case 2:
2449  "Mode: Pick up one item and stop.");
2450  break;
2451 
2452  case 3:
2454  "Mode: Stop before picking up.");
2455  break;
2456 
2457  case 4:
2459  "Mode: Pick up all items.");
2460  break;
2461 
2462  case 5:
2464  "Mode: Pick up all items and stop.");
2465  break;
2466 
2467  case 6:
2469  "Mode: Pick up all magic items.");
2470  break;
2471 
2472  case 7:
2474  "Mode: Pick up all coins and gems");
2475  break;
2476  }
2477 }
2478 
2487 void command_search_items(object *op, const char *params) {
2488  if (settings.search_items == FALSE)
2489  return;
2490 
2491  if (!params || *params == '\0') {
2492  if (op->contr->search_str[0] == '\0') {
2494  "Example: search magic+1 "
2495  "Would automatically pick up all "
2496  "items containing the word 'magic+1'.");
2497  return;
2498  }
2499  op->contr->search_str[0] = '\0';
2501  "Search mode turned off.");
2502  fix_object(op);
2503  return;
2504  }
2505  if ((int)strlen(params) >= MAX_BUF) {
2507  "Search string too long.");
2508  return;
2509  }
2510  strcpy(op->contr->search_str, params);
2512  "Searching for '%s'.",
2513  op->contr->search_str);
2514  fix_object(op);
2515 }
2516 
2532 void command_rename_item(object *op, const char *params) {
2533  char buf[VERY_BIG_BUF], name[MAX_BUF];
2534  tag_t itemnumber;
2535  object *item = NULL;
2536  object *tmp;
2537  const char *closebrace;
2538  size_t counter;
2539 
2540  if (*params != '\0') {
2541  /* Let's skip white spaces */
2542  while (' ' == *params)
2543  params++;
2544 
2545  /* Checking the first part */
2546  itemnumber = atoi(params);
2547  if (itemnumber != 0) {
2548  FOR_INV_PREPARE(op, inv)
2549  if (inv->count == itemnumber && !inv->invisible) {
2550  item = inv;
2551  break;
2552  }
2553  FOR_INV_FINISH();
2554  if (!item) {
2556  "Tried to rename an invalid item.");
2557  return;
2558  }
2559  while (isdigit(*params) || ' ' == *params)
2560  params++;
2561  } else if ('<' == *params) {
2562  /* Got old name, let's get it & find appropriate matching item */
2563  closebrace = strchr(params, '>');
2564  if (!closebrace) {
2566  "Syntax error!");
2567  return;
2568  }
2569  /* Sanity check for buffer overruns */
2570  if (closebrace-params > 127) {
2572  "Old name too long (up to 127 characters allowed)!");
2573  return;
2574  }
2575  /* Copy the old name */
2576  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2577 
2578  /* Find best matching item */
2579  item = find_best_object_match(op, buf);
2580  if (!item) {
2582  "Could not find a matching item to rename.");
2583  return;
2584  }
2585 
2586  /* Now need to move pointer to just after > */
2587  params = closebrace+1;
2588  while (' ' == *params)
2589  params++;
2590  } else {
2591  /* Use marked item */
2592  item = find_marked_object(op);
2593  if (!item) {
2595  "No marked item to rename.");
2596  return;
2597  }
2598  }
2599 
2600  /* Now let's find the new name */
2601  if (!strncmp(params, "to ", 3)) {
2602  params += 3;
2603  while (' ' == *params)
2604  params++;
2605  if ('<' != *params) {
2607  "Syntax error, expecting < at start of new name!");
2608  return;
2609  }
2610  closebrace = strchr(params+1, '>');
2611  if (!closebrace) {
2613  "Syntax error, expecting > at end of new name!");
2614  return;
2615  }
2616 
2617  /* Sanity check for buffer overruns */
2618  if (closebrace-params > 127) {
2620  "New name too long (up to 127 characters allowed)!");
2621  return;
2622  }
2623 
2624  /* Copy the new name */
2625  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2626 
2627  /* Let's check it for weird characters */
2628  for (counter = 0; counter < strlen(buf); counter++) {
2629  if (isalnum(buf[counter]))
2630  continue;
2631  if (' ' == buf[counter])
2632  continue;
2633  if ('\'' == buf[counter])
2634  continue;
2635  if ('+' == buf[counter])
2636  continue;
2637  if ('_' == buf[counter])
2638  continue;
2639  if ('-' == buf[counter])
2640  continue;
2641 
2642  /* If we come here, then the name contains an invalid character...
2643  * tell the player & exit
2644  */
2646  "Invalid new name!");
2647  return;
2648  }
2649  } else {
2650  /* If param contains something, then syntax error... */
2651  if (strlen(params)) {
2653  "Syntax error, expected 'to <' after old name!");
2654  return;
2655  }
2656  /* New name is empty */
2657  buf[0] = '\0';
2658  }
2659  } else {
2660  /* Last case: *params=='\0' */
2661  item = find_marked_object(op);
2662  if (!item) {
2664  "No marked item to rename.");
2665  return;
2666  }
2667  buf[0] = '\0';
2668  }
2669 
2670  /* Coming here, everything is fine... */
2671  if (!strlen(buf)) {
2672  /* Clear custom name */
2673  if (object_get_value(item, CUSTOM_NAME_FIELD) == NULL) {
2675  "This item has no custom name.");
2676  return;
2677  }
2678 
2679  object_set_value(item, CUSTOM_NAME_FIELD, NULL, 0);
2680  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2682  "You stop calling your %s with weird names.",
2683  name);
2684  } else {
2685  sstring custom_name = object_get_value(item, CUSTOM_NAME_FIELD);
2686  if (custom_name != NULL && strcmp(custom_name, buf) == 0) {
2687  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2689  "You keep calling your %s %s.",
2690  name, buf);
2691  return;
2692  }
2693 
2694  /* Set custom name */
2696 
2697  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2699  "Your %s will now be called %s.",
2700  name, buf);
2701  }
2702 
2703  tmp = object_merge(item, NULL);
2704  if (tmp == NULL) {
2705  /* object was not merged - if it was, object_merge() handles updating for us. */
2706  esrv_update_item(UPD_NAME, op, item);
2707  }
2708 }
2709 
2718 void command_lock_item(object *op, const char *params) {
2719  object *item;
2720  object *tmp;
2721  char name[HUGE_BUF];
2722 
2723  if (*params == '\0' || strlen(params) == 0) {
2725  "Lock what item?");
2726  return;
2727  }
2728 
2729  item = find_best_object_match(op, params);
2730  if (!item) {
2732  "Can't find any matching item.");
2733  return;
2734  }
2735 
2736  query_short_name(item, name, HUGE_BUF);
2737  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2739  "Unlocked %s.", name);
2740  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2741  } else {
2743  "Locked %s.", name);
2744  SET_FLAG(item, FLAG_INV_LOCKED);
2745  }
2746 
2747  tmp = object_merge(item, NULL);
2748  if (tmp == NULL) {
2749  /* object was not merged, if it was object_merge() handles updates for us */
2750  esrv_update_item(UPD_FLAGS, op, item);
2751  }
2752 }
2753 
2761 void command_use(object *op, const char *params) {
2762  char *with, copy[MAX_BUF];
2763  object *first, *second/*, *add*/;
2764  /*archetype *arch;*/
2765  /*int count;*/
2766  /*sstring data;*/
2767  recipe *transformation;
2768 
2769  if (!IS_PLAYER(op))
2770  return;
2771 
2772  strlcpy(copy, params, sizeof(copy));
2773  with = strstr(copy, " with ");
2774  if (!with) {
2775  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2776  return;
2777  }
2778 
2779  with[0] = '\0';
2780  with = with+strlen(" with ");
2781 
2782  first = find_best_object_match(op, copy);
2783  if (!first) {
2784  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2785  return;
2786  }
2787  second = find_best_object_match(op, with);
2788  if (!second) {
2789  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2790  return;
2791  }
2792 
2793  transformation = NULL;
2794  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2796  if (transformation->ingred_count != 1)
2797  continue;
2798 
2799 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2800  if (strcmp(second->name, transformation->ingred->name) == 0) {
2802  object *generated = create_archetype(transformation->arch_name[0]);
2803  if (transformation->yield)
2804  generated->nrof = transformation->yield;
2805  object_insert_in_ob(generated, op);
2806  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2808  return;
2809  }
2810  }
2811  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2812  return;
2813 
2814  /*
2815  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2816  data = object_get_value(second, copy);
2817  if (!data) {
2818  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2819  data = object_get_value(second, copy);
2820  if (!data) {
2821  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2822  data = object_get_value(second, copy);
2823  if (!data) {
2824  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2825  return 1;
2826  }
2827  }
2828  }
2829 
2830  while (data != NULL) {
2831  if (strncmp(data, "add ", 4) == 0) {
2832  data += 4;
2833  if (isdigit(*data)) {
2834  count = atol(data);
2835  data = strchr(data, ' ')+1;
2836  } else
2837  count = 1;
2838  with = strchr(data, ' ');
2839  if (!with) {
2840  strncpy(copy, data, sizeof(copy));
2841  data = NULL;
2842  } else {
2843  *with = '\0';
2844  strncpy(copy, data, sizeof(copy));
2845  data += strlen(copy)+1;
2846  }
2847  arch = find_archetype(copy);
2848  if (!arch) {
2849  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2850  return 1;
2851  }
2852  add = object_create_arch(arch);
2853  add->nrof = count;
2854  object_insert_in_ob(add, op);
2855  } else if (strncmp(data, "remove $", 8) == 0) {
2856  data += 8;
2857  if (*data == '1') {
2858  if (first)
2859  first = object_decrease_nrof_by_one(first);
2860  data += 2;
2861  } else if (*data == '2') {
2862  if (second)
2863  second = object_decrease_nrof_by_one(second);
2864  data += 2;
2865  } else {
2866  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2867  return 1;
2868  }
2869  } else {
2870  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2871  return 1;
2872  }
2873  }
2874 
2875  return 1;
2876  */
2877 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:70
object_value_set
bool object_value_set(const object *op, const char *const key)
Determine if an extra value is set.
Definition: object.cpp:4361
drop
void drop(object *op, object *tmp)
Drop an item, either on the floor or in a container.
Definition: c_object.cpp:1170
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:897
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
Global 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:796
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:534
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:411
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:2532
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:2036
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:1616
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:1987
SK_DET_MAGIC
@ SK_DET_MAGIC
Detect magic.
Definition: skills.h:30
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:320
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:128
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:2761
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:1880
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:776
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
EVENT_DROP
#define EVENT_DROP
Object dropped on the floor.
Definition: events.h:35
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:1814
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:536
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:1569
command_pickup
void command_pickup(object *op, const char *params)
'pickup' command.
Definition: c_object.cpp:2369
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:533
matcher_params::item_to_pick
int item_to_pick
Index of the item to pick, 1-based.
Definition: c_object.cpp:716
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:643
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:355
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:1695
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:251
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:309
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:2842
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:2434
POISONING
@ POISONING
Definition: object.h:223
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:408
command_drop
void command_drop(object *op, const char *params)
'drop' command.
Definition: c_object.cpp:1356
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:108
command_empty
void command_empty(object *op, const char *params)
'empty' command.
Definition: c_object.cpp:1452
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:658
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:1545
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:939
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:742
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:328
matcher_params::pickup_type
int pickup_type
Value in Pickup modes to match against.
Definition: c_object.cpp:721
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:594
matcher_params::name
char name[MAX_BUF]
Name to match for.
Definition: c_object.cpp:720
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:1788
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:756
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:530
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:4093
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:518
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:380
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:1360
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:1414
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:319
NDI_GOLD
#define NDI_GOLD
Definition: newclient.h:258
command_dropall
void command_dropall(object *op, const char *params)
Command to drop all items that have not been locked.
Definition: c_object.cpp:1232
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:591
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:713
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:56
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:4559
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:808
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:415
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:2085
command_search_items
void command_search_items(object *op, const char *params)
'search-items' command.
Definition: c_object.cpp:2487
inventory
void inventory(object *op, object *inv)
Prints object's inventory.
Definition: c_object.cpp:2175
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
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:2346
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:3153
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:718
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:535
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:537
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:266
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:733
query_weight
void query_weight(const object *op, char *buf, size_t size)
Formats the item's weight.
Definition: item.cpp:420
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:312
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:3852
stringbuffer_trim_whitespace
void stringbuffer_trim_whitespace(StringBuffer *sb)
Trim trailing whitespace from a stringbuffer.
Definition: stringbuffer.cpp:222
EVENT_PICKUP
#define EVENT_PICKUP
Object picked up.
Definition: events.h:36
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
cost_str
char * cost_str(uint64_t cost)
Definition: shop.cpp:308
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:1336
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
pick_up
bool pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.cpp:520
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:2622
shop_contains
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: map.cpp:2764
command_examine
void command_examine(object *op, const char *params)
'examine' command.
Definition: c_object.cpp:1491
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:1875
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:325
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
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
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:1522
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:2240
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:322
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:239
Settings::real_wiz
uint8_t real_wiz
Use mud-like wizards.
Definition: global.h:272
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:1818
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:1075
EX_ID_FAILED
@ EX_ID_FAILED
Definition: c_object.cpp:1698
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:1843
DRINK
@ DRINK
Definition: object.h:162
sell_item
void sell_item(object *op, object *pl)
Player is selling an item.
Definition: shop.cpp:915
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:2718
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:723
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:695
Settings::search_items
uint8_t search_items
Search_items command.
Definition: global.h:268
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:4484
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:847
BOOTS
@ BOOTS
Definition: object.h:217
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:717
PU_SHIELD
#define PU_SHIELD
Definition: define.h:122
EX_ID_NO_SKILL
@ EX_ID_NO_SKILL
Definition: c_object.cpp:1697
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:592
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:1696
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:154
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:1712
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