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 
302 bool csv_contains(std::string list, std::string item, std::string delim) {
303  size_t pos;
304  while (true) {
305  pos = list.find(delim);
306  auto match = list.substr(0, pos);
307  if (item == match)
308  return true;
309 
310  if (pos == std::string::npos)
311  return false;
312  list.erase(0, pos + 1);
313  }
314  return false;
315 }
316 
329 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
330  /* buf needs to be big (more than 256 chars) because you can get
331  * very long item names.
332  */
333  char buf[HUGE_BUF], name[MAX_BUF];
334  object *env = tmp->env;
335  uint32_t weight, effective_weight_limit;
336  const int tmp_nrof = NROF(tmp);
337  tag_t tag;
338  mapstruct* map = tmp->map;
339  int16_t x = tmp->x, y = tmp->y;
340 
341  /* IF the player is flying & trying to take the item out of a container
342  * that is in his inventory, let him. tmp->env points to the container
343  * (sack, luggage, etc), tmp->env->env then points to the player (nested
344  * containers not allowed as of now)
345  */
346  if ((pl->move_type&MOVE_FLYING)
347  && !QUERY_FLAG(pl, FLAG_WIZ)
348  && object_get_player_container(tmp) != pl) {
350  "You are levitating, you can't reach the ground!");
351  return;
352  }
353  if (QUERY_FLAG(tmp, FLAG_NO_DROP))
354  return;
355 
356  if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
358  "The object disappears in a puff of smoke! It must have been an illusion.");
359  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
360  object_remove(tmp);
362  return;
363  }
364 
365  if (nrof > tmp_nrof || nrof == 0)
366  nrof = tmp_nrof;
367 
368  /* Figure out how much weight this object will add to the player */
369  weight = tmp->weight*nrof;
370  if (tmp->inv)
371  weight += tmp->carrying*(100-tmp->stats.Str)/100;
372 
373  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
374 
375  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
377  "That item is too heavy for you to pick up.");
378  return;
379  }
380 
382  SET_FLAG(tmp, FLAG_WAS_WIZ);
383 
384  if (nrof != tmp_nrof) {
385  char failure[MAX_BUF];
386 
387  tmp = object_split(tmp, nrof, failure, sizeof(failure));
388  if (!tmp) {
390  failure);
391  return;
392  }
393  } else {
394  /* If the object is in a container, send a delete to the client.
395  * - we are moving all the items from the container to elsewhere,
396  * so it needs to be deleted.
397  */
398  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
399  object_remove(tmp); /* Unlink it */
400  }
401  }
402  query_name(tmp, name, MAX_BUF);
403 
404  if (pl->type == PLAYER && QUERY_FLAG(tmp, FLAG_UNPAID)) {
405  char *value = cost_str(shop_price_buy(tmp, pl));
406  if (op == pl) {
407  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
408  } else {
409  snprintf(buf, sizeof(buf), "%s will cost you %s. You place it in your %s.", name, value, op->name);
410  }
411  free(value);
412  } else {
413  if (op == pl) {
414  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
415  } else {
416  snprintf(buf, sizeof(buf), "You pick up the %s and put it in your %s.", name, op->name);
417  }
418  }
419 
420  /* Now item is about to be picked. */
421  tag = tmp->count;
422  if (events_execute_object_event(tmp, EVENT_PICKUP, pl, op, NULL, SCRIPT_FIX_ALL) != 0) {
423  /* put item back, if it still exists */
424  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
425  if (env != NULL) {
426  object_insert_in_ob(tmp, env);
427  } else {
428  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
429  }
430  }
431  return;
432  }
433 
435  buf);
436 
437  object_insert_in_ob(tmp, op);
438 
439  /* All the stuff below deals with client/server code, and is only
440  * usable by players
441  */
442  if (pl->type != PLAYER)
443  return;
444 
445  /* Additional weight changes speed, etc */
446  fix_object(pl);
447 
448  /* These are needed to update the weight for the container we
449  * are putting the object in.
450  */
451  if (op != pl) {
452  esrv_update_item(UPD_WEIGHT, pl, op);
453  esrv_update_item(UPD_WEIGHT, pl, pl);
454  }
455 
456  /* Update the container the object was in */
457  if (env && env != pl && env != op)
459 }
460 
470 bool pick_up(object *op, object *alt) {
471 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
472  object *tmp = NULL, *tmp1;
473  mapstruct *tmp_map = NULL;
474  int count;
475 
476  /* Decide which object to pick. */
477  if (alt) {
478  if (!object_can_pick(op, alt)) {
480  "You can't pick up the %s.",
481  alt->name);
482  return false;
483  }
484  tmp = alt;
485  } else {
486  if (op->below == NULL || !object_can_pick(op, op->below)) {
488  "There is nothing to pick up here.");
489  return false;
490  }
491  tmp = op->below;
492  }
493 
494  /* it is possible that the object is a thrown object and is flying about.
495  * in that case, what we want to pick up is the payload. Objects
496  * that are thrown are encapsulated into a thrown object.
497  * stop_item() returns the payload (unlinked from map) and gets rid of the
498  * container object. If this object isn't picked up, we need to insert
499  * it back on the map.
500  * A bug here is that even attempting to pick up one of these objects will
501  * result in this logic being called even if player is unable to pick it
502  * up.
503  */
504 
505  tmp_map = tmp->map;
506  tmp1 = stop_item(tmp);
507  if (tmp1 == NULL)
508  return false;
509 
510  /* If it is a thrown object, insert it back into the map here.
511  * makes life easier further along. Do no merge so pick up code
512  * behaves more sanely.
513  */
514  if (tmp1 != tmp) {
515  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
516  }
517 
518  if (tmp == NULL)
519  return false;
520 
521  if (!object_can_pick(op, tmp))
522  return false;
523 
524  /* Establish how many of the object we are picking up */
525  if (op->type == PLAYER) {
526  count = op->contr->count;
527  if (count == 0)
528  count = tmp->nrof;
529  } else
530  count = tmp->nrof;
531 
532  /* container is open, so use it */
533  if (op->container) {
534  alt = op->container;
535  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
536  return false;
537  } else {
538  /* non container pickup. See if player has any
539  * active containers.
540  */
541  object *container = NULL;
542 
543  /* Look for any active containers that can hold this item.
544  * we cover two cases here - the perfect match case, where we
545  * break out of the loop, and the general case (have a container),
546  * Moved this into a single loop - reduces redundant code, is
547  * more efficient and easier to follow. MSW 2009-04-06
548  */
549  alt = op->inv;
551  if (alt->type == CONTAINER
552  && QUERY_FLAG(alt, FLAG_APPLIED)
553  && sack_can_hold(NULL, alt, tmp, count)) {
554  if (alt->race && alt->race == tmp->race) {
555  break; /* perfect match */
556  } else if (!container) {
557  container = alt;
558  }
559  }
561  /* Note container could be null, but no reason to check for it */
562  if (!alt)
563  alt = container;
564 
565  if (!alt)
566  alt = op; /* No free containers */
567  }
568  /* see if this object is already in this container. If so,
569  * move it to player inventory from this container.
570  */
571  if (tmp->env == alt) {
572  alt = op;
573  }
574 
575  /* Don't allow players to be put into containers. Instead,
576  * just put them in the players inventory.
577  */
578  if ((tmp->type == CONTAINER || tmp->type == MIMIC) && alt->type==CONTAINER) {
579  alt = op;
580  }
581 #ifdef PICKUP_DEBUG
582  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
583 #endif
584 
585  /* startequip items are not allowed to be put into containers
586  * Not sure why we have this limitation
587  */
588  if (op->type == PLAYER
589  && alt->type == CONTAINER
590  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
592  "This object cannot be put into containers!");
593  return false;
594  }
595 
596  pick_up_object(op, alt, tmp, count);
597  if (op->type == PLAYER)
598  op->contr->count = 0;
599  return true;
600 }
601 
608 int object_matches_pickup_mode(const object *item, int mode) {
609  switch(mode) {
610  case PU_FOOD:
611  return item->type == FOOD;
612  case PU_DRINK:
613  return item->type == DRINK || (item->type == POISON && !QUERY_FLAG(item, FLAG_KNOWN_CURSED));
614  case PU_FLESH:
615  return item->type == FLESH;
616  case PU_POTION:
617  return item->type == POTION;
618  case PU_SPELLBOOK:
619  return item->type == SPELLBOOK;
620  case PU_SKILLSCROLL:
621  return item->type == SKILLSCROLL;
622  case PU_READABLES:
623  return item->type == BOOK || item->type == SCROLL;
624  case PU_MAGIC_DEVICE:
625  return item->type == WAND || item->type == ROD || item->type == WEAPON_IMPROVER || item->type == ARMOUR_IMPROVER || item->type == SKILL_TOOL;
626  case PU_MAGICAL:
628  case PU_VALUABLES:
629  return item->type == MONEY || item->type == GEM;
630  case PU_JEWELS:
631  return item->type == RING || item->type == AMULET;
632  case PU_BOW:
633  return item->type == BOW;
634  case PU_ARROW:
635  return item->type == ARROW;
636  case PU_ARMOUR:
637  return item->type == ARMOUR;
638  case PU_HELMET:
639  return item->type == HELMET;
640  case PU_SHIELD:
641  return item->type == SHIELD;
642  case PU_BOOTS:
643  return item->type == BOOTS;
644  case PU_GLOVES:
645  return item->type == GLOVES;
646  case PU_CLOAK:
647  return item->type == CLOAK;
648  case PU_MISSILEWEAPON:
649  return item->type == WEAPON && QUERY_FLAG(item, FLAG_IS_THROWN);
650  case PU_MELEEWEAPON:
651  return item->type == WEAPON;
652  case PU_KEY:
653  return item->type == KEY || item->type == SPECIAL_KEY;
654  case PU_CONTAINER:
655  return item->type == CONTAINER;
656  case PU_CURSED:
657  return QUERY_FLAG(item, FLAG_KNOWN_CURSED);
658  }
659  return 0;
660 }
661 
664  union {
665  struct {
669  };
670  char name[MAX_BUF];
672  };
673  int missed;
674 };
675 
683 typedef int (*item_matcher)(object *who, matcher_params *params, object *item);
684 
692 static int matcher_all(object *who, matcher_params *params, object *item) {
693  (void)who;
694  (void)params;
695  (void)item;
696  return 1;
697 }
698 
706 static int matcher_number(object *who, matcher_params *params, object *item) {
707  if (params->item_must_be_pickable == 0 || object_can_pick(who, item)) {
708  params->item_number++;
709  }
710  if (params->item_to_pick == params->item_number) {
711  /* Since we don't always increase item_number, multiple items may have the same index,
712  including unpickable ones, so to avoid failure messages just ensure no other item can be picked. */
713  params->item_to_pick = 0;
714  return 1;
715  }
716  return 0;
717 }
718 
726 static int matcher_name(object *who, matcher_params *params, object *item) {
727  int ival = object_matches_string(who, item, params->name);
728  if (ival > 0) {
729  if (ival <= 2 && !object_can_pick(who, item)) {
730  if (!QUERY_FLAG(item, FLAG_IS_FLOOR))/* don't count floor tiles */
731  params->missed++;
732  return 0;
733  }
734  return 1;
735  }
736  return 0;
737 }
738 
746 static int matcher_pickup_type(object *who, matcher_params *params, object *item) {
747  (void)who;
748  return object_matches_pickup_mode(item, params->pickup_type);
749 }
750 
758 static item_matcher make_matcher(object *who, const char *params, matcher_params *mp) {
759  memset(mp, 0, sizeof(*mp));
760  if (params[0] == '\0') {
761  mp->item_to_pick = 1;
762  mp->item_must_be_pickable = 1;
763  return &matcher_number;
764  }
765  if (params[0] == '#') {
766  mp->item_to_pick = atoi(params + 1);
767  if (mp->item_to_pick == 0) {
769  return NULL;
770  }
771  return &matcher_number;
772  }
773  if (params[0] == '*') {
774  if (params[1] == '\0') {
775  return &matcher_all;
776  }
777  int idx = get_pickup_mode_index(params + 1);
778  if (idx == -1) {
779  draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, "Invalid items %s", params + 1);
780  return NULL;
781  }
782  mp->pickup_type = pickup_modes[idx];
783  return &matcher_pickup_type;
784  }
785  strncpy(mp->name, params, sizeof(mp->name) - 1);
786  return &matcher_name;
787 }
788 
797 void command_take(object *op, const char *params) {
798  object *tmp;
799  int did_one = 0;
800 
801  if (op->container)
802  tmp = op->container->inv;
803  else {
804  tmp = op->above;
805  if (tmp)
806  while (tmp->above) {
807  tmp = tmp->above;
808  }
809  if (!tmp)
810  tmp = op->below;
811  }
812 
813  if (tmp == NULL) {
815  "Nothing to take!");
816  return;
817  }
818 
819  matcher_params mp;
820  item_matcher matcher = make_matcher(op, params, &mp);
821  if (!matcher) {
822  return; // Player already informed of failure.
823  }
824 
826 
828  if (tmp->invisible) {
829  continue;
830  }
831  if ((*matcher)(op, &mp, tmp)) {
832  pick_up(op, tmp);
833  did_one = 1;
834  }
836 
837  /* Nothing picked up, check if unable to pick or nothing to pick. */
838  if (params[0] == '\0' && !did_one) {
839  int found = 0;
840  FOR_BELOW_PREPARE(op, tmp)
841  if (!tmp->invisible) {
843  "You can't pick up a %s.",
844  tmp->name ? tmp->name : "null");
845  found = 1;
846  break;
847  }
849  if (!found)
851  "There is nothing to pick up.");
852  }
853 
854  if (mp.missed == 1)
856  "You were unable to take one of the items.");
857  else if (mp.missed > 1)
859  "You were unable to take %d of the items.",
860  mp.missed);
861 
862  /* Now update player and send information. */
864  fix_object(op);
865  if (op->type == PLAYER) {
866  op->contr->count = 0;
867  esrv_update_item(UPD_WEIGHT, op, op);
868  }
869 }
870 
889 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
890  object *sack2, *orig = sack;
891  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
892 
893  if (sack == tmp)
894  return; /* Can't put an object in itself */
895  query_name(sack, name_sack, MAX_BUF);
896  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
898  "The %s is not a container.",
899  name_sack);
900  return;
901  }
902  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
903  query_name(tmp, name_tmp, MAX_BUF);
905  "You cannot put the %s in the %s.",
906  name_tmp, name_sack);
907  return;
908  }
909  if (tmp->type == CONTAINER) {
910  if (tmp->inv) {
911  if (tmp->slaying)
912  return;
913  /* Eneq(@csd.uu.se): If the object to be dropped is a container
914  * and does not require a key to be opened,
915  * we instead move the contents of that container into the active
916  * container, this is only done if the object has something in it.
917  * If object is container but need a key, just don't do anything
918  */
919  sack2 = tmp;
920  query_name(tmp, name_tmp, MAX_BUF);
922  "You move the items from %s into %s.",
923  name_tmp, name_sack);
924 
925  FOR_INV_PREPARE(tmp, tmp2) {
926  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
927  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
928  put_object_in_sack(op, sack, tmp2, 0);
929  } else {
932  "Your %s fills up.",
933  name_sack);
934  break;
935  }
936  } FOR_INV_FINISH();
937  esrv_update_item(UPD_WEIGHT, op, sack2);
938  return;
939  } else {
940  query_name(tmp, name_tmp, MAX_BUF);
942  "You can not put a %s into a %s",
943  name_tmp,
944  name_sack);
945  return;
946  }
947  }
948 
949  /* Don't worry about this for containers - our caller should have
950  * already checked this.
951  */
952  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
953  return;
954 
955  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
956  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
957  return;
958  }
959 
960  /* we want to put some portion of the item into the container */
961  if (nrof && tmp->nrof != nrof) {
962  char failure[MAX_BUF];
963 
964  tmp = object_split(tmp, nrof, failure, sizeof(failure));
965 
966  if (!tmp) {
968  failure);
969  return;
970  }
971  } else
972  object_remove(tmp);
973 
974  if (sack->nrof > 1) {
975  orig = object_split(sack, sack->nrof-1, NULL, 0);
976  set_object_face_main(orig);
977  CLEAR_FLAG(orig, FLAG_APPLIED);
978  if (sack->env) {
979  object_insert_in_ob(orig, sack->env);
980  } else {
981  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
982  orig->move_off = 0;
983  }
984  }
985 
986  query_name(tmp, name_tmp, MAX_BUF);
988  "You put the %s in %s.",
989  name_tmp, name_sack);
990 
991  object_insert_in_ob(tmp, sack);
992  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
993  fix_object(op); /* This is overkill, fix_player() is called somewhere */
994  /* in object.c */
995 
996  /* If a transport, need to update all the players in the transport
997  * the view of what is in it.
998  */
999  if (sack->type == TRANSPORT) {
1000  FOR_INV_PREPARE(sack, tmp)
1001  if (tmp->type == PLAYER)
1002  tmp->contr->socket->update_look = 1;
1003  FOR_INV_FINISH();
1004  } else {
1005  /* update the sacks weight */
1006  esrv_update_item(UPD_WEIGHT, op, sack);
1007  }
1008 }
1009 
1025 object *drop_object(object *op, object *tmp, uint32_t nrof) {
1026  tag_t tmp_tag;
1027 
1028  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1029  return NULL;
1030  }
1031 
1032  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1033  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
1034  return NULL; /* can't unapply it */
1035  }
1036 
1037  if (events_execute_object_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1038  return NULL;
1039 
1040  /* ensure the plugin didn't destroy the object */
1041  if (QUERY_FLAG(tmp, FLAG_REMOVED))
1042  return NULL;
1043 
1044  /* We are only dropping some of the items. We split the current objec
1045  * off
1046  */
1047  if (nrof && tmp->nrof != nrof) {
1048  char failure[MAX_BUF];
1049 
1050  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1051  if (!tmp) {
1053  failure);
1054  return NULL;
1055  }
1056  } else
1057  object_remove(tmp);
1058 
1059  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
1060  char name[MAX_BUF];
1061 
1062  query_name(tmp, name, MAX_BUF);
1064  "You drop the %s. The gods who lent it to you retrieve it.",
1065  name);
1067 
1068  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1069  fix_object(op);
1070 
1071  return NULL;
1072  }
1073 
1074  /* If SAVE_INTERVAL is commented out, we never want to save
1075  * the player here.
1076  */
1077 #ifdef SAVE_INTERVAL
1078  /* I'm not sure why there is a value check - since the save
1079  * is done every SAVE_INTERVAL seconds, why care the value
1080  * of what he is dropping?
1081  */
1082  if (op->type == PLAYER
1083  && !QUERY_FLAG(tmp, FLAG_UNPAID)
1084  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
1085  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
1086  save_player(op, 1);
1087  op->contr->last_save_time = time(NULL);
1088  }
1089 #endif /* SAVE_INTERVAL */
1090 
1091 
1092  tmp_tag = tmp->count;
1093  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
1094  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
1095  sell_item(tmp, op);
1096  }
1097 
1098  /* Call this before we update the various windows/players. At least
1099  * that we, we know the weight is correct.
1100  */
1101  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
1102  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1103  /* in object.c */
1104 
1105  /* Need to update weight of player */
1106  if (op->type == PLAYER)
1107  esrv_update_item(UPD_WEIGHT, op, op);
1108  }
1109  return tmp;
1110 }
1111 
1120 void drop(object *op, object *tmp) {
1121  /* Hopeful fix for disappearing objects when dropping from a container -
1122  * somehow, players get an invisible object in the container, and the
1123  * old logic would skip over invisible objects - works fine for the
1124  * playes inventory, but drop inventory wants to use the next value.
1125  */
1126  if (tmp->invisible) {
1127  /* if the following is the case, it must be in an container. */
1128  if (tmp->env && tmp->env->type != PLAYER) {
1129  /* Just toss the object - probably shouldn't be hanging
1130  * around anyways
1131  */
1132  object_remove(tmp);
1134  return;
1135  } else {
1137  if (!tmp->invisible)
1138  break;
1140  }
1141  }
1142 
1143  if (tmp == NULL) {
1145  "You don't have anything to drop.");
1146  return;
1147  }
1148  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1150  "This item is locked");
1151  return;
1152  }
1153  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1154  return;
1155  }
1156 
1157  if (op->container) {
1158  if (op->type == PLAYER) {
1159  put_object_in_sack(op, op->container, tmp, op->contr->count);
1160  } else {
1161  put_object_in_sack(op, op->container, tmp, 0);
1162  };
1163  } else {
1164  if (op->type == PLAYER) {
1165  drop_object(op, tmp, op->contr->count);
1166  } else {
1167  drop_object(op, tmp, 0);
1168  };
1169  }
1170  if (op->type == PLAYER)
1171  op->contr->count = 0;
1172 }
1173 
1182 void command_dropall(object *op, const char *params) {
1183  int count = 0;
1184 
1185  if (op->inv == NULL) {
1186  draw_ext_info(NDI_UNIQUE, 0, op,
1188  "Nothing to drop!");
1189  return;
1190  }
1191 
1192  if (op->contr)
1193  count = op->contr->count;
1194 
1195  /* Set this so we don't call it for _every_ object that
1196  * is dropped.
1197  */
1199 
1200  /*
1201  * This is the default. Drops everything not locked or considered
1202  * not something that should be dropped.
1203  * Care must be taken that the next item pointer is not to money as
1204  * the drop() routine will do unknown things to it when dropping
1205  * in a shop. --Tero.Pelander@utu.fi
1206  */
1207  if (*params == '\0') {
1208  FOR_INV_PREPARE(op, curinv) {
1209  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1210  && curinv->type != MONEY
1211  && curinv->type != FOOD
1212  && curinv->type != KEY
1213  && curinv->type != SPECIAL_KEY
1214  && curinv->type != GEM
1215  && !curinv->invisible
1216  && (curinv->type != CONTAINER || op->container != curinv)) {
1217  drop(op, curinv);
1218  if (op->contr)
1219  op->contr->count = count;
1220  }
1221  } FOR_INV_FINISH();
1222  } else if (strcmp(params, "weapons") == 0) {
1223  FOR_INV_PREPARE(op, curinv) {
1224  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1225  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1226  drop(op, curinv);
1227  if (op->contr)
1228  op->contr->count = count;
1229  }
1230  } FOR_INV_FINISH();
1231  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1232  FOR_INV_PREPARE(op, curinv) {
1233  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1234  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1235  drop(op, curinv);
1236  if (op->contr)
1237  op->contr->count = count;
1238  }
1239  } FOR_INV_FINISH();
1240  } else if (strcmp(params, "food") == 0) {
1241  FOR_INV_PREPARE(op, curinv) {
1242  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1243  && (curinv->type == FOOD || curinv->type == DRINK)) {
1244  drop(op, curinv);
1245  if (op->contr)
1246  op->contr->count = count;
1247  }
1248  } FOR_INV_FINISH();
1249  } else if (strcmp(params, "flesh") == 0) {
1250  FOR_INV_PREPARE(op, curinv) {
1251  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1252  && (curinv->type == FLESH)) {
1253  drop(op, curinv);
1254  if (op->contr)
1255  op->contr->count = count;
1256  }
1257  } FOR_INV_FINISH();
1258  } else if (strcmp(params, "misc") == 0) {
1259  FOR_INV_PREPARE(op, curinv) {
1260  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1261  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1262  switch (curinv->type) {
1263  case BOOK:
1264  case SPELLBOOK:
1265  case GIRDLE:
1266  case AMULET:
1267  case RING:
1268  case CLOAK:
1269  case BOOTS:
1270  case GLOVES:
1271  case BRACERS:
1272  case SCROLL:
1273  case ARMOUR_IMPROVER:
1274  case WEAPON_IMPROVER:
1275  case WAND:
1276  case ROD:
1277  case POTION:
1278  drop(op, curinv);
1279  if (op->contr)
1280  op->contr->count = count;
1281  break;
1282 
1283  default:
1284  break;
1285  }
1286  }
1287  } FOR_INV_FINISH();
1288  }
1289  op->contr->socket->update_look = 1;
1291  /* call it now, once */
1292  fix_object(op);
1293  /* Need to update weight of player. Likewise, only do it once */
1294  if (op->type == PLAYER)
1295  esrv_update_item(UPD_WEIGHT, op, op);
1296 }
1297 
1306 void command_drop(object *op, const char *params) {
1307  int did_one = 0;
1308  int missed = 0;
1309 
1310  if (*params == '\0') {
1312  "Drop what?");
1313  return;
1314  }
1315 
1316  matcher_params mp;
1317  item_matcher matcher = make_matcher(op, params, &mp);
1318  if (!matcher) {
1319  return;
1320  }
1321 
1323 
1324  FOR_INV_PREPARE(op, tmp) {
1325  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1326  continue;
1327  if ((*matcher)(op, &mp, tmp)) {
1328  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1329  missed++;
1330  } else {
1331  drop(op, tmp);
1332  }
1333  did_one = 1;
1334  }
1335  } FOR_INV_FINISH();
1336  if (!did_one)
1338  "Nothing to drop.");
1339  if (missed == 1)
1341  "One item couldn't be dropped because it was locked.");
1342  else if (missed > 1)
1344  "%d items couldn't be dropped because they were locked.",
1345  missed);
1346 
1347  /* Now update player and send information. */
1349  fix_object(op);
1350  if (op->type == PLAYER) {
1351  op->contr->count = 0;
1352  esrv_update_item(UPD_WEIGHT, op, op);
1353  }
1354 }
1355 
1364 static void empty_container(object *container, object *pl) {
1365  int left = 0;
1366  char name[MAX_BUF];
1367 
1368  if (!container->inv)
1369  return;
1370 
1371  FOR_INV_PREPARE(container, inv) {
1372  object *next;
1373 
1374  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1375  /* you can have locked items in container. */
1376  left++;
1377  continue;
1378  }
1379  next = inv->below;
1380  drop(pl, inv);
1381  if (inv->below == next)
1382  /* item couldn't be dropped for some reason. */
1383  left++;
1384  } FOR_INV_FINISH();
1385  esrv_update_item(UPD_WEIGHT, pl, container);
1386 
1387  query_name(container, name, sizeof(name));
1388  if (left)
1389  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1390  else
1392 }
1393 
1402 void command_empty(object *op, const char *params) {
1403  object *container;
1404 
1405  if (*params == '\0') {
1407  "Empty what?");
1408  return;
1409  }
1410 
1411  if (strcmp(params, "all") == 0) {
1412  FOR_INV_PREPARE(op, inv)
1413  if (inv->type == CONTAINER)
1414  empty_container(inv, op);
1415  FOR_INV_FINISH();
1416  return;
1417  }
1418 
1419  container = find_best_object_match(op, params);
1420  if (!container) {
1422  "No such item.");
1423  return;
1424  }
1425  if (container->type != CONTAINER) {
1427  "This is not a container!");
1428  return;
1429  }
1430  empty_container(container, op);
1431 }
1432 
1441 void command_examine(object *op, const char *params) {
1442  if (*params == '\0') {
1443  FOR_BELOW_PREPARE(op, tmp)
1444  if (LOOK_OBJ(tmp)) {
1445  examine(op, tmp);
1446  break;
1447  }
1448  FOR_BELOW_FINISH();
1449  } else {
1450  object *tmp = find_best_object_match(op, params);
1451 
1452  if (tmp)
1453  examine(op, tmp);
1454  else
1456  "Could not find an object that matches %s",
1457  params);
1458  }
1459 }
1460 
1472 object *find_marked_object(object *op) {
1473  if (!op || !op->contr || !op->contr->mark)
1474  return NULL;
1475 
1476  /* This may seem like overkill, but we need to make sure that they
1477  * player hasn't dropped the item. We use count on the off chance that
1478  * an item got reincarnated at some point.
1479  */
1480  /*
1481  FOR_INV_PREPARE(op, tmp) {
1482  if (tmp->invisible)
1483  continue;
1484  if (tmp == op->contr->mark) {
1485  if (tmp->count == op->contr->mark_count)
1486  return tmp;
1487  else {
1488  op->contr->mark = NULL;
1489  op->contr->mark_count = 0;
1490  return NULL;
1491  }
1492  }
1493  } FOR_INV_FINISH();
1494  */
1495  /* Try a different way of doing this
1496  * We check the environment of the marked object
1497  * to make sure it is still in the player's inventory.
1498  * In addition, we ensure there is the correct tag for that item.
1499  *
1500  * Neila Hawkins 2018-10-23
1501  */
1502  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1503  return op->contr->mark;
1504  // Otherwise reset the mark, since it is no longer valid.
1505  op->contr->mark = NULL;
1506  op->contr->mark_count = 0;
1507  return NULL;
1508 }
1509 
1519 void command_mark(object *op, const char *params) {
1520  char name[MAX_BUF];
1521 
1522  if (!op->contr)
1523  return;
1524  if (*params == '\0') {
1525  object *mark = find_marked_object(op);
1526  if (!mark)
1528  "You have no marked object.");
1529  else {
1530  query_name(mark, name, MAX_BUF);
1532  "%s is marked.",
1533  name);
1534  }
1535  } else {
1536  object *mark1 = find_best_object_match(op, params);
1537 
1538  if (!mark1) {
1540  "Could not find an object that matches %s",
1541  params);
1542  return;
1543  } else {
1544  op->contr->mark = mark1;
1545  op->contr->mark_count = mark1->count;
1546  query_name(mark1, name, MAX_BUF);
1548  "Marked item %s",
1549  name);
1550  return;
1551  }
1552  }
1553  /*shouldnt get here */
1554 }
1555 
1566 void examine_monster(object *op, object *tmp, int level) {
1567  object *mon = HEAD(tmp), *probe;
1568 
1569  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1571  "It is an undead force.");
1572  if (mon->level > op->level)
1574  "It is likely more powerful than you.");
1575  else if (mon->level < op->level)
1577  "It is likely less powerful than you.");
1578  else
1580  "It is probably as powerful as you.");
1581 
1582  if (mon->attacktype&AT_ACID)
1584  "You smell an acrid odor.");
1585 
1586  /* Anyone know why this used to use the clone value instead of the
1587  * maxhp field? This seems that it should give more accurate results.
1588  */
1589  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1590  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1591  case 0:
1593  "It is critically wounded.");
1594  break;
1595 
1596  case 1:
1598  "It is in a bad shape.");
1599  break;
1600 
1601  case 2:
1603  "It is hurt.");
1604  break;
1605 
1606  case 3:
1608  "It is somewhat hurt.");
1609  break;
1610 
1611  default:
1613  "It is in excellent shape.");
1614  break;
1615  }
1616  if (object_present_in_ob(POISONING, mon) != NULL)
1618  "It looks very ill.");
1619 
1620  if (level < 10)
1621  return;
1622  knowledge_add_probe_monster(op, mon);
1623 
1624  if (level < 15)
1625  return;
1626 
1627  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1628  if (probe != NULL && probe->level > level)
1629  return;
1630 
1631  if (probe == NULL) {
1633  free_string(probe->name);
1634  probe->name = add_string("probe_force");
1637  object_insert_in_ob(probe, mon);
1638  fix_object(mon);
1639  }
1640  probe->level = level;
1641  if (level / 10 > probe->duration)
1642  probe->duration = level / 10;
1643 }
1644 
1646  EX_ID_ABORT, // Not safe to continue
1647  EX_ID_NO_SKILL, // Player lacks the requisite skill(s)
1648  EX_ID_FAILED // Player has the skill but failed their ID roll
1649 };
1650 
1662 ex_autoid_result examine_autoidentify(object *op, object *tmp) {
1663  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1664  int exp = 0;
1665  object *skill = find_skill_by_number(op, SK_DET_MAGIC);
1666  if (skill && (object_can_pick(op, tmp))) {
1667  exp = detect_magic_on_item(op, tmp, skill);
1668  if (exp) {
1669  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1671  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1672  }
1673  }
1674 
1675  skill = find_skill_by_number(op, SK_DET_CURSE);
1676  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1677  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1678  exp = detect_curse_on_item(op, tmp, skill);
1679  if (exp) {
1680  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1682  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1683  }
1684  }
1685 
1686  const typedata *tmptype = get_typedata(tmp->type);
1687  if (!tmptype) {
1688  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid\n", tmp->count, tmp->type);
1689  return EX_ID_ABORT;
1690  }
1691 
1692  bool have_skill = false;
1693  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1694  skill = find_skill_by_number(op, tmptype->identifyskill);
1695  if (skill) {
1696  have_skill = true;
1697  /* identify_object_with_skill() may merge tmp with another
1698  * object, so once that happens, we really can not do
1699  * any further processing with tmp. It would be possible
1700  * to modify identify_object_with_skill() to return
1701  * the merged object, but it is currently set to return
1702  * exp, so it would have to do it via modifying the
1703  * passed in value, but many other consumers would
1704  * need to be modified for that.
1705  */
1706  exp = identify_object_with_skill(tmp, op, skill, 1);
1707  if (exp) {
1708  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1709  return EX_ID_ABORT;
1710  }
1711  }
1712 
1713  /* The primary id skill didn't work, let's try the secondary one */
1714  skill = find_skill_by_number(op, tmptype->identifyskill2);
1715  if (skill) {
1716  have_skill = true;
1717  /* if we've reached here, then the first skill will have been attempted
1718  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1719  * that now, and try with the secondary ID skill, if it fails, then the
1720  * flag will be reset anyway, if it succeeds, it won't matter.*/
1722  exp = identify_object_with_skill(tmp, op, skill, 1);
1723  if (exp) {
1724  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1725  return EX_ID_ABORT;
1726  }
1727  }
1728  }
1729  return have_skill ? EX_ID_FAILED : EX_ID_NO_SKILL;
1730 }
1731 
1740 void examine_weight_and_material(object *op, object *tmp) {
1741  bool pl = tmp->nrof > 1;
1742  float weight = (tmp->nrof ? tmp->nrof : 1) * ((float)tmp->weight/1000.0);
1743 
1744  if (tmp->materialname && weight) {
1746  "%s made of %s and %s %3.3f kg.",
1747  pl ? "They are" : "It is", tmp->materialname,
1748  pl ? "weigh" : "weighs", weight);
1749  } else if (tmp->materialname) {
1751  "%s made of %s.", pl ? "They are" : "It is", tmp->materialname);
1752  } else if (weight) {
1754  "%s %3.3f kg.", pl ? "They weigh" : "it weighs", weight);
1755  }
1756 }
1757 
1766 void examine_wand_charge_level(object *op, object *tmp) {
1767  if (!is_identified(tmp)) return;
1768  const char *desc;
1769  if (tmp->stats.food <= 0) {
1770  desc = "It is completely depleted.";
1771  } else if (tmp->stats.food <= 2) {
1772  desc = "It is nearly depleted.";
1773  } else if (tmp->stats.food <= 4) {
1774  desc = "It is very low on power.";
1775  } else if (tmp->stats.food <= 8) {
1776  desc = "It is low on power.";
1777  } else if (tmp->stats.food <= 16) {
1778  desc = "It is well charged.";
1779  } else if (tmp->stats.food <= 32) {
1780  desc = "It is fully charged.";
1781  } else {
1782  desc = "It is overflowing with power.";
1783  }
1785 }
1786 
1795 void examine_rod_charge_level(object *op, object *tmp) {
1796  if (!is_identified(tmp)) return;
1797  if (!tmp->inv) // rod has no spell
1798  return;
1799  const int castings = tmp->stats.hp/SP_level_spellpoint_cost(tmp, tmp->inv, SPELL_HIGHEST);
1800  const char *desc;
1801  /* Rods get less precise information than wands/staves as part of balancing
1802  out their reusability -- in particular, you can't tell if a rod is *almost*
1803  out of shots or *completely* out of shots without trying it. */
1804  if (castings <= 1) {
1805  desc = "It is nearly depleted.";
1806  } else if (castings <= 3) {
1807  desc = "It hums with power.";
1808  } else {
1809  desc = "It crackles with power.";
1810  }
1812 }
1813 
1827 bool examine_fluff(object *op, object *tmp, bool output) {
1828  /* No message for stuff the player hasn't IDed. */
1829  if (!is_identified(tmp)) {
1830  return false;
1831  }
1832 
1833  // We use stringbuffer throughout this function so that we can use
1834  // trim_whitespace to conveniently strip trailing newlines, ensuring that
1835  // the output of examine is contiguous.
1836  // TODO: It might be better to strip the newlines in object_set_msg
1837  // and append them at print time, rather than ensuring that the msg
1838  // is newline-terminated and stripping off the newlines when we don't
1839  // want them; C string handling makes the latter a lot less convenient.
1840  if (tmp->msg && strncasecmp(tmp->msg, "@match", 6)) {
1841  if (!output) return true;
1843  stringbuffer_append_string(sb, tmp->msg);
1845  char *const msg = stringbuffer_finish(sb);
1847  free(msg);
1848  }
1849 
1850  switch (tmp->type) {
1851  /* Stuff with embedded skills. */
1852  case SKILLSCROLL:
1853  case SKILL_TOOL:
1854  {
1855  // Embedded skills are stored as an archetype name and don't get reified
1856  // until the player actually reads/equips the object, so we need to turn
1857  // the name into an actual archetype and then read the msg out of that.
1858  if (!tmp->skill) break; // Blank skill scroll, somehow.
1860  if (!skill) {
1861  if (!output) break; // Still need to check for lore later.
1862  // Skill name doesn't correspond to any actual skill.
1864  "Unfortunately, it is damaged beyond %s.",
1865  (tmp->type == SKILLSCROLL) ? "comprehension" : "repair");
1866  break;
1867  }
1868  if (skill->clone.msg) {
1869  if (!output) return true;
1871  "%s lets you %s a skill:",
1872  tmp->nrof > 1 ? "These objects" : "This object",
1873  (tmp->type == SKILLSCROLL) ? "learn" : "use");
1874 
1876  stringbuffer_append_string(sb, skill->clone.msg);
1878  char *const fluff = stringbuffer_finish(sb);
1879  // SPELL_INFO is not a perfect match here, but it should display in the
1880  // same manner as the spell descriptions below and there's no SKILL_INFO
1881  // message type.
1883  free(fluff);
1884  }
1885  break;
1886  }
1887 
1888  /* Stuff with embedded spells. */
1889  case SPELLBOOK:
1890  case SCROLL:
1891  case WAND:
1892  case ROD:
1893  case POTION:
1894  {
1895  if (tmp->inv && tmp->inv->msg) {
1896  if (!output) return true;
1898  "%s holds%s a spell:",
1899  tmp->nrof > 1 ? "These objects" : "This object",
1900  tmp->type == SPELLBOOK ? " knowledge of" : "");
1901 
1903  stringbuffer_append_string(sb, tmp->inv->msg);
1905  char *const fluff = stringbuffer_finish(sb);
1907  free(fluff);
1908  }
1909  }
1910  }
1911 
1912  if (tmp->lore) {
1913  if (!output) return true;
1915  "%s a story:", tmp->nrof > 1 ? "These objects have" : "This object has");
1917  stringbuffer_append_string(sb, tmp->lore);
1919  char *const msg = stringbuffer_finish(sb);
1921  free(msg);
1922  }
1923 
1924  // If we get this far in output=false mode, we didn't hit any of the earlier
1925  // escape hatches and thus have nothing to output. In normal use we'll hit
1926  // this regardless and assume we output something.
1927  return output;
1928 }
1929 
1939 void examine(object *op, object *tmp) {
1940  if (tmp == NULL || tmp->type == CLOSE_CON)
1941  return;
1942 
1943  /* If the player has examined this twice in a row, do a more detailed
1944  examine. last_examined shouldn't get set unless we already know that
1945  examine_fluff() will do something interesting. */
1946  if (op->contr->last_examined == tmp->count) {
1947  op->contr->last_examined = 0;
1949  "You examine the %s more closely.", tmp->nrof > 1 ? tmp->name_pl : tmp->name);
1950  examine_fluff(op, tmp, true);
1952  " "); /* Blank line */
1953  return;
1954  }
1955 
1956  int i;
1957  char prefix[MAX_BUF] = "";
1958  char buf[VERY_BIG_BUF] = "";
1959  if (is_identified(tmp)) {
1960  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof<=1 ? "That is" : "Those are");
1961  } else {
1962  switch(examine_autoidentify(op, tmp)) {
1963  case EX_ID_NO_SKILL:
1964  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:",
1965  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
1966  break;
1967  case EX_ID_FAILED:
1968  snprintf(prefix, MAX_BUF, "You fail to understand %s:",
1969  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
1970  break;
1971  case EX_ID_ABORT:
1972  default:
1973  /* Item may have been merged with something else, not safe to proceed. */
1974  return;
1975  }
1976  }
1977 
1978  /* now we need to get the rest of the object description */
1979  ob_describe(tmp, op, 1, buf, sizeof(buf));
1980 
1982  "%s %s", prefix, buf);
1983  buf[0] = '\0';
1984  sstring custom_name = object_get_value(tmp, CUSTOM_NAME_FIELD);
1985  if (custom_name) {
1987  "You name it %s",
1988  custom_name);
1989  }
1990 
1991  method_ret ret = ob_examine(tmp, op, 1, buf, sizeof(buf));
1992  if (ret == METHOD_UNHANDLED) {
1993  switch (tmp->type) {
1994  case WAND:
1995  examine_wand_charge_level(op, tmp);
1996  break;
1997 
1998  case ROD:
1999  examine_rod_charge_level(op, tmp);
2000  break;
2001 
2002  case BOOK:
2003  if (tmp->msg != NULL)
2004  snprintf(buf, sizeof(buf), "Something is written in it.");
2005  break;
2006  }
2007  }
2008 
2009  if (buf[0] != '\0')
2011  buf);
2012 
2013  examine_weight_and_material(op, tmp);
2014 
2015  /* Where to wear this item */
2016  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
2017  if (tmp->body_info[i]) {
2018  if (op->body_info[i]) {
2019  if (tmp->body_info[i] < -1) {
2021  "%s %s (%d).", tmp->nrof > 1 ? "They go" : "It goes",
2022  body_locations[i].use_name, -tmp->body_info[i]);
2023  } else {
2025  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2027  }
2028  } else {
2030  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2032  }
2033  }
2034  }
2035 
2036  int in_shop = shop_contains(op);
2037 
2038  if (!QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2039  char *value = cost_approx_str(tmp, op);
2040  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
2041  free(value);
2043  buf);
2044  if (in_shop) {
2045  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
2046  if (object_value_set(tmp, "pshop_owner")) {
2047  const char *seller = object_get_value(tmp, "pshop_owner");
2048  snprintf(buf, sizeof(buf), "%s is selling this item.", seller);
2050  }
2051 
2052  value = cost_str(shop_price_buy(tmp, op));
2053  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
2054  free(value);
2055  } else {
2056  value = cost_str(shop_price_sell(tmp, op));
2057  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
2058  free(value);
2059  }
2061  buf);
2062  }
2063  }
2064 
2065  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2066  examine_monster(op, tmp, 0);
2067 
2068  /* Is this item buildable? */
2069  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
2070  int conn;
2071  bool has_link = false;
2072  if (QUERY_FLAG(tmp, FLAG_IS_LINKED) && (conn = get_button_value(tmp))) {
2073  FOR_INV_PREPARE(op, tmp_inv) {
2074  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
2075  && strcmp(tmp_inv->slaying, op->map->path) == 0
2076  && tmp_inv->msg != NULL
2077  && tmp_inv->path_attuned == (uint32_t) conn) {
2078 
2079  has_link = true;
2082  "This is a buildable item, connected with: %s",
2083  tmp_inv->msg);
2084  break;
2085  }
2086  } FOR_INV_FINISH();
2087  }
2088  if (!has_link) {
2090  "This is a buildable item.");
2091  }
2092  }
2093 
2094  /* Does it have fluff text? */
2095  if (examine_fluff(op, tmp, false)) {
2096  op->contr->last_examined = tmp->count;
2098  "Examine again for more details.");
2099  } else {
2100  op->contr->last_examined = 0;
2101  }
2102 
2104  " "); /* Blank line */
2105 
2106  if (is_identified(tmp)) {
2108  }
2109 }
2110 
2119 void inventory(object *op, object *inv) {
2120  const char *in;
2121  int items = 0, length;
2122  char weight[MAX_BUF], name[MAX_BUF];
2123 
2124  if (inv == NULL && op == NULL) {
2126  "Inventory of what object?");
2127  return;
2128  }
2129  FOR_INV_PREPARE(inv ? inv : op, tmp)
2130  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
2131  || !op || QUERY_FLAG(op, FLAG_WIZ))
2132  items++;
2133  FOR_INV_FINISH();
2134  if (inv == NULL) { /* player's inventory */
2135  if (items == 0) {
2137  "You carry nothing.");
2138  return;
2139  } else {
2140  length = 28;
2141  in = "";
2143  "Inventory:");
2144  }
2145  } else {
2146  if (items == 0)
2147  return;
2148  else {
2149  length = 28;
2150  in = " ";
2151  }
2152  }
2153  FOR_INV_PREPARE(inv ? inv : op, tmp) {
2154  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
2155  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
2156  continue;
2157  query_weight(tmp, weight, MAX_BUF);
2158  query_name(tmp, name, MAX_BUF);
2159  if (!op || QUERY_FLAG(op, FLAG_WIZ))
2161  "[fixed]%s- %-*.*s (%5d) %-8s",
2162  in, length, length, name, tmp->count, weight);
2163  else
2165  "[fixed]%s- %-*.*s %-8s",
2166  in, length+8, length+8, name, weight);
2167  } FOR_INV_FINISH();
2168  if (!inv && op) {
2169  query_weight(op, weight, MAX_BUF);
2171  "[fixed]%-*s %-8s",
2172  41, "Total weight :", weight);
2173  }
2174 }
2175 
2184 static void display_new_pickup(const object *op, int old) {
2185  int i = op->contr->mode;
2186 
2187  esrv_send_pickup(op->contr);
2188 
2189  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
2190  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
2192  "Pickup is now %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
2193  }
2194  return;
2195  }
2196 
2198  "%d NEWMODE",
2199  i&PU_NEWMODE ? 1 : 0);
2201  "%d DEBUG",
2202  i&PU_DEBUG ? 1 : 0);
2204  "%d INHIBIT",
2205  i&PU_INHIBIT ? 1 : 0);
2207  "%d STOP",
2208  i&PU_STOP ? 1 : 0);
2209 
2211  "%d <= x pickup weight/value RATIO (0==off)",
2212  (i&PU_RATIO)*5);
2213 
2215  "%d FOOD",
2216  i&PU_FOOD ? 1 : 0);
2218  "%d DRINK",
2219  i&PU_DRINK ? 1 : 0);
2221  "%d VALUABLES",
2222  i&PU_VALUABLES ? 1 : 0);
2223 
2225  "%d BOW",
2226  i&PU_BOW ? 1 : 0);
2228  "%d ARROW",
2229  i&PU_ARROW ? 1 : 0);
2230 
2232  "%d HELMET",
2233  i&PU_HELMET ? 1 : 0);
2235  "%d SHIELD",
2236  i&PU_SHIELD ? 1 : 0);
2238  "%d ARMOUR",
2239  i&PU_ARMOUR ? 1 : 0);
2240 
2242  "%d BOOTS",
2243  i&PU_BOOTS ? 1 : 0);
2245  "%d GLOVES",
2246  i&PU_GLOVES ? 1 : 0);
2248  "%d CLOAK",
2249  i&PU_CLOAK ? 1 : 0);
2251  "%d KEY",
2252  i&PU_KEY ? 1 : 0);
2253 
2255  "%d MISSILEWEAPON",
2256  i&PU_MISSILEWEAPON ? 1 : 0);
2258  "%d MELEEWEAPON",
2259  i&PU_MELEEWEAPON ? 1 : 0);
2261  "%d MAGICAL",
2262  i&PU_MAGICAL ? 1 : 0);
2264  "%d POTION",
2265  i&PU_POTION ? 1 : 0);
2266 
2268  "%d SPELLBOOK",
2269  i&PU_SPELLBOOK ? 1 : 0);
2271  "%d SKILLSCROLL",
2272  i&PU_SKILLSCROLL ? 1 : 0);
2274  "%d READABLES",
2275  i&PU_READABLES ? 1 : 0);
2277  "%d MAGICDEVICE",
2278  i&PU_MAGIC_DEVICE ? 1 : 0);
2279 
2281  "%d NOT CURSED",
2282  i&PU_NOT_CURSED ? 1 : 0);
2283 
2285  "%d JEWELS",
2286  i&PU_JEWELS ? 1 : 0);
2287 
2289  "%d FLESH",
2290  i&PU_FLESH ? 1 : 0);
2291 
2293  "%d CONTAINER",
2294  i&PU_CONTAINER ? 1 : 0);
2295 
2297  "%d CURSED",
2298  i&PU_CURSED ? 1 : 0);
2299 
2301  "");
2302 }
2303 
2313 void command_pickup(object *op, const char *params) {
2314  uint32_t i;
2315 
2316  if (*params == '\0') {
2317  /* if the new mode is used, just print the settings */
2318  if (op->contr->mode&PU_NEWMODE) {
2319  display_new_pickup(op, op->contr->mode);
2320  return;
2321  }
2322  if (1)
2323  LOG(llevDebug, "command_pickup: !params\n");
2324  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
2325  return;
2326  }
2327 
2328  while (*params == ' ')
2329  params++;
2330 
2331  if (*params == '+' || *params == '-' || *params == '!') {
2332  int index = get_pickup_mode_index(params + 1);
2333 
2334  if (index != -1) {
2335  int old = op->contr->mode;
2336  i = op->contr->mode;
2337  if (!(i&PU_NEWMODE))
2338  i = PU_NEWMODE;
2339  if (*params == '+')
2340  i = i|pickup_modes[index];
2341  else if (*params == '-')
2342  i = i&~pickup_modes[index];
2343  else {
2344  if (i&pickup_modes[index])
2345  i = i&~pickup_modes[index];
2346  else
2347  i = i|pickup_modes[index];
2348  }
2349  op->contr->mode = i;
2350  display_new_pickup(op, old);
2351  return;
2352  }
2354  "Pickup: invalid item %s\n",
2355  params);
2356  return;
2357  }
2358 
2359  if (sscanf(params, "%u", &i) != 1) {
2360  if (1)
2361  LOG(llevDebug, "command_pickup: params==NULL\n");
2363  "Usage: pickup <0-7> or <value_density> .");
2364  return;
2365  }
2366  set_pickup_mode(op, i);
2367  display_new_pickup(op, op->contr->mode);
2368 }
2369 
2378 static void set_pickup_mode(const object *op, int i) {
2379  op->contr->mode = i;
2380  switch (op->contr->mode) {
2381  case 0:
2383  "Mode: Don't pick up.");
2384  break;
2385 
2386  case 1:
2388  "Mode: Pick up one item.");
2389  break;
2390 
2391  case 2:
2393  "Mode: Pick up one item and stop.");
2394  break;
2395 
2396  case 3:
2398  "Mode: Stop before picking up.");
2399  break;
2400 
2401  case 4:
2403  "Mode: Pick up all items.");
2404  break;
2405 
2406  case 5:
2408  "Mode: Pick up all items and stop.");
2409  break;
2410 
2411  case 6:
2413  "Mode: Pick up all magic items.");
2414  break;
2415 
2416  case 7:
2418  "Mode: Pick up all coins and gems");
2419  break;
2420  }
2421 }
2422 
2431 void command_search_items(object *op, const char *params) {
2432  if (settings.search_items == FALSE)
2433  return;
2434 
2435  if (!params || *params == '\0') {
2436  if (op->contr->search_str[0] == '\0') {
2438  "Example: search magic+1 "
2439  "Would automatically pick up all "
2440  "items containing the word 'magic+1'.");
2441  return;
2442  }
2443  op->contr->search_str[0] = '\0';
2445  "Search mode turned off.");
2446  fix_object(op);
2447  return;
2448  }
2449  if ((int)strlen(params) >= MAX_BUF) {
2451  "Search string too long.");
2452  return;
2453  }
2454  strcpy(op->contr->search_str, params);
2456  "Searching for '%s'.",
2457  op->contr->search_str);
2458  fix_object(op);
2459 }
2460 
2476 void command_rename_item(object *op, const char *params) {
2477  char buf[VERY_BIG_BUF], name[MAX_BUF];
2478  tag_t itemnumber;
2479  object *item = NULL;
2480  object *tmp;
2481  const char *closebrace;
2482  size_t counter;
2483 
2484  if (*params != '\0') {
2485  /* Let's skip white spaces */
2486  while (' ' == *params)
2487  params++;
2488 
2489  /* Checking the first part */
2490  itemnumber = atoi(params);
2491  if (itemnumber != 0) {
2492  FOR_INV_PREPARE(op, inv)
2493  if (inv->count == itemnumber && !inv->invisible) {
2494  item = inv;
2495  break;
2496  }
2497  FOR_INV_FINISH();
2498  if (!item) {
2500  "Tried to rename an invalid item.");
2501  return;
2502  }
2503  while (isdigit(*params) || ' ' == *params)
2504  params++;
2505  } else if ('<' == *params) {
2506  /* Got old name, let's get it & find appropriate matching item */
2507  closebrace = strchr(params, '>');
2508  if (!closebrace) {
2510  "Syntax error!");
2511  return;
2512  }
2513  /* Sanity check for buffer overruns */
2514  if (closebrace-params > 127) {
2516  "Old name too long (up to 127 characters allowed)!");
2517  return;
2518  }
2519  /* Copy the old name */
2520  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2521 
2522  /* Find best matching item */
2523  item = find_best_object_match(op, buf);
2524  if (!item) {
2526  "Could not find a matching item to rename.");
2527  return;
2528  }
2529 
2530  /* Now need to move pointer to just after > */
2531  params = closebrace+1;
2532  while (' ' == *params)
2533  params++;
2534  } else {
2535  /* Use marked item */
2536  item = find_marked_object(op);
2537  if (!item) {
2539  "No marked item to rename.");
2540  return;
2541  }
2542  }
2543 
2544  /* Now let's find the new name */
2545  if (!strncmp(params, "to ", 3)) {
2546  params += 3;
2547  while (' ' == *params)
2548  params++;
2549  if ('<' != *params) {
2551  "Syntax error, expecting < at start of new name!");
2552  return;
2553  }
2554  closebrace = strchr(params+1, '>');
2555  if (!closebrace) {
2557  "Syntax error, expecting > at end of new name!");
2558  return;
2559  }
2560 
2561  /* Sanity check for buffer overruns */
2562  if (closebrace-params > 127) {
2564  "New name too long (up to 127 characters allowed)!");
2565  return;
2566  }
2567 
2568  /* Copy the new name */
2569  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2570 
2571  /* Let's check it for weird characters */
2572  for (counter = 0; counter < strlen(buf); counter++) {
2573  if (isalnum(buf[counter]))
2574  continue;
2575  if (' ' == buf[counter])
2576  continue;
2577  if ('\'' == buf[counter])
2578  continue;
2579  if ('+' == buf[counter])
2580  continue;
2581  if ('_' == buf[counter])
2582  continue;
2583  if ('-' == buf[counter])
2584  continue;
2585 
2586  /* If we come here, then the name contains an invalid character...
2587  * tell the player & exit
2588  */
2590  "Invalid new name!");
2591  return;
2592  }
2593  } else {
2594  /* If param contains something, then syntax error... */
2595  if (strlen(params)) {
2597  "Syntax error, expected 'to <' after old name!");
2598  return;
2599  }
2600  /* New name is empty */
2601  buf[0] = '\0';
2602  }
2603  } else {
2604  /* Last case: *params=='\0' */
2605  item = find_marked_object(op);
2606  if (!item) {
2608  "No marked item to rename.");
2609  return;
2610  }
2611  buf[0] = '\0';
2612  }
2613 
2614  /* Coming here, everything is fine... */
2615  if (!strlen(buf)) {
2616  /* Clear custom name */
2617  if (object_get_value(item, CUSTOM_NAME_FIELD) == NULL) {
2619  "This item has no custom name.");
2620  return;
2621  }
2622 
2623  object_set_value(item, CUSTOM_NAME_FIELD, NULL, 0);
2624  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2626  "You stop calling your %s with weird names.",
2627  name);
2628  } else {
2629  sstring custom_name = object_get_value(item, CUSTOM_NAME_FIELD);
2630  if (custom_name != NULL && strcmp(custom_name, buf) == 0) {
2631  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2633  "You keep calling your %s %s.",
2634  name, buf);
2635  return;
2636  }
2637 
2638  /* Set custom name */
2640 
2641  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2643  "Your %s will now be called %s.",
2644  name, buf);
2645  }
2646 
2647  tmp = object_merge(item, NULL);
2648  if (tmp == NULL) {
2649  /* object was not merged - if it was, object_merge() handles updating for us. */
2650  esrv_update_item(UPD_NAME, op, item);
2651  }
2652 }
2653 
2662 void command_lock_item(object *op, const char *params) {
2663  object *item;
2664  object *tmp;
2665  char name[HUGE_BUF];
2666 
2667  if (*params == '\0' || strlen(params) == 0) {
2669  "Lock what item?");
2670  return;
2671  }
2672 
2673  item = find_best_object_match(op, params);
2674  if (!item) {
2676  "Can't find any matching item.");
2677  return;
2678  }
2679 
2680  query_short_name(item, name, HUGE_BUF);
2681  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2683  "Unlocked %s.", name);
2684  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2685  } else {
2687  "Locked %s.", name);
2688  SET_FLAG(item, FLAG_INV_LOCKED);
2689  }
2690 
2691  tmp = object_merge(item, NULL);
2692  if (tmp == NULL) {
2693  /* object was not merged, if it was object_merge() handles updates for us */
2694  esrv_update_item(UPD_FLAGS, op, item);
2695  }
2696 }
2697 
2705 void command_use(object *op, const char *params) {
2706  char *with, copy[MAX_BUF];
2707  object *first, *second/*, *add*/;
2708  /*archetype *arch;*/
2709  /*int count;*/
2710  /*sstring data;*/
2711  recipe *transformation;
2712 
2713  if (!IS_PLAYER(op))
2714  return;
2715 
2716  strlcpy(copy, params, sizeof(copy));
2717  with = strstr(copy, " with ");
2718  if (!with) {
2719  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2720  return;
2721  }
2722 
2723  with[0] = '\0';
2724  with = with+strlen(" with ");
2725 
2726  first = find_best_object_match(op, copy);
2727  if (!first) {
2728  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2729  return;
2730  }
2731  second = find_best_object_match(op, with);
2732  if (!second) {
2733  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2734  return;
2735  }
2736 
2737  transformation = NULL;
2738  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2740  if (transformation->ingred_count != 1)
2741  continue;
2742 
2743 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2744  if (strcmp(second->name, transformation->ingred->name) == 0) {
2746  object *generated = create_archetype(transformation->arch_name[0]);
2747  if (transformation->yield)
2748  generated->nrof = transformation->yield;
2749  object_insert_in_ob(generated, op);
2750  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2752  return;
2753  }
2754  }
2755  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2756  return;
2757 
2758  /*
2759  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2760  data = object_get_value(second, copy);
2761  if (!data) {
2762  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2763  data = object_get_value(second, copy);
2764  if (!data) {
2765  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2766  data = object_get_value(second, copy);
2767  if (!data) {
2768  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2769  return 1;
2770  }
2771  }
2772  }
2773 
2774  while (data != NULL) {
2775  if (strncmp(data, "add ", 4) == 0) {
2776  data += 4;
2777  if (isdigit(*data)) {
2778  count = atol(data);
2779  data = strchr(data, ' ')+1;
2780  } else
2781  count = 1;
2782  with = strchr(data, ' ');
2783  if (!with) {
2784  strncpy(copy, data, sizeof(copy));
2785  data = NULL;
2786  } else {
2787  *with = '\0';
2788  strncpy(copy, data, sizeof(copy));
2789  data += strlen(copy)+1;
2790  }
2791  arch = find_archetype(copy);
2792  if (!arch) {
2793  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2794  return 1;
2795  }
2796  add = object_create_arch(arch);
2797  add->nrof = count;
2798  object_insert_in_ob(add, op);
2799  } else if (strncmp(data, "remove $", 8) == 0) {
2800  data += 8;
2801  if (*data == '1') {
2802  if (first)
2803  first = object_decrease_nrof_by_one(first);
2804  data += 2;
2805  } else if (*data == '2') {
2806  if (second)
2807  second = object_decrease_nrof_by_one(second);
2808  data += 2;
2809  } else {
2810  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2811  return 1;
2812  }
2813  } else {
2814  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2815  return 1;
2816  }
2817  }
2818 
2819  return 1;
2820  */
2821 }
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:1120
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:442
MIMIC
@ MIMIC
Definition: object.h:254
PLAYER
@ PLAYER
Definition: object.h:112
global.h
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
csv_contains
bool csv_contains(std::string list, std::string item, std::string delim)
Split list by comma, then see if item matches anything in the list.
Definition: c_object.cpp:302
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:746
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:15
AT_ACID
#define AT_ACID
Random equipped item might corrode when hit (64)
Definition: attack.h:84
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:534
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
Problems requiring server admin to fix.
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:389
MOVE_FLYING
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:386
WAND
@ WAND
Definition: object.h:225
player::mode
uint32_t mode
Mode of player for pickup.
Definition: player.h:125
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:82
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:369
FLESH
@ FLESH
animal 'body parts' -b.t.
Definition: object.h:192
ob_examine
method_ret ob_examine(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Get examine text for OP as seen by OBSERVER.
Definition: ob_methods.cpp:113
GLOVES
@ GLOVES
Definition: object.h:218
FLAG_IS_LINKED
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:302
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:298
GIRDLE
@ GIRDLE
Definition: object.h:228
PU_KEY
#define PU_KEY
Definition: define.h:128
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:371
time
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 and afterward any time the value is but over time
Definition: protocol.txt:416
KEY
@ KEY
Definition: object.h:132
command_rename_item
void command_rename_item(object *op, const char *params)
Changing the custom name of an item.
Definition: c_object.cpp:2476
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:214
AP_APPLY
#define AP_APPLY
Item is to be applied.
Definition: define.h:558
examine_monster
void examine_monster(object *op, object *tmp, int level)
Player examine a monster.
Definition: c_object.cpp:1566
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:1939
SK_DET_MAGIC
@ SK_DET_MAGIC
Detect magic.
Definition: skills.h:30
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:320
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:688
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:712
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:2705
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
AP_UNAPPLY
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:559
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:1886
command_uskill
void command_uskill(object *pl, const char *params)
'use_skill' command.
Definition: c_object.cpp:144
FLAG_IS_CAULDRON
#define FLAG_IS_CAULDRON
container can make alchemical stuff
Definition: define.h:325
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:726
FLAG_WIZ
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:218
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
PU_STOP
#define PU_STOP
Definition: define.h:110
PU_NEWMODE
#define PU_NEWMODE
Definition: define.h:111
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:1766
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:357
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:1519
command_pickup
void command_pickup(object *op, const char *params)
'pickup' command.
Definition: c_object.cpp:2313
PU_CURSED
#define PU_CURSED
Definition: define.h:144
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
recipe::arch_name
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:381
TRANSPORT
@ TRANSPORT
see doc/Developers/objects
Definition: object.h:113
PU_DEBUG
#define PU_DEBUG
Definition: define.h:108
skills.h
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can't use command.
Definition: newclient.h:533
PU_SKILLSCROLL
#define PU_SKILLSCROLL
Definition: define.h:136
matcher_params::item_to_pick
int item_to_pick
Index of the item to pick, 1-based.
Definition: c_object.cpp:666
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:360
apply_by_living_below
void apply_by_living_below(object *pl)
Attempt to apply the object 'below' the player.
Definition: apply.cpp:357
ex_autoid_result
ex_autoid_result
Definition: c_object.cpp:1645
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
FLAG_NO_SKILL_IDENT
#define FLAG_NO_SKILL_IDENT
If set, item cannot be identified w/ a skill.
Definition: define.h:322
buf
StringBuffer * buf
Definition: readable.cpp:1564
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
PU_SHIELD
#define PU_SHIELD
Definition: define.h:122
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:2378
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:1306
body_locations_struct::nonuse_name
const char * nonuse_name
Name to describe objects we can't use.
Definition: object.h:25
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
PU_FOOD
#define PU_FOOD
Definition: define.h:115
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
PU_FLESH
#define PU_FLESH
Definition: define.h:142
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:695
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:307
socket_struct::update_look
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:109
command_empty
void command_empty(object *op, const char *params)
'empty' command.
Definition: c_object.cpp:1402
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:608
METHOD_UNHANDLED
#define METHOD_UNHANDLED
Definition: ob_methods.h:16
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
typedata
Link an object type with skill needed to identify, and general name.
Definition: define.h:89
PU_BOW
#define PU_BOW
Definition: define.h:118
object::y
int16_t y
Position in the map for this object.
Definition: object.h:335
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
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
get_button_value
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.cpp:751
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:889
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:284
AP_NULL
#define AP_NULL
Nothing specific.
Definition: define.h:557
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:996
matcher_all
static int matcher_all(object *who, matcher_params *params, object *item)
Function allowing all objects.
Definition: c_object.cpp:692
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
POISON
@ POISON
Definition: object.h:118
linked_char::name
const char * name
Definition: global.h:103
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:306
FLAG_NO_DROP
#define FLAG_NO_DROP
Object can't be dropped.
Definition: define.h:275
command_throw
void command_throw(object *op, const char *params)
'throw' command.
Definition: c_object.cpp:239
PU_CLOAK
#define PU_CLOAK
Definition: define.h:127
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:328
FLAG_UNPAID
#define FLAG_UNPAID
Object hasn't been paid for yet.
Definition: define.h:223
matcher_params::pickup_type
int pickup_type
Value in Pickup modes to match against.
Definition: c_object.cpp:671
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:593
matcher_params::name
char name[MAX_BUF]
Name to match for.
Definition: c_object.cpp:670
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
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:1740
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:706
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: container.cpp:66
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:487
SK_DET_CURSE
@ SK_DET_CURSE
Detect curse.
Definition: skills.h:33
MSG_TYPE_COMMAND_INFO
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:530
add_string
sstring add_string(const char *str)
Share a string.
Definition: shstr.cpp:137
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
FLAG_MONSTER
#define FLAG_MONSTER
Will attack players.
Definition: define.h:232
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
Definition: define.h:738
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:329
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
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:1355
ob_describe
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Returns the description (short item name) of an object, as seen by the given observer.
Definition: ob_methods.cpp:92
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:1364
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:348
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:1182
FOR_INV_FINISH
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:661
FLAG_NO_PICK
#define FLAG_NO_PICK
Object can't be picked up.
Definition: define.h:226
AP_OPEN
#define AP_OPEN
Item is a container to be fully opened.
Definition: define.h:560
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:819
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
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:663
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
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:758
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:95
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Can't see what's underneath this object.
Definition: define.h:289
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:734
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
PU_READABLES
#define PU_READABLES
Definition: define.h:137
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:761
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:2431
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
inventory
void inventory(object *op, object *inv)
Prints object's inventory.
Definition: c_object.cpp:2119
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:316
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:209
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:2224
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:225
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
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:294
PU_ARROW
#define PU_ARROW
Definition: define.h:120
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:668
PU_SPELLBOOK
#define PU_SPELLBOOK
Definition: define.h:135
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:213
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:535
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
PU_MELEEWEAPON
#define PU_MELEEWEAPON
Definition: define.h:131
player::mark
object * mark
Marked object.
Definition: player.h:215
method_ret
char method_ret
Define some standard return values for callbacks which don't need to return any other results.
Definition: ob_methods.h:14
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
MSG_TYPE_COMMAND_INVENTORY
#define MSG_TYPE_COMMAND_INVENTORY
Inventory listing.
Definition: newclient.h:537
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:683
query_weight
void query_weight(const object *op, char *buf, size_t size)
Formats the item's weight.
Definition: item.cpp:420
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: container.cpp:127
object::name
sstring name
The name of the object, obviously...
Definition: object.h:319
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:217
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
EVENT_PICKUP
#define EVENT_PICKUP
Object picked up.
Definition: events.h:36
PU_RATIO
#define PU_RATIO
Definition: define.h:113
cost_str
char * cost_str(uint64_t cost)
Definition: shop.cpp:308
mapstruct
This is a game-map.
Definition: map.h:320
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:301
FLAG_IS_BUILDABLE
#define FLAG_IS_BUILDABLE
Can build on item.
Definition: define.h:354
FLAG_IS_THROWN
#define FLAG_IS_THROWN
Object is designed to be thrown.
Definition: define.h:236
sstring
const typedef char * sstring
Definition: sstring.h:2
FLAG_UNDEAD
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:257
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:470
PU_DRINK
#define PU_DRINK
Definition: define.h:116
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:2755
command_examine
void command_examine(object *op, const char *params)
'examine' command.
Definition: c_object.cpp:1441
FLAG_APPLIED
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:222
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:1827
apply_by_living
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Living thing is applying an object.
Definition: apply.cpp:299
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:367
Settings::max_stat
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:326
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
SKILL_TOOL
@ SKILL_TOOL
Allows the use of a skill.
Definition: object.h:194
object_get_value
sstring object_get_value(const object *op, const char *const key)
Get an extra value by key.
Definition: object.cpp:4331
AP_NO_MERGE
#define AP_NO_MERGE
Don't try to merge object after (un)applying it.
Definition: define.h:565
PU_POTION
#define PU_POTION
Definition: define.h:133
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:1472
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:370
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:818
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:255
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:2184
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:580
level
int level
Definition: readable.cpp:1562
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:124
FLAG_NO_FIX_PLAYER
#define FLAG_NO_FIX_PLAYER
fix_object() won't be called
Definition: define.h:264
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:167
UPD_NAME
#define UPD_NAME
Definition: newclient.h:322
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:275
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:316
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
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
PU_MAGIC_DEVICE
#define PU_MAGIC_DEVICE
Definition: define.h:138
PU_ARMOUR
#define PU_ARMOUR
Definition: define.h:123
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:1025
EX_ID_FAILED
@ EX_ID_FAILED
Definition: c_object.cpp:1648
object::move_off
MoveType move_off
Move types affected moving off this space.
Definition: object.h:440
examine_rod_charge_level
void examine_rod_charge_level(object *op, object *tmp)
Output charge information for a rod.
Definition: c_object.cpp:1795
FLAG_PROBE
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:244
PU_HELMET
#define PU_HELMET
Definition: define.h:121
DRINK
@ DRINK
Definition: object.h:162
sell_item
void sell_item(object *op, object *pl)
Player is selling an item.
Definition: shop.cpp:909
VERY_BIG_BUF
#define VERY_BIG_BUF
Definition: define.h:36
command_lock_item
void command_lock_item(object *op, const char *params)
Alternate way to lock/unlock items (command line).
Definition: c_object.cpp:2662
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
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:342
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:221
player::socket
socket_struct * socket
Socket information for this player.
Definition: player.h:109
matcher_params::missed
int missed
How many items were missed when matching.
Definition: c_object.cpp:673
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:691
Settings::search_items
uint8_t search_items
Search_items command.
Definition: global.h:271
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
list
How to Install a Crossfire Server on you must install a python script engine on your computer Python is the default script engine of Crossfire You can find the python engine you have only to install them The VisualC Crossfire settings are for but you habe then to change the pathes in the VC settings Go in Settings C and Settings Link and change the optional include and libs path to the new python installation path o except the maps ! You must download a map package and install them the share folder Its must look like doubleclick on crossfire32 dsw There are projects in your libcross lib and plugin_python You need to compile all Easiest way is to select the plugin_python ReleaseLog as active this will compile all others too Then in Visual C press< F7 > to compile If you don t have an appropriate compiler you can try to get the the VC copies the crossfire32 exe in the crossfire folder and the plugin_python dll in the crossfire share plugins folder we will remove it when we get time for it o Last showing lots of weird write to the Crossfire mailing list
Definition: INSTALL_WIN32.txt:50
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
SK_FIND_TRAPS
@ SK_FIND_TRAPS
Find traps.
Definition: skills.h:34
PU_MAGICAL
#define PU_MAGICAL
Definition: define.h:132
PU_VALUABLES
#define PU_VALUABLES
Definition: define.h:117
command_take
void command_take(object *op, const char *params)
This takes (picks up) an item.
Definition: c_object.cpp:797
BOOTS
@ BOOTS
Definition: object.h:217
pickup_names
static const char * pickup_names[]
Valid names for pickup types.
Definition: c_object.cpp:33
matcher_params::item_number
int item_number
Index of the checked item, 1-based.
Definition: c_object.cpp:667
EX_ID_NO_SKILL
@ EX_ID_NO_SKILL
Definition: c_object.cpp:1647
SHIELD
@ SHIELD
Definition: object.h:140
object::attacktype
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:352
PU_GLOVES
#define PU_GLOVES
Definition: define.h:126
object_get_player_container
object * object_get_player_container(object *op)
Finds the player carrying an object.
Definition: object.cpp:592
living.h
SK_THROWING
@ SK_THROWING
Throwing.
Definition: skills.h:44
EX_ID_ABORT
@ EX_ID_ABORT
Definition: c_object.cpp:1646
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:654
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:15
MONEY
@ MONEY
Definition: object.h:142
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:584
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:1662
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
living::Str
int8_t Str
Definition: living.h:36
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