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 <assert.h>
22 #include <ctype.h>
23 #include <math.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "living.h"
28 #include "loader.h"
29 #include "shop.h"
30 #include "skills.h"
31 #include "sproto.h"
32 
34 static const char *pickup_names[] = {
35  "debug", "inhibit", "stop", "food", "drink",
36  "valuables", "bow", "arrow", "helmet", "shield",
37  "armour", "boots", "gloves", "cloak", "key",
38  "missile", "melee", "magical", "potion", "spellbook",
39  "skillscroll", "readables", "magicdevice", "notcursed", "jewels",
40  "flesh", "container", "cursed", NULL
41 };
42 
44 static const uint32_t pickup_modes[] = {
49 };
50 
59 static int get_pickup_mode_index(const char *name) {
60  int best = -1;
61  size_t len = strlen(name);
62  for (size_t mode = 0; pickup_names[mode]; mode++) {
63  if (!strcmp(pickup_names[mode], name)) {
64  return mode;
65  }
66  if (len < strlen(pickup_names[mode]) && strncmp(name, pickup_names[mode], len) == 0) {
67  if (best != -2) {
68  if (best != -1) {
69  best = -2;
70  } else {
71  best = mode;
72  }
73  }
74  }
75  }
76  return best != -2 ? best : -1;
77 }
78 
79 static void set_pickup_mode(const object *op, int i);
80 
81 /*
82  * Object id parsing functions
83  */
84 
102 static object *find_best_apply_object_match(object *start, object *pl, const char *params, int aflag) {
103  object *tmp, *best = NULL;
104  int match_val = 0, tmpmatch;
105 
106  tmp = start;
108  if (!player_can_find(pl, tmp))
109  continue;
110  if (aflag == AP_APPLY && QUERY_FLAG(tmp, FLAG_APPLIED))
111  continue;
112  if (aflag == AP_UNAPPLY && !QUERY_FLAG(tmp, FLAG_APPLIED))
113  continue;
114  tmpmatch = object_matches_string(pl, tmp, params);
115  if (tmpmatch > match_val) {
116  match_val = tmpmatch;
117  best = tmp;
118  }
120  return best;
121 }
122 
133 static object *find_best_object_match(object *pl, const char *params) {
134  return find_best_apply_object_match(pl->inv, pl, params, AP_NULL);
135 }
136 
145 void command_uskill(object *pl, const char *params) {
146  if (*params == '\0') {
148  "Usage: use_skill <skill name>");
149  return;
150  }
151  use_skill(pl, params);
152 }
153 
162 void command_rskill(object *pl, const char *params) {
163  object *skill;
164 
165  if (*params == '\0') {
167  "Usage: ready_skill <skill name>");
168  return;
169  }
170  skill = find_skill_by_name(pl, params);
171 
172  if (!skill) {
174  "You have no knowledge of the skill %s",
175  params);
176  return;
177  }
178  change_skill(pl, skill, 0);
179 }
180 
189 static void do_skill_by_number(object *op, int skill_subtype, const char *params,
190  const char *missing_message) {
191  object *skop = find_skill_by_number(op, skill_subtype);
192  if (skop) {
193  do_skill(op, op, skop, op->facing, *params == '\0' ? NULL : params);
194  return;
195  }
196 
198  missing_message);
199 }
200 
201 /* These functions (command_search, command_disarm) are really juse wrappers for
202  * things like 'use_skill ...'). In fact, they should really be obsoleted
203  * and replaced with those.
204  */
213 void command_search(object *op, const char *params) {
214  do_skill_by_number(op, SK_FIND_TRAPS, params, "You don't know how to search for unusual things.");
215 }
216 
225 void command_disarm(object *op, const char *params) {
226  do_skill_by_number(op, SK_DISARM_TRAPS, params, "You don't know how to disarm traps.");
227 }
228 
240 void command_throw(object *op, const char *params) {
241  do_skill_by_number(op, SK_THROWING, params, "You have no knowledge of the skill throwing.");
242 }
243 
252 void command_apply(object *op, const char *params) {
253  int aflag = 0;
254  object *inv = op->inv;
255  object *item;
256 
257  if (*params == '\0') {
259  return;
260  }
261 
262  while (*params == ' ')
263  params++;
264  if (!strncmp(params, "-a ", 3)) {
265  aflag = AP_APPLY;
266  params += 3;
267  }
268  if (!strncmp(params, "-u ", 3)) {
269  aflag = AP_UNAPPLY;
270  params += 3;
271  }
272  if (!strncmp(params, "-o ", 3)) {
273  aflag = AP_OPEN;
274  params += 3;
275  }
276  if (!strncmp(params, "-b ", 3)) {
277  params += 3;
278  if (op->container)
279  inv = op->container->inv;
280  else {
281  inv = op;
282  while (inv->above)
283  inv = inv->above;
284  }
285  }
286  while (*params == ' ')
287  params++;
288 
289  item = find_best_apply_object_match(inv, op, params, aflag);
290  if (item == NULL)
291  item = find_best_apply_object_match(inv, op, params, AP_NULL);
292  if (item) {
293  apply_by_living(op, item, aflag, 0);
294  } else
296  "Could not find any match to the %s.",
297  params);
298 }
299 
303 bool csv_contains(std::string list, std::string item, std::string delim) {
304  size_t pos;
305  while (true) {
306  pos = list.find(delim);
307  auto match = list.substr(0, pos);
308  if (item == match)
309  return true;
310 
311  if (pos == std::string::npos)
312  return false;
313  list.erase(0, pos + 1);
314  }
315  return false;
316 }
317 
330 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
331  /* buf needs to be big (more than 256 chars) because you can get
332  * very long item names.
333  */
334  char buf[HUGE_BUF], name[MAX_BUF];
335  object *env = tmp->env;
336  uint32_t weight, effective_weight_limit;
337  const int tmp_nrof = NROF(tmp);
338  tag_t tag;
339  mapstruct* map = tmp->map;
340  int16_t x = tmp->x, y = tmp->y;
341 
342  /* IF the player is flying & trying to take the item out of a container
343  * that is in his inventory, let him. tmp->env points to the container
344  * (sack, luggage, etc), tmp->env->env then points to the player (nested
345  * containers not allowed as of now)
346  */
347  if ((pl->move_type&MOVE_FLYING)
348  && !QUERY_FLAG(pl, FLAG_WIZ)
349  && object_get_player_container(tmp) != pl) {
351  "You are levitating, you can't reach the ground!");
352  return;
353  }
354  if (QUERY_FLAG(tmp, FLAG_NO_DROP))
355  return;
356 
357  if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
359  "The object disappears in a puff of smoke! It must have been an illusion.");
360  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
361  object_remove(tmp);
363  return;
364  }
365 
366  if (nrof > tmp_nrof || nrof == 0)
367  nrof = tmp_nrof;
368 
369  /* Figure out how much weight this object will add to the player */
370  weight = tmp->weight*nrof;
371  if (tmp->inv)
372  weight += tmp->carrying*(100-tmp->stats.Str)/100;
373 
374  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
375 
376  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
378  "That item is too heavy for you to pick up.");
379  return;
380  }
381 
383  SET_FLAG(tmp, FLAG_WAS_WIZ);
384 
385  if (nrof != tmp_nrof) {
386  char failure[MAX_BUF];
387 
388  tmp = object_split(tmp, nrof, failure, sizeof(failure));
389  if (!tmp) {
391  failure);
392  return;
393  }
394  } else {
395  /* If the object is in a container, send a delete to the client.
396  * - we are moving all the items from the container to elsewhere,
397  * so it needs to be deleted.
398  */
399  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
400  object_remove(tmp); /* Unlink it */
401  }
402  }
403  query_name(tmp, name, MAX_BUF);
404 
405  if (pl->type == PLAYER && QUERY_FLAG(tmp, FLAG_UNPAID)) {
406  char *value = cost_str(shop_price_buy(tmp, pl));
407  if (op == pl) {
408  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
409  } else {
410  snprintf(buf, sizeof(buf), "%s will cost you %s. You place it in your %s.", name, value, op->name);
411  }
412  free(value);
413  } else {
414  if (op == pl) {
415  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
416  } else {
417  snprintf(buf, sizeof(buf), "You pick up the %s and put it in your %s.", name, op->name);
418  }
419  }
420 
421  /* Now item is about to be picked. */
422  tag = tmp->count;
423  if (events_execute_object_event(tmp, EVENT_PICKUP, pl, op, NULL, SCRIPT_FIX_ALL) != 0) {
424  /* put item back, if it still exists */
425  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
426  if (env != NULL) {
427  object_insert_in_ob(tmp, env);
428  } else {
429  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
430  }
431  }
432  return;
433  }
434 
436  buf);
437 
438  object_insert_in_ob(tmp, op);
439 
440  /* All the stuff below deals with client/server code, and is only
441  * usable by players
442  */
443  if (pl->type != PLAYER)
444  return;
445 
446  /* Additional weight changes speed, etc */
447  fix_object(pl);
448 
449  /* These are needed to update the weight for the container we
450  * are putting the object in.
451  */
452  if (op != pl) {
453  esrv_update_item(UPD_WEIGHT, pl, op);
454  esrv_update_item(UPD_WEIGHT, pl, pl);
455  }
456 
457  /* Update the container the object was in */
458  if (env && env != pl && env != op)
460 }
461 
471 bool pick_up(object *op, object *alt) {
472 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
473  object *tmp = NULL, *tmp1;
474  mapstruct *tmp_map = NULL;
475  int count;
476 
477  /* Decide which object to pick. */
478  if (alt) {
479  if (!object_can_pick(op, alt)) {
481  "You can't pick up the %s.",
482  alt->name);
483  return false;
484  }
485  tmp = alt;
486  } else {
487  if (op->below == NULL || !object_can_pick(op, op->below)) {
489  "There is nothing to pick up here.");
490  return false;
491  }
492  tmp = op->below;
493  }
494 
495  /* it is possible that the object is a thrown object and is flying about.
496  * in that case, what we want to pick up is the payload. Objects
497  * that are thrown are encapsulated into a thrown object.
498  * stop_item() returns the payload (unlinked from map) and gets rid of the
499  * container object. If this object isn't picked up, we need to insert
500  * it back on the map.
501  * A bug here is that even attempting to pick up one of these objects will
502  * result in this logic being called even if player is unable to pick it
503  * up.
504  */
505 
506  tmp_map = tmp->map;
507  tmp1 = stop_item(tmp);
508  if (tmp1 == NULL)
509  return false;
510 
511  /* If it is a thrown object, insert it back into the map here.
512  * makes life easier further along. Do no merge so pick up code
513  * behaves more sanely.
514  */
515  if (tmp1 != tmp) {
516  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
517  }
518 
519  if (tmp == NULL)
520  return false;
521 
522  if (!object_can_pick(op, tmp))
523  return false;
524 
525  /* Establish how many of the object we are picking up */
526  if (op->type == PLAYER) {
527  count = op->contr->count;
528  if (count == 0)
529  count = tmp->nrof;
530  } else
531  count = tmp->nrof;
532 
533  /* container is open, so use it */
534  if (op->container) {
535  alt = op->container;
536  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
537  return false;
538  } else {
539  /* non container pickup. See if player has any
540  * active containers.
541  */
542  object *container = NULL;
543 
544  /* Look for any active containers that can hold this item.
545  * we cover two cases here - the perfect match case, where we
546  * break out of the loop, and the general case (have a container),
547  * Moved this into a single loop - reduces redundant code, is
548  * more efficient and easier to follow. MSW 2009-04-06
549  */
550  alt = op->inv;
552  if (alt->type == CONTAINER
553  && QUERY_FLAG(alt, FLAG_APPLIED)
554  && sack_can_hold(NULL, alt, tmp, count)) {
555  if (alt->race && alt->race == tmp->race) {
556  break; /* perfect match */
557  } else if (!container) {
558  container = alt;
559  }
560  }
562  /* Note container could be null, but no reason to check for it */
563  if (!alt)
564  alt = container;
565 
566  if (!alt)
567  alt = op; /* No free containers */
568  }
569  /* see if this object is already in this container. If so,
570  * move it to player inventory from this container.
571  */
572  if (tmp->env == alt) {
573  alt = op;
574  }
575 
576  /* Don't allow players to be put into containers. Instead,
577  * just put them in the players inventory.
578  */
579  if ((tmp->type == CONTAINER || tmp->type == MIMIC) && alt->type==CONTAINER) {
580  alt = op;
581  }
582 #ifdef PICKUP_DEBUG
583  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
584 #endif
585 
586  /* startequip items are not allowed to be put into containers
587  * Not sure why we have this limitation
588  */
589  if (op->type == PLAYER
590  && alt->type == CONTAINER
591  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
593  "This object cannot be put into containers!");
594  return false;
595  }
596 
597  pick_up_object(op, alt, tmp, count);
598  if (op->type == PLAYER)
599  op->contr->count = 0;
600  return true;
601 }
602 
609 int object_matches_pickup_mode(const object *item, int mode) {
610  switch(mode) {
611  case PU_FOOD:
612  return item->type == FOOD;
613  case PU_DRINK:
614  return item->type == DRINK || (item->type == POISON && !QUERY_FLAG(item, FLAG_KNOWN_CURSED));
615  case PU_FLESH:
616  return item->type == FLESH;
617  case PU_POTION:
618  return item->type == POTION;
619  case PU_SPELLBOOK:
620  return item->type == SPELLBOOK;
621  case PU_SKILLSCROLL:
622  return item->type == SKILLSCROLL;
623  case PU_READABLES:
624  return item->type == BOOK || item->type == SCROLL;
625  case PU_MAGIC_DEVICE:
626  return item->type == WAND || item->type == ROD || item->type == WEAPON_IMPROVER || item->type == ARMOUR_IMPROVER || item->type == SKILL_TOOL;
627  case PU_MAGICAL:
629  case PU_VALUABLES:
630  return item->type == MONEY || item->type == GEM;
631  case PU_JEWELS:
632  return item->type == RING || item->type == AMULET;
633  case PU_BOW:
634  return item->type == BOW;
635  case PU_ARROW:
636  return item->type == ARROW;
637  case PU_ARMOUR:
638  return item->type == ARMOUR;
639  case PU_HELMET:
640  return item->type == HELMET;
641  case PU_SHIELD:
642  return item->type == SHIELD;
643  case PU_BOOTS:
644  return item->type == BOOTS;
645  case PU_GLOVES:
646  return item->type == GLOVES;
647  case PU_CLOAK:
648  return item->type == CLOAK;
649  case PU_MISSILEWEAPON:
650  return item->type == WEAPON && QUERY_FLAG(item, FLAG_IS_THROWN);
651  case PU_MELEEWEAPON:
652  return item->type == WEAPON;
653  case PU_KEY:
654  return item->type == KEY || item->type == SPECIAL_KEY;
655  case PU_CONTAINER:
656  return item->type == CONTAINER;
657  case PU_CURSED:
658  return QUERY_FLAG(item, FLAG_KNOWN_CURSED);
659  }
660  return 0;
661 }
662 
665  union {
666  struct {
670  };
671  char name[MAX_BUF];
673  };
674  int missed;
675 };
676 
684 typedef int (*item_matcher)(object *who, matcher_params *params, object *item);
685 
693 static int matcher_all(object *who, matcher_params *params, object *item) {
694  (void)who;
695  (void)params;
696  (void)item;
697  return 1;
698 }
699 
707 static int matcher_number(object *who, matcher_params *params, object *item) {
708  if (params->item_must_be_pickable == 0 || object_can_pick(who, item)) {
709  params->item_number++;
710  }
711  if (params->item_to_pick == params->item_number) {
712  /* Since we don't always increase item_number, multiple items may have the same index,
713  including unpickable ones, so to avoid failure messages just ensure no other item can be picked. */
714  params->item_to_pick = 0;
715  return 1;
716  }
717  return 0;
718 }
719 
727 static int matcher_name(object *who, matcher_params *params, object *item) {
728  int ival = object_matches_string(who, item, params->name);
729  if (ival > 0) {
730  if (ival <= 2 && !object_can_pick(who, item)) {
731  if (!QUERY_FLAG(item, FLAG_IS_FLOOR))/* don't count floor tiles */
732  params->missed++;
733  return 0;
734  }
735  return 1;
736  }
737  return 0;
738 }
739 
747 static int matcher_pickup_type(object *who, matcher_params *params, object *item) {
748  (void)who;
749  return object_matches_pickup_mode(item, params->pickup_type);
750 }
751 
759 static item_matcher make_matcher(object *who, const char *params, matcher_params *mp) {
760  memset(mp, 0, sizeof(*mp));
761  if (params[0] == '\0') {
762  mp->item_to_pick = 1;
763  mp->item_must_be_pickable = 1;
764  return &matcher_number;
765  }
766  if (params[0] == '#') {
767  mp->item_to_pick = atoi(params + 1);
768  if (mp->item_to_pick == 0) {
770  return NULL;
771  }
772  return &matcher_number;
773  }
774  if (params[0] == '*') {
775  if (params[1] == '\0') {
776  return &matcher_all;
777  }
778  int idx = get_pickup_mode_index(params + 1);
779  if (idx == -1) {
780  draw_ext_info_format(NDI_UNIQUE, 0, who, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_ERROR, "Invalid items %s", params + 1);
781  return NULL;
782  }
783  mp->pickup_type = pickup_modes[idx];
784  return &matcher_pickup_type;
785  }
786  strncpy(mp->name, params, sizeof(mp->name) - 1);
787  return &matcher_name;
788 }
789 
798 void command_take(object *op, const char *params) {
799  object *tmp;
800  int did_one = 0;
801 
802  if (op->container)
803  tmp = op->container->inv;
804  else {
805  tmp = op->above;
806  if (tmp)
807  while (tmp->above) {
808  tmp = tmp->above;
809  }
810  if (!tmp)
811  tmp = op->below;
812  }
813 
814  if (tmp == NULL) {
816  "Nothing to take!");
817  return;
818  }
819 
820  matcher_params mp;
821  item_matcher matcher = make_matcher(op, params, &mp);
822  if (!matcher) {
823  return; // Player already informed of failure.
824  }
825 
827 
829  if (tmp->invisible) {
830  continue;
831  }
832  if ((*matcher)(op, &mp, tmp)) {
833  pick_up(op, tmp);
834  did_one = 1;
835  }
837 
838  /* Nothing picked up, check if unable to pick or nothing to pick. */
839  if (params[0] == '\0' && !did_one) {
840  int found = 0;
841  FOR_BELOW_PREPARE(op, tmp)
842  if (!tmp->invisible) {
844  "You can't pick up a %s.",
845  tmp->name ? tmp->name : "null");
846  found = 1;
847  break;
848  }
850  if (!found)
852  "There is nothing to pick up.");
853  }
854 
855  if (mp.missed == 1)
857  "You were unable to take one of the items.");
858  else if (mp.missed > 1)
860  "You were unable to take %d of the items.",
861  mp.missed);
862 
863  /* Now update player and send information. */
865  fix_object(op);
866  if (op->type == PLAYER) {
867  op->contr->count = 0;
868  esrv_update_item(UPD_WEIGHT, op, op);
869  }
870 }
871 
890 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
891  object *sack2, *orig = sack;
892  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
893 
894  if (sack == tmp)
895  return; /* Can't put an object in itself */
896  query_name(sack, name_sack, MAX_BUF);
897  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
899  "The %s is not a container.",
900  name_sack);
901  return;
902  }
903  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
904  query_name(tmp, name_tmp, MAX_BUF);
906  "You cannot put the %s in the %s.",
907  name_tmp, name_sack);
908  return;
909  }
910  if (tmp->type == CONTAINER) {
911  if (tmp->inv) {
912  if (tmp->slaying)
913  return;
914  /* Eneq(@csd.uu.se): If the object to be dropped is a container
915  * and does not require a key to be opened,
916  * we instead move the contents of that container into the active
917  * container, this is only done if the object has something in it.
918  * If object is container but need a key, just don't do anything
919  */
920  sack2 = tmp;
921  query_name(tmp, name_tmp, MAX_BUF);
923  "You move the items from %s into %s.",
924  name_tmp, name_sack);
925 
926  FOR_INV_PREPARE(tmp, tmp2) {
927  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
928  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
929  put_object_in_sack(op, sack, tmp2, 0);
930  } else {
933  "Your %s fills up.",
934  name_sack);
935  break;
936  }
937  } FOR_INV_FINISH();
938  esrv_update_item(UPD_WEIGHT, op, sack2);
939  return;
940  } else {
941  query_name(tmp, name_tmp, MAX_BUF);
943  "You can not put a %s into a %s",
944  name_tmp,
945  name_sack);
946  return;
947  }
948  }
949 
950  /* Don't worry about this for containers - our caller should have
951  * already checked this.
952  */
953  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
954  return;
955 
956  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
957  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
958  return;
959  }
960 
961  /* we want to put some portion of the item into the container */
962  if (nrof && tmp->nrof != nrof) {
963  char failure[MAX_BUF];
964 
965  tmp = object_split(tmp, nrof, failure, sizeof(failure));
966 
967  if (!tmp) {
969  failure);
970  return;
971  }
972  } else
973  object_remove(tmp);
974 
975  if (sack->nrof > 1) {
976  orig = object_split(sack, sack->nrof-1, NULL, 0);
977  set_object_face_main(orig);
978  CLEAR_FLAG(orig, FLAG_APPLIED);
979  if (sack->env) {
980  object_insert_in_ob(orig, sack->env);
981  } else {
982  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
983  orig->move_off = 0;
984  }
985  }
986 
987  query_name(tmp, name_tmp, MAX_BUF);
989  "You put the %s in %s.",
990  name_tmp, name_sack);
991 
992  object_insert_in_ob(tmp, sack);
993  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
994  fix_object(op); /* This is overkill, fix_player() is called somewhere */
995  /* in object.c */
996 
997  /* If a transport, need to update all the players in the transport
998  * the view of what is in it.
999  */
1000  if (sack->type == TRANSPORT) {
1001  FOR_INV_PREPARE(sack, tmp)
1002  if (tmp->type == PLAYER)
1003  tmp->contr->socket->update_look = 1;
1004  FOR_INV_FINISH();
1005  } else {
1006  /* update the sacks weight */
1007  esrv_update_item(UPD_WEIGHT, op, sack);
1008  }
1009 }
1010 
1026 object *drop_object(object *op, object *tmp, uint32_t nrof) {
1027  tag_t tmp_tag;
1028 
1029  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1030  return NULL;
1031  }
1032 
1033  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1034  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
1035  return NULL; /* can't unapply it */
1036  }
1037 
1038  if (events_execute_object_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1039  return NULL;
1040 
1041  /* ensure the plugin didn't destroy the object */
1042  if (QUERY_FLAG(tmp, FLAG_REMOVED))
1043  return NULL;
1044 
1045  /* We are only dropping some of the items. We split the current objec
1046  * off
1047  */
1048  if (nrof && tmp->nrof != nrof) {
1049  char failure[MAX_BUF];
1050 
1051  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1052  if (!tmp) {
1054  failure);
1055  return NULL;
1056  }
1057  } else
1058  object_remove(tmp);
1059 
1060  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
1061  char name[MAX_BUF];
1062 
1063  query_name(tmp, name, MAX_BUF);
1065  "You drop the %s. The gods who lent it to you retrieve it.",
1066  name);
1068 
1069  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
1070  fix_object(op);
1071 
1072  return NULL;
1073  }
1074 
1075  /* If SAVE_INTERVAL is commented out, we never want to save
1076  * the player here.
1077  */
1078 #ifdef SAVE_INTERVAL
1079  /* I'm not sure why there is a value check - since the save
1080  * is done every SAVE_INTERVAL seconds, why care the value
1081  * of what he is dropping?
1082  */
1083  if (op->type == PLAYER
1084  && !QUERY_FLAG(tmp, FLAG_UNPAID)
1085  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
1086  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
1087  save_player(op, 1);
1088  op->contr->last_save_time = time(NULL);
1089  }
1090 #endif /* SAVE_INTERVAL */
1091 
1092 
1093  tmp_tag = tmp->count;
1094  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
1095  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
1096  sell_item(tmp, op);
1097  }
1098 
1099  /* Call this before we update the various windows/players. At least
1100  * that we, we know the weight is correct.
1101  */
1102  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
1103  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1104  /* in object.c */
1105 
1106  /* Need to update weight of player */
1107  if (op->type == PLAYER)
1108  esrv_update_item(UPD_WEIGHT, op, op);
1109  }
1110  return tmp;
1111 }
1112 
1121 void drop(object *op, object *tmp) {
1122  /* Hopeful fix for disappearing objects when dropping from a container -
1123  * somehow, players get an invisible object in the container, and the
1124  * old logic would skip over invisible objects - works fine for the
1125  * playes inventory, but drop inventory wants to use the next value.
1126  */
1127  if (tmp->invisible) {
1128  /* if the following is the case, it must be in an container. */
1129  if (tmp->env && tmp->env->type != PLAYER) {
1130  /* Just toss the object - probably shouldn't be hanging
1131  * around anyways
1132  */
1133  object_remove(tmp);
1135  return;
1136  } else {
1138  if (!tmp->invisible)
1139  break;
1141  }
1142  }
1143 
1144  if (tmp == NULL) {
1146  "You don't have anything to drop.");
1147  return;
1148  }
1149  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1151  "This item is locked");
1152  return;
1153  }
1154  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1155  return;
1156  }
1157 
1158  if (op->container) {
1159  if (op->type == PLAYER) {
1160  put_object_in_sack(op, op->container, tmp, op->contr->count);
1161  } else {
1162  put_object_in_sack(op, op->container, tmp, 0);
1163  };
1164  } else {
1165  if (op->type == PLAYER) {
1166  drop_object(op, tmp, op->contr->count);
1167  } else {
1168  drop_object(op, tmp, 0);
1169  };
1170  }
1171  if (op->type == PLAYER)
1172  op->contr->count = 0;
1173 }
1174 
1183 void command_dropall(object *op, const char *params) {
1184  if (op->inv == NULL) {
1185  draw_ext_info(NDI_UNIQUE, 0, op,
1187  "Nothing to drop!");
1188  return;
1189  }
1190 
1191  assert(op->contr);
1192  int count = op->contr->count;
1193 
1194  /* Set this so we don't call it for _every_ object that
1195  * is dropped.
1196  */
1198 
1199  /*
1200  * This is the default. Drops everything not locked or considered
1201  * not something that should be dropped.
1202  * Care must be taken that the next item pointer is not to money as
1203  * the drop() routine will do unknown things to it when dropping
1204  * in a shop. --Tero.Pelander@utu.fi
1205  */
1206  if (*params == '\0') {
1207  FOR_INV_PREPARE(op, curinv) {
1208  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1209  && curinv->type != MONEY
1210  && curinv->type != FOOD
1211  && curinv->type != KEY
1212  && curinv->type != SPECIAL_KEY
1213  && curinv->type != GEM
1214  && !curinv->invisible
1215  && (curinv->type != CONTAINER || op->container != curinv)) {
1216  drop(op, curinv);
1217  op->contr->count = count;
1218  }
1219  } FOR_INV_FINISH();
1220  } else if (strcmp(params, "weapons") == 0) {
1221  FOR_INV_PREPARE(op, curinv) {
1222  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1223  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1224  drop(op, curinv);
1225  op->contr->count = count;
1226  }
1227  } FOR_INV_FINISH();
1228  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1229  FOR_INV_PREPARE(op, curinv) {
1230  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1231  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1232  drop(op, curinv);
1233  op->contr->count = count;
1234  }
1235  } FOR_INV_FINISH();
1236  } else if (strcmp(params, "food") == 0) {
1237  FOR_INV_PREPARE(op, curinv) {
1238  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1239  && (curinv->type == FOOD || curinv->type == DRINK)) {
1240  drop(op, curinv);
1241  op->contr->count = count;
1242  }
1243  } FOR_INV_FINISH();
1244  } else if (strcmp(params, "flesh") == 0) {
1245  FOR_INV_PREPARE(op, curinv) {
1246  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1247  && (curinv->type == FLESH)) {
1248  drop(op, curinv);
1249  op->contr->count = count;
1250  }
1251  } FOR_INV_FINISH();
1252  } else if (strcmp(params, "misc") == 0) {
1253  FOR_INV_PREPARE(op, curinv) {
1254  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1255  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1256  switch (curinv->type) {
1257  case BOOK:
1258  case SPELLBOOK:
1259  case GIRDLE:
1260  case AMULET:
1261  case RING:
1262  case CLOAK:
1263  case BOOTS:
1264  case GLOVES:
1265  case BRACERS:
1266  case SCROLL:
1267  case ARMOUR_IMPROVER:
1268  case WEAPON_IMPROVER:
1269  case WAND:
1270  case ROD:
1271  case POTION:
1272  drop(op, curinv);
1273  op->contr->count = count;
1274  break;
1275 
1276  default:
1277  break;
1278  }
1279  }
1280  } FOR_INV_FINISH();
1281  }
1282  op->contr->socket->update_look = 1;
1284  /* call it now, once */
1285  fix_object(op);
1286  /* Need to update weight of player. Likewise, only do it once */
1287  if (op->type == PLAYER)
1288  esrv_update_item(UPD_WEIGHT, op, op);
1289 }
1290 
1299 void command_drop(object *op, const char *params) {
1300  int did_one = 0;
1301  int missed = 0;
1302 
1303  if (*params == '\0') {
1305  "Drop what?");
1306  return;
1307  }
1308 
1309  matcher_params mp;
1310  item_matcher matcher = make_matcher(op, params, &mp);
1311  if (!matcher) {
1312  return;
1313  }
1314 
1316 
1317  FOR_INV_PREPARE(op, tmp) {
1318  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1319  continue;
1320  if ((*matcher)(op, &mp, tmp)) {
1321  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1322  missed++;
1323  } else {
1324  drop(op, tmp);
1325  }
1326  did_one = 1;
1327  }
1328  } FOR_INV_FINISH();
1329  if (!did_one)
1331  "Nothing to drop.");
1332  if (missed == 1)
1334  "One item couldn't be dropped because it was locked.");
1335  else if (missed > 1)
1337  "%d items couldn't be dropped because they were locked.",
1338  missed);
1339 
1340  /* Now update player and send information. */
1342  fix_object(op);
1343  if (op->type == PLAYER) {
1344  op->contr->count = 0;
1345  esrv_update_item(UPD_WEIGHT, op, op);
1346  }
1347 }
1348 
1357 static void empty_container(object *container, object *pl) {
1358  int left = 0;
1359  char name[MAX_BUF];
1360 
1361  if (!container->inv)
1362  return;
1363 
1364  FOR_INV_PREPARE(container, inv) {
1365  object *next;
1366 
1367  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1368  /* you can have locked items in container. */
1369  left++;
1370  continue;
1371  }
1372  next = inv->below;
1373  drop(pl, inv);
1374  if (inv->below == next)
1375  /* item couldn't be dropped for some reason. */
1376  left++;
1377  } FOR_INV_FINISH();
1378  esrv_update_item(UPD_WEIGHT, pl, container);
1379 
1380  query_name(container, name, sizeof(name));
1381  if (left)
1382  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1383  else
1385 }
1386 
1395 void command_empty(object *op, const char *params) {
1396  object *container;
1397 
1398  if (*params == '\0') {
1400  "Empty what?");
1401  return;
1402  }
1403 
1404  if (strcmp(params, "all") == 0) {
1405  FOR_INV_PREPARE(op, inv)
1406  if (inv->type == CONTAINER)
1407  empty_container(inv, op);
1408  FOR_INV_FINISH();
1409  return;
1410  }
1411 
1412  container = find_best_object_match(op, params);
1413  if (!container) {
1415  "No such item.");
1416  return;
1417  }
1418  if (container->type != CONTAINER) {
1420  "This is not a container!");
1421  return;
1422  }
1423  empty_container(container, op);
1424 }
1425 
1434 void command_examine(object *op, const char *params) {
1435  if (*params == '\0') {
1436  FOR_BELOW_PREPARE(op, tmp)
1437  if (LOOK_OBJ(tmp)) {
1438  examine(op, tmp);
1439  break;
1440  }
1441  FOR_BELOW_FINISH();
1442  } else {
1443  object *tmp = find_best_object_match(op, params);
1444 
1445  if (tmp)
1446  examine(op, tmp);
1447  else
1449  "Could not find an object that matches %s",
1450  params);
1451  }
1452 }
1453 
1465 object *find_marked_object(object *op) {
1466  if (!op || !op->contr || !op->contr->mark)
1467  return NULL;
1468 
1469  /* This may seem like overkill, but we need to make sure that they
1470  * player hasn't dropped the item. We use count on the off chance that
1471  * an item got reincarnated at some point.
1472  */
1473  /*
1474  FOR_INV_PREPARE(op, tmp) {
1475  if (tmp->invisible)
1476  continue;
1477  if (tmp == op->contr->mark) {
1478  if (tmp->count == op->contr->mark_count)
1479  return tmp;
1480  else {
1481  op->contr->mark = NULL;
1482  op->contr->mark_count = 0;
1483  return NULL;
1484  }
1485  }
1486  } FOR_INV_FINISH();
1487  */
1488  /* Try a different way of doing this
1489  * We check the environment of the marked object
1490  * to make sure it is still in the player's inventory.
1491  * In addition, we ensure there is the correct tag for that item.
1492  *
1493  * Neila Hawkins 2018-10-23
1494  */
1495  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1496  return op->contr->mark;
1497  // Otherwise reset the mark, since it is no longer valid.
1498  op->contr->mark = NULL;
1499  op->contr->mark_count = 0;
1500  return NULL;
1501 }
1502 
1512 void command_mark(object *op, const char *params) {
1513  char name[MAX_BUF];
1514 
1515  if (!op->contr)
1516  return;
1517  if (*params == '\0') {
1518  object *mark = find_marked_object(op);
1519  if (!mark)
1521  "You have no marked object.");
1522  else {
1523  query_name(mark, name, MAX_BUF);
1525  "%s is marked.",
1526  name);
1527  }
1528  } else {
1529  object *mark1 = find_best_object_match(op, params);
1530 
1531  if (!mark1) {
1533  "Could not find an object that matches %s",
1534  params);
1535  return;
1536  } else {
1537  op->contr->mark = mark1;
1538  op->contr->mark_count = mark1->count;
1539  query_name(mark1, name, MAX_BUF);
1541  "Marked item %s",
1542  name);
1543  return;
1544  }
1545  }
1546  /*shouldnt get here */
1547 }
1548 
1559 void examine_monster(object *op, object *tmp, int level) {
1560  object *mon = HEAD(tmp), *probe;
1561 
1562  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1564  "It is an undead force.");
1565  if (mon->level > op->level)
1567  "It is likely more powerful than you.");
1568  else if (mon->level < op->level)
1570  "It is likely less powerful than you.");
1571  else
1573  "It is probably as powerful as you.");
1574 
1575  if (mon->attacktype&AT_ACID)
1577  "You smell an acrid odor.");
1578 
1579  /* Anyone know why this used to use the clone value instead of the
1580  * maxhp field? This seems that it should give more accurate results.
1581  */
1582  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1583  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1584  case 0:
1586  "It is critically wounded.");
1587  break;
1588 
1589  case 1:
1591  "It is in a bad shape.");
1592  break;
1593 
1594  case 2:
1596  "It is hurt.");
1597  break;
1598 
1599  case 3:
1601  "It is somewhat hurt.");
1602  break;
1603 
1604  default:
1606  "It is in excellent shape.");
1607  break;
1608  }
1609  if (object_present_in_ob(POISONING, mon) != NULL)
1611  "It looks very ill.");
1612 
1613  if (level < 10)
1614  return;
1615  knowledge_add_probe_monster(op, mon);
1616 
1617  if (level < 15)
1618  return;
1619 
1620  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1621  if (probe != NULL && probe->level > level)
1622  return;
1623 
1624  if (probe == NULL) {
1626  free_string(probe->name);
1627  probe->name = add_string("probe_force");
1630  object_insert_in_ob(probe, mon);
1631  fix_object(mon);
1632  }
1633  probe->level = level;
1634  if (level / 10 > probe->duration)
1635  probe->duration = level / 10;
1636 }
1637 
1639  EX_ID_ABORT, // Not safe to continue
1640  EX_ID_NO_SKILL, // Player lacks the requisite skill(s)
1641  EX_ID_FAILED // Player has the skill but failed their ID roll
1642 };
1643 
1655 ex_autoid_result examine_autoidentify(object *op, object *tmp) {
1656  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1657  int exp = 0;
1658  object *skill = find_skill_by_number(op, SK_DET_MAGIC);
1659  if (skill && (object_can_pick(op, tmp))) {
1660  exp = detect_magic_on_item(op, tmp, skill);
1661  if (exp) {
1662  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1664  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1665  }
1666  }
1667 
1668  skill = find_skill_by_number(op, SK_DET_CURSE);
1669  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1670  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1671  exp = detect_curse_on_item(op, tmp, skill);
1672  if (exp) {
1673  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1675  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1676  }
1677  }
1678 
1679  const typedata *tmptype = get_typedata(tmp->type);
1680  if (!tmptype) {
1681  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid\n", tmp->count, tmp->type);
1682  return EX_ID_ABORT;
1683  }
1684 
1685  bool have_skill = false;
1686  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1687  skill = find_skill_by_number(op, tmptype->identifyskill);
1688  if (skill) {
1689  have_skill = true;
1690  /* identify_object_with_skill() may merge tmp with another
1691  * object, so once that happens, we really can not do
1692  * any further processing with tmp. It would be possible
1693  * to modify identify_object_with_skill() to return
1694  * the merged object, but it is currently set to return
1695  * exp, so it would have to do it via modifying the
1696  * passed in value, but many other consumers would
1697  * need to be modified for that.
1698  */
1699  exp = identify_object_with_skill(tmp, op, skill, 1);
1700  if (exp) {
1701  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1702  return EX_ID_ABORT;
1703  }
1704  }
1705 
1706  /* The primary id skill didn't work, let's try the secondary one */
1707  skill = find_skill_by_number(op, tmptype->identifyskill2);
1708  if (skill) {
1709  have_skill = true;
1710  /* if we've reached here, then the first skill will have been attempted
1711  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1712  * that now, and try with the secondary ID skill, if it fails, then the
1713  * flag will be reset anyway, if it succeeds, it won't matter.*/
1715  exp = identify_object_with_skill(tmp, op, skill, 1);
1716  if (exp) {
1717  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1718  return EX_ID_ABORT;
1719  }
1720  }
1721  }
1722  return have_skill ? EX_ID_FAILED : EX_ID_NO_SKILL;
1723 }
1724 
1733 void examine_weight_and_material(object *op, object *tmp) {
1734  bool pl = tmp->nrof > 1;
1735  float weight = (tmp->nrof ? tmp->nrof : 1) * ((float)tmp->weight/1000.0);
1736 
1737  if (tmp->materialname && weight) {
1739  "%s made of %s and %s %3.3f kg.",
1740  pl ? "They are" : "It is", tmp->materialname,
1741  pl ? "weigh" : "weighs", weight);
1742  } else if (tmp->materialname) {
1744  "%s made of %s.", pl ? "They are" : "It is", tmp->materialname);
1745  } else if (weight) {
1747  "%s %3.3f kg.", pl ? "They weigh" : "it weighs", weight);
1748  }
1749 }
1750 
1759 void examine_wand_charge_level(object *op, object *tmp) {
1760  if (!is_identified(tmp)) return;
1761  const char *desc;
1762  if (tmp->stats.food <= 0) {
1763  desc = "It is completely depleted.";
1764  } else if (tmp->stats.food <= 2) {
1765  desc = "It is nearly depleted.";
1766  } else if (tmp->stats.food <= 4) {
1767  desc = "It is very low on power.";
1768  } else if (tmp->stats.food <= 8) {
1769  desc = "It is low on power.";
1770  } else if (tmp->stats.food <= 16) {
1771  desc = "It is well charged.";
1772  } else if (tmp->stats.food <= 32) {
1773  desc = "It is fully charged.";
1774  } else {
1775  desc = "It is overflowing with power.";
1776  }
1778 }
1779 
1788 void examine_rod_charge_level(object *op, object *tmp) {
1789  if (!is_identified(tmp)) return;
1790  if (!tmp->inv) // rod has no spell
1791  return;
1792  const int castings = tmp->stats.hp/SP_level_spellpoint_cost(tmp, tmp->inv, SPELL_HIGHEST);
1793  const char *desc;
1794  /* Rods get less precise information than wands/staves as part of balancing
1795  out their reusability -- in particular, you can't tell if a rod is *almost*
1796  out of shots or *completely* out of shots without trying it. */
1797  if (castings <= 1) {
1798  desc = "It is nearly depleted.";
1799  } else if (castings <= 3) {
1800  desc = "It hums with power.";
1801  } else {
1802  desc = "It crackles with power.";
1803  }
1805 }
1806 
1820 bool examine_fluff(object *op, object *tmp, bool output) {
1821  /* No message for stuff the player hasn't IDed. */
1822  if (!is_identified(tmp)) {
1823  return false;
1824  }
1825 
1826  // We use stringbuffer throughout this function so that we can use
1827  // trim_whitespace to conveniently strip trailing newlines, ensuring that
1828  // the output of examine is contiguous.
1829  // TODO: It might be better to strip the newlines in object_set_msg
1830  // and append them at print time, rather than ensuring that the msg
1831  // is newline-terminated and stripping off the newlines when we don't
1832  // want them; C string handling makes the latter a lot less convenient.
1833  if (tmp->msg && strncasecmp(tmp->msg, "@match", 6)) {
1834  if (!output) return true;
1836  stringbuffer_append_string(sb, tmp->msg);
1838  char *const msg = stringbuffer_finish(sb);
1840  free(msg);
1841  }
1842 
1843  switch (tmp->type) {
1844  /* Stuff with embedded skills. */
1845  case SKILLSCROLL:
1846  case SKILL_TOOL:
1847  {
1848  // Embedded skills are stored as an archetype name and don't get reified
1849  // until the player actually reads/equips the object, so we need to turn
1850  // the name into an actual archetype and then read the msg out of that.
1851  if (!tmp->skill) break; // Blank skill scroll, somehow.
1853  if (!skill) {
1854  if (!output) break; // Still need to check for lore later.
1855  // Skill name doesn't correspond to any actual skill.
1857  "Unfortunately, it is damaged beyond %s.",
1858  (tmp->type == SKILLSCROLL) ? "comprehension" : "repair");
1859  break;
1860  }
1861  if (skill->clone.msg) {
1862  if (!output) return true;
1864  "%s lets you %s a skill:",
1865  tmp->nrof > 1 ? "These objects" : "This object",
1866  (tmp->type == SKILLSCROLL) ? "learn" : "use");
1867 
1869  stringbuffer_append_string(sb, skill->clone.msg);
1871  char *const fluff = stringbuffer_finish(sb);
1872  // SPELL_INFO is not a perfect match here, but it should display in the
1873  // same manner as the spell descriptions below and there's no SKILL_INFO
1874  // message type.
1876  free(fluff);
1877  }
1878  break;
1879  }
1880 
1881  /* Stuff with embedded spells. */
1882  case SPELLBOOK:
1883  case SCROLL:
1884  case WAND:
1885  case ROD:
1886  case POTION:
1887  {
1888  if (tmp->inv && tmp->inv->msg) {
1889  if (!output) return true;
1891  "%s holds%s a spell:",
1892  tmp->nrof > 1 ? "These objects" : "This object",
1893  tmp->type == SPELLBOOK ? " knowledge of" : "");
1894 
1896  stringbuffer_append_string(sb, tmp->inv->msg);
1898  char *const fluff = stringbuffer_finish(sb);
1900  free(fluff);
1901  }
1902  }
1903  }
1904 
1905  if (tmp->lore) {
1906  if (!output) return true;
1908  "%s a story:", tmp->nrof > 1 ? "These objects have" : "This object has");
1910  stringbuffer_append_string(sb, tmp->lore);
1912  char *const msg = stringbuffer_finish(sb);
1914  free(msg);
1915  }
1916 
1917  // If we get this far in output=false mode, we didn't hit any of the earlier
1918  // escape hatches and thus have nothing to output. In normal use we'll hit
1919  // this regardless and assume we output something.
1920  return output;
1921 }
1922 
1932 void examine(object *op, object *tmp) {
1933  if (tmp == NULL || tmp->type == CLOSE_CON)
1934  return;
1935 
1936  /* If the player has examined this twice in a row, do a more detailed
1937  examine. last_examined shouldn't get set unless we already know that
1938  examine_fluff() will do something interesting. */
1939  if (op->contr->last_examined == tmp->count) {
1940  op->contr->last_examined = 0;
1942  "You examine the %s more closely.", tmp->nrof > 1 ? tmp->name_pl : tmp->name);
1943  examine_fluff(op, tmp, true);
1945  " "); /* Blank line */
1946  return;
1947  }
1948 
1949  int i;
1950  char prefix[MAX_BUF] = "";
1951  char buf[VERY_BIG_BUF] = "";
1952  if (is_identified(tmp)) {
1953  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof<=1 ? "That is" : "Those are");
1954  } else {
1955  switch(examine_autoidentify(op, tmp)) {
1956  case EX_ID_NO_SKILL:
1957  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:",
1958  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
1959  break;
1960  case EX_ID_FAILED:
1961  snprintf(prefix, MAX_BUF, "You fail to understand %s:",
1962  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
1963  break;
1964  case EX_ID_ABORT:
1965  default:
1966  /* Item may have been merged with something else, not safe to proceed. */
1967  return;
1968  }
1969  }
1970 
1971  /* now we need to get the rest of the object description */
1972  ob_describe(tmp, op, 1, buf, sizeof(buf));
1973 
1975  "%s %s", prefix, buf);
1976  buf[0] = '\0';
1977  sstring custom_name = object_get_value(tmp, CUSTOM_NAME_FIELD);
1978  if (custom_name) {
1980  "You name it %s",
1981  custom_name);
1982  }
1983 
1984  method_ret ret = ob_examine(tmp, op, 1, buf, sizeof(buf));
1985  if (ret == METHOD_UNHANDLED) {
1986  switch (tmp->type) {
1987  case WAND:
1988  examine_wand_charge_level(op, tmp);
1989  break;
1990 
1991  case ROD:
1992  examine_rod_charge_level(op, tmp);
1993  break;
1994 
1995  case BOOK:
1996  if (tmp->msg != NULL)
1997  snprintf(buf, sizeof(buf), "Something is written in it.");
1998  break;
1999  }
2000  }
2001 
2002  if (buf[0] != '\0')
2004  buf);
2005 
2006  examine_weight_and_material(op, tmp);
2007 
2008  /* Where to wear this item */
2009  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
2010  if (tmp->body_info[i]) {
2011  if (op->body_info[i]) {
2012  if (tmp->body_info[i] < -1) {
2014  "%s %s (%d).", tmp->nrof > 1 ? "They go" : "It goes",
2015  body_locations[i].use_name, -tmp->body_info[i]);
2016  } else {
2018  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2020  }
2021  } else {
2023  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2025  }
2026  }
2027  }
2028 
2029  int in_shop = shop_contains(op);
2030 
2031  if (!QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2032  char *value = cost_approx_str(tmp, op);
2033  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
2034  free(value);
2036  buf);
2037  if (in_shop) {
2038  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
2039  if (object_value_set(tmp, "pshop_owner")) {
2040  const char *seller = object_get_value(tmp, "pshop_owner");
2041  snprintf(buf, sizeof(buf), "%s is selling this item.", seller);
2043  }
2044 
2045  value = cost_str(shop_price_buy(tmp, op));
2046  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
2047  free(value);
2048  } else {
2049  value = cost_str(shop_price_sell(tmp, op));
2050  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
2051  free(value);
2052  }
2054  buf);
2055  }
2056  }
2057 
2058  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2059  examine_monster(op, tmp, 0);
2060 
2061  /* Is this item buildable? */
2062  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
2063  int conn;
2064  bool has_link = false;
2065  if (QUERY_FLAG(tmp, FLAG_IS_LINKED) && (conn = get_button_value(tmp))) {
2066  FOR_INV_PREPARE(op, tmp_inv) {
2067  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
2068  && strcmp(tmp_inv->slaying, op->map->path) == 0
2069  && tmp_inv->msg != NULL
2070  && tmp_inv->path_attuned == (uint32_t) conn) {
2071 
2072  has_link = true;
2075  "This is a buildable item, connected with: %s",
2076  tmp_inv->msg);
2077  break;
2078  }
2079  } FOR_INV_FINISH();
2080  }
2081  if (!has_link) {
2083  "This is a buildable item.");
2084  }
2085  }
2086 
2087  /* Does it have fluff text? */
2088  if (examine_fluff(op, tmp, false)) {
2089  op->contr->last_examined = tmp->count;
2091  "Examine again for more details.");
2092  } else {
2093  op->contr->last_examined = 0;
2094  }
2095 
2097  " "); /* Blank line */
2098 
2099  if (is_identified(tmp)) {
2101  }
2102 }
2103 
2112 void inventory(object *op, object *inv) {
2113  const char *in;
2114  int items = 0, length;
2115  char weight[MAX_BUF], name[MAX_BUF];
2116 
2117  if (inv == NULL && op == NULL) {
2119  "Inventory of what object?");
2120  return;
2121  }
2122  FOR_INV_PREPARE(inv ? inv : op, tmp)
2123  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
2124  || !op || QUERY_FLAG(op, FLAG_WIZ))
2125  items++;
2126  FOR_INV_FINISH();
2127  if (inv == NULL) { /* player's inventory */
2128  if (items == 0) {
2130  "You carry nothing.");
2131  return;
2132  } else {
2133  length = 28;
2134  in = "";
2136  "Inventory:");
2137  }
2138  } else {
2139  if (items == 0)
2140  return;
2141  else {
2142  length = 28;
2143  in = " ";
2144  }
2145  }
2146  FOR_INV_PREPARE(inv ? inv : op, tmp) {
2147  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
2148  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
2149  continue;
2150  query_weight(tmp, weight, MAX_BUF);
2151  query_name(tmp, name, MAX_BUF);
2152  if (!op || QUERY_FLAG(op, FLAG_WIZ))
2154  "[fixed]%s- %-*.*s (%5d) %-8s",
2155  in, length, length, name, tmp->count, weight);
2156  else
2158  "[fixed]%s- %-*.*s %-8s",
2159  in, length+8, length+8, name, weight);
2160  } FOR_INV_FINISH();
2161  if (!inv && op) {
2162  query_weight(op, weight, MAX_BUF);
2164  "[fixed]%-*s %-8s",
2165  41, "Total weight :", weight);
2166  }
2167 }
2168 
2177 static void display_new_pickup(const object *op, int old) {
2178  int i = op->contr->mode;
2179 
2180  esrv_send_pickup(op->contr);
2181 
2182  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
2183  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
2185  "Pickup is now %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
2186  }
2187  return;
2188  }
2189 
2191  "%d NEWMODE",
2192  i&PU_NEWMODE ? 1 : 0);
2194  "%d DEBUG",
2195  i&PU_DEBUG ? 1 : 0);
2197  "%d INHIBIT",
2198  i&PU_INHIBIT ? 1 : 0);
2200  "%d STOP",
2201  i&PU_STOP ? 1 : 0);
2202 
2204  "%d <= x pickup weight/value RATIO (0==off)",
2205  (i&PU_RATIO)*5);
2206 
2208  "%d FOOD",
2209  i&PU_FOOD ? 1 : 0);
2211  "%d DRINK",
2212  i&PU_DRINK ? 1 : 0);
2214  "%d VALUABLES",
2215  i&PU_VALUABLES ? 1 : 0);
2216 
2218  "%d BOW",
2219  i&PU_BOW ? 1 : 0);
2221  "%d ARROW",
2222  i&PU_ARROW ? 1 : 0);
2223 
2225  "%d HELMET",
2226  i&PU_HELMET ? 1 : 0);
2228  "%d SHIELD",
2229  i&PU_SHIELD ? 1 : 0);
2231  "%d ARMOUR",
2232  i&PU_ARMOUR ? 1 : 0);
2233 
2235  "%d BOOTS",
2236  i&PU_BOOTS ? 1 : 0);
2238  "%d GLOVES",
2239  i&PU_GLOVES ? 1 : 0);
2241  "%d CLOAK",
2242  i&PU_CLOAK ? 1 : 0);
2244  "%d KEY",
2245  i&PU_KEY ? 1 : 0);
2246 
2248  "%d MISSILEWEAPON",
2249  i&PU_MISSILEWEAPON ? 1 : 0);
2251  "%d MELEEWEAPON",
2252  i&PU_MELEEWEAPON ? 1 : 0);
2254  "%d MAGICAL",
2255  i&PU_MAGICAL ? 1 : 0);
2257  "%d POTION",
2258  i&PU_POTION ? 1 : 0);
2259 
2261  "%d SPELLBOOK",
2262  i&PU_SPELLBOOK ? 1 : 0);
2264  "%d SKILLSCROLL",
2265  i&PU_SKILLSCROLL ? 1 : 0);
2267  "%d READABLES",
2268  i&PU_READABLES ? 1 : 0);
2270  "%d MAGICDEVICE",
2271  i&PU_MAGIC_DEVICE ? 1 : 0);
2272 
2274  "%d NOT CURSED",
2275  i&PU_NOT_CURSED ? 1 : 0);
2276 
2278  "%d JEWELS",
2279  i&PU_JEWELS ? 1 : 0);
2280 
2282  "%d FLESH",
2283  i&PU_FLESH ? 1 : 0);
2284 
2286  "%d CONTAINER",
2287  i&PU_CONTAINER ? 1 : 0);
2288 
2290  "%d CURSED",
2291  i&PU_CURSED ? 1 : 0);
2292 
2294  "");
2295 }
2296 
2306 void command_pickup(object *op, const char *params) {
2307  uint32_t i;
2308 
2309  if (*params == '\0') {
2310  /* if the new mode is used, just print the settings */
2311  if (op->contr->mode&PU_NEWMODE) {
2312  display_new_pickup(op, op->contr->mode);
2313  return;
2314  }
2315  if (1)
2316  LOG(llevDebug, "command_pickup: !params\n");
2317  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
2318  return;
2319  }
2320 
2321  while (*params == ' ')
2322  params++;
2323 
2324  if (*params == '+' || *params == '-' || *params == '!') {
2325  int index = get_pickup_mode_index(params + 1);
2326 
2327  if (index != -1) {
2328  int old = op->contr->mode;
2329  i = op->contr->mode;
2330  if (!(i&PU_NEWMODE))
2331  i = PU_NEWMODE;
2332  if (*params == '+')
2333  i = i|pickup_modes[index];
2334  else if (*params == '-')
2335  i = i&~pickup_modes[index];
2336  else {
2337  if (i&pickup_modes[index])
2338  i = i&~pickup_modes[index];
2339  else
2340  i = i|pickup_modes[index];
2341  }
2342  op->contr->mode = i;
2343  display_new_pickup(op, old);
2344  return;
2345  }
2347  "Pickup: invalid item %s\n",
2348  params);
2349  return;
2350  }
2351 
2352  if (sscanf(params, "%u", &i) != 1) {
2353  if (1)
2354  LOG(llevDebug, "command_pickup: params==NULL\n");
2356  "Usage: pickup <0-7> or <value_density> .");
2357  return;
2358  }
2359  set_pickup_mode(op, i);
2360  display_new_pickup(op, op->contr->mode);
2361 }
2362 
2371 static void set_pickup_mode(const object *op, int i) {
2372  op->contr->mode = i;
2373  switch (op->contr->mode) {
2374  case 0:
2376  "Mode: Don't pick up.");
2377  break;
2378 
2379  case 1:
2381  "Mode: Pick up one item.");
2382  break;
2383 
2384  case 2:
2386  "Mode: Pick up one item and stop.");
2387  break;
2388 
2389  case 3:
2391  "Mode: Stop before picking up.");
2392  break;
2393 
2394  case 4:
2396  "Mode: Pick up all items.");
2397  break;
2398 
2399  case 5:
2401  "Mode: Pick up all items and stop.");
2402  break;
2403 
2404  case 6:
2406  "Mode: Pick up all magic items.");
2407  break;
2408 
2409  case 7:
2411  "Mode: Pick up all coins and gems");
2412  break;
2413  }
2414 }
2415 
2424 void command_search_items(object *op, const char *params) {
2425  if (settings.search_items == FALSE)
2426  return;
2427 
2428  if (!params || *params == '\0') {
2429  if (op->contr->search_str[0] == '\0') {
2431  "Example: search magic+1 "
2432  "Would automatically pick up all "
2433  "items containing the word 'magic+1'.");
2434  return;
2435  }
2436  op->contr->search_str[0] = '\0';
2438  "Search mode turned off.");
2439  fix_object(op);
2440  return;
2441  }
2442  if ((int)strlen(params) >= MAX_BUF) {
2444  "Search string too long.");
2445  return;
2446  }
2447  strcpy(op->contr->search_str, params);
2449  "Searching for '%s'.",
2450  op->contr->search_str);
2451  fix_object(op);
2452 }
2453 
2469 void command_rename_item(object *op, const char *params) {
2470  char buf[VERY_BIG_BUF], name[MAX_BUF];
2471  tag_t itemnumber;
2472  object *item = NULL;
2473  object *tmp;
2474  const char *closebrace;
2475  size_t counter;
2476 
2477  if (*params != '\0') {
2478  /* Let's skip white spaces */
2479  while (' ' == *params)
2480  params++;
2481 
2482  /* Checking the first part */
2483  itemnumber = atoi(params);
2484  if (itemnumber != 0) {
2485  FOR_INV_PREPARE(op, inv)
2486  if (inv->count == itemnumber && !inv->invisible) {
2487  item = inv;
2488  break;
2489  }
2490  FOR_INV_FINISH();
2491  if (!item) {
2493  "Tried to rename an invalid item.");
2494  return;
2495  }
2496  while (isdigit(*params) || ' ' == *params)
2497  params++;
2498  } else if ('<' == *params) {
2499  /* Got old name, let's get it & find appropriate matching item */
2500  closebrace = strchr(params, '>');
2501  if (!closebrace) {
2503  "Syntax error!");
2504  return;
2505  }
2506  /* Sanity check for buffer overruns */
2507  if (closebrace-params > 127) {
2509  "Old name too long (up to 127 characters allowed)!");
2510  return;
2511  }
2512  /* Copy the old name */
2513  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2514 
2515  /* Find best matching item */
2516  item = find_best_object_match(op, buf);
2517  if (!item) {
2519  "Could not find a matching item to rename.");
2520  return;
2521  }
2522 
2523  /* Now need to move pointer to just after > */
2524  params = closebrace+1;
2525  while (' ' == *params)
2526  params++;
2527  } else {
2528  /* Use marked item */
2529  item = find_marked_object(op);
2530  if (!item) {
2532  "No marked item to rename.");
2533  return;
2534  }
2535  }
2536 
2537  /* Now let's find the new name */
2538  if (!strncmp(params, "to ", 3)) {
2539  params += 3;
2540  while (' ' == *params)
2541  params++;
2542  if ('<' != *params) {
2544  "Syntax error, expecting < at start of new name!");
2545  return;
2546  }
2547  closebrace = strchr(params+1, '>');
2548  if (!closebrace) {
2550  "Syntax error, expecting > at end of new name!");
2551  return;
2552  }
2553 
2554  /* Sanity check for buffer overruns */
2555  if (closebrace-params > 127) {
2557  "New name too long (up to 127 characters allowed)!");
2558  return;
2559  }
2560 
2561  /* Copy the new name */
2562  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2563 
2564  /* Let's check it for weird characters */
2565  for (counter = 0; counter < strlen(buf); counter++) {
2566  if (isalnum(buf[counter]))
2567  continue;
2568  if (' ' == buf[counter])
2569  continue;
2570  if ('\'' == buf[counter])
2571  continue;
2572  if ('+' == buf[counter])
2573  continue;
2574  if ('_' == buf[counter])
2575  continue;
2576  if ('-' == buf[counter])
2577  continue;
2578 
2579  /* If we come here, then the name contains an invalid character...
2580  * tell the player & exit
2581  */
2583  "Invalid new name!");
2584  return;
2585  }
2586  } else {
2587  /* If param contains something, then syntax error... */
2588  if (strlen(params)) {
2590  "Syntax error, expected 'to <' after old name!");
2591  return;
2592  }
2593  /* New name is empty */
2594  buf[0] = '\0';
2595  }
2596  } else {
2597  /* Last case: *params=='\0' */
2598  item = find_marked_object(op);
2599  if (!item) {
2601  "No marked item to rename.");
2602  return;
2603  }
2604  buf[0] = '\0';
2605  }
2606 
2607  /* Coming here, everything is fine... */
2608  if (!strlen(buf)) {
2609  /* Clear custom name */
2610  if (object_get_value(item, CUSTOM_NAME_FIELD) == NULL) {
2612  "This item has no custom name.");
2613  return;
2614  }
2615 
2616  object_set_value(item, CUSTOM_NAME_FIELD, NULL, 0);
2617  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2619  "You stop calling your %s with weird names.",
2620  name);
2621  } else {
2622  sstring custom_name = object_get_value(item, CUSTOM_NAME_FIELD);
2623  if (custom_name != NULL && strcmp(custom_name, buf) == 0) {
2624  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2626  "You keep calling your %s %s.",
2627  name, buf);
2628  return;
2629  }
2630 
2631  /* Set custom name */
2633 
2634  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2636  "Your %s will now be called %s.",
2637  name, buf);
2638  }
2639 
2640  tmp = object_merge(item, NULL);
2641  if (tmp == NULL) {
2642  /* object was not merged - if it was, object_merge() handles updating for us. */
2643  esrv_update_item(UPD_NAME, op, item);
2644  }
2645 }
2646 
2655 void command_lock_item(object *op, const char *params) {
2656  object *item;
2657  object *tmp;
2658  char name[HUGE_BUF];
2659 
2660  if (*params == '\0' || strlen(params) == 0) {
2662  "Lock what item?");
2663  return;
2664  }
2665 
2666  item = find_best_object_match(op, params);
2667  if (!item) {
2669  "Can't find any matching item.");
2670  return;
2671  }
2672 
2673  query_short_name(item, name, HUGE_BUF);
2674  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2676  "Unlocked %s.", name);
2677  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2678  } else {
2680  "Locked %s.", name);
2681  SET_FLAG(item, FLAG_INV_LOCKED);
2682  }
2683 
2684  tmp = object_merge(item, NULL);
2685  if (tmp == NULL) {
2686  /* object was not merged, if it was object_merge() handles updates for us */
2687  esrv_update_item(UPD_FLAGS, op, item);
2688  }
2689 }
2690 
2698 void command_use(object *op, const char *params) {
2699  char *with, copy[MAX_BUF];
2700  object *first, *second/*, *add*/;
2701  /*archetype *arch;*/
2702  /*int count;*/
2703  /*sstring data;*/
2704  recipe *transformation;
2705 
2706  if (!IS_PLAYER(op))
2707  return;
2708 
2709  strlcpy(copy, params, sizeof(copy));
2710  with = strstr(copy, " with ");
2711  if (!with) {
2712  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2713  return;
2714  }
2715 
2716  with[0] = '\0';
2717  with = with+strlen(" with ");
2718 
2719  first = find_best_object_match(op, copy);
2720  if (!first) {
2721  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2722  return;
2723  }
2724  second = find_best_object_match(op, with);
2725  if (!second) {
2726  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2727  return;
2728  }
2729 
2730  transformation = NULL;
2731  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2733  if (transformation->ingred_count != 1)
2734  continue;
2735 
2736 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2737  if (strcmp(second->name, transformation->ingred->name) == 0) {
2739  object *generated = create_archetype(transformation->arch_name[0]);
2740  if (transformation->yield)
2741  generated->nrof = transformation->yield;
2742  object_insert_in_ob(generated, op);
2743  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2745  return;
2746  }
2747  }
2748  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2749  return;
2750 
2751  /*
2752  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2753  data = object_get_value(second, copy);
2754  if (!data) {
2755  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2756  data = object_get_value(second, copy);
2757  if (!data) {
2758  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2759  data = object_get_value(second, copy);
2760  if (!data) {
2761  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2762  return 1;
2763  }
2764  }
2765  }
2766 
2767  while (data != NULL) {
2768  if (strncmp(data, "add ", 4) == 0) {
2769  data += 4;
2770  if (isdigit(*data)) {
2771  count = atol(data);
2772  data = strchr(data, ' ')+1;
2773  } else
2774  count = 1;
2775  with = strchr(data, ' ');
2776  if (!with) {
2777  strncpy(copy, data, sizeof(copy));
2778  data = NULL;
2779  } else {
2780  *with = '\0';
2781  strncpy(copy, data, sizeof(copy));
2782  data += strlen(copy)+1;
2783  }
2784  arch = find_archetype(copy);
2785  if (!arch) {
2786  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2787  return 1;
2788  }
2789  add = object_create_arch(arch);
2790  add->nrof = count;
2791  object_insert_in_ob(add, op);
2792  } else if (strncmp(data, "remove $", 8) == 0) {
2793  data += 8;
2794  if (*data == '1') {
2795  if (first)
2796  first = object_decrease_nrof_by_one(first);
2797  data += 2;
2798  } else if (*data == '2') {
2799  if (second)
2800  second = object_decrease_nrof_by_one(second);
2801  data += 2;
2802  } else {
2803  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2804  return 1;
2805  }
2806  } else {
2807  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2808  return 1;
2809  }
2810  }
2811 
2812  return 1;
2813  */
2814 }
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:4375
drop
void drop(object *op, object *tmp)
Drop an item, either on the floor or in a container.
Definition: c_object.cpp:1121
object::name_pl
sstring name_pl
The plural name of the object.
Definition: object.h:325
find_recipe_for_tool
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Find a recipe for a specified tool.
Definition: recipe.cpp:897
do_skill
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Main skills use function-similar in scope to cast_spell().
Definition: skill_util.cpp:442
MIMIC
@ MIMIC
Definition: object.h:254
PLAYER
@ PLAYER
Definition: object.h:112
global.h
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
csv_contains
bool csv_contains(std::string list, std::string item, std::string delim)
Split list by comma, then see if item matches anything in the list.
Definition: c_object.cpp:303
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:747
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:15
AT_ACID
#define AT_ACID
Random equipped item might corrode when hit (64)
Definition: attack.h:84
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:534
BOW
@ BOW
Definition: object.h:123
BRACERS
@ BRACERS
Definition: object.h:222
CLOSE_CON
@ CLOSE_CON
Eneq((at)csd.uu.se): Id for close_container archetype.
Definition: object.h:234
llevError
@ llevError
Problems requiring server admin to fix.
Definition: logger.h:11
ARMOUR_IMPROVER
@ ARMOUR_IMPROVER
Definition: object.h:237
command_search
void command_search(object *op, const char *params)
'search' command.
Definition: c_object.cpp:213
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
This returns the first skill pointer of the given subtype (the one that accumulates exp,...
Definition: main.cpp:389
MOVE_FLYING
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:386
WAND
@ WAND
Definition: object.h:225
player::mode
uint32_t mode
Mode of player for pickup.
Definition: player.h:125
LOG
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.cpp:82
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:369
FLESH
@ FLESH
animal 'body parts' -b.t.
Definition: object.h:192
ob_examine
method_ret ob_examine(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Get examine text for OP as seen by OBSERVER.
Definition: ob_methods.cpp:113
GLOVES
@ GLOVES
Definition: object.h:218
FLAG_IS_LINKED
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:302
object::inv
object * inv
Pointer to the first object in the inventory.
Definition: object.h:300
GIRDLE
@ GIRDLE
Definition: object.h:228
PU_KEY
#define PU_KEY
Definition: define.h:128
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:411
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:371
time
same as sound ncom command like but with extra the client want tick commands so it knows animation timing the client wants to be informed of pickup mode changes Mode will be sent when the player successfully logs and afterward any time the value is but over time
Definition: protocol.txt:416
KEY
@ KEY
Definition: object.h:132
command_rename_item
void command_rename_item(object *op, const char *params)
Changing the custom name of an item.
Definition: c_object.cpp:2469
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:2050
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:1559
FALSE
#define FALSE
Definition: compat.h:14
object::arch
struct archetype * arch
Pointer to archetype.
Definition: object.h:426
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Create a new string buffer.
Definition: stringbuffer.cpp:24
examine
void examine(object *op, object *tmp)
Player examines some object.
Definition: c_object.cpp:1932
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:372
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:337
command_rskill
void command_rskill(object *pl, const char *params)
'ready_skill' command.
Definition: c_object.cpp:162
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:2698
object::map
struct mapstruct * map
Pointer to the map in which this object is present.
Definition: object.h:307
WEAPON
@ WEAPON
Definition: object.h:124
AP_UNAPPLY
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:559
typedata::identifyskill
int identifyskill
Skill used to identify this object class.
Definition: define.h:93
esrv_send_pickup
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.cpp:1886
command_uskill
void command_uskill(object *pl, const char *params)
'use_skill' command.
Definition: c_object.cpp:145
FLAG_IS_CAULDRON
#define FLAG_IS_CAULDRON
container can make alchemical stuff
Definition: define.h:325
AMULET
@ AMULET
Definition: object.h:144
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
matcher_name
static int matcher_name(object *who, matcher_params *params, object *item)
Check if an item matches a string.
Definition: c_object.cpp:727
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:1759
object::count
tag_t count
Unique object number for this object.
Definition: object.h:309
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:1512
command_pickup
void command_pickup(object *op, const char *params)
'pickup' command.
Definition: c_object.cpp:2306
PU_CURSED
#define PU_CURSED
Definition: define.h:144
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
recipe::arch_name
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:381
TRANSPORT
@ TRANSPORT
see doc/Developers/objects
Definition: object.h:113
PU_DEBUG
#define PU_DEBUG
Definition: define.h:108
skills.h
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can't use command.
Definition: newclient.h:533
PU_SKILLSCROLL
#define PU_SKILLSCROLL
Definition: define.h:136
matcher_params::item_to_pick
int item_to_pick
Index of the item to pick, 1-based.
Definition: c_object.cpp:667
MSG_TYPE_SPELL_INFO
#define MSG_TYPE_SPELL_INFO
random info about spell, not related to failure/success
Definition: newclient.h:643
mapstruct::path
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:360
apply_by_living_below
void apply_by_living_below(object *pl)
Attempt to apply the object 'below' the player.
Definition: apply.cpp:357
ex_autoid_result
ex_autoid_result
Definition: c_object.cpp:1638
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:363
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Execute an event on the specified object.
Definition: events.cpp:309
FLAG_NO_SKILL_IDENT
#define FLAG_NO_SKILL_IDENT
If set, item cannot be identified w/ a skill.
Definition: define.h:322
buf
StringBuffer * buf
Definition: readable.cpp:1564
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.cpp:2856
object::above
object * above
Pointer to the object stacked above this one.
Definition: object.h:298
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:2371
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:1299
body_locations_struct::nonuse_name
const char * nonuse_name
Name to describe objects we can't use.
Definition: object.h:25
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
PU_FOOD
#define PU_FOOD
Definition: define.h:115
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
PU_FLESH
#define PU_FLESH
Definition: define.h:142
FLAG_REMOVED
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:219
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:695
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
The object is known to be cursed.
Definition: define.h:307
socket_struct::update_look
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:109
command_empty
void command_empty(object *op, const char *params)
'empty' command.
Definition: c_object.cpp:1395
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:609
METHOD_UNHANDLED
#define METHOD_UNHANDLED
Definition: ob_methods.h:16
object::carrying
int32_t carrying
How much weight this object contains.
Definition: object.h:379
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:522
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:337
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:32
FLAG_FREED
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:220
get_button_value
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.cpp:751
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects,...
Definition: object.cpp:1558
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:890
object::contr
struct player * contr
Pointer to the player which control this object.
Definition: object.h:286
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:626
HELMET
@ HELMET
Definition: object.h:141
use_skill
int use_skill(object *op, const char *string)
Similar to invoke command, it executes the skill in the direction that the user is facing.
Definition: skill_util.cpp:996
matcher_all
static int matcher_all(object *who, matcher_params *params, object *item)
Function allowing all objects.
Definition: c_object.cpp:693
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
POISON
@ POISON
Definition: object.h:118
linked_char::name
const char * name
Definition: global.h:103
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
The object is known to be magical.
Definition: define.h:306
FLAG_NO_DROP
#define FLAG_NO_DROP
Object can't be dropped.
Definition: define.h:275
command_throw
void command_throw(object *op, const char *params)
'throw' command.
Definition: c_object.cpp:240
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:672
query_name
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.cpp:593
matcher_params::name
char name[MAX_BUF]
Name to match for.
Definition: c_object.cpp:671
POTION
@ POTION
Definition: object.h:116
body_locations_struct::use_name
const char * use_name
Name used when describing an item we can use.
Definition: object.h:24
examine_weight_and_material
void examine_weight_and_material(object *op, object *tmp)
Output weight and material information for an examined object.
Definition: c_object.cpp:1733
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:707
sack_can_hold
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Check if an item op can be put into a sack.
Definition: container.cpp:66
archetype::clone
object clone
An object from which to do object_copy()
Definition: object.h:489
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
StringBuffer
std::string StringBuffer
The string buffer state.
Definition: stringbuffer.h:33
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:608
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:330
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:297
object::move_type
MoveType move_type
Type of movement this object uses.
Definition: object.h:438
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:4107
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:362
is_identified
int is_identified(const object *op)
Return true if the item is identified, either because it is of a type that doesn't ever need identifi...
Definition: item.cpp:1355
ob_describe
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Returns the description (short item name) of an object, as seen by the given observer.
Definition: ob_methods.cpp:92
SPECIAL_KEY
@ SPECIAL_KEY
Definition: object.h:129
empty_container
static void empty_container(object *container, object *pl)
Put all contents of the container on the ground below the player or in opened container,...
Definition: c_object.cpp:1357
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
object::type
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:350
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:358
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:1183
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:664
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:485
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.cpp:4574
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:759
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Append a string to a string buffer instance.
Definition: stringbuffer.cpp:44
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:328
object::facing
int8_t facing
Object is oriented/facing that way.
Definition: object.h:347
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:102
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:2099
command_search_items
void command_search_items(object *op, const char *params)
'search-items' command.
Definition: c_object.cpp:2424
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
inventory
void inventory(object *op, object *inv)
Prints object's inventory.
Definition: c_object.cpp:2112
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:316
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level,...
Definition: skill_util.cpp:209
recipe::ingred_count
int ingred_count
Number of items in ingred.
Definition: recipe.h:23
env
static std::shared_ptr< inja::Environment > env
Rendering environment.
Definition: mapper.cpp:2224
MAX_BUF
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
do_skill_by_number
static void do_skill_by_number(object *op, int skill_subtype, const char *params, const char *missing_message)
Attempt to use a skill from its subtype.
Definition: c_object.cpp:189
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Portable implementation of strlcpy(3).
Definition: porting.cpp:225
object_insert_in_map
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
This function inserts the object in the two-way linked list which represents what is on a map.
Definition: object.cpp:2360
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:3167
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:377
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:225
IS_PLAYER
static bool IS_PLAYER(object *op)
Definition: object.h:610
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:669
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:44
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:133
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:59
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:334
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:329
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:684
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:321
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:3866
stringbuffer_trim_whitespace
void stringbuffer_trim_whitespace(StringBuffer *sb)
Trim trailing whitespace from a stringbuffer.
Definition: stringbuffer.cpp:125
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
EVENT_PICKUP
#define EVENT_PICKUP
Object picked up.
Definition: events.h:36
PU_RATIO
#define PU_RATIO
Definition: define.h:113
cost_str
char * cost_str(uint64_t cost)
Definition: shop.cpp:308
mapstruct
This is a game-map.
Definition: map.h:320
object::env
object * env
Pointer to the object which is the environment.
Definition: object.h:303
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:252
pick_up
bool pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.cpp:471
PU_DRINK
#define PU_DRINK
Definition: define.h:116
object::skill
sstring skill
Name of the skill this object uses/grants.
Definition: object.h:331
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:2636
shop_contains
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: map.cpp:2743
command_examine
void command_examine(object *op, const char *params)
'examine' command.
Definition: c_object.cpp:1434
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:1820
apply_by_living
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Living thing is applying an object.
Definition: apply.cpp:299
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.cpp:367
Settings::max_stat
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:326
object::msg
sstring msg
If this is a book/sign/magic mouth/etc.
Definition: object.h:332
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:4345
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:1465
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:2177
INS_NO_MERGE
#define INS_NO_MERGE
Don't try to merge with other items.
Definition: object.h:581
level
int level
Definition: readable.cpp:1562
typedata::identifyskill2
int identifyskill2
Second skill used to identify this object class.
Definition: define.h:94
player::count
uint32_t count
Any numbers typed before a command.
Definition: player.h:124
FLAG_NO_FIX_PLAYER
#define FLAG_NO_FIX_PLAYER
fix_object() won't be called
Definition: define.h:264
object::body_info
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:384
player::last_examined
tag_t last_examined
Tag of most recently 'examined object.
Definition: player.h:167
UPD_NAME
#define UPD_NAME
Definition: newclient.h:322
loader.h
save_player
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.cpp:239
Settings::real_wiz
uint8_t real_wiz
Use mud-like wizards.
Definition: global.h:275
draw_ext_info
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Sends message to player(s).
Definition: main.cpp:316
stop_item
object * stop_item(object *op)
An item (ARROW or such) stops moving.
Definition: time.cpp:455
FOOD
@ FOOD
Definition: object.h:117
object::container
object * container
Current container being used.
Definition: object.h:301
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:1832
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:1026
EX_ID_FAILED
@ EX_ID_FAILED
Definition: c_object.cpp:1641
object::move_off
MoveType move_off
Move types affected moving off this space.
Definition: object.h:442
examine_rod_charge_level
void examine_rod_charge_level(object *op, object *tmp)
Output charge information for a rod.
Definition: c_object.cpp:1788
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:2655
WEAPON_IMPROVER
@ WEAPON_IMPROVER
Definition: object.h:238
archetype::name
sstring name
More definite name, like "generate_kobold".
Definition: object.h:486
SCROLL
@ SCROLL
Definition: object.h:226
object::nrof
uint32_t nrof
Number of objects.
Definition: object.h:344
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:674
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.cpp:691
Settings::search_items
uint8_t search_items
Search_items command.
Definition: global.h:271
object::stats
living stats
Str, Con, Dex, etc.
Definition: object.h:380
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:4498
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:798
BOOTS
@ BOOTS
Definition: object.h:217
pickup_names
static const char * pickup_names[]
Valid names for pickup types.
Definition: c_object.cpp:34
matcher_params::item_number
int item_number
Index of the checked item, 1-based.
Definition: c_object.cpp:668
EX_ID_NO_SKILL
@ EX_ID_NO_SKILL
Definition: c_object.cpp:1640
SHIELD
@ SHIELD
Definition: object.h:140
object::attacktype
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:354
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:598
living.h
SK_THROWING
@ SK_THROWING
Throwing.
Definition: skills.h:44
EX_ID_ABORT
@ EX_ID_ABORT
Definition: c_object.cpp:1639
SPELLBOOK
@ SPELLBOOK
Definition: object.h:208
CUSTOM_NAME_FIELD
#define CUSTOM_NAME_FIELD
Key in an object for the player-assigned custom name.
Definition: object.h:98
shop_price_sell
uint64_t shop_price_sell(const object *obj, object *who)
Adjust the value of an item to be sold based on the player's bargaining skill and charisma.
Definition: shop.cpp:154
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:654
living::hp
int16_t hp
Hit Points.
Definition: living.h:40
FORCE
@ FORCE
Definition: object.h:229
llevDebug
@ llevDebug
Only for debugging purposes.
Definition: logger.h:15
MONEY
@ MONEY
Definition: object.h:142
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:585
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:1655
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