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 
1676  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1677  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1678  exp = detect_curse_on_item(op, tmp, skill);
1679  if (exp) {
1680  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1682  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1683  }
1684  }
1685 
1686  const typedata *tmptype = get_typedata(tmp->type);
1687  if (!tmptype) {
1688  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid\n", tmp->count, tmp->type);
1689  return EX_ID_ABORT;
1690  }
1691 
1692  bool have_skill = false;
1693  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1694  skill = find_skill_by_number(op, tmptype->identifyskill);
1695  if (skill) {
1696  /* identify_object_with_skill() may merge tmp with another
1697  * object, so once that happens, we really can not do
1698  * any further processing with tmp. It would be possible
1699  * to modify identify_object_with_skill() to return
1700  * the merged object, but it is currently set to return
1701  * exp, so it would have to do it via modifying the
1702  * passed in value, but many other consumers would
1703  * need to be modified for that.
1704  */
1705  exp = identify_object_with_skill(tmp, op, skill, 1);
1706  if (exp) {
1707  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1708  return EX_ID_ABORT;
1709  }
1710  }
1711 
1712  /* The primary id skill didn't work, let's try the secondary one */
1713  skill = find_skill_by_number(op, tmptype->identifyskill2);
1714  if (skill) {
1715  /* if we've reached here, then the first skill will have been attempted
1716  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1717  * that now, and try with the secondary ID skill, if it fails, then the
1718  * flag will be reset anyway, if it succeeds, it won't matter.*/
1720  exp = identify_object_with_skill(tmp, op, skill, 1);
1721  if (exp) {
1722  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1723  return EX_ID_ABORT;
1724  }
1725  }
1726  }
1727  return have_skill ? EX_ID_FAILED : EX_ID_NO_SKILL;
1728 }
1729 
1738 void examine_weight_and_material(object *op, object *tmp) {
1739  bool pl = tmp->nrof > 1;
1740  float weight = (tmp->nrof ? tmp->nrof : 1) * ((float)tmp->weight/1000.0);
1741 
1742  if (tmp->materialname && weight) {
1744  "%s made of %s and %s %3.3f kg.",
1745  pl ? "They are" : "It is", tmp->materialname,
1746  pl ? "weigh" : "weighs", weight);
1747  } else if (tmp->materialname) {
1749  "%s made of %s.", pl ? "They are" : "It is", tmp->materialname);
1750  } else if (weight) {
1752  "%s %3.3f kg.", pl ? "They weigh" : "it weighs", weight);
1753  }
1754 }
1755 
1764 void examine_wand_charge_level(object *op, object *tmp) {
1765  if (!is_identified(tmp)) return;
1766  const char *desc;
1767  if (tmp->stats.food <= 0) {
1768  desc = "It is completely depleted.";
1769  } else if (tmp->stats.food <= 2) {
1770  desc = "It is nearly depleted.";
1771  } else if (tmp->stats.food <= 4) {
1772  desc = "It is very low on power.";
1773  } else if (tmp->stats.food <= 8) {
1774  desc = "It is low on power.";
1775  } else if (tmp->stats.food <= 16) {
1776  desc = "It is well charged.";
1777  } else if (tmp->stats.food <= 32) {
1778  desc = "It is fully charged.";
1779  } else {
1780  desc = "It is overflowing with power.";
1781  }
1783 }
1784 
1793 void examine_rod_charge_level(object *op, object *tmp) {
1794  if (!is_identified(tmp)) return;
1795  if (!tmp->inv) // rod has no spell
1796  return;
1797  const int castings = tmp->stats.hp/SP_level_spellpoint_cost(tmp, tmp->inv, SPELL_HIGHEST);
1798  const char *desc;
1799  /* Rods get less precise information than wands/staves as part of balancing
1800  out their reusability -- in particular, you can't tell if a rod is *almost*
1801  out of shots or *completely* out of shots without trying it. */
1802  if (castings <= 1) {
1803  desc = "It is nearly depleted.";
1804  } else if (castings <= 3) {
1805  desc = "It hums with power.";
1806  } else {
1807  desc = "It crackles with power.";
1808  }
1810 }
1811 
1825 bool examine_fluff(object *op, object *tmp, bool output) {
1826  /* No message for stuff the player hasn't IDed. */
1827  if (!is_identified(tmp)) {
1828  return false;
1829  }
1830 
1831  // We use stringbuffer throughout this function so that we can use
1832  // trim_whitespace to conveniently strip trailing newlines, ensuring that
1833  // the output of examine is contiguous.
1834  // TODO: It might be better to strip the newlines in object_set_msg
1835  // and append them at print time, rather than ensuring that the msg
1836  // is newline-terminated and stripping off the newlines when we don't
1837  // want them; C string handling makes the latter a lot less convenient.
1838  if (tmp->msg && strncasecmp(tmp->msg, "@match", 6)) {
1839  if (!output) return true;
1841  stringbuffer_append_string(sb, tmp->msg);
1843  char *const msg = stringbuffer_finish(sb);
1845  free(msg);
1846  }
1847 
1848  switch (tmp->type) {
1849  /* Stuff with embedded skills. */
1850  case SKILLSCROLL:
1851  case SKILL_TOOL:
1852  {
1853  // Embedded skills are stored as an archetype name and don't get reified
1854  // until the player actually reads/equips the object, so we need to turn
1855  // the name into an actual archetype and then read the msg out of that.
1856  if (!tmp->skill) break; // Blank skill scroll, somehow.
1858  if (!skill) {
1859  if (!output) break; // Still need to check for lore later.
1860  // Skill name doesn't correspond to any actual skill.
1862  "Unfortunately, it is damaged beyond %s.",
1863  (tmp->type == SKILLSCROLL) ? "comprehension" : "repair");
1864  break;
1865  }
1866  if (skill->clone.msg) {
1867  if (!output) return true;
1869  "%s lets you %s a skill:",
1870  tmp->nrof > 1 ? "These objects" : "This object",
1871  (tmp->type == SKILLSCROLL) ? "learn" : "use");
1872 
1874  stringbuffer_append_string(sb, skill->clone.msg);
1876  char *const fluff = stringbuffer_finish(sb);
1877  // SPELL_INFO is not a perfect match here, but it should display in the
1878  // same manner as the spell descriptions below and there's no SKILL_INFO
1879  // message type.
1881  free(fluff);
1882  }
1883  break;
1884  }
1885 
1886  /* Stuff with embedded spells. */
1887  case SPELLBOOK:
1888  case SCROLL:
1889  case WAND:
1890  case ROD:
1891  case POTION:
1892  {
1893  if (tmp->inv && tmp->inv->msg) {
1894  if (!output) return true;
1896  "%s holds%s a spell:",
1897  tmp->nrof > 1 ? "These objects" : "This object",
1898  tmp->type == SPELLBOOK ? " knowledge of" : "");
1899 
1901  stringbuffer_append_string(sb, tmp->inv->msg);
1903  char *const fluff = stringbuffer_finish(sb);
1905  free(fluff);
1906  }
1907  }
1908  }
1909 
1910  if (tmp->lore) {
1911  if (!output) return true;
1913  "%s a story:", tmp->nrof > 1 ? "These objects have" : "This object has");
1915  stringbuffer_append_string(sb, tmp->lore);
1917  char *const msg = stringbuffer_finish(sb);
1919  free(msg);
1920  }
1921 
1922  // If we get this far in output=false mode, we didn't hit any of the earlier
1923  // escape hatches and thus have nothing to output. In normal use we'll hit
1924  // this regardless and assume we output something.
1925  return output;
1926 }
1927 
1937 void examine(object *op, object *tmp) {
1938  if (tmp == NULL || tmp->type == CLOSE_CON)
1939  return;
1940 
1941  /* If the player has examined this twice in a row, do a more detailed
1942  examine. last_examined shouldn't get set unless we already know that
1943  examine_fluff() will do something interesting. */
1944  if (op->contr->last_examined == tmp->count) {
1945  op->contr->last_examined = 0;
1947  "You examine the %s more closely.", tmp->nrof > 1 ? tmp->name_pl : tmp->name);
1948  examine_fluff(op, tmp, true);
1950  " "); /* Blank line */
1951  return;
1952  }
1953 
1954  int i;
1955  char prefix[MAX_BUF] = "";
1956  char buf[VERY_BIG_BUF] = "";
1957  if (is_identified(tmp)) {
1958  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof<=1 ? "That is" : "Those are");
1959  } else {
1960  switch(examine_autoidentify(op, tmp)) {
1961  case EX_ID_NO_SKILL:
1962  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:",
1963  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
1964  break;
1965  case EX_ID_FAILED:
1966  snprintf(prefix, MAX_BUF, "You fail to understand %s:",
1967  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
1968  break;
1969  case EX_ID_ABORT:
1970  default:
1971  /* Item may have been merged with something else, not safe to proceed. */
1972  return;
1973  }
1974  }
1975 
1976  /* now we need to get the rest of the object description */
1977  ob_describe(tmp, op, 1, buf, sizeof(buf));
1978 
1980  "%s %s", prefix, buf);
1981  buf[0] = '\0';
1982  sstring custom_name = object_get_value(tmp, CUSTOM_NAME_FIELD);
1983  if (custom_name) {
1985  "You name it %s",
1986  custom_name);
1987  }
1988 
1989  method_ret ret = ob_examine(tmp, op, 1, buf, sizeof(buf));
1990  if (ret == METHOD_UNHANDLED) {
1991  switch (tmp->type) {
1992  case WAND:
1993  examine_wand_charge_level(op, tmp);
1994  break;
1995 
1996  case ROD:
1997  examine_rod_charge_level(op, tmp);
1998  break;
1999 
2000  case BOOK:
2001  if (tmp->msg != NULL)
2002  snprintf(buf, sizeof(buf), "Something is written in it.");
2003  break;
2004  }
2005  }
2006 
2007  if (buf[0] != '\0')
2009  buf);
2010 
2011  examine_weight_and_material(op, tmp);
2012 
2013  /* Where to wear this item */
2014  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
2015  if (tmp->body_info[i]) {
2016  if (op->body_info[i]) {
2017  if (tmp->body_info[i] < -1) {
2019  "%s %s (%d).", tmp->nrof > 1 ? "They go" : "It goes",
2020  body_locations[i].use_name, -tmp->body_info[i]);
2021  } else {
2023  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2025  }
2026  } else {
2028  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2030  }
2031  }
2032  }
2033 
2034  int in_shop = shop_contains(op);
2035 
2036  if (!QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2037  char *value = cost_approx_str(tmp, op);
2038  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
2039  free(value);
2041  buf);
2042  if (in_shop) {
2043  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
2044  if (object_value_set(tmp, "pshop_owner")) {
2045  const char *seller = object_get_value(tmp, "pshop_owner");
2046  snprintf(buf, sizeof(buf), "%s is selling this item.", seller);
2048  }
2049 
2050  value = cost_str(shop_price_buy(tmp, op));
2051  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
2052  free(value);
2053  } else {
2054  value = cost_str(shop_price_sell(tmp, op));
2055  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
2056  free(value);
2057  }
2059  buf);
2060  }
2061  }
2062 
2063  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2064  examine_monster(op, tmp, 0);
2065 
2066  /* Is this item buildable? */
2067  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
2068  int conn;
2069  bool has_link = false;
2070  if (QUERY_FLAG(tmp, FLAG_IS_LINKED) && (conn = get_button_value(tmp))) {
2071  FOR_INV_PREPARE(op, tmp_inv) {
2072  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
2073  && strcmp(tmp_inv->slaying, op->map->path) == 0
2074  && tmp_inv->msg != NULL
2075  && tmp_inv->path_attuned == (uint32_t) conn) {
2076 
2077  has_link = true;
2080  "This is a buildable item, connected with: %s",
2081  tmp_inv->msg);
2082  break;
2083  }
2084  } FOR_INV_FINISH();
2085  }
2086  if (!has_link) {
2088  "This is a buildable item.");
2089  }
2090  }
2091 
2092  /* Does it have fluff text? */
2093  if (examine_fluff(op, tmp, false)) {
2094  op->contr->last_examined = tmp->count;
2096  "Examine again for more details.");
2097  } else {
2098  op->contr->last_examined = 0;
2099  }
2100 
2102  " "); /* Blank line */
2103 
2104  if (is_identified(tmp)) {
2106  }
2107 }
2108 
2117 void inventory(object *op, object *inv) {
2118  const char *in;
2119  int items = 0, length;
2120  char weight[MAX_BUF], name[MAX_BUF];
2121 
2122  if (inv == NULL && op == NULL) {
2124  "Inventory of what object?");
2125  return;
2126  }
2127  FOR_INV_PREPARE(inv ? inv : op, tmp)
2128  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
2129  || !op || QUERY_FLAG(op, FLAG_WIZ))
2130  items++;
2131  FOR_INV_FINISH();
2132  if (inv == NULL) { /* player's inventory */
2133  if (items == 0) {
2135  "You carry nothing.");
2136  return;
2137  } else {
2138  length = 28;
2139  in = "";
2141  "Inventory:");
2142  }
2143  } else {
2144  if (items == 0)
2145  return;
2146  else {
2147  length = 28;
2148  in = " ";
2149  }
2150  }
2151  FOR_INV_PREPARE(inv ? inv : op, tmp) {
2152  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
2153  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
2154  continue;
2155  query_weight(tmp, weight, MAX_BUF);
2156  query_name(tmp, name, MAX_BUF);
2157  if (!op || QUERY_FLAG(op, FLAG_WIZ))
2159  "[fixed]%s- %-*.*s (%5d) %-8s",
2160  in, length, length, name, tmp->count, weight);
2161  else
2163  "[fixed]%s- %-*.*s %-8s",
2164  in, length+8, length+8, name, weight);
2165  } FOR_INV_FINISH();
2166  if (!inv && op) {
2167  query_weight(op, weight, MAX_BUF);
2169  "[fixed]%-*s %-8s",
2170  41, "Total weight :", weight);
2171  }
2172 }
2173 
2182 static void display_new_pickup(const object *op, int old) {
2183  int i = op->contr->mode;
2184 
2185  esrv_send_pickup(op->contr);
2186 
2187  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
2188  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
2190  "Pickup is now %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
2191  }
2192  return;
2193  }
2194 
2196  "%d NEWMODE",
2197  i&PU_NEWMODE ? 1 : 0);
2199  "%d DEBUG",
2200  i&PU_DEBUG ? 1 : 0);
2202  "%d INHIBIT",
2203  i&PU_INHIBIT ? 1 : 0);
2205  "%d STOP",
2206  i&PU_STOP ? 1 : 0);
2207 
2209  "%d <= x pickup weight/value RATIO (0==off)",
2210  (i&PU_RATIO)*5);
2211 
2213  "%d FOOD",
2214  i&PU_FOOD ? 1 : 0);
2216  "%d DRINK",
2217  i&PU_DRINK ? 1 : 0);
2219  "%d VALUABLES",
2220  i&PU_VALUABLES ? 1 : 0);
2221 
2223  "%d BOW",
2224  i&PU_BOW ? 1 : 0);
2226  "%d ARROW",
2227  i&PU_ARROW ? 1 : 0);
2228 
2230  "%d HELMET",
2231  i&PU_HELMET ? 1 : 0);
2233  "%d SHIELD",
2234  i&PU_SHIELD ? 1 : 0);
2236  "%d ARMOUR",
2237  i&PU_ARMOUR ? 1 : 0);
2238 
2240  "%d BOOTS",
2241  i&PU_BOOTS ? 1 : 0);
2243  "%d GLOVES",
2244  i&PU_GLOVES ? 1 : 0);
2246  "%d CLOAK",
2247  i&PU_CLOAK ? 1 : 0);
2249  "%d KEY",
2250  i&PU_KEY ? 1 : 0);
2251 
2253  "%d MISSILEWEAPON",
2254  i&PU_MISSILEWEAPON ? 1 : 0);
2256  "%d MELEEWEAPON",
2257  i&PU_MELEEWEAPON ? 1 : 0);
2259  "%d MAGICAL",
2260  i&PU_MAGICAL ? 1 : 0);
2262  "%d POTION",
2263  i&PU_POTION ? 1 : 0);
2264 
2266  "%d SPELLBOOK",
2267  i&PU_SPELLBOOK ? 1 : 0);
2269  "%d SKILLSCROLL",
2270  i&PU_SKILLSCROLL ? 1 : 0);
2272  "%d READABLES",
2273  i&PU_READABLES ? 1 : 0);
2275  "%d MAGICDEVICE",
2276  i&PU_MAGIC_DEVICE ? 1 : 0);
2277 
2279  "%d NOT CURSED",
2280  i&PU_NOT_CURSED ? 1 : 0);
2281 
2283  "%d JEWELS",
2284  i&PU_JEWELS ? 1 : 0);
2285 
2287  "%d FLESH",
2288  i&PU_FLESH ? 1 : 0);
2289 
2291  "%d CONTAINER",
2292  i&PU_CONTAINER ? 1 : 0);
2293 
2295  "%d CURSED",
2296  i&PU_CURSED ? 1 : 0);
2297 
2299  "");
2300 }
2301 
2311 void command_pickup(object *op, const char *params) {
2312  uint32_t i;
2313 
2314  if (*params == '\0') {
2315  /* if the new mode is used, just print the settings */
2316  if (op->contr->mode&PU_NEWMODE) {
2317  display_new_pickup(op, op->contr->mode);
2318  return;
2319  }
2320  if (1)
2321  LOG(llevDebug, "command_pickup: !params\n");
2322  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
2323  return;
2324  }
2325 
2326  while (*params == ' ')
2327  params++;
2328 
2329  if (*params == '+' || *params == '-' || *params == '!') {
2330  int index = get_pickup_mode_index(params + 1);
2331 
2332  if (index != -1) {
2333  int old = op->contr->mode;
2334  i = op->contr->mode;
2335  if (!(i&PU_NEWMODE))
2336  i = PU_NEWMODE;
2337  if (*params == '+')
2338  i = i|pickup_modes[index];
2339  else if (*params == '-')
2340  i = i&~pickup_modes[index];
2341  else {
2342  if (i&pickup_modes[index])
2343  i = i&~pickup_modes[index];
2344  else
2345  i = i|pickup_modes[index];
2346  }
2347  op->contr->mode = i;
2348  display_new_pickup(op, old);
2349  return;
2350  }
2352  "Pickup: invalid item %s\n",
2353  params);
2354  return;
2355  }
2356 
2357  if (sscanf(params, "%u", &i) != 1) {
2358  if (1)
2359  LOG(llevDebug, "command_pickup: params==NULL\n");
2361  "Usage: pickup <0-7> or <value_density> .");
2362  return;
2363  }
2364  set_pickup_mode(op, i);
2365  display_new_pickup(op, op->contr->mode);
2366 }
2367 
2376 static void set_pickup_mode(const object *op, int i) {
2377  op->contr->mode = i;
2378  switch (op->contr->mode) {
2379  case 0:
2381  "Mode: Don't pick up.");
2382  break;
2383 
2384  case 1:
2386  "Mode: Pick up one item.");
2387  break;
2388 
2389  case 2:
2391  "Mode: Pick up one item and stop.");
2392  break;
2393 
2394  case 3:
2396  "Mode: Stop before picking up.");
2397  break;
2398 
2399  case 4:
2401  "Mode: Pick up all items.");
2402  break;
2403 
2404  case 5:
2406  "Mode: Pick up all items and stop.");
2407  break;
2408 
2409  case 6:
2411  "Mode: Pick up all magic items.");
2412  break;
2413 
2414  case 7:
2416  "Mode: Pick up all coins and gems");
2417  break;
2418  }
2419 }
2420 
2429 void command_search_items(object *op, const char *params) {
2430  if (settings.search_items == FALSE)
2431  return;
2432 
2433  if (!params || *params == '\0') {
2434  if (op->contr->search_str[0] == '\0') {
2436  "Example: search magic+1 "
2437  "Would automatically pick up all "
2438  "items containing the word 'magic+1'.");
2439  return;
2440  }
2441  op->contr->search_str[0] = '\0';
2443  "Search mode turned off.");
2444  fix_object(op);
2445  return;
2446  }
2447  if ((int)strlen(params) >= MAX_BUF) {
2449  "Search string too long.");
2450  return;
2451  }
2452  strcpy(op->contr->search_str, params);
2454  "Searching for '%s'.",
2455  op->contr->search_str);
2456  fix_object(op);
2457 }
2458 
2474 void command_rename_item(object *op, const char *params) {
2475  char buf[VERY_BIG_BUF], name[MAX_BUF];
2476  tag_t itemnumber;
2477  object *item = NULL;
2478  object *tmp;
2479  const char *closebrace;
2480  size_t counter;
2481 
2482  if (*params != '\0') {
2483  /* Let's skip white spaces */
2484  while (' ' == *params)
2485  params++;
2486 
2487  /* Checking the first part */
2488  itemnumber = atoi(params);
2489  if (itemnumber != 0) {
2490  FOR_INV_PREPARE(op, inv)
2491  if (inv->count == itemnumber && !inv->invisible) {
2492  item = inv;
2493  break;
2494  }
2495  FOR_INV_FINISH();
2496  if (!item) {
2498  "Tried to rename an invalid item.");
2499  return;
2500  }
2501  while (isdigit(*params) || ' ' == *params)
2502  params++;
2503  } else if ('<' == *params) {
2504  /* Got old name, let's get it & find appropriate matching item */
2505  closebrace = strchr(params, '>');
2506  if (!closebrace) {
2508  "Syntax error!");
2509  return;
2510  }
2511  /* Sanity check for buffer overruns */
2512  if (closebrace-params > 127) {
2514  "Old name too long (up to 127 characters allowed)!");
2515  return;
2516  }
2517  /* Copy the old name */
2518  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2519 
2520  /* Find best matching item */
2521  item = find_best_object_match(op, buf);
2522  if (!item) {
2524  "Could not find a matching item to rename.");
2525  return;
2526  }
2527 
2528  /* Now need to move pointer to just after > */
2529  params = closebrace+1;
2530  while (' ' == *params)
2531  params++;
2532  } else {
2533  /* Use marked item */
2534  item = find_marked_object(op);
2535  if (!item) {
2537  "No marked item to rename.");
2538  return;
2539  }
2540  }
2541 
2542  /* Now let's find the new name */
2543  if (!strncmp(params, "to ", 3)) {
2544  params += 3;
2545  while (' ' == *params)
2546  params++;
2547  if ('<' != *params) {
2549  "Syntax error, expecting < at start of new name!");
2550  return;
2551  }
2552  closebrace = strchr(params+1, '>');
2553  if (!closebrace) {
2555  "Syntax error, expecting > at end of new name!");
2556  return;
2557  }
2558 
2559  /* Sanity check for buffer overruns */
2560  if (closebrace-params > 127) {
2562  "New name too long (up to 127 characters allowed)!");
2563  return;
2564  }
2565 
2566  /* Copy the new name */
2567  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2568 
2569  /* Let's check it for weird characters */
2570  for (counter = 0; counter < strlen(buf); counter++) {
2571  if (isalnum(buf[counter]))
2572  continue;
2573  if (' ' == buf[counter])
2574  continue;
2575  if ('\'' == buf[counter])
2576  continue;
2577  if ('+' == buf[counter])
2578  continue;
2579  if ('_' == buf[counter])
2580  continue;
2581  if ('-' == buf[counter])
2582  continue;
2583 
2584  /* If we come here, then the name contains an invalid character...
2585  * tell the player & exit
2586  */
2588  "Invalid new name!");
2589  return;
2590  }
2591  } else {
2592  /* If param contains something, then syntax error... */
2593  if (strlen(params)) {
2595  "Syntax error, expected 'to <' after old name!");
2596  return;
2597  }
2598  /* New name is empty */
2599  buf[0] = '\0';
2600  }
2601  } else {
2602  /* Last case: *params=='\0' */
2603  item = find_marked_object(op);
2604  if (!item) {
2606  "No marked item to rename.");
2607  return;
2608  }
2609  buf[0] = '\0';
2610  }
2611 
2612  /* Coming here, everything is fine... */
2613  if (!strlen(buf)) {
2614  /* Clear custom name */
2615  if (object_get_value(item, CUSTOM_NAME_FIELD) == NULL) {
2617  "This item has no custom name.");
2618  return;
2619  }
2620 
2621  object_set_value(item, CUSTOM_NAME_FIELD, NULL, 0);
2622  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2624  "You stop calling your %s with weird names.",
2625  name);
2626  } else {
2627  sstring custom_name = object_get_value(item, CUSTOM_NAME_FIELD);
2628  if (custom_name != NULL && strcmp(custom_name, buf) == 0) {
2629  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2631  "You keep calling your %s %s.",
2632  name, buf);
2633  return;
2634  }
2635 
2636  /* Set custom name */
2638 
2639  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2641  "Your %s will now be called %s.",
2642  name, buf);
2643  }
2644 
2645  tmp = object_merge(item, NULL);
2646  if (tmp == NULL) {
2647  /* object was not merged - if it was, object_merge() handles updating for us. */
2648  esrv_update_item(UPD_NAME, op, item);
2649  }
2650 }
2651 
2660 void command_lock_item(object *op, const char *params) {
2661  object *item;
2662  object *tmp;
2663  char name[HUGE_BUF];
2664 
2665  if (*params == '\0' || strlen(params) == 0) {
2667  "Lock what item?");
2668  return;
2669  }
2670 
2671  item = find_best_object_match(op, params);
2672  if (!item) {
2674  "Can't find any matching item.");
2675  return;
2676  }
2677 
2678  query_short_name(item, name, HUGE_BUF);
2679  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2681  "Unlocked %s.", name);
2682  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2683  } else {
2685  "Locked %s.", name);
2686  SET_FLAG(item, FLAG_INV_LOCKED);
2687  }
2688 
2689  tmp = object_merge(item, NULL);
2690  if (tmp == NULL) {
2691  /* object was not merged, if it was object_merge() handles updates for us */
2692  esrv_update_item(UPD_FLAGS, op, item);
2693  }
2694 }
2695 
2703 void command_use(object *op, const char *params) {
2704  char *with, copy[MAX_BUF];
2705  object *first, *second/*, *add*/;
2706  /*archetype *arch;*/
2707  /*int count;*/
2708  /*sstring data;*/
2709  recipe *transformation;
2710 
2711  if (!IS_PLAYER(op))
2712  return;
2713 
2714  strlcpy(copy, params, sizeof(copy));
2715  with = strstr(copy, " with ");
2716  if (!with) {
2717  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2718  return;
2719  }
2720 
2721  with[0] = '\0';
2722  with = with+strlen(" with ");
2723 
2724  first = find_best_object_match(op, copy);
2725  if (!first) {
2726  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2727  return;
2728  }
2729  second = find_best_object_match(op, with);
2730  if (!second) {
2731  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2732  return;
2733  }
2734 
2735  transformation = NULL;
2736  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2738  if (transformation->ingred_count != 1)
2739  continue;
2740 
2741 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2742  if (strcmp(second->name, transformation->ingred->name) == 0) {
2744  object *generated = create_archetype(transformation->arch_name[0]);
2745  if (transformation->yield)
2746  generated->nrof = transformation->yield;
2747  object_insert_in_ob(generated, op);
2748  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2750  return;
2751  }
2752  }
2753  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2754  return;
2755 
2756  /*
2757  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2758  data = object_get_value(second, copy);
2759  if (!data) {
2760  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2761  data = object_get_value(second, copy);
2762  if (!data) {
2763  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2764  data = object_get_value(second, copy);
2765  if (!data) {
2766  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2767  return 1;
2768  }
2769  }
2770  }
2771 
2772  while (data != NULL) {
2773  if (strncmp(data, "add ", 4) == 0) {
2774  data += 4;
2775  if (isdigit(*data)) {
2776  count = atol(data);
2777  data = strchr(data, ' ')+1;
2778  } else
2779  count = 1;
2780  with = strchr(data, ' ');
2781  if (!with) {
2782  strncpy(copy, data, sizeof(copy));
2783  data = NULL;
2784  } else {
2785  *with = '\0';
2786  strncpy(copy, data, sizeof(copy));
2787  data += strlen(copy)+1;
2788  }
2789  arch = find_archetype(copy);
2790  if (!arch) {
2791  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2792  return 1;
2793  }
2794  add = object_create_arch(arch);
2795  add->nrof = count;
2796  object_insert_in_ob(add, op);
2797  } else if (strncmp(data, "remove $", 8) == 0) {
2798  data += 8;
2799  if (*data == '1') {
2800  if (first)
2801  first = object_decrease_nrof_by_one(first);
2802  data += 2;
2803  } else if (*data == '2') {
2804  if (second)
2805  second = object_decrease_nrof_by_one(second);
2806  data += 2;
2807  } else {
2808  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2809  return 1;
2810  }
2811  } else {
2812  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2813  return 1;
2814  }
2815  }
2816 
2817  return 1;
2818  */
2819 }
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:443
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
Error, serious thing.
Definition: logger.h:11
ARMOUR_IMPROVER
@ ARMOUR_IMPROVER
Definition: object.h:237
command_search
void command_search(object *op, const char *params)
'search' command.
Definition: c_object.cpp:212
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
This returns the first skill pointer of the given subtype (the one that accumulates exp,...
Definition: main.cpp:375
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:58
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
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:2474
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:1937
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:2703
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:1880
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
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
AMULET
@ AMULET
Definition: object.h:144
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
matcher_name
static int matcher_name(object *who, matcher_params *params, object *item)
Check if an item matches a string.
Definition: c_object.cpp: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:1764
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:2311
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:380
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:358
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:1565
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2842
object::above
object * above
Pointer to the object stacked above this one.
Definition: object.h:296
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:2376
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
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
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:108
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:749
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1545
put_object_in_sack
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Something tries to put an object into another.
Definition: c_object.cpp: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:988
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:99
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:594
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
output
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended it will issue a classical message output
Definition: media-tags.txt:36
examine_weight_and_material
void examine_weight_and_material(object *op, object *tmp)
Output weight and material information for an examined object.
Definition: c_object.cpp:1738
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
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:1357
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:2429
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
inventory
void inventory(object *op, object *inv)
Prints object's inventory.
Definition: c_object.cpp:2117
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:2222
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
do_skill_by_number
static void do_skill_by_number(object *op, int skill_subtype, const char *params, const char *missing_message)
Attempt to use a skill from its subtype.
Definition: c_object.cpp:188
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:222
object_insert_in_map
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
This function inserts the object in the two-way linked list which represents what is on a map.
Definition: object.cpp:2346
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:318
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:2763
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:1825
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:359
Settings::max_stat
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:325
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:330
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:2182
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:1563
typedata::identifyskill2
int identifyskill2
Second skill used to identify this object class.
Definition: define.h:94
player::count
uint32_t count
Any numbers typed before a command.
Definition: player.h: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:272
stop_item
object * stop_item(object *op)
An item (ARROW or such) stops moving.
Definition: time.cpp:455
FOOD
@ FOOD
Definition: object.h:117
object::container
object * container
Current container being used.
Definition: object.h:299
skill
skill
Definition: arch-handbook.txt:585
object_remove
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to.
Definition: object.cpp:1818
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:1793
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:2660
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:692
Settings::search_items
uint8_t search_items
Search_items command.
Definition: global.h:268
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:378
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:13
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