Crossfire Server, Trunk
c_object.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 1999-2014 Mark Wedel and the Crossfire Development Team
5  * Copyright (c) 1992 Frank Tore Johansen
6  *
7  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
8  * welcome to redistribute it under certain conditions. For details, please
9  * see COPYING and LICENSE.
10  *
11  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
12  */
19 #include "global.h"
20 
21 #include <ctype.h>
22 #include <math.h>
23 #include <stdlib.h>
24 #include <string.h>
25 
26 #include "living.h"
27 #include "loader.h"
28 #include "shop.h"
29 #include "skills.h"
30 #include "sproto.h"
31 
33 static const char *pickup_names[] = {
34  "debug", "inhibit", "stop", "food", "drink",
35  "valuables", "bow", "arrow", "helmet", "shield",
36  "armour", "boots", "gloves", "cloak", "key",
37  "missile", "melee", "magical", "potion", "spellbook",
38  "skillscroll", "readables", "magicdevice", "notcursed", "jewels",
39  "flesh", "container", "cursed", NULL
40 };
41 
43 static const uint32_t pickup_modes[] = {
48 };
49 
58 static int get_pickup_mode_index(const char *name) {
59  int best = -1;
60  size_t len = strlen(name);
61  for (size_t mode = 0; pickup_names[mode]; mode++) {
62  if (!strcmp(pickup_names[mode], name)) {
63  return mode;
64  }
65  if (len < strlen(pickup_names[mode]) && strncmp(name, pickup_names[mode], len) == 0) {
66  if (best != -2) {
67  if (best != -1) {
68  best = -2;
69  } else {
70  best = mode;
71  }
72  }
73  }
74  }
75  return best != -2 ? best : -1;
76 }
77 
78 static void set_pickup_mode(const object *op, int i);
79 
80 /*
81  * Object id parsing functions
82  */
83 
101 static object *find_best_apply_object_match(object *start, object *pl, const char *params, int aflag) {
102  object *tmp, *best = NULL;
103  int match_val = 0, tmpmatch;
104 
105  tmp = start;
107  if (!player_can_find(pl, tmp))
108  continue;
109  if (aflag == AP_APPLY && QUERY_FLAG(tmp, FLAG_APPLIED))
110  continue;
111  if (aflag == AP_UNAPPLY && !QUERY_FLAG(tmp, FLAG_APPLIED))
112  continue;
113  tmpmatch = object_matches_string(pl, tmp, params);
114  if (tmpmatch > match_val) {
115  match_val = tmpmatch;
116  best = tmp;
117  }
119  return best;
120 }
121 
132 static object *find_best_object_match(object *pl, const char *params) {
134 }
135 
144 void command_uskill(object *pl, const char *params) {
145  if (*params == '\0') {
147  "Usage: use_skill <skill name>");
148  return;
149  }
150  use_skill(pl, params);
151 }
152 
161 void command_rskill(object *pl, const char *params) {
162  object *skill;
163 
164  if (*params == '\0') {
166  "Usage: ready_skill <skill name>");
167  return;
168  }
170 
171  if (!skill) {
173  "You have no knowledge of the skill %s",
174  params);
175  return;
176  }
177  change_skill(pl, skill, 0);
178 }
179 
188 static void do_skill_by_number(object *op, int skill_subtype, const char *params,
189  const char *missing_message) {
190  object *skop = find_skill_by_number(op, skill_subtype);
191  if (skop) {
192  do_skill(op, op, skop, op->facing, *params == '\0' ? NULL : params);
193  return;
194  }
195 
197  missing_message);
198 }
199 
200 /* These functions (command_search, command_disarm) are really juse wrappers for
201  * things like 'use_skill ...'). In fact, they should really be obsoleted
202  * and replaced with those.
203  */
212 void command_search(object *op, const char *params) {
213  do_skill_by_number(op, SK_FIND_TRAPS, params, "You don't know how to search for unusual things.");
214 }
215 
224 void command_disarm(object *op, const char *params) {
225  do_skill_by_number(op, SK_DISARM_TRAPS, params, "You don't know how to disarm traps.");
226 }
227 
239 void command_throw(object *op, const char *params) {
240  do_skill_by_number(op, SK_THROWING, params, "You have no knowledge of the skill throwing.");
241 }
242 
251 void command_apply(object *op, const char *params) {
252  int aflag = 0;
253  object *inv = op->inv;
254  object *item;
255 
256  if (*params == '\0') {
258  return;
259  }
260 
261  while (*params == ' ')
262  params++;
263  if (!strncmp(params, "-a ", 3)) {
264  aflag = AP_APPLY;
265  params += 3;
266  }
267  if (!strncmp(params, "-u ", 3)) {
268  aflag = AP_UNAPPLY;
269  params += 3;
270  }
271  if (!strncmp(params, "-o ", 3)) {
272  aflag = AP_OPEN;
273  params += 3;
274  }
275  if (!strncmp(params, "-b ", 3)) {
276  params += 3;
277  if (op->container)
278  inv = op->container->inv;
279  else {
280  inv = op;
281  while (inv->above)
282  inv = inv->above;
283  }
284  }
285  while (*params == ' ')
286  params++;
287 
289  if (item == NULL)
291  if (item) {
292  apply_by_living(op, item, aflag, 0);
293  } else
295  "Could not find any match to the %s.",
296  params);
297 }
298 
317 int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof) {
318  char name[MAX_BUF];
319  query_name(sack, name, MAX_BUF);
320 
321  if (!QUERY_FLAG(sack, FLAG_APPLIED)) {
323  "The %s is not active.",
324  name);
325  return 0;
326  }
327  if (sack == op) {
329  "You can't put the %s into itself.",
330  name);
331  return 0;
332  }
333  if (sack->race
334  && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type))) {
336  "You can put only %s into the %s.",
337  sack->race, name);
338  return 0;
339  }
340  if (op->type == SPECIAL_KEY && sack->slaying && op->slaying) {
342  "You can't put the key into %s.",
343  name);
344  return 0;
345  }
346  if (sack->weight_limit) {
347  int32_t new_weight;
348 
349  new_weight = sack->carrying+(nrof ? nrof : 1)
350  /* Most non-containers should have op->carrying == 0. Icecubes, however, will not,
351  * and we need to handle those.
352  * Daniel Hawkins 2021-01-21
353  */
354  *(op->weight+(op->type == CONTAINER ? op->carrying*op->stats.Str : op->carrying))
355  *(100-sack->stats.Str)/100;
356  if (new_weight > sack->weight_limit) {
358  "That won't fit in the %s!",
359  name);
360  return 0;
361  }
362  }
363  /* All other checks pass, must be OK */
364  return 1;
365 }
366 
379 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
380  /* buf needs to be big (more than 256 chars) because you can get
381  * very long item names.
382  */
383  char buf[HUGE_BUF], name[MAX_BUF];
384  object *env = tmp->env;
385  uint32_t weight, effective_weight_limit;
386  const int tmp_nrof = NROF(tmp);
387  tag_t tag;
388  mapstruct* map = tmp->map;
389  int16_t x = tmp->x, y = tmp->y;
390 
391  /* IF the player is flying & trying to take the item out of a container
392  * that is in his inventory, let him. tmp->env points to the container
393  * (sack, luggage, etc), tmp->env->env then points to the player (nested
394  * containers not allowed as of now)
395  */
396  if ((pl->move_type&MOVE_FLYING)
397  && !QUERY_FLAG(pl, FLAG_WIZ)
400  "You are levitating, you can't reach the ground!");
401  return;
402  }
404  return;
405 
408  "The object disappears in a puff of smoke! It must have been an illusion.");
409  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
412  return;
413  }
414 
415  if (nrof > tmp_nrof || nrof == 0)
416  nrof = tmp_nrof;
417 
418  /* Figure out how much weight this object will add to the player */
419  weight = tmp->weight*nrof;
420  if (tmp->inv)
421  weight += tmp->carrying*(100-tmp->stats.Str)/100;
422 
423  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
424 
425  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
427  "That item is too heavy for you to pick up.");
428  return;
429  }
430 
433 
434  if (nrof != tmp_nrof) {
435  char failure[MAX_BUF];
436 
437  tmp = object_split(tmp, nrof, failure, sizeof(failure));
438  if (!tmp) {
440  failure);
441  return;
442  }
443  } else {
444  /* If the object is in a container, send a delete to the client.
445  * - we are moving all the items from the container to elsewhere,
446  * so it needs to be deleted.
447  */
448  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
449  object_remove(tmp); /* Unlink it */
450  }
451  }
453 
454  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
455  char *value = cost_str(shop_price_buy(tmp, pl));
456  if (op == pl) {
457  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
458  } else {
459  snprintf(buf, sizeof(buf), "%s will cost you %s. You place it in your %s.", name, value, op->name);
460  }
461  free(value);
462  } else {
463  if (op == pl) {
464  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
465  } else {
466  snprintf(buf, sizeof(buf), "You pick up the %s and put it in your %s.", name, op->name);
467  }
468  }
469 
470  /* Now item is about to be picked. */
471  tag = tmp->count;
473  /* put item back, if it still exists */
474  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
475  if (env != NULL) {
477  } else {
478  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
479  }
480  }
481  return;
482  }
483 
485  buf);
486 
488 
489  /* All the stuff below deals with client/server code, and is only
490  * usable by players
491  */
492  if (pl->type != PLAYER)
493  return;
494 
495  /* Additional weight changes speed, etc */
496  fix_object(pl);
497 
498  /* These are needed to update the weight for the container we
499  * are putting the object in.
500  */
501  if (op != pl) {
504  }
505 
506  /* Update the container the object was in */
507  if (env && env != pl && env != op)
509 }
510 
519 void pick_up(object *op, object *alt) {
520 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
521  object *tmp = NULL, *tmp1;
522  mapstruct *tmp_map = NULL;
523  int count;
524 
525  /* Decide which object to pick. */
526  if (alt) {
527  if (!object_can_pick(op, alt)) {
529  "You can't pick up the %s.",
530  alt->name);
531  return;
532  }
533  tmp = alt;
534  } else {
535  if (op->below == NULL || !object_can_pick(op, op->below)) {
537  "There is nothing to pick up here.");
538  return;
539  }
540  tmp = op->below;
541  }
542 
543  /* it is possible that the object is a thrown object and is flying about.
544  * in that case, what we want to pick up is the payload. Objects
545  * that are thrown are encapsulated into a thrown object.
546  * stop_item() returns the payload (unlinked from map) and gets rid of the
547  * container object. If this object isn't picked up, we need to insert
548  * it back on the map.
549  * A bug here is that even attempting to pick up one of these objects will
550  * result in this logic being called even if player is unable to pick it
551  * up.
552  */
553 
554  tmp_map = tmp->map;
555  tmp1 = stop_item(tmp);
556  if (tmp1 == NULL)
557  return;
558 
559  /* If it is a thrown object, insert it back into the map here.
560  * makes life easier further along. Do no merge so pick up code
561  * behaves more sanely.
562  */
563  if (tmp1 != tmp) {
564  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
565  }
566 
567  if (tmp == NULL)
568  return;
569 
570  if (!object_can_pick(op, tmp))
571  return;
572 
573  /* Establish how many of the object we are picking up */
574  if (op->type == PLAYER) {
575  count = op->contr->count;
576  if (count == 0)
577  count = tmp->nrof;
578  } else
579  count = tmp->nrof;
580 
581  /* container is open, so use it */
582  if (op->container) {
583  alt = op->container;
584  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
585  return;
586  } else {
587  /* non container pickup. See if player has any
588  * active containers.
589  */
590  object *container = NULL;
591 
592  /* Look for any active containers that can hold this item.
593  * we cover two cases here - the perfect match case, where we
594  * break out of the loop, and the general case (have a container),
595  * Moved this into a single loop - reduces redundant code, is
596  * more efficient and easier to follow. MSW 2009-04-06
597  */
598  alt = op->inv;
600  if (alt->type == CONTAINER
601  && QUERY_FLAG(alt, FLAG_APPLIED)
602  && sack_can_hold(NULL, alt, tmp, count)) {
603  if (alt->race && alt->race == tmp->race) {
604  break; /* perfect match */
605  } else if (!container) {
606  container = alt;
607  }
608  }
610  /* Note container could be null, but no reason to check for it */
611  if (!alt)
612  alt = container;
613 
614  if (!alt)
615  alt = op; /* No free containers */
616  }
617  /* see if this object is already in this container. If so,
618  * move it to player inventory from this container.
619  */
620  if (tmp->env == alt) {
621  alt = op;
622  }
623 
624  /* Don't allow players to be put into containers. Instead,
625  * just put them in the players inventory.
626  */
627  if ((tmp->type == CONTAINER || tmp->type == MIMIC) && alt->type==CONTAINER) {
628  alt = op;
629  }
630 #ifdef PICKUP_DEBUG
631  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
632 #endif
633 
634  /* startequip items are not allowed to be put into containers
635  * Not sure why we have this limitation
636  */
637  if (op->type == PLAYER
638  && alt->type == CONTAINER
641  "This object cannot be put into containers!");
642  return;
643  }
644 
645  pick_up_object(op, alt, tmp, count);
646  if (op->type == PLAYER)
647  op->contr->count = 0;
648 }
649 
656 int object_matches_pickup_mode(const object *item, int mode) {
657  switch(mode) {
658  case PU_FOOD:
659  return item->type == FOOD;
660  case PU_DRINK:
661  return item->type == DRINK || (item->type == POISON && !QUERY_FLAG(item, FLAG_KNOWN_CURSED));
662  case PU_FLESH:
663  return item->type == FLESH;
664  case PU_POTION:
665  return item->type == POTION;
666  case PU_SPELLBOOK:
667  return item->type == SPELLBOOK;
668  case PU_SKILLSCROLL:
669  return item->type == SKILLSCROLL;
670  case PU_READABLES:
671  return item->type == BOOK || item->type == SCROLL;
672  case PU_MAGIC_DEVICE:
673  return item->type == WAND || item->type == ROD || item->type == WEAPON_IMPROVER || item->type == ARMOUR_IMPROVER || item->type == SKILL_TOOL;
674  case PU_MAGICAL:
676  case PU_VALUABLES:
677  return item->type == MONEY || item->type == GEM;
678  case PU_JEWELS:
679  return item->type == RING || item->type == AMULET;
680  case PU_BOW:
681  return item->type == BOW;
682  case PU_ARROW:
683  return item->type == ARROW;
684  case PU_ARMOUR:
685  return item->type == ARMOUR;
686  case PU_HELMET:
687  return item->type == HELMET;
688  case PU_SHIELD:
689  return item->type == SHIELD;
690  case PU_BOOTS:
691  return item->type == BOOTS;
692  case PU_GLOVES:
693  return item->type == GLOVES;
694  case PU_CLOAK:
695  return item->type == CLOAK;
696  case PU_MISSILEWEAPON:
697  return item->type == WEAPON && QUERY_FLAG(item, FLAG_IS_THROWN);
698  case PU_MELEEWEAPON:
699  return item->type == WEAPON;
700  case PU_KEY:
701  return item->type == KEY || item->type == SPECIAL_KEY;
702  case PU_CONTAINER:
703  return item->type == CONTAINER;
704  case PU_CURSED:
706  }
707  return 0;
708 }
709 
712  union {
713  struct {
717  };
718  char name[MAX_BUF];
720  };
721  int missed;
722 };
723 
731 typedef int (*item_matcher)(object *who, matcher_params *params, object *item);
732 
740 static int matcher_all(object *who, matcher_params *params, object *item) {
741  (void)who;
742  (void)params;
743  (void)item;
744  return 1;
745 }
746 
754 static int matcher_number(object *who, matcher_params *params, object *item) {
755  if (params->item_must_be_pickable == 0 || object_can_pick(who, item)) {
756  params->item_number++;
757  }
758  if (params->item_to_pick == params->item_number) {
759  /* Since we don't always increase item_number, multiple items may have the same index,
760  including unpickable ones, so to avoid failure messages just ensure no other item can be picked. */
761  params->item_to_pick = 0;
762  return 1;
763  }
764  return 0;
765 }
766 
774 static int matcher_name(object *who, matcher_params *params, object *item) {
775  int ival = object_matches_string(who, item, params->name);
776  if (ival > 0) {
777  if (ival <= 2 && !object_can_pick(who, item)) {
778  if (!QUERY_FLAG(item, FLAG_IS_FLOOR))/* don't count floor tiles */
779  params->missed++;
780  return 0;
781  }
782  return 1;
783  }
784  return 0;
785 }
786 
794 static int matcher_pickup_type(object *who, matcher_params *params, object *item) {
795  (void)who;
796  return object_matches_pickup_mode(item, params->pickup_type);
797 }
798 
806 static item_matcher make_matcher(object *who, const char *params, matcher_params *mp) {
807  memset(mp, 0, sizeof(*mp));
808  if (params[0] == '\0') {
809  mp->item_to_pick = 1;
810  mp->item_must_be_pickable = 1;
811  return &matcher_number;
812  }
813  if (params[0] == '#') {
814  mp->item_to_pick = atoi(params + 1);
815  if (mp->item_to_pick == 0) {
817  return NULL;
818  }
819  return &matcher_number;
820  }
821  if (params[0] == '*') {
822  if (params[1] == '\0') {
823  return &matcher_all;
824  }
825  int idx = get_pickup_mode_index(params + 1);
826  if (idx == -1) {
828  return NULL;
829  }
830  mp->pickup_type = pickup_modes[idx];
831  return &matcher_pickup_type;
832  }
833  strncpy(mp->name, params, sizeof(mp->name) - 1);
834  return &matcher_name;
835 }
836 
845 void command_take(object *op, const char *params) {
846  object *tmp;
847  int did_one = 0;
848 
849  if (op->container)
850  tmp = op->container->inv;
851  else {
852  tmp = op->above;
853  if (tmp)
854  while (tmp->above) {
855  tmp = tmp->above;
856  }
857  if (!tmp)
858  tmp = op->below;
859  }
860 
861  if (tmp == NULL) {
863  "Nothing to take!");
864  return;
865  }
866 
867  matcher_params mp;
868  item_matcher matcher = make_matcher(op, params, &mp);
869  if (!matcher) {
870  return; // Player already informed of failure.
871  }
872 
874 
876  if (tmp->invisible) {
877  continue;
878  }
879  if ((*matcher)(op, &mp, tmp)) {
880  pick_up(op, tmp);
881  did_one = 1;
882  }
884 
885  /* Nothing picked up, check if unable to pick or nothing to pick. */
886  if (params[0] == '\0' && !did_one) {
887  int found = 0;
889  if (!tmp->invisible) {
891  "You can't pick up a %s.",
892  tmp->name ? tmp->name : "null");
893  found = 1;
894  break;
895  }
897  if (!found)
899  "There is nothing to pick up.");
900  }
901 
902  if (mp.missed == 1)
904  "You were unable to take one of the items.");
905  else if (mp.missed > 1)
907  "You were unable to take %d of the items.",
908  mp.missed);
909 
910  /* Now update player and send information. */
912  fix_object(op);
913  if (op->type == PLAYER) {
914  op->contr->count = 0;
916  }
917 }
918 
937 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
938  object *sack2, *orig = sack;
939  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
940 
941  if (sack == tmp)
942  return; /* Can't put an object in itself */
943  query_name(sack, name_sack, MAX_BUF);
944  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
946  "The %s is not a container.",
947  name_sack);
948  return;
949  }
951  query_name(tmp, name_tmp, MAX_BUF);
953  "You cannot put the %s in the %s.",
954  name_tmp, name_sack);
955  return;
956  }
957  if (tmp->type == CONTAINER) {
958  if (tmp->inv) {
959  if (tmp->slaying)
960  return;
961  /* Eneq(@csd.uu.se): If the object to be dropped is a container
962  * and does not require a key to be opened,
963  * we instead move the contents of that container into the active
964  * container, this is only done if the object has something in it.
965  * If object is container but need a key, just don't do anything
966  */
967  sack2 = tmp;
968  query_name(tmp, name_tmp, MAX_BUF);
970  "You move the items from %s into %s.",
971  name_tmp, name_sack);
972 
973  FOR_INV_PREPARE(tmp, tmp2) {
974  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
975  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
976  put_object_in_sack(op, sack, tmp2, 0);
977  } else {
980  "Your %s fills up.",
981  name_sack);
982  break;
983  }
984  } FOR_INV_FINISH();
985  esrv_update_item(UPD_WEIGHT, op, sack2);
986  return;
987  } else {
988  query_name(tmp, name_tmp, MAX_BUF);
990  "You can not put a %s into a %s",
991  name_tmp,
992  name_sack);
993  return;
994  }
995  }
996 
997  /* Don't worry about this for containers - our caller should have
998  * already checked this.
999  */
1000  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
1001  return;
1002 
1003  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1005  return;
1006  }
1007 
1008  /* we want to put some portion of the item into the container */
1009  if (nrof && tmp->nrof != nrof) {
1010  char failure[MAX_BUF];
1011 
1012  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1013 
1014  if (!tmp) {
1016  failure);
1017  return;
1018  }
1019  } else
1020  object_remove(tmp);
1021 
1022  if (sack->nrof > 1) {
1023  orig = object_split(sack, sack->nrof-1, NULL, 0);
1024  set_object_face_main(orig);
1025  CLEAR_FLAG(orig, FLAG_APPLIED);
1026  if (sack->env) {
1027  object_insert_in_ob(orig, sack->env);
1028  } else {
1029  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
1030  orig->move_off = 0;
1031  }
1032  }
1033 
1034  query_name(tmp, name_tmp, MAX_BUF);
1036  "You put the %s in %s.",
1037  name_tmp, name_sack);
1038 
1039  object_insert_in_ob(tmp, sack);
1041  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1042  /* in object.c */
1043 
1044  /* If a transport, need to update all the players in the transport
1045  * the view of what is in it.
1046  */
1047  if (sack->type == TRANSPORT) {
1048  FOR_INV_PREPARE(sack, tmp)
1049  if (tmp->type == PLAYER)
1050  tmp->contr->socket->update_look = 1;
1051  FOR_INV_FINISH();
1052  } else {
1053  /* update the sacks weight */
1054  esrv_update_item(UPD_WEIGHT, op, sack);
1055  }
1056 }
1057 
1073 object *drop_object(object *op, object *tmp, uint32_t nrof) {
1074  tag_t tmp_tag;
1075 
1076  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1077  return NULL;
1078  }
1079 
1080  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
1082  return NULL; /* can't unapply it */
1083  }
1084 
1085  if (events_execute_object_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
1086  return NULL;
1087 
1088  /* ensure the plugin didn't destroy the object */
1089  if (QUERY_FLAG(tmp, FLAG_REMOVED))
1090  return NULL;
1091 
1092  /* We are only dropping some of the items. We split the current objec
1093  * off
1094  */
1095  if (nrof && tmp->nrof != nrof) {
1096  char failure[MAX_BUF];
1097 
1098  tmp = object_split(tmp, nrof, failure, sizeof(failure));
1099  if (!tmp) {
1101  failure);
1102  return NULL;
1103  }
1104  } else
1105  object_remove(tmp);
1106 
1107  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
1108  char name[MAX_BUF];
1109 
1112  "You drop the %s. The gods who lent it to you retrieve it.",
1113  name);
1115 
1117  fix_object(op);
1118 
1119  return NULL;
1120  }
1121 
1122  /* If SAVE_INTERVAL is commented out, we never want to save
1123  * the player here.
1124  */
1125 #ifdef SAVE_INTERVAL
1126  /* I'm not sure why there is a value check - since the save
1127  * is done every SAVE_INTERVAL seconds, why care the value
1128  * of what he is dropping?
1129  */
1130  if (op->type == PLAYER
1131  && !QUERY_FLAG(tmp, FLAG_UNPAID)
1132  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
1133  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
1134  save_player(op, 1);
1135  op->contr->last_save_time = time(NULL);
1136  }
1137 #endif /* SAVE_INTERVAL */
1138 
1139 
1140  tmp_tag = tmp->count;
1142  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
1143  sell_item(tmp, op);
1144  }
1145 
1146  /* Call this before we update the various windows/players. At least
1147  * that we, we know the weight is correct.
1148  */
1149  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
1150  fix_object(op); /* This is overkill, fix_player() is called somewhere */
1151  /* in object.c */
1152 
1153  /* Need to update weight of player */
1154  if (op->type == PLAYER)
1156  }
1157  return tmp;
1158 }
1159 
1168 void drop(object *op, object *tmp) {
1169  /* Hopeful fix for disappearing objects when dropping from a container -
1170  * somehow, players get an invisible object in the container, and the
1171  * old logic would skip over invisible objects - works fine for the
1172  * playes inventory, but drop inventory wants to use the next value.
1173  */
1174  if (tmp->invisible) {
1175  /* if the following is the case, it must be in an container. */
1176  if (tmp->env && tmp->env->type != PLAYER) {
1177  /* Just toss the object - probably shouldn't be hanging
1178  * around anyways
1179  */
1180  object_remove(tmp);
1182  return;
1183  } else {
1185  if (!tmp->invisible)
1186  break;
1188  }
1189  }
1190 
1191  if (tmp == NULL) {
1193  "You don't have anything to drop.");
1194  return;
1195  }
1196  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1198  "This item is locked");
1199  return;
1200  }
1201  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
1202  return;
1203  }
1204 
1205  if (op->container) {
1206  if (op->type == PLAYER) {
1207  put_object_in_sack(op, op->container, tmp, op->contr->count);
1208  } else {
1209  put_object_in_sack(op, op->container, tmp, 0);
1210  };
1211  } else {
1212  if (op->type == PLAYER) {
1213  drop_object(op, tmp, op->contr->count);
1214  } else {
1215  drop_object(op, tmp, 0);
1216  };
1217  }
1218  if (op->type == PLAYER)
1219  op->contr->count = 0;
1220 }
1221 
1230 void command_dropall(object *op, const char *params) {
1231  int count = 0;
1232 
1233  if (op->inv == NULL) {
1236  "Nothing to drop!");
1237  return;
1238  }
1239 
1240  if (op->contr)
1241  count = op->contr->count;
1242 
1243  /* Set this so we don't call it for _every_ object that
1244  * is dropped.
1245  */
1247 
1248  /*
1249  * This is the default. Drops everything not locked or considered
1250  * not something that should be dropped.
1251  * Care must be taken that the next item pointer is not to money as
1252  * the drop() routine will do unknown things to it when dropping
1253  * in a shop. --Tero.Pelander@utu.fi
1254  */
1255  if (*params == '\0') {
1256  FOR_INV_PREPARE(op, curinv) {
1257  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1258  && curinv->type != MONEY
1259  && curinv->type != FOOD
1260  && curinv->type != KEY
1261  && curinv->type != SPECIAL_KEY
1262  && curinv->type != GEM
1263  && !curinv->invisible
1264  && (curinv->type != CONTAINER || op->container != curinv)) {
1265  drop(op, curinv);
1266  if (op->contr)
1267  op->contr->count = count;
1268  }
1269  } FOR_INV_FINISH();
1270  } else if (strcmp(params, "weapons") == 0) {
1271  FOR_INV_PREPARE(op, curinv) {
1272  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1273  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1274  drop(op, curinv);
1275  if (op->contr)
1276  op->contr->count = count;
1277  }
1278  } FOR_INV_FINISH();
1279  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1280  FOR_INV_PREPARE(op, curinv) {
1281  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1282  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1283  drop(op, curinv);
1284  if (op->contr)
1285  op->contr->count = count;
1286  }
1287  } FOR_INV_FINISH();
1288  } else if (strcmp(params, "food") == 0) {
1289  FOR_INV_PREPARE(op, curinv) {
1290  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1291  && (curinv->type == FOOD || curinv->type == DRINK)) {
1292  drop(op, curinv);
1293  if (op->contr)
1294  op->contr->count = count;
1295  }
1296  } FOR_INV_FINISH();
1297  } else if (strcmp(params, "flesh") == 0) {
1298  FOR_INV_PREPARE(op, curinv) {
1299  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1300  && (curinv->type == FLESH)) {
1301  drop(op, curinv);
1302  if (op->contr)
1303  op->contr->count = count;
1304  }
1305  } FOR_INV_FINISH();
1306  } else if (strcmp(params, "misc") == 0) {
1307  FOR_INV_PREPARE(op, curinv) {
1308  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1309  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1310  switch (curinv->type) {
1311  case BOOK:
1312  case SPELLBOOK:
1313  case GIRDLE:
1314  case AMULET:
1315  case RING:
1316  case CLOAK:
1317  case BOOTS:
1318  case GLOVES:
1319  case BRACERS:
1320  case SCROLL:
1321  case ARMOUR_IMPROVER:
1322  case WEAPON_IMPROVER:
1323  case WAND:
1324  case ROD:
1325  case POTION:
1326  drop(op, curinv);
1327  if (op->contr)
1328  op->contr->count = count;
1329  break;
1330 
1331  default:
1332  break;
1333  }
1334  }
1335  } FOR_INV_FINISH();
1336  }
1337  op->contr->socket->update_look = 1;
1339  /* call it now, once */
1340  fix_object(op);
1341  /* Need to update weight of player. Likewise, only do it once */
1342  if (op->type == PLAYER)
1344 }
1345 
1354 void command_drop(object *op, const char *params) {
1355  int did_one = 0;
1356  int missed = 0;
1357 
1358  if (*params == '\0') {
1360  "Drop what?");
1361  return;
1362  }
1363 
1364  matcher_params mp;
1365  item_matcher matcher = make_matcher(op, params, &mp);
1366  if (!matcher) {
1367  return;
1368  }
1369 
1371 
1372  FOR_INV_PREPARE(op, tmp) {
1373  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1374  continue;
1375  if ((*matcher)(op, &mp, tmp)) {
1376  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
1377  missed++;
1378  } else {
1379  drop(op, tmp);
1380  }
1381  did_one = 1;
1382  }
1383  } FOR_INV_FINISH();
1384  if (!did_one)
1386  "Nothing to drop.");
1387  if (missed == 1)
1389  "One item couldn't be dropped because it was locked.");
1390  else if (missed > 1)
1392  "%d items couldn't be dropped because they were locked.",
1393  missed);
1394 
1395  /* Now update player and send information. */
1397  fix_object(op);
1398  if (op->type == PLAYER) {
1399  op->contr->count = 0;
1401  }
1402 }
1403 
1412 static void empty_container(object *container, object *pl) {
1413  int left = 0;
1414  char name[MAX_BUF];
1415 
1416  if (!container->inv)
1417  return;
1418 
1419  FOR_INV_PREPARE(container, inv) {
1420  object *next;
1421 
1422  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1423  /* you can have locked items in container. */
1424  left++;
1425  continue;
1426  }
1427  next = inv->below;
1428  drop(pl, inv);
1429  if (inv->below == next)
1430  /* item couldn't be dropped for some reason. */
1431  left++;
1432  } FOR_INV_FINISH();
1433  esrv_update_item(UPD_WEIGHT, pl, container);
1434 
1435  query_name(container, name, sizeof(name));
1436  if (left)
1437  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1438  else
1440 }
1441 
1450 void command_empty(object *op, const char *params) {
1451  object *container;
1452 
1453  if (*params == '\0') {
1455  "Empty what?");
1456  return;
1457  }
1458 
1459  if (strcmp(params, "all") == 0) {
1461  if (inv->type == CONTAINER)
1463  FOR_INV_FINISH();
1464  return;
1465  }
1466 
1467  container = find_best_object_match(op, params);
1468  if (!container) {
1470  "No such item.");
1471  return;
1472  }
1473  if (container->type != CONTAINER) {
1475  "This is not a container!");
1476  return;
1477  }
1478  empty_container(container, op);
1479 }
1480 
1489 void command_examine(object *op, const char *params) {
1490  if (*params == '\0') {
1492  if (LOOK_OBJ(tmp)) {
1493  examine(op, tmp);
1494  break;
1495  }
1496  FOR_BELOW_FINISH();
1497  } else {
1498  object *tmp = find_best_object_match(op, params);
1499 
1500  if (tmp)
1501  examine(op, tmp);
1502  else
1504  "Could not find an object that matches %s",
1505  params);
1506  }
1507 }
1508 
1520 object *find_marked_object(object *op) {
1521  if (!op || !op->contr || !op->contr->mark)
1522  return NULL;
1523 
1524  /* This may seem like overkill, but we need to make sure that they
1525  * player hasn't dropped the item. We use count on the off chance that
1526  * an item got reincarnated at some point.
1527  */
1528  /*
1529  FOR_INV_PREPARE(op, tmp) {
1530  if (tmp->invisible)
1531  continue;
1532  if (tmp == op->contr->mark) {
1533  if (tmp->count == op->contr->mark_count)
1534  return tmp;
1535  else {
1536  op->contr->mark = NULL;
1537  op->contr->mark_count = 0;
1538  return NULL;
1539  }
1540  }
1541  } FOR_INV_FINISH();
1542  */
1543  /* Try a different way of doing this
1544  * We check the environment of the marked object
1545  * to make sure it is still in the player's inventory.
1546  * In addition, we ensure there is the correct tag for that item.
1547  *
1548  * Daniel Hawkins 2018-10-23
1549  */
1550  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1551  return op->contr->mark;
1552  // Otherwise reset the mark, since it is no longer valid.
1553  op->contr->mark = NULL;
1554  op->contr->mark_count = 0;
1555  return NULL;
1556 }
1557 
1567 void command_mark(object *op, const char *params) {
1568  char name[MAX_BUF];
1569 
1570  if (!op->contr)
1571  return;
1572  if (*params == '\0') {
1573  object *mark = find_marked_object(op);
1574  if (!mark)
1576  "You have no marked object.");
1577  else {
1578  query_name(mark, name, MAX_BUF);
1580  "%s is marked.",
1581  name);
1582  }
1583  } else {
1584  object *mark1 = find_best_object_match(op, params);
1585 
1586  if (!mark1) {
1588  "Could not find an object that matches %s",
1589  params);
1590  return;
1591  } else {
1592  op->contr->mark = mark1;
1593  op->contr->mark_count = mark1->count;
1594  query_name(mark1, name, MAX_BUF);
1596  "Marked item %s",
1597  name);
1598  return;
1599  }
1600  }
1601  /*shouldnt get here */
1602 }
1603 
1614 void examine_monster(object *op, object *tmp, int level) {
1615  object *mon = HEAD(tmp), *probe;
1616 
1617  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1619  "It is an undead force.");
1620  if (mon->level > op->level)
1622  "It is likely more powerful than you.");
1623  else if (mon->level < op->level)
1625  "It is likely less powerful than you.");
1626  else
1628  "It is probably as powerful as you.");
1629 
1630  if (mon->attacktype&AT_ACID)
1632  "You smell an acrid odor.");
1633 
1634  /* Anyone know why this used to use the clone value instead of the
1635  * maxhp field? This seems that it should give more accurate results.
1636  */
1637  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1638  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1639  case 0:
1641  "It is critically wounded.");
1642  break;
1643 
1644  case 1:
1646  "It is in a bad shape.");
1647  break;
1648 
1649  case 2:
1651  "It is hurt.");
1652  break;
1653 
1654  case 3:
1656  "It is somewhat hurt.");
1657  break;
1658 
1659  default:
1661  "It is in excellent shape.");
1662  break;
1663  }
1664  if (object_present_in_ob(POISONING, mon) != NULL)
1666  "It looks very ill.");
1667 
1668  if (level < 10)
1669  return;
1671 
1672  if (level < 15)
1673  return;
1674 
1675  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1676  if (probe != NULL && probe->level > level)
1677  return;
1678 
1679  if (probe == NULL) {
1681  free_string(probe->name);
1682  probe->name = add_string("probe_force");
1686  fix_object(mon);
1687  }
1688  probe->level = level;
1689  if (level / 10 > probe->duration)
1690  probe->duration = level / 10;
1691 }
1692 
1694  EX_ID_ABORT, // Not safe to continue
1695  EX_ID_NO_SKILL, // Player lacks the requisite skill(s)
1696  EX_ID_FAILED // Player has the skill but failed their ID roll
1697 };
1698 
1711  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1712  int exp = 0;
1714  if (skill && (object_can_pick(op, tmp))) {
1715  exp = detect_magic_on_item(op, tmp, skill);
1716  if (exp) {
1717  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1719  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1720  }
1721  }
1722 
1724  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1726  exp = detect_curse_on_item(op, tmp, skill);
1727  if (exp) {
1728  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1730  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1731  }
1732  }
1733 
1734  const typedata *tmptype = get_typedata(tmp->type);
1735  if (!tmptype) {
1736  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid\n", tmp->count, tmp->type);
1737  return EX_ID_ABORT;
1738  }
1739 
1740  bool have_skill = false;
1743  if (skill) {
1744  /* identify_object_with_skill() may merge tmp with another
1745  * object, so once that happens, we really can not do
1746  * any further processing with tmp. It would be possible
1747  * to modify identify_object_with_skill() to return
1748  * the merged object, but it is currently set to return
1749  * exp, so it would have to do it via modifying the
1750  * passed in value, but many other consumers would
1751  * need to be modified for that.
1752  */
1753  exp = identify_object_with_skill(tmp, op, skill, 1);
1754  if (exp) {
1755  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1756  return EX_ID_ABORT;
1757  }
1758  }
1759 
1760  /* The primary id skill didn't work, let's try the secondary one */
1762  if (skill) {
1763  /* if we've reached here, then the first skill will have been attempted
1764  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1765  * that now, and try with the secondary ID skill, if it fails, then the
1766  * flag will be reset anyway, if it succeeds, it won't matter.*/
1768  exp = identify_object_with_skill(tmp, op, skill, 1);
1769  if (exp) {
1770  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1771  return EX_ID_ABORT;
1772  }
1773  }
1774  }
1775  return have_skill ? EX_ID_FAILED : EX_ID_NO_SKILL;
1776 }
1777 
1786 void examine_weight_and_material(object *op, object *tmp) {
1787  bool pl = tmp->nrof > 1;
1788  float weight = (tmp->nrof ? tmp->nrof : 1) * ((float)tmp->weight/1000.0);
1789 
1790  if (tmp->materialname && weight) {
1792  "%s made of %s and %s %3.3f kg.",
1793  pl ? "They are" : "It is", tmp->materialname,
1794  pl ? "weigh" : "weighs", weight);
1795  } else if (tmp->materialname) {
1797  "%s made of %s.", pl ? "They are" : "It is", tmp->materialname);
1798  } else if (weight) {
1800  "%s %3.3f kg.", pl ? "They weigh" : "it weighs", weight);
1801  }
1802 }
1803 
1812 void examine_wand_charge_level(object *op, object *tmp) {
1813  if (!is_identified(tmp)) return;
1814  const char *desc;
1815  if (tmp->stats.food <= 0) {
1816  desc = "It is completely depleted.";
1817  } else if (tmp->stats.food <= 2) {
1818  desc = "It is nearly depleted.";
1819  } else if (tmp->stats.food <= 4) {
1820  desc = "It is very low on power.";
1821  } else if (tmp->stats.food <= 8) {
1822  desc = "It is low on power.";
1823  } else if (tmp->stats.food <= 16) {
1824  desc = "It is well charged.";
1825  } else if (tmp->stats.food <= 32) {
1826  desc = "It is fully charged.";
1827  } else {
1828  desc = "It is overflowing with power.";
1829  }
1831 }
1832 
1841 void examine_rod_charge_level(object *op, object *tmp) {
1842  if (!is_identified(tmp)) return;
1843  const int castings = tmp->stats.hp/SP_level_spellpoint_cost(tmp, tmp->inv, SPELL_HIGHEST);
1844  const char *desc;
1845  /* Rods get less precise information than wands/staves as part of balancing
1846  out their reusability -- in particular, you can't tell if a rod is *almost*
1847  out of shots or *completely* out of shots without trying it. */
1848  if (castings <= 1) {
1849  desc = "It is nearly depleted.";
1850  } else if (castings <= 3) {
1851  desc = "It hums with power.";
1852  } else {
1853  desc = "It crackles with power.";
1854  }
1856 }
1857 
1871 bool examine_fluff(object *op, object *tmp, bool output) {
1872  /* No message for stuff the player hasn't IDed. */
1874  return false;
1875  }
1876 
1877  // We use stringbuffer throughout this function so that we can use
1878  // trim_whitespace to conveniently strip trailing newlines, ensuring that
1879  // the output of examine is contiguous.
1880  // TODO: It might be better to strip the newlines in object_set_msg
1881  // and append them at print time, rather than ensuring that the msg
1882  // is newline-terminated and stripping off the newlines when we don't
1883  // want them; C string handling makes the latter a lot less convenient.
1884  if (tmp->msg && strncasecmp(tmp->msg, "@match", 6)) {
1885  if (!output) return true;
1887  stringbuffer_append_string(sb, tmp->msg);
1889  char *const msg = stringbuffer_finish(sb);
1891  free(msg);
1892  }
1893 
1894  switch (tmp->type) {
1895  /* Stuff with embedded skills. */
1896  case SKILLSCROLL:
1897  case SKILL_TOOL:
1898  {
1899  // Embedded skills are stored as an archetype name and don't get reified
1900  // until the player actually reads/equips the object, so we need to turn
1901  // the name into an actual archetype and then read the msg out of that.
1902  if (!tmp->skill) break; // Blank skill scroll, somehow.
1904  if (!skill) {
1905  if (!output) break; // Still need to check for lore later.
1906  // Skill name doesn't correspond to any actual skill.
1908  "Unfortunately, it is damaged beyond %s.",
1909  (tmp->type == SKILLSCROLL) ? "comprehension" : "repair");
1910  break;
1911  }
1912  if (skill->clone.msg) {
1913  if (!output) return true;
1915  "%s lets you %s a skill:",
1916  tmp->nrof > 1 ? "These objects" : "This object",
1917  (tmp->type == SKILLSCROLL) ? "learn" : "use");
1918 
1920  stringbuffer_append_string(sb, skill->clone.msg);
1922  char *const fluff = stringbuffer_finish(sb);
1923  // SPELL_INFO is not a perfect match here, but it should display in the
1924  // same manner as the spell descriptions below and there's no SKILL_INFO
1925  // message type.
1927  free(fluff);
1928  }
1929  break;
1930  }
1931 
1932  /* Stuff with embedded spells. */
1933  case SPELLBOOK:
1934  case SCROLL:
1935  case WAND:
1936  case ROD:
1937  case POTION:
1938  {
1939  if (tmp->inv && tmp->inv->msg) {
1940  if (!output) return true;
1942  "%s holds%s a spell:",
1943  tmp->nrof > 1 ? "These objects" : "This object",
1944  tmp->type == SPELLBOOK ? " knowledge of" : "");
1945 
1947  stringbuffer_append_string(sb, tmp->inv->msg);
1949  char *const fluff = stringbuffer_finish(sb);
1951  free(fluff);
1952  }
1953  }
1954  }
1955 
1956  if (tmp->lore) {
1957  if (!output) return true;
1959  "%s a story:", tmp->nrof > 1 ? "These objects have" : "This object has");
1961  stringbuffer_append_string(sb, tmp->lore);
1963  char *const msg = stringbuffer_finish(sb);
1965  free(msg);
1966  }
1967 
1968  // If we get this far in output=false mode, we didn't hit any of the earlier
1969  // escape hatches and thus have nothing to output. In normal use we'll hit
1970  // this regardless and assume we output something.
1971  return output;
1972 }
1973 
1983 void examine(object *op, object *tmp) {
1984  if (tmp == NULL || tmp->type == CLOSE_CON)
1985  return;
1986 
1987  /* If the player has examined this twice in a row, do a more detailed
1988  examine. last_examined shouldn't get set unless we already know that
1989  examine_fluff() will do something interesting. */
1990  if (op->contr->last_examined == tmp->count) {
1991  op->contr->last_examined = 0;
1993  "You examine the %s more closely.", tmp->nrof > 1 ? tmp->name_pl : tmp->name);
1994  examine_fluff(op, tmp, true);
1996  " "); /* Blank line */
1997  return;
1998  }
1999 
2000  int i;
2001  char prefix[MAX_BUF] = "";
2002  char buf[VERY_BIG_BUF] = "";
2003  if (is_identified(tmp)) {
2004  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof<=1 ? "That is" : "Those are");
2005  } else {
2006  switch(examine_autoidentify(op, tmp)) {
2007  case EX_ID_NO_SKILL:
2008  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:",
2009  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
2010  break;
2011  case EX_ID_FAILED:
2012  snprintf(prefix, MAX_BUF, "You fail to understand %s:",
2013  tmp->nrof<=1 ? "that fully; it is" : "those fully; they are");
2014  break;
2015  case EX_ID_ABORT:
2016  default:
2017  /* Item may have been merged with something else, not safe to proceed. */
2018  return;
2019  }
2020  }
2021 
2022  /* now we need to get the rest of the object description */
2023  ob_describe(tmp, op, 1, buf, sizeof(buf));
2024 
2026  "%s %s", prefix, buf);
2027  buf[0] = '\0';
2029  if (custom_name) {
2031  "You name it %s",
2032  custom_name);
2033  }
2034 
2035  switch (tmp->type) {
2036  case WAND:
2038  break;
2039 
2040  case ROD:
2042  break;
2043 
2044  case BOOK:
2045  if (tmp->msg != NULL)
2046  snprintf(buf, sizeof(buf), "Something is written in it.");
2047  break;
2048 
2049  case CONTAINER:
2050  if (tmp->race != NULL) {
2051  if (tmp->weight_limit && tmp->stats.Str < 100)
2052  snprintf(buf, sizeof(buf), "It can hold only %s and its weight limit is %.1f kg.", tmp->race, tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
2053  else
2054  snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
2055  } else
2056  if (tmp->weight_limit && tmp->stats.Str < 100)
2057  snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
2058  break;
2059  }
2060 
2061  if (buf[0] != '\0')
2063  buf);
2064 
2066 
2067  /* Where to wear this item */
2068  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
2069  if (tmp->body_info[i]) {
2070  if (op->body_info[i]) {
2071  if (tmp->body_info[i] < -1) {
2073  "%s %s (%d).", tmp->nrof > 1 ? "They go" : "It goes",
2074  body_locations[i].use_name, -tmp->body_info[i]);
2075  } else {
2077  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2079  }
2080  } else {
2082  "%s %s.", tmp->nrof > 1 ? "They go" : "It goes",
2084  }
2085  }
2086  }
2087 
2088  int in_shop = shop_contains(op);
2089 
2090  if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
2091  char *value = cost_approx_str(tmp, op);
2092  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
2093  free(value);
2095  buf);
2096  if (in_shop) {
2097  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
2099  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
2100  free(value);
2101  } else {
2103  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
2104  free(value);
2105  }
2107  buf);
2108  }
2109  }
2110 
2111  if (QUERY_FLAG(tmp, FLAG_MONSTER))
2112  examine_monster(op, tmp, 0);
2113 
2114  /* Is this item buildable? */
2116  int conn;
2117  bool has_link = false;
2118  if (QUERY_FLAG(tmp, FLAG_IS_LINKED) && (conn = get_button_value(tmp))) {
2119  FOR_INV_PREPARE(op, tmp_inv) {
2120  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
2121  && strcmp(tmp_inv->slaying, op->map->path) == 0
2122  && tmp_inv->msg != NULL
2123  && tmp_inv->path_attuned == (uint32_t) conn) {
2124 
2125  has_link = true;
2128  "This is a buildable item, connected with: %s",
2129  tmp_inv->msg);
2130  break;
2131  }
2132  } FOR_INV_FINISH();
2133  }
2134  if (!has_link) {
2136  "This is a buildable item.");
2137  }
2138  }
2139 
2140  /* Does it have fluff text? */
2141  if (examine_fluff(op, tmp, false)) {
2142  op->contr->last_examined = tmp->count;
2144  "Examine again for more details.");
2145  } else {
2146  op->contr->last_examined = 0;
2147  }
2148 
2150  " "); /* Blank line */
2151 
2152  if (is_identified(tmp)) {
2154  }
2155 }
2156 
2165 void inventory(object *op, object *inv) {
2166  const char *in;
2167  int items = 0, length;
2168  char weight[MAX_BUF], name[MAX_BUF];
2169 
2170  if (inv == NULL && op == NULL) {
2172  "Inventory of what object?");
2173  return;
2174  }
2175  FOR_INV_PREPARE(inv ? inv : op, tmp)
2176  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
2177  || !op || QUERY_FLAG(op, FLAG_WIZ))
2178  items++;
2179  FOR_INV_FINISH();
2180  if (inv == NULL) { /* player's inventory */
2181  if (items == 0) {
2183  "You carry nothing.");
2184  return;
2185  } else {
2186  length = 28;
2187  in = "";
2189  "Inventory:");
2190  }
2191  } else {
2192  if (items == 0)
2193  return;
2194  else {
2195  length = 28;
2196  in = " ";
2197  }
2198  }
2199  FOR_INV_PREPARE(inv ? inv : op, tmp) {
2200  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
2201  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
2202  continue;
2205  if (!op || QUERY_FLAG(op, FLAG_WIZ))
2207  "[fixed]%s- %-*.*s (%5d) %-8s",
2208  in, length, length, name, tmp->count, weight);
2209  else
2211  "[fixed]%s- %-*.*s %-8s",
2212  in, length+8, length+8, name, weight);
2213  } FOR_INV_FINISH();
2214  if (!inv && op) {
2217  "[fixed]%-*s %-8s",
2218  41, "Total weight :", weight);
2219  }
2220 }
2221 
2230 static void display_new_pickup(const object *op, int old) {
2231  int i = op->contr->mode;
2232 
2233  esrv_send_pickup(op->contr);
2234 
2235  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
2236  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
2238  "Pickup is now %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
2239  }
2240  return;
2241  }
2242 
2244  "%d NEWMODE",
2245  i&PU_NEWMODE ? 1 : 0);
2247  "%d DEBUG",
2248  i&PU_DEBUG ? 1 : 0);
2250  "%d INHIBIT",
2251  i&PU_INHIBIT ? 1 : 0);
2253  "%d STOP",
2254  i&PU_STOP ? 1 : 0);
2255 
2257  "%d <= x pickup weight/value RATIO (0==off)",
2258  (i&PU_RATIO)*5);
2259 
2261  "%d FOOD",
2262  i&PU_FOOD ? 1 : 0);
2264  "%d DRINK",
2265  i&PU_DRINK ? 1 : 0);
2267  "%d VALUABLES",
2268  i&PU_VALUABLES ? 1 : 0);
2269 
2271  "%d BOW",
2272  i&PU_BOW ? 1 : 0);
2274  "%d ARROW",
2275  i&PU_ARROW ? 1 : 0);
2276 
2278  "%d HELMET",
2279  i&PU_HELMET ? 1 : 0);
2281  "%d SHIELD",
2282  i&PU_SHIELD ? 1 : 0);
2284  "%d ARMOUR",
2285  i&PU_ARMOUR ? 1 : 0);
2286 
2288  "%d BOOTS",
2289  i&PU_BOOTS ? 1 : 0);
2291  "%d GLOVES",
2292  i&PU_GLOVES ? 1 : 0);
2294  "%d CLOAK",
2295  i&PU_CLOAK ? 1 : 0);
2297  "%d KEY",
2298  i&PU_KEY ? 1 : 0);
2299 
2301  "%d MISSILEWEAPON",
2302  i&PU_MISSILEWEAPON ? 1 : 0);
2304  "%d MELEEWEAPON",
2305  i&PU_MELEEWEAPON ? 1 : 0);
2307  "%d MAGICAL",
2308  i&PU_MAGICAL ? 1 : 0);
2310  "%d POTION",
2311  i&PU_POTION ? 1 : 0);
2312 
2314  "%d SPELLBOOK",
2315  i&PU_SPELLBOOK ? 1 : 0);
2317  "%d SKILLSCROLL",
2318  i&PU_SKILLSCROLL ? 1 : 0);
2320  "%d READABLES",
2321  i&PU_READABLES ? 1 : 0);
2323  "%d MAGICDEVICE",
2324  i&PU_MAGIC_DEVICE ? 1 : 0);
2325 
2327  "%d NOT CURSED",
2328  i&PU_NOT_CURSED ? 1 : 0);
2329 
2331  "%d JEWELS",
2332  i&PU_JEWELS ? 1 : 0);
2333 
2335  "%d FLESH",
2336  i&PU_FLESH ? 1 : 0);
2337 
2339  "%d CONTAINER",
2340  i&PU_CONTAINER ? 1 : 0);
2341 
2343  "%d CURSED",
2344  i&PU_CURSED ? 1 : 0);
2345 
2347  "");
2348 }
2349 
2359 void command_pickup(object *op, const char *params) {
2360  uint32_t i;
2361 
2362  if (*params == '\0') {
2363  /* if the new mode is used, just print the settings */
2364  if (op->contr->mode&PU_NEWMODE) {
2365  display_new_pickup(op, op->contr->mode);
2366  return;
2367  }
2368  if (1)
2369  LOG(llevDebug, "command_pickup: !params\n");
2370  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
2371  return;
2372  }
2373 
2374  while (*params == ' ')
2375  params++;
2376 
2377  if (*params == '+' || *params == '-' || *params == '!') {
2378  int index = get_pickup_mode_index(params + 1);
2379 
2380  if (index != -1) {
2381  int old = op->contr->mode;
2382  i = op->contr->mode;
2383  if (!(i&PU_NEWMODE))
2384  i = PU_NEWMODE;
2385  if (*params == '+')
2386  i = i|pickup_modes[index];
2387  else if (*params == '-')
2388  i = i&~pickup_modes[index];
2389  else {
2390  if (i&pickup_modes[index])
2391  i = i&~pickup_modes[index];
2392  else
2393  i = i|pickup_modes[index];
2394  }
2395  op->contr->mode = i;
2396  display_new_pickup(op, old);
2397  return;
2398  }
2400  "Pickup: invalid item %s\n",
2401  params);
2402  return;
2403  }
2404 
2405  if (sscanf(params, "%u", &i) != 1) {
2406  if (1)
2407  LOG(llevDebug, "command_pickup: params==NULL\n");
2409  "Usage: pickup <0-7> or <value_density> .");
2410  return;
2411  }
2412  set_pickup_mode(op, i);
2413  display_new_pickup(op, op->contr->mode);
2414 }
2415 
2424 static void set_pickup_mode(const object *op, int i) {
2425  op->contr->mode = i;
2426  switch (op->contr->mode) {
2427  case 0:
2429  "Mode: Don't pick up.");
2430  break;
2431 
2432  case 1:
2434  "Mode: Pick up one item.");
2435  break;
2436 
2437  case 2:
2439  "Mode: Pick up one item and stop.");
2440  break;
2441 
2442  case 3:
2444  "Mode: Stop before picking up.");
2445  break;
2446 
2447  case 4:
2449  "Mode: Pick up all items.");
2450  break;
2451 
2452  case 5:
2454  "Mode: Pick up all items and stop.");
2455  break;
2456 
2457  case 6:
2459  "Mode: Pick up all magic items.");
2460  break;
2461 
2462  case 7:
2464  "Mode: Pick up all coins and gems");
2465  break;
2466  }
2467 }
2468 
2477 void command_search_items(object *op, const char *params) {
2478  if (settings.search_items == FALSE)
2479  return;
2480 
2481  if (!params || *params == '\0') {
2482  if (op->contr->search_str[0] == '\0') {
2484  "Example: search magic+1 "
2485  "Would automatically pick up all "
2486  "items containing the word 'magic+1'.");
2487  return;
2488  }
2489  op->contr->search_str[0] = '\0';
2491  "Search mode turned off.");
2492  fix_object(op);
2493  return;
2494  }
2495  if ((int)strlen(params) >= MAX_BUF) {
2497  "Search string too long.");
2498  return;
2499  }
2500  strcpy(op->contr->search_str, params);
2502  "Searching for '%s'.",
2503  op->contr->search_str);
2504  fix_object(op);
2505 }
2506 
2522 void command_rename_item(object *op, const char *params) {
2523  char buf[VERY_BIG_BUF], name[MAX_BUF];
2524  tag_t itemnumber;
2525  object *item = NULL;
2526  object *tmp;
2527  const char *closebrace;
2528  size_t counter;
2529 
2530  if (*params != '\0') {
2531  /* Let's skip white spaces */
2532  while (' ' == *params)
2533  params++;
2534 
2535  /* Checking the first part */
2536  itemnumber = atoi(params);
2537  if (itemnumber != 0) {
2539  if (inv->count == itemnumber && !inv->invisible) {
2540  item = inv;
2541  break;
2542  }
2543  FOR_INV_FINISH();
2544  if (!item) {
2546  "Tried to rename an invalid item.");
2547  return;
2548  }
2549  while (isdigit(*params) || ' ' == *params)
2550  params++;
2551  } else if ('<' == *params) {
2552  /* Got old name, let's get it & find appropriate matching item */
2553  closebrace = strchr(params, '>');
2554  if (!closebrace) {
2556  "Syntax error!");
2557  return;
2558  }
2559  /* Sanity check for buffer overruns */
2560  if (closebrace-params > 127) {
2562  "Old name too long (up to 127 characters allowed)!");
2563  return;
2564  }
2565  /* Copy the old name */
2566  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2567 
2568  /* Find best matching item */
2570  if (!item) {
2572  "Could not find a matching item to rename.");
2573  return;
2574  }
2575 
2576  /* Now need to move pointer to just after > */
2577  params = closebrace+1;
2578  while (' ' == *params)
2579  params++;
2580  } else {
2581  /* Use marked item */
2583  if (!item) {
2585  "No marked item to rename.");
2586  return;
2587  }
2588  }
2589 
2590  /* Now let's find the new name */
2591  if (!strncmp(params, "to ", 3)) {
2592  params += 3;
2593  while (' ' == *params)
2594  params++;
2595  if ('<' != *params) {
2597  "Syntax error, expecting < at start of new name!");
2598  return;
2599  }
2600  closebrace = strchr(params+1, '>');
2601  if (!closebrace) {
2603  "Syntax error, expecting > at end of new name!");
2604  return;
2605  }
2606 
2607  /* Sanity check for buffer overruns */
2608  if (closebrace-params > 127) {
2610  "New name too long (up to 127 characters allowed)!");
2611  return;
2612  }
2613 
2614  /* Copy the new name */
2615  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2616 
2617  /* Let's check it for weird characters */
2618  for (counter = 0; counter < strlen(buf); counter++) {
2619  if (isalnum(buf[counter]))
2620  continue;
2621  if (' ' == buf[counter])
2622  continue;
2623  if ('\'' == buf[counter])
2624  continue;
2625  if ('+' == buf[counter])
2626  continue;
2627  if ('_' == buf[counter])
2628  continue;
2629  if ('-' == buf[counter])
2630  continue;
2631 
2632  /* If we come here, then the name contains an invalid character...
2633  * tell the player & exit
2634  */
2636  "Invalid new name!");
2637  return;
2638  }
2639  } else {
2640  /* If param contains something, then syntax error... */
2641  if (strlen(params)) {
2643  "Syntax error, expected 'to <' after old name!");
2644  return;
2645  }
2646  /* New name is empty */
2647  buf[0] = '\0';
2648  }
2649  } else {
2650  /* Last case: *params=='\0' */
2652  if (!item) {
2654  "No marked item to rename.");
2655  return;
2656  }
2657  buf[0] = '\0';
2658  }
2659 
2660  /* Coming here, everything is fine... */
2661  if (!strlen(buf)) {
2662  /* Clear custom name */
2663  if (object_get_value(item, CUSTOM_NAME_FIELD) == NULL) {
2665  "This item has no custom name.");
2666  return;
2667  }
2668 
2670  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2672  "You stop calling your %s with weird names.",
2673  name);
2674  } else {
2676  if (custom_name != NULL && strcmp(custom_name, buf) == 0) {
2677  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2679  "You keep calling your %s %s.",
2680  name, buf);
2681  return;
2682  }
2683 
2684  /* Set custom name */
2686 
2687  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2689  "Your %s will now be called %s.",
2690  name, buf);
2691  }
2692 
2693  tmp = object_merge(item, NULL);
2694  if (tmp == NULL) {
2695  /* object was not merged - if it was, object_merge() handles updating for us. */
2697  }
2698 }
2699 
2708 void command_lock_item(object *op, const char *params) {
2709  object *item;
2710  object *tmp;
2711  char name[HUGE_BUF];
2712 
2713  if (*params == '\0' || strlen(params) == 0) {
2715  "Lock what item?");
2716  return;
2717  }
2718 
2720  if (!item) {
2722  "Can't find any matching item.");
2723  return;
2724  }
2725 
2729  "Unlocked %s.", name);
2731  } else {
2733  "Locked %s.", name);
2735  }
2736 
2737  tmp = object_merge(item, NULL);
2738  if (tmp == NULL) {
2739  /* object was not merged, if it was object_merge() handles updates for us */
2741  }
2742 }
2743 
2751 void command_use(object *op, const char *params) {
2752  char *with, copy[MAX_BUF];
2753  object *first, *second/*, *add*/;
2754  /*archetype *arch;*/
2755  /*int count;*/
2756  /*sstring data;*/
2757  recipe *transformation;
2758 
2759  if (!IS_PLAYER(op))
2760  return;
2761 
2762  strlcpy(copy, params, sizeof(copy));
2763  with = strstr(copy, " with ");
2764  if (!with) {
2765  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2766  return;
2767  }
2768 
2769  with[0] = '\0';
2770  with = with+strlen(" with ");
2771 
2772  first = find_best_object_match(op, copy);
2773  if (!first) {
2775  return;
2776  }
2777  second = find_best_object_match(op, with);
2778  if (!second) {
2780  return;
2781  }
2782 
2783  transformation = NULL;
2784  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2786  if (transformation->ingred_count != 1)
2787  continue;
2788 
2789 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2790  if (strcmp(second->name, transformation->ingred->name) == 0) {
2792  object *generated = create_archetype(transformation->arch_name[0]);
2793  if (transformation->yield)
2794  generated->nrof = transformation->yield;
2795  object_insert_in_ob(generated, op);
2796  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2798  return;
2799  }
2800  }
2802  return;
2803 
2804  /*
2805  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2806  data = object_get_value(second, copy);
2807  if (!data) {
2808  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2809  data = object_get_value(second, copy);
2810  if (!data) {
2811  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2812  data = object_get_value(second, copy);
2813  if (!data) {
2814  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2815  return 1;
2816  }
2817  }
2818  }
2819 
2820  while (data != NULL) {
2821  if (strncmp(data, "add ", 4) == 0) {
2822  data += 4;
2823  if (isdigit(*data)) {
2824  count = atol(data);
2825  data = strchr(data, ' ')+1;
2826  } else
2827  count = 1;
2828  with = strchr(data, ' ');
2829  if (!with) {
2830  strncpy(copy, data, sizeof(copy));
2831  data = NULL;
2832  } else {
2833  *with = '\0';
2834  strncpy(copy, data, sizeof(copy));
2835  data += strlen(copy)+1;
2836  }
2837  arch = find_archetype(copy);
2838  if (!arch) {
2839  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2840  return 1;
2841  }
2842  add = object_create_arch(arch);
2843  add->nrof = count;
2844  object_insert_in_ob(add, op);
2845  } else if (strncmp(data, "remove $", 8) == 0) {
2846  data += 8;
2847  if (*data == '1') {
2848  if (first)
2849  first = object_decrease_nrof_by_one(first);
2850  data += 2;
2851  } else if (*data == '2') {
2852  if (second)
2853  second = object_decrease_nrof_by_one(second);
2854  data += 2;
2855  } else {
2856  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2857  return 1;
2858  }
2859  } else {
2860  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2861  return 1;
2862  }
2863  }
2864 
2865  return 1;
2866  */
2867 }
object_was_destroyed
#define object_was_destroyed(op, old_tag)
Definition: object.h:70
drop
void drop(object *op, object *tmp)
Definition: c_object.cpp:1168
find_recipe_for_tool
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Definition: recipe.cpp:894
give.next
def next
Definition: give.py:44
do_skill
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.cpp:431
MIMIC
@ MIMIC
Definition: object.h:254
PLAYER
@ PLAYER
Definition: object.h:112
PU_BOOTS
#define PU_BOOTS
Definition: define.h:125
global.h
castle_read.prefix
string prefix
Definition: castle_read.py:31
settings
struct Settings settings
Definition: init.cpp:139
living::maxhp
int16_t maxhp
Definition: living.h:41
matcher_pickup_type
static int matcher_pickup_type(object *who, matcher_params *params, object *item)
Definition: c_object.cpp:794
NUM_BODY_LOCATIONS
#define NUM_BODY_LOCATIONS
Definition: object.h:15
MSG_TYPE_COMMAND_SUCCESS
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:519
AP_APPLY
#define AP_APPLY
Definition: define.h:574
BOW
@ BOW
Definition: object.h:123
BRACERS
@ BRACERS
Definition: object.h:222
CLOSE_CON
@ CLOSE_CON
Definition: object.h:234
llevError
@ llevError
Definition: logger.h:11
ARMOUR_IMPROVER
@ ARMOUR_IMPROVER
Definition: object.h:237
command_search
void command_search(object *op, const char *params)
Definition: c_object.cpp:212
find_skill_by_number
object * find_skill_by_number(object *who, int skillno)
Definition: main.cpp:375
AP_NO_MERGE
#define AP_NO_MERGE
Definition: define.h:581
WAND
@ WAND
Definition: object.h:225
LOG
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.cpp:51
FLAG_UNDEAD
#define FLAG_UNDEAD
Definition: define.h:270
SET_FLAG
#define SET_FLAG(xyz, p)
Definition: define.h:224
FLESH
@ FLESH
Definition: object.h:192
PU_NOT_CURSED
#define PU_NOT_CURSED
Definition: define.h:140
PU_ARROW
#define PU_ARROW
Definition: define.h:120
GLOVES
@ GLOVES
Definition: object.h:218
object::inv
object * inv
Definition: object.h:298
GIRDLE
@ GIRDLE
Definition: object.h:228
diamondslots.x
x
Definition: diamondslots.py:15
FLAG_STARTEQUIP
#define FLAG_STARTEQUIP
Definition: define.h:268
CFweardisguise.tag
tag
Definition: CFweardisguise.py:25
MSG_TYPE_SKILL
#define MSG_TYPE_SKILL
Definition: newclient.h:396
QUERY_FLAG
#define QUERY_FLAG(xyz, p)
Definition: define.h:226
PU_INHIBIT
#define PU_INHIBIT
Definition: define.h:109
command_rename_item
void command_rename_item(object *op, const char *params)
Definition: c_object.cpp:2522
recipe::yield
int yield
Definition: recipe.h:21
Settings::search_items
uint8_t search_items
Definition: global.h:267
object_merge
object * object_merge(object *op, object *top)
Definition: object.cpp:2046
examine_monster
void examine_monster(object *op, object *tmp, int level)
Definition: c_object.cpp:1614
FALSE
#define FALSE
Definition: compat.h:14
stringbuffer_new
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.cpp:57
examine
void examine(object *op, object *tmp)
Definition: c_object.cpp:1983
SK_DET_MAGIC
@ SK_DET_MAGIC
Definition: skills.h:30
UPD_WEIGHT
#define UPD_WEIGHT
Definition: newclient.h:305
FOR_BELOW_PREPARE
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:704
GEM
@ GEM
Definition: object.h:172
detect_curse_on_item
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Definition: skills.cpp:703
object::x
int16_t x
Definition: object.h:335
command_rskill
void command_rskill(object *pl, const char *params)
Definition: c_object.cpp:161
shop_price_buy
uint64_t shop_price_buy(const object *obj, object *who)
Definition: shop.cpp:190
ARMOUR
@ ARMOUR
Definition: object.h:125
SK_DISARM_TRAPS
@ SK_DISARM_TRAPS
Definition: skills.h:46
command_use
void command_use(object *op, const char *params)
Definition: c_object.cpp:2751
PU_FOOD
#define PU_FOOD
Definition: define.h:115
object::map
struct mapstruct * map
Definition: object.h:305
WEAPON
@ WEAPON
Definition: object.h:124
typedata::identifyskill
int identifyskill
Definition: define.h:93
esrv_send_pickup
void esrv_send_pickup(player *pl)
Definition: request.cpp:1795
PU_BOW
#define PU_BOW
Definition: define.h:118
command_uskill
void command_uskill(object *pl, const char *params)
Definition: c_object.cpp:144
PU_MAGIC_DEVICE
#define PU_MAGIC_DEVICE
Definition: define.h:138
commongive.inv
inv
Definition: commongive.py:29
time
non standard information is not specified or uptime this means how long since the executable has been started A particular host may have been running a server for quite a long time
Definition: arch-handbook.txt:206
AMULET
@ AMULET
Definition: object.h:144
draw_ext_info_format
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...) PRINTF_ARGS(6
matcher_name
static int matcher_name(object *who, matcher_params *params, object *item)
Definition: c_object.cpp:774
mon
object * mon
Definition: comet_perf.cpp:75
MIN
#define MIN(x, y)
Definition: compat.h:21
SKILL
@ SKILL
Definition: object.h:148
examine_wand_charge_level
void examine_wand_charge_level(object *op, object *tmp)
Definition: c_object.cpp:1812
object::count
tag_t count
Definition: object.h:307
Ice.tmp
int tmp
Definition: Ice.py:207
change_skill
int change_skill(object *who, object *new_skill, int flag)
Definition: skill_util.cpp:359
MSG_TYPE_COMMAND_EXAMINE
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:521
mode
linux kernel c mode(defun linux-c-mode() "C mode with adjusted defaults for use with the Linux kernel."(interactive)(c-mode)(c-set-style "K&R")(setq c-basic-offset 8))
fix_object
void fix_object(object *op)
Definition: living.cpp:1125
command_mark
void command_mark(object *op, const char *params)
Definition: c_object.cpp:1567
command_pickup
void command_pickup(object *op, const char *params)
Definition: c_object.cpp:2359
PU_MISSILEWEAPON
#define PU_MISSILEWEAPON
Definition: define.h:130
recipe::arch_name
char ** arch_name
Definition: recipe.h:13
TRANSPORT
@ TRANSPORT
Definition: object.h:113
PU_FLESH
#define PU_FLESH
Definition: define.h:142
PU_READABLES
#define PU_READABLES
Definition: define.h:137
skills.h
PU_POTION
#define PU_POTION
Definition: define.h:133
MSG_TYPE_COMMAND_ERROR
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:518
matcher_params::item_to_pick
int item_to_pick
Definition: c_object.cpp:714
FLAG_PROBE
#define FLAG_PROBE
Definition: define.h:257
FLAG_INV_LOCKED
#define FLAG_INV_LOCKED
Definition: define.h:329
MSG_TYPE_SPELL_INFO
#define MSG_TYPE_SPELL_INFO
Definition: newclient.h:628
object_get_value
const char * object_get_value(const object *op, const char *const key)
Definition: object.cpp:4337
apply_by_living_below
void apply_by_living_below(object *pl)
Definition: apply.cpp:695
ex_autoid_result
ex_autoid_result
Definition: c_object.cpp:1693
FLAG_APPLIED
#define FLAG_APPLIED
Definition: define.h:235
NDI_BLUE
#define NDI_BLUE
Definition: newclient.h:236
object::level
int16_t level
Definition: object.h:361
events_execute_object_event
int events_execute_object_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: events.cpp:292
buf
StringBuffer * buf
Definition: readable.cpp:1552
object_insert_in_ob
object * object_insert_in_ob(object *op, object *where)
Definition: object.cpp:2848
HUGE_BUF
#define HUGE_BUF
Definition: define.h:37
set_pickup_mode
static void set_pickup_mode(const object *op, int i)
Definition: c_object.cpp:2424
POISONING
@ POISONING
Definition: object.h:223
MSG_TYPE_COMMAND
#define MSG_TYPE_COMMAND
Definition: newclient.h:393
command_drop
void command_drop(object *op, const char *params)
Definition: c_object.cpp:1354
body_locations_struct::nonuse_name
const char * nonuse_name
Definition: object.h:25
FLAG_NO_PICK
#define FLAG_NO_PICK
Definition: define.h:239
name
Plugin animator file specs[Config] name
Definition: animfiles.txt:4
FOR_BELOW_FINISH
#define FOR_BELOW_FINISH()
Definition: define.h:711
draw_ext_info
vs only yadda is in because all tags get reset on the next draw_ext_info In the second since it is all in one draw_ext_info
Definition: media-tags.txt:61
command_empty
void command_empty(object *op, const char *params)
Definition: c_object.cpp:1450
object_matches_pickup_mode
int object_matches_pickup_mode(const object *item, int mode)
Definition: c_object.cpp:656
object::carrying
int32_t carrying
Definition: object.h:377
LOOK_OBJ
#define LOOK_OBJ(ob)
Definition: object.h:512
AP_NULL
#define AP_NULL
Definition: define.h:573
PU_GLOVES
#define PU_GLOVES
Definition: define.h:126
typedata
Definition: define.h:89
object::y
int16_t y
Definition: object.h:335
PU_CONTAINER
#define PU_CONTAINER
Definition: define.h:143
autojail.who
who
Definition: autojail.py:3
CLOAK
@ CLOAK
Definition: object.h:209
stringbuffer_finish
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.cpp:76
get_button_value
int get_button_value(const object *button)
Definition: button.cpp:749
object_free_drop_inventory
void object_free_drop_inventory(object *ob)
Definition: object.cpp:1555
put_object_in_sack
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.cpp:937
NROF
static uint32_t NROF(const object *const ob)
Definition: object.h:616
HELMET
@ HELMET
Definition: object.h:141
use_skill
int use_skill(object *op, const char *string)
Definition: skill_util.cpp:964
matcher_all
static int matcher_all(object *who, matcher_params *params, object *item)
Definition: c_object.cpp:740
disinfect.map
map
Definition: disinfect.py:4
object_decrease_nrof_by_one
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:32
POISON
@ POISON
Definition: object.h:118
PU_RATIO
#define PU_RATIO
Definition: define.h:113
FLAG_WAS_WIZ
#define FLAG_WAS_WIZ
Definition: define.h:234
linked_char::name
const char * name
Definition: global.h:97
PU_KEY
#define PU_KEY
Definition: define.h:128
command_throw
void command_throw(object *op, const char *params)
Definition: c_object.cpp:239
get_typedata
const typedata * get_typedata(int itemtype)
Definition: item.cpp:327
EVENT_PICKUP
#define EVENT_PICKUP
Definition: events.h:28
matcher_params::pickup_type
int pickup_type
Definition: c_object.cpp:719
query_name
void query_name(const object *op, char *buf, size_t size)
Definition: item.cpp:592
matcher_params::name
char name[MAX_BUF]
Definition: c_object.cpp:718
POTION
@ POTION
Definition: object.h:116
body_locations_struct::use_name
const char * use_name
Definition: object.h:24
FLAG_KNOWN_CURSED
#define FLAG_KNOWN_CURSED
Definition: define.h:320
output
**Media tags please refer to the protocol file in doc Developers protocol Quick for your pleasure an example[/b][i] This is an old full of dirt and partially destroyed[hand] My dear as you two years i had to leave quickly Words have come to me of powerful magic scrolls discovered in an old temple by my uncle I have moved to study them I not forgot your knowledge in ancient languages I need your help for[print][b] Some parts of document are to damaged to be readable[/b][arcane] Arghis[color=Red] k h[color=dark slate blue] ark[color=#004000] fido[/color][hand] please come as fast as possible my friend[print][b] The bottom of letter seems deliberatly shredded What is but not limited book signs rules Media tags are made of with inside them the name of tag and optional parameters for the tag Unlike html or there is no notion of opening and closing tag A client not able to understand a tag is supposed to ignore it when server is communicating with and old client that does not understand a a specific extended it will issue a classical message output
Definition: media-tags.txt:36
examine_weight_and_material
void examine_weight_and_material(object *op, object *tmp)
Definition: c_object.cpp:1786
EVENT_DROP
#define EVENT_DROP
Definition: events.h:27
matcher_number
static int matcher_number(object *who, matcher_params *params, object *item)
Definition: c_object.cpp:754
SK_DET_CURSE
@ SK_DET_CURSE
Definition: skills.h:33
set_object_face_main
int set_object_face_main(object *op)
Definition: apply.cpp:146
MSG_TYPE_COMMAND_INFO
#define MSG_TYPE_COMMAND_INFO
Definition: newclient.h:515
object::weight_limit
int32_t weight_limit
Definition: object.h:376
add_string
sstring add_string(const char *str)
Definition: shstr.cpp:124
knowledge_add_probe_monster
void knowledge_add_probe_monster(object *op, object *mon)
Definition: knowledge.cpp:1525
FOR_OB_AND_BELOW_FINISH
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:754
HEAD
#define HEAD(op)
Definition: object.h:598
player_can_find
bool player_can_find(object *op, object *ob)
Definition: item.cpp:587
pick_up_object
static void pick_up_object(object *pl, object *op, object *tmp, int nrof)
Definition: c_object.cpp:379
transport_can_hold
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.cpp:54
ROD
@ ROD
Definition: object.h:114
CONTAINER
@ CONTAINER
Definition: object.h:236
object_find_by_type_and_name
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.cpp:4099
query_short_name
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.cpp:517
PU_STOP
#define PU_STOP
Definition: define.h:110
PU_VALUABLES
#define PU_VALUABLES
Definition: define.h:117
FLAG_FREED
#define FLAG_FREED
Definition: define.h:233
SCRIPT_FIX_ALL
#define SCRIPT_FIX_ALL
Definition: global.h:388
navar-midane_pickup.msg
list msg
Definition: navar-midane_pickup.py:13
is_identified
int is_identified(const object *op)
Definition: item.cpp:1352
ob_describe
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Definition: ob_methods.cpp:91
SPECIAL_KEY
@ SPECIAL_KEY
Definition: object.h:129
empty_container
static void empty_container(object *container, object *pl)
Definition: c_object.cpp:1412
MOVE_FLYING
#define MOVE_FLYING
Definition: define.h:395
SPELL_HIGHEST
#define SPELL_HIGHEST
Definition: spells.h:60
object::type
uint8_t type
Definition: object.h:348
INS_NO_MERGE
#define INS_NO_MERGE
Definition: object.h:571
SKILLSCROLL
@ SKILLSCROLL
Definition: object.h:239
UPD_FLAGS
#define UPD_FLAGS
Definition: newclient.h:304
NDI_GOLD
#define NDI_GOLD
Definition: newclient.h:243
command_dropall
void command_dropall(object *op, const char *params)
Definition: c_object.cpp:1230
FOR_INV_FINISH
#define FOR_INV_FINISH()
Definition: define.h:677
identify_object_with_skill
int identify_object_with_skill(object *tmp, object *pl, object *skill, int print_on_success)
Definition: skills.cpp:810
INS_BELOW_ORIGINATOR
#define INS_BELOW_ORIGINATOR
Definition: object.h:575
living::food
int32_t food
Definition: living.h:48
MSG_TYPE_SKILL_MISSING
#define MSG_TYPE_SKILL_MISSING
Definition: newclient.h:576
PU_SPELLBOOK
#define PU_SPELLBOOK
Definition: define.h:135
change_exp
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.cpp:2168
disinfect.count
int count
Definition: disinfect.py:7
matcher_params
Definition: c_object.cpp:711
knowledge_item_can_be_used_alchemy
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Definition: knowledge.cpp:1331
tag_t
uint32_t tag_t
Definition: object.h:14
body_locations
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
Definition: item.cpp:54
archetype
Definition: object.h:474
object_matches_string
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.cpp:4565
PU_MELEEWEAPON
#define PU_MELEEWEAPON
Definition: define.h:131
sproto.h
ARROW
@ ARROW
Definition: object.h:122
make_matcher
static item_matcher make_matcher(object *who, const char *params, matcher_params *mp)
Definition: c_object.cpp:806
FLAG_NO_DROP
#define FLAG_NO_DROP
Definition: define.h:288
stringbuffer_append_string
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.cpp:95
PU_MAGICAL
#define PU_MAGICAL
Definition: define.h:132
FOR_OB_AND_BELOW_PREPARE
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:750
MSG_TYPE_SPELL
#define MSG_TYPE_SPELL
Definition: newclient.h:400
BOOK
@ BOOK
Definition: object.h:119
SP_level_spellpoint_cost
int16_t SP_level_spellpoint_cost(object *caster, object *spell, int flags)
Definition: spell_util.cpp:236
object::race
sstring race
Definition: object.h:326
find_best_apply_object_match
static object * find_best_apply_object_match(object *start, object *pl, const char *params, int aflag)
Definition: c_object.cpp:101
RING
@ RING
Definition: object.h:190
detect_magic_on_item
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Definition: skills.cpp:752
PU_HELMET
#define PU_HELMET
Definition: define.h:121
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
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)
Definition: object.cpp:2095
command_search_items
void command_search_items(object *op, const char *params)
Definition: c_object.cpp:2477
inventory
void inventory(object *op, object *inv)
Definition: c_object.cpp:2165
FLAG_MONSTER
#define FLAG_MONSTER
Definition: define.h:245
find_skill_by_name
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.cpp:211
recipe::ingred_count
int ingred_count
Definition: recipe.h:23
env
static std::shared_ptr< inja::Environment > env
Definition: mapper.cpp:2170
pick_up
void pick_up(object *op, object *alt)
Definition: c_object.cpp:519
MAX_BUF
#define MAX_BUF
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)
Definition: c_object.cpp:188
strlcpy
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.cpp:222
object_insert_in_map
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.cpp:2356
sack_can_hold
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Definition: c_object.cpp:317
create_archetype
object * create_archetype(const char *name)
Definition: arch.cpp:278
object_present_in_ob
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.cpp:3159
get_weight_limit
uint32_t get_weight_limit(int stat)
Definition: living.cpp:2362
free_string
void free_string(sstring str)
Definition: shstr.cpp:280
command_disarm
void command_disarm(object *op, const char *params)
Definition: c_object.cpp:224
IS_PLAYER
static bool IS_PLAYER(object *op)
Definition: object.h:600
matcher_params::item_must_be_pickable
int item_must_be_pickable
Definition: c_object.cpp:716
probe
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Definition: spell_effect.cpp:699
is_valid_types_gen.found
found
Definition: is_valid_types_gen.py:39
recipe
Definition: recipe.h:10
MSG_TYPE_COMMAND_FAILURE
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:520
FLAG_KNOWN_MAGICAL
#define FLAG_KNOWN_MAGICAL
Definition: define.h:319
pickup_modes
static const uint32_t pickup_modes[]
Definition: c_object.cpp:43
find_best_object_match
static object * find_best_object_match(object *pl, const char *params)
Definition: c_object.cpp:132
get_pickup_mode_index
static int get_pickup_mode_index(const char *name)
Definition: c_object.cpp:58
FLAG_REMOVED
#define FLAG_REMOVED
Definition: define.h:232
MSG_TYPE_COMMAND_INVENTORY
#define MSG_TYPE_COMMAND_INVENTORY
Definition: newclient.h:522
FLAG_WIZ
#define FLAG_WIZ
Definition: define.h:231
NDI_UNIQUE
#define NDI_UNIQUE
Definition: newclient.h:251
object::slaying
sstring slaying
Definition: object.h:327
item_matcher
int(* item_matcher)(object *who, matcher_params *params, object *item)
Definition: c_object.cpp:731
query_weight
void query_weight(const object *op, char *buf, size_t size)
Definition: item.cpp:419
object::name
sstring name
Definition: object.h:319
PU_CLOAK
#define PU_CLOAK
Definition: define.h:127
AP_OPEN
#define AP_OPEN
Definition: define.h:576
cost_approx_str
char * cost_approx_str(const object *obj, object *who)
Definition: shop.cpp:369
object_can_pick
int object_can_pick(const object *who, const object *item)
Definition: object.cpp:3858
stringbuffer_trim_whitespace
void stringbuffer_trim_whitespace(StringBuffer *sb)
Definition: stringbuffer.cpp:222
KEY
@ KEY
Definition: object.h:132
PU_JEWELS
#define PU_JEWELS
Definition: define.h:141
item
Definition: item.py:1
cost_str
char * cost_str(uint64_t cost)
Definition: shop.cpp:365
FLAG_IS_BUILDABLE
#define FLAG_IS_BUILDABLE
Definition: define.h:367
is_identifiable_type
int is_identifiable_type(const object *op)
Definition: item.cpp:1328
mapstruct
Definition: map.h:314
object::env
object * env
Definition: object.h:301
sstring
const typedef char * sstring
Definition: sstring.h:2
command_apply
void command_apply(object *op, const char *params)
Definition: c_object.cpp:251
give.op
op
Definition: give.py:33
autojail.value
value
Definition: autojail.py:6
shop.h
object_split
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.cpp:2628
command_examine
void command_examine(object *op, const char *params)
Definition: c_object.cpp:1489
PU_ARMOUR
#define PU_ARMOUR
Definition: define.h:123
examine_fluff
bool examine_fluff(object *op, object *tmp, bool output)
Definition: c_object.cpp:1871
apply_by_living
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Definition: apply.cpp:637
esrv_update_item
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.cpp:359
PU_NEWMODE
#define PU_NEWMODE
Definition: define.h:111
SKILL_TOOL
@ SKILL_TOOL
Definition: object.h:194
FLAG_NO_FIX_PLAYER
#define FLAG_NO_FIX_PLAYER
Definition: define.h:277
roll-o-matic.params
params
Definition: roll-o-matic.py:193
diamondslots.y
y
Definition: diamondslots.py:16
find_marked_object
object * find_marked_object(object *op)
Definition: c_object.cpp:1520
CLEAR_FLAG
#define CLEAR_FLAG(xyz, p)
Definition: define.h:225
npc_dialog.index
int index
Definition: npc_dialog.py:102
SK_SUBTRACT_SKILL_EXP
#define SK_SUBTRACT_SKILL_EXP
Definition: skills.h:81
apply_special
int apply_special(object *who, object *op, int aflags)
Definition: apply.cpp:1156
Settings::max_stat
uint8_t max_stat
Definition: global.h:324
display_new_pickup
static void display_new_pickup(const object *op, int old)
Definition: c_object.cpp:2230
level
int level
Definition: readable.cpp:1550
typedata::identifyskill2
int identifyskill2
Definition: define.h:94
make_face_from_files.int
int
Definition: make_face_from_files.py:32
UPD_NAME
#define UPD_NAME
Definition: newclient.h:307
AT_ACID
#define AT_ACID
Definition: attack.h:82
loader.h
save_player
int save_player(object *op, int flag)
Definition: login.cpp:230
stop_item
object * stop_item(object *op)
Definition: time.cpp:455
FOOD
@ FOOD
Definition: object.h:117
skill
skill
Definition: arch-handbook.txt:585
first
Crossfire Protocol most of the time after the actual code was already omit certain important and possibly make life miserable any new developer or curious player should be able to find most of the relevant information here If inconsistencies are found or this documentation proves to be consider the latest server side protocol code in the public source code repository as the authoritative reference Introduction If you were ever curious enough to telnet or netcat to a Crossfire chances are you were sorely disappointed While the protocol may seem to use plain text at first
Definition: protocol.txt:20
object_remove
void object_remove(object *op)
Definition: object.cpp:1828
recipe::ingred
linked_char * ingred
Definition: recipe.h:22
drop_object
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.cpp:1073
EX_ID_FAILED
@ EX_ID_FAILED
Definition: c_object.cpp:1696
object::move_off
MoveType move_off
Definition: object.h:438
FLAG_UNPAID
#define FLAG_UNPAID
Definition: define.h:236
examine_rod_charge_level
void examine_rod_charge_level(object *op, object *tmp)
Definition: c_object.cpp:1841
DRINK
@ DRINK
Definition: object.h:162
sell_item
void sell_item(object *op, object *pl)
Definition: shop.cpp:966
VERY_BIG_BUF
#define VERY_BIG_BUF
Definition: define.h:36
PU_CURSED
#define PU_CURSED
Definition: define.h:144
command_lock_item
void command_lock_item(object *op, const char *params)
Definition: c_object.cpp:2708
WEAPON_IMPROVER
@ WEAPON_IMPROVER
Definition: object.h:238
SCROLL
@ SCROLL
Definition: object.h:226
FLAG_IS_LINKED
#define FLAG_IS_LINKED
Definition: define.h:315
object::nrof
uint32_t nrof
Definition: object.h:342
say.item
dictionary item
Definition: say.py:149
matcher_params::missed
int missed
Definition: c_object.cpp:721
query_base_name
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.cpp:693
object::stats
living stats
Definition: object.h:378
object_set_value
int object_set_value(object *op, const char *key, const char *value, int add_key)
Definition: object.cpp:4490
AP_UNAPPLY
#define AP_UNAPPLY
Definition: define.h:575
SK_FIND_TRAPS
@ SK_FIND_TRAPS
Definition: skills.h:34
PU_DRINK
#define PU_DRINK
Definition: define.h:116
command_take
void command_take(object *op, const char *params)
Definition: c_object.cpp:845
BOOTS
@ BOOTS
Definition: object.h:217
shop_contains
bool shop_contains(object *ob)
Definition: shop.cpp:1296
pickup_names
static const char * pickup_names[]
Definition: c_object.cpp:33
FLAG_IS_CAULDRON
#define FLAG_IS_CAULDRON
Definition: define.h:338
matcher_params::item_number
int item_number
Definition: c_object.cpp:715
StringBuffer
Definition: stringbuffer.cpp:25
PU_SHIELD
#define PU_SHIELD
Definition: define.h:122
EX_ID_NO_SKILL
@ EX_ID_NO_SKILL
Definition: c_object.cpp:1695
SHIELD
@ SHIELD
Definition: object.h:140
object::attacktype
uint32_t attacktype
Definition: object.h:352
FLAG_NO_SKILL_IDENT
#define FLAG_NO_SKILL_IDENT
Definition: define.h:335
object_get_player_container
object * object_get_player_container(object *op)
Definition: object.cpp:607
altar_valkyrie.pl
pl
Definition: altar_valkyrie.py:28
living.h
FLAG_IS_THROWN
#define FLAG_IS_THROWN
Definition: define.h:249
SK_THROWING
@ SK_THROWING
Definition: skills.h:44
EX_ID_ABORT
@ EX_ID_ABORT
Definition: c_object.cpp:1694
SPELLBOOK
@ SPELLBOOK
Definition: object.h:208
CUSTOM_NAME_FIELD
#define CUSTOM_NAME_FIELD
Definition: object.h:98
shop_price_sell
uint64_t shop_price_sell(const object *obj, object *who)
Definition: shop.cpp:211
FOR_INV_PREPARE
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:670
living::hp
int16_t hp
Definition: living.h:40
FORCE
@ FORCE
Definition: object.h:229
llevDebug
@ llevDebug
Definition: logger.h:13
MONEY
@ MONEY
Definition: object.h:142
Settings::real_wiz
uint8_t real_wiz
Definition: global.h:271
FLAG_IS_FLOOR
#define FLAG_IS_FLOOR
Definition: define.h:302
examine_autoidentify
ex_autoid_result examine_autoidentify(object *op, object *tmp)
Definition: c_object.cpp:1710
FORCE_NAME
#define FORCE_NAME
Definition: spells.h:169
living::Str
int8_t Str
Definition: living.h:36
PU_DEBUG
#define PU_DEBUG
Definition: define.h:108
get_archetype_by_skill_name
archetype * get_archetype_by_skill_name(const char *skill, int type)
Definition: arch.cpp:80
PU_SKILLSCROLL
#define PU_SKILLSCROLL
Definition: define.h:136
level
Definition: level.py:1