Crossfire Server, Trunk  R213250
c_object.c
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 
32 static void set_pickup_mode(const object *op, int i);
33 
34 /*
35  * Object id parsing functions
36  */
37 
55 static object *find_best_apply_object_match(object *start, object *pl, const char *params, int aflag) {
56  object *tmp, *best = NULL;
57  int match_val = 0, tmpmatch;
58 
59  tmp = start;
61  if (tmp->invisible)
62  continue;
63  if (aflag == AP_APPLY && QUERY_FLAG(tmp, FLAG_APPLIED))
64  continue;
65  if (aflag == AP_UNAPPLY && !QUERY_FLAG(tmp, FLAG_APPLIED))
66  continue;
67  tmpmatch = object_matches_string(pl, tmp, params);
68  if (tmpmatch > match_val) {
69  match_val = tmpmatch;
70  best = tmp;
71  }
73  return best;
74 }
75 
86 static object *find_best_object_match(object *pl, const char *params) {
87  return find_best_apply_object_match(pl->inv, pl, params, AP_NULL);
88 }
89 
98 void command_uskill(object *pl, const char *params) {
99  if (*params == '\0') {
101  "Usage: use_skill <skill name>");
102  return;
103  }
104  use_skill(pl, params);
105 }
106 
115 void command_rskill(object *pl, const char *params) {
116  object *skill;
117 
118  if (*params == '\0') {
120  "Usage: ready_skill <skill name>");
121  return;
122  }
123  skill = find_skill_by_name(pl, params);
124 
125  if (!skill) {
127  "You have no knowledge of the skill %s",
128  params);
129  return;
130  }
131  change_skill(pl, skill, 0);
132 }
133 
142 static void do_skill_by_number(object *op, int skill_subtype, const char *params,
143  const char *missing_message) {
144  object *skop = find_skill_by_number(op, skill_subtype);
145  if (skop) {
146  do_skill(op, op, skop, op->facing, *params == '\0' ? NULL : params);
147  return;
148  }
149 
151  missing_message);
152 }
153 
154 /* These functions (command_search, command_disarm) are really juse wrappers for
155  * things like 'use_skill ...'). In fact, they should really be obsoleted
156  * and replaced with those.
157  */
166 void command_search(object *op, const char *params) {
167  do_skill_by_number(op, SK_FIND_TRAPS, params, "You don't know how to search for unusual things.");
168 }
169 
178 void command_disarm(object *op, const char *params) {
179  do_skill_by_number(op, SK_DISARM_TRAPS, params, "You don't know how to disarm traps.");
180 }
181 
193 void command_throw(object *op, const char *params) {
194  do_skill_by_number(op, SK_THROWING, params, "You have no knowledge of the skill throwing.");
195 }
196 
205 void command_apply(object *op, const char *params) {
206  int aflag = 0;
207  object *inv = op->inv;
208  object *item;
209 
210  if (*params == '\0') {
212  return;
213  }
214 
215  while (*params == ' ')
216  params++;
217  if (!strncmp(params, "-a ", 3)) {
218  aflag = AP_APPLY;
219  params += 3;
220  }
221  if (!strncmp(params, "-u ", 3)) {
222  aflag = AP_UNAPPLY;
223  params += 3;
224  }
225  if (!strncmp(params, "-b ", 3)) {
226  params += 3;
227  if (op->container)
228  inv = op->container->inv;
229  else {
230  inv = op;
231  while (inv->above)
232  inv = inv->above;
233  }
234  }
235  while (*params == ' ')
236  params++;
237 
238  item = find_best_apply_object_match(inv, op, params, aflag);
239  if (item == NULL)
240  item = find_best_apply_object_match(inv, op, params, AP_NULL);
241  if (item) {
242  apply_by_living(op, item, aflag, 0);
243  } else
245  "Could not find any match to the %s.",
246  params);
247 }
248 
267 int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof) {
268  char name[MAX_BUF];
269  query_name(sack, name, MAX_BUF);
270 
271  if (!QUERY_FLAG(sack, FLAG_APPLIED)) {
273  "The %s is not active.",
274  name);
275  return 0;
276  }
277  if (sack == op) {
279  "You can't put the %s into itself.",
280  name);
281  return 0;
282  }
283  if (sack->race
284  && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type))) {
286  "You can put only %s into the %s.",
287  sack->race, name);
288  return 0;
289  }
290  if (op->type == SPECIAL_KEY && sack->slaying && op->slaying) {
292  "You can't put the key into %s.",
293  name);
294  return 0;
295  }
296  if (sack->weight_limit) {
297  int32_t new_weight;
298 
299  new_weight = sack->carrying+(nrof ? nrof : 1)
300  *(op->weight+(op->type == CONTAINER ? op->carrying*op->stats.Str : 0))
301  *(100-sack->stats.Str)/100;
302  if (new_weight > sack->weight_limit) {
304  "That won't fit in the %s!",
305  name);
306  return 0;
307  }
308  }
309  /* All other checks pass, must be OK */
310  return 1;
311 }
312 
325 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
326  /* buf needs to be big (more than 256 chars) because you can get
327  * very long item names.
328  */
329  char buf[HUGE_BUF], name[MAX_BUF];
330  object *env = tmp->env;
331  uint32_t weight, effective_weight_limit;
332  const int tmp_nrof = NROF(tmp);
333  tag_t tag;
334  mapstruct* map = tmp->map;
335  int16_t x = tmp->x, y = tmp->y;
336 
337  /* IF the player is flying & trying to take the item out of a container
338  * that is in his inventory, let him. tmp->env points to the container
339  * (sack, luggage, etc), tmp->env->env then points to the player (nested
340  * containers not allowed as of now)
341  */
342  if ((pl->move_type&MOVE_FLYING)
343  && !QUERY_FLAG(pl, FLAG_WIZ)
344  && object_get_player_container(tmp) != pl) {
346  "You are levitating, you can't reach the ground!");
347  return;
348  }
349  if (QUERY_FLAG(tmp, FLAG_NO_DROP))
350  return;
351 
352  if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
354  "The object disappears in a puff of smoke! It must have been an illusion.");
355  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
356  object_remove(tmp);
358  return;
359  }
360 
361  if (nrof > tmp_nrof || nrof == 0)
362  nrof = tmp_nrof;
363 
364  /* Figure out how much weight this object will add to the player */
365  weight = tmp->weight*nrof;
366  if (tmp->inv)
367  weight += tmp->carrying*(100-tmp->stats.Str)/100;
368 
369  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
370 
371  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
373  "That item is too heavy for you to pick up.");
374  return;
375  }
376 
378  SET_FLAG(tmp, FLAG_WAS_WIZ);
379 
380  if (nrof != tmp_nrof) {
381  char failure[MAX_BUF];
382 
383  tmp = object_split(tmp, nrof, failure, sizeof(failure));
384  if (!tmp) {
386  failure);
387  return;
388  }
389  } else {
390  /* If the object is in a container, send a delete to the client.
391  * - we are moving all the items from the container to elsewhere,
392  * so it needs to be deleted.
393  */
394  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
395  object_remove(tmp); /* Unlink it */
396  }
397  }
398  query_name(tmp, name, MAX_BUF);
399 
400  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
401  char *value = cost_str(shop_price_buy(tmp, pl));
402  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
403  free(value);
404  } else
405  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
406 
407  /* Now item is about to be picked. */
408  tag = tmp->count;
409  if (execute_event(tmp, EVENT_PICKUP, pl, op, NULL, SCRIPT_FIX_ALL) != 0) {
410  /* put item back, if it still exists */
411  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
412  if (env != NULL) {
413  object_insert_in_ob(tmp, env);
414  } else {
415  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
416  }
417  }
418  return;
419  }
420 
422  buf);
423 
424  tmp = object_insert_in_ob(tmp, op);
425 
426  /* All the stuff below deals with client/server code, and is only
427  * usable by players
428  */
429  if (pl->type != PLAYER)
430  return;
431 
432  /* Additional weight changes speed, etc */
433  fix_object(pl);
434 
435  /* These are needed to update the weight for the container we
436  * are putting the object in.
437  */
438  if (op != pl) {
439  esrv_update_item(UPD_WEIGHT, pl, op);
440  esrv_update_item(UPD_WEIGHT, pl, pl);
441  }
442 
443  /* Update the container the object was in */
444  if (env && env != pl && env != op)
445  esrv_update_item(UPD_WEIGHT, pl, env);
446 }
447 
456 void pick_up(object *op, object *alt) {
457 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
458  object *tmp = NULL, *tmp1;
459  mapstruct *tmp_map = NULL;
460  int count;
461 
462  /* Decide which object to pick. */
463  if (alt) {
464  if (!object_can_pick(op, alt)) {
466  "You can't pick up the %s.",
467  alt->name);
468  return;
469  }
470  tmp = alt;
471  } else {
472  if (op->below == NULL || !object_can_pick(op, op->below)) {
474  "There is nothing to pick up here.");
475  return;
476  }
477  tmp = op->below;
478  }
479 
480  /* it is possible that the object is a thrown object and is flying about.
481  * in that case, what we want to pick up is the payload. Objects
482  * that are thrown are encapsulated into a thrown object.
483  * stop_item() returns the payload (unlinked from map) and gets rid of the
484  * container object. If this object isn't picked up, we need to insert
485  * it back on the map.
486  * A bug here is that even attempting to pick up one of these objects will
487  * result in this logic being called even if player is unable to pick it
488  * up.
489  */
490 
491  tmp_map = tmp->map;
492  tmp1 = stop_item(tmp);
493  if (tmp1 == NULL)
494  return;
495 
496  /* If it is a thrown object, insert it back into the map here.
497  * makes life easier further along. Do no merge so pick up code
498  * behaves more sanely.
499  */
500  if (tmp1 != tmp) {
501  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
502  }
503 
504  if (tmp == NULL)
505  return;
506 
507  if (!object_can_pick(op, tmp))
508  return;
509 
510  /* Establish how many of the object we are picking up */
511  if (op->type == PLAYER) {
512  count = op->contr->count;
513  if (count == 0)
514  count = tmp->nrof;
515  } else
516  count = tmp->nrof;
517 
518  /* container is open, so use it */
519  if (op->container) {
520  alt = op->container;
521  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
522  return;
523  } else {
524  /* non container pickup. See if player has any
525  * active containers.
526  */
527  object *container = NULL;
528 
529  /* Look for any active containers that can hold this item.
530  * we cover two cases here - the perfect match case, where we
531  * break out of the loop, and the general case (have a container),
532  * Moved this into a single loop - reduces redundant code, is
533  * more efficient and easier to follow. MSW 2009-04-06
534  */
535  alt = op->inv;
537  if (alt->type == CONTAINER
538  && QUERY_FLAG(alt, FLAG_APPLIED)
539  && sack_can_hold(NULL, alt, tmp, count)) {
540  if (alt->race && alt->race == tmp->race) {
541  break; /* perfect match */
542  } else if (!container) {
543  container = alt;
544  }
545  }
547  /* Note container could be null, but no reason to check for it */
548  if (!alt)
549  alt = container;
550 
551  if (!alt)
552  alt = op; /* No free containers */
553  }
554  /* see if this object is already in this container. If so,
555  * move it to player inventory from this container.
556  */
557  if (tmp->env == alt) {
558  alt = op;
559  }
560 
561  /* Don't allow players to be put into containers. Instead,
562  * just put them in the players inventory.
563  */
564  if (tmp->type == CONTAINER && alt->type==CONTAINER) {
565  alt = op;
566  }
567 #ifdef PICKUP_DEBUG
568  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
569 #endif
570 
571  /* startequip items are not allowed to be put into containers
572  * Not sure why we have this limitation
573  */
574  if (op->type == PLAYER
575  && alt->type == CONTAINER
576  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
578  "This object cannot be put into containers!");
579  return;
580  }
581 
582  pick_up_object(op, alt, tmp, count);
583  if (op->type == PLAYER)
584  op->contr->count = 0;
585 }
586 
595 void command_take(object *op, const char *params) {
596  object *tmp;
597  int ival;
598  int missed = 0;
599 
600  if (op->container)
601  tmp = op->container->inv;
602  else {
603  tmp = op->above;
604  if (tmp)
605  while (tmp->above) {
606  tmp = tmp->above;
607  }
608  if (!tmp)
609  tmp = op->below;
610  }
611 
612  if (tmp == NULL) {
614  "Nothing to take!");
615  return;
616  }
617 
618  /* Makes processing easier */
619  if (*params == '\0')
620  params = NULL;
621 
623  if (tmp->invisible) {
624  continue;
625  }
626  /* This following two if and else if could be merged into line
627  * but that probably will make it more difficult to read, and
628  * not make it any more efficient
629  */
630  if (params) {
631  ival = object_matches_string(op, tmp, params);
632  if (ival > 0) {
633  if (ival <= 2 && !object_can_pick(op, tmp)) {
634  if (!QUERY_FLAG(tmp, FLAG_IS_FLOOR))/* don't count floor tiles */
635  missed++;
636  } else
637  pick_up(op, tmp);
638  }
639  } else {
640  if (object_can_pick(op, tmp)) {
641  pick_up(op, tmp);
642  break;
643  }
644  }
646  if (!params && !tmp) {
647  int found = 0;
648  FOR_BELOW_PREPARE(op, tmp)
649  if (!tmp->invisible) {
651  "You can't pick up a %s.",
652  tmp->name ? tmp->name : "null");
653  found = 1;
654  break;
655  }
657  if (!found)
659  "There is nothing to pick up.");
660  }
661  if (missed == 1)
663  "You were unable to take one of the items.");
664  else if (missed > 1)
666  "You were unable to take %d of the items.",
667  missed);
668 }
669 
688 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
689  object *sack2, *orig = sack;
690  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
691 
692  if (sack == tmp)
693  return; /* Can't put an object in itself */
694  query_name(sack, name_sack, MAX_BUF);
695  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
697  "The %s is not a container.",
698  name_sack);
699  return;
700  }
701  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
702  query_name(tmp, name_tmp, MAX_BUF);
704  "You cannot put the %s in the %s.",
705  name_tmp, name_sack);
706  return;
707  }
708  if (tmp->type == CONTAINER) {
709  if (tmp->inv) {
710  if (tmp->slaying)
711  return;
712  /* Eneq(@csd.uu.se): If the object to be dropped is a container
713  * and does not require a key to be opened,
714  * we instead move the contents of that container into the active
715  * container, this is only done if the object has something in it.
716  * If object is container but need a key, just don't do anything
717  */
718  sack2 = tmp;
719  query_name(tmp, name_tmp, MAX_BUF);
721  "You move the items from %s into %s.",
722  name_tmp, name_sack);
723 
724  FOR_INV_PREPARE(tmp, tmp2) {
725  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
726  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
727  put_object_in_sack(op, sack, tmp2, 0);
728  } else {
731  "Your %s fills up.",
732  name_sack);
733  break;
734  }
735  } FOR_INV_FINISH();
736  esrv_update_item(UPD_WEIGHT, op, sack2);
737  return;
738  } else {
739  query_name(tmp, name_tmp, MAX_BUF);
741  "You can not put a %s into a %s",
742  name_tmp,
743  name_sack);
744  return;
745  }
746  }
747 
748  /* Don't worry about this for containers - our caller should have
749  * already checked this.
750  */
751  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
752  return;
753 
754  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
755  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
756  return;
757  }
758 
759  /* we want to put some portion of the item into the container */
760  if (nrof && tmp->nrof != nrof) {
761  char failure[MAX_BUF];
762 
763  tmp = object_split(tmp, nrof, failure, sizeof(failure));
764 
765  if (!tmp) {
767  failure);
768  return;
769  }
770  } else
771  object_remove(tmp);
772 
773  if (sack->nrof > 1) {
774  orig = object_split(sack, sack->nrof-1, NULL, 0);
775  set_object_face_main(orig);
776  CLEAR_FLAG(orig, FLAG_APPLIED);
777  if (sack->env) {
778  object_insert_in_ob(orig, sack->env);
779  } else {
780  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
781  orig->move_off = 0;
782  }
783  }
784 
785  query_name(tmp, name_tmp, MAX_BUF);
787  "You put the %s in %s.",
788  name_tmp, name_sack);
789 
790  object_insert_in_ob(tmp, sack);
791  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
792  fix_object(op); /* This is overkill, fix_player() is called somewhere */
793  /* in object.c */
794 
795  /* If a transport, need to update all the players in the transport
796  * the view of what is in it.
797  */
798  if (sack->type == TRANSPORT) {
799  FOR_INV_PREPARE(sack, tmp)
800  if (tmp->type == PLAYER)
801  tmp->contr->socket.update_look = 1;
802  FOR_INV_FINISH();
803  } else {
804  /* update the sacks weight */
805  esrv_update_item(UPD_WEIGHT, op, sack);
806  }
807 }
808 
824 object *drop_object(object *op, object *tmp, uint32_t nrof) {
825  tag_t tmp_tag;
826 
827  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
828  return NULL;
829  }
830 
831  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
832  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
833  return NULL; /* can't unapply it */
834  }
835 
836  /* Lauwenmark: Handle for plugin drop event */
837  if (execute_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
838  return NULL;
839 
840  /* ensure the plugin didn't destroy the object */
841  if (QUERY_FLAG(tmp, FLAG_REMOVED))
842  return NULL;
843 
844  /* We are only dropping some of the items. We split the current objec
845  * off
846  */
847  if (nrof && tmp->nrof != nrof) {
848  char failure[MAX_BUF];
849 
850  tmp = object_split(tmp, nrof, failure, sizeof(failure));
851  if (!tmp) {
853  failure);
854  return NULL;
855  }
856  } else
857  object_remove(tmp);
858 
859  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
860  char name[MAX_BUF];
861 
862  query_name(tmp, name, MAX_BUF);
864  "You drop the %s. The gods who lent it to you retrieve it.",
865  name);
867 
868  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
869  fix_object(op);
870 
871  return NULL;
872  }
873 
874  /* If SAVE_INTERVAL is commented out, we never want to save
875  * the player here.
876  */
877 #ifdef SAVE_INTERVAL
878  /* I'm not sure why there is a value check - since the save
879  * is done every SAVE_INTERVAL seconds, why care the value
880  * of what he is dropping?
881  */
882  if (op->type == PLAYER
883  && !QUERY_FLAG(tmp, FLAG_UNPAID)
884  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
885  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
886  save_player(op, 1);
887  op->contr->last_save_time = time(NULL);
888  }
889 #endif /* SAVE_INTERVAL */
890 
891 
892  tmp_tag = tmp->count;
893  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
894  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
895  sell_item(tmp, op);
896  }
897 
898  /* Call this before we update the various windows/players. At least
899  * that we, we know the weight is correct.
900  */
901  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
902  fix_object(op); /* This is overkill, fix_player() is called somewhere */
903  /* in object.c */
904 
905  /* Need to update weight of player */
906  if (op->type == PLAYER)
907  esrv_update_item(UPD_WEIGHT, op, op);
908  }
909  return tmp;
910 }
911 
920 void drop(object *op, object *tmp) {
921  /* Hopeful fix for disappearing objects when dropping from a container -
922  * somehow, players get an invisible object in the container, and the
923  * old logic would skip over invisible objects - works fine for the
924  * playes inventory, but drop inventory wants to use the next value.
925  */
926  if (tmp->invisible) {
927  /* if the following is the case, it must be in an container. */
928  if (tmp->env && tmp->env->type != PLAYER) {
929  /* Just toss the object - probably shouldn't be hanging
930  * around anyways
931  */
932  object_remove(tmp);
934  return;
935  } else {
937  if (!tmp->invisible)
938  break;
940  }
941  }
942 
943  if (tmp == NULL) {
945  "You don't have anything to drop.");
946  return;
947  }
948  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
950  "This item is locked");
951  return;
952  }
953  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
954  return;
955  }
956 
957  if (op->container) {
958  if (op->type == PLAYER) {
959  put_object_in_sack(op, op->container, tmp, op->contr->count);
960  } else {
961  put_object_in_sack(op, op->container, tmp, 0);
962  };
963  } else {
964  if (op->type == PLAYER) {
965  drop_object(op, tmp, op->contr->count);
966  } else {
967  drop_object(op, tmp, 0);
968  };
969  }
970  if (op->type == PLAYER)
971  op->contr->count = 0;
972 }
973 
982 void command_dropall(object *op, const char *params) {
983  int count = 0;
984 
985  if (op->inv == NULL) {
986  draw_ext_info(NDI_UNIQUE, 0, op,
988  "Nothing to drop!");
989  return;
990  }
991 
992  if (op->contr)
993  count = op->contr->count;
994 
995  /* Set this so we don't call it for _every_ object that
996  * is dropped.
997  */
999 
1000  /*
1001  * This is the default. Drops everything not locked or considered
1002  * not something that should be dropped.
1003  * Care must be taken that the next item pointer is not to money as
1004  * the drop() routine will do unknown things to it when dropping
1005  * in a shop. --Tero.Pelander@utu.fi
1006  */
1007  if (*params == '\0') {
1008  FOR_INV_PREPARE(op, curinv) {
1009  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1010  && curinv->type != MONEY
1011  && curinv->type != FOOD
1012  && curinv->type != KEY
1013  && curinv->type != SPECIAL_KEY
1014  && curinv->type != GEM
1015  && !curinv->invisible
1016  && (curinv->type != CONTAINER || op->container != curinv)) {
1017  drop(op, curinv);
1018  if (op->contr)
1019  op->contr->count = count;
1020  }
1021  } FOR_INV_FINISH();
1022  } else if (strcmp(params, "weapons") == 0) {
1023  FOR_INV_PREPARE(op, curinv) {
1024  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1025  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1026  drop(op, curinv);
1027  if (op->contr)
1028  op->contr->count = count;
1029  }
1030  } FOR_INV_FINISH();
1031  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1032  FOR_INV_PREPARE(op, curinv) {
1033  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1034  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1035  drop(op, curinv);
1036  if (op->contr)
1037  op->contr->count = count;
1038  }
1039  } FOR_INV_FINISH();
1040  } else if (strcmp(params, "food") == 0) {
1041  FOR_INV_PREPARE(op, curinv) {
1042  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1043  && (curinv->type == FOOD || curinv->type == DRINK)) {
1044  drop(op, curinv);
1045  if (op->contr)
1046  op->contr->count = count;
1047  }
1048  } FOR_INV_FINISH();
1049  } else if (strcmp(params, "flesh") == 0) {
1050  FOR_INV_PREPARE(op, curinv) {
1051  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1052  && (curinv->type == FLESH)) {
1053  drop(op, curinv);
1054  if (op->contr)
1055  op->contr->count = count;
1056  }
1057  } FOR_INV_FINISH();
1058  } else if (strcmp(params, "misc") == 0) {
1059  FOR_INV_PREPARE(op, curinv) {
1060  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1061  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1062  switch (curinv->type) {
1063  case BOOK:
1064  case SPELLBOOK:
1065  case GIRDLE:
1066  case AMULET:
1067  case RING:
1068  case CLOAK:
1069  case BOOTS:
1070  case GLOVES:
1071  case BRACERS:
1072  case SCROLL:
1073  case ARMOUR_IMPROVER:
1074  case WEAPON_IMPROVER:
1075  case WAND:
1076  case ROD:
1077  case POTION:
1078  drop(op, curinv);
1079  if (op->contr)
1080  op->contr->count = count;
1081  break;
1082 
1083  default:
1084  break;
1085  }
1086  }
1087  } FOR_INV_FINISH();
1088  }
1089  op->contr->socket.update_look = 1;
1091  /* call it now, once */
1092  fix_object(op);
1093  /* Need to update weight of player. Likewise, only do it once */
1094  if (op->type == PLAYER)
1095  esrv_update_item(UPD_WEIGHT, op, op);
1096 }
1097 
1106 void command_drop(object *op, const char *params) {
1107  int did_one = 0;
1108  int ival = 0;
1109  int missed = 0;
1110 
1111  if (*params == '\0') {
1113  "Drop what?");
1114  return;
1115  } else {
1116  FOR_INV_PREPARE(op, tmp) {
1117  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1118  continue;
1119  ival = object_matches_string(op, tmp, params);
1120  if (ival > 0) {
1121  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED) && (ival == 1 || ival == 2))
1122  missed++;
1123  else
1124  drop(op, tmp);
1125  did_one = 1;
1126  }
1127  } FOR_INV_FINISH();
1128  if (!did_one)
1130  "Nothing to drop.");
1131  if (missed == 1)
1133  "One item couldn't be dropped because it was locked.");
1134  else if (missed > 1)
1136  "%d items couldn't be dropped because they were locked.",
1137  missed);
1138  }
1139  if (op->type == PLAYER) {
1140  op->contr->count = 0;
1141  /*
1142  * Don't force a whole look update, items were transferred during their move.
1143  * Also this would send a 'delinv 0' to the client, which would make it appear
1144  * an opened container was closed.
1145  */
1146  /*op->contr->socket.update_look = 1;*/
1147  }
1148 }
1149 
1158 static void empty_container(object *container, object *pl) {
1159  int left = 0;
1160  char name[MAX_BUF];
1161 
1162  if (!container->inv)
1163  return;
1164 
1165  FOR_INV_PREPARE(container, inv) {
1166  object *next;
1167 
1168  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1169  /* you can have locked items in container. */
1170  left++;
1171  continue;
1172  }
1173  next = inv->below;
1174  drop(pl, inv);
1175  if (inv->below == next)
1176  /* item couldn't be dropped for some reason. */
1177  left++;
1178  } FOR_INV_FINISH();
1179  esrv_update_item(UPD_WEIGHT, pl, container);
1180 
1181  query_name(container, name, sizeof(name));
1182  if (left)
1183  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1184  else
1185  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s.", name);
1186 }
1187 
1196 void command_empty(object *op, const char *params) {
1197  object *container;
1198 
1199  if (*params == '\0') {
1201  "Empty what?");
1202  return;
1203  }
1204 
1205  if (strcmp(params, "all") == 0) {
1206  FOR_INV_PREPARE(op, inv)
1207  if (inv->type == CONTAINER)
1208  empty_container(inv, op);
1209  FOR_INV_FINISH();
1210  return;
1211  }
1212 
1213  container = find_best_object_match(op, params);
1214  if (!container) {
1216  "No such item.");
1217  return;
1218  }
1219  if (container->type != CONTAINER) {
1221  "This is not a container!");
1222  return;
1223  }
1224  empty_container(container, op);
1225 }
1226 
1235 void command_examine(object *op, const char *params) {
1236  if (*params == '\0') {
1237  FOR_BELOW_PREPARE(op, tmp)
1238  if (LOOK_OBJ(tmp)) {
1239  examine(op, tmp);
1240  break;
1241  }
1242  FOR_BELOW_FINISH();
1243  } else {
1244  object *tmp = find_best_object_match(op, params);
1245 
1246  if (tmp)
1247  examine(op, tmp);
1248  else
1250  "Could not find an object that matches %s",
1251  params);
1252  }
1253 }
1254 
1266 object *find_marked_object(object *op) {
1267  if (!op || !op->contr || !op->contr->mark)
1268  return NULL;
1269 
1270  /* This may seem like overkill, but we need to make sure that they
1271  * player hasn't dropped the item. We use count on the off chance that
1272  * an item got reincarnated at some point.
1273  */
1274  /*
1275  FOR_INV_PREPARE(op, tmp) {
1276  if (tmp->invisible)
1277  continue;
1278  if (tmp == op->contr->mark) {
1279  if (tmp->count == op->contr->mark_count)
1280  return tmp;
1281  else {
1282  op->contr->mark = NULL;
1283  op->contr->mark_count = 0;
1284  return NULL;
1285  }
1286  }
1287  } FOR_INV_FINISH();
1288  */
1289  /* Try a different way of doing this
1290  * We check the environment of the marked object
1291  * to make sure it is still in the player's inventory.
1292  * In addition, we ensure there is the correct quantity of that item.
1293  *
1294  * Daniel Hawkins 2018-10-23
1295  */
1296  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1297  return op->contr->mark;
1298  // Otherwise reset the mark, since it is no longer valid.
1299  op->contr->mark = NULL;
1300  op->contr->mark_count = 0;
1301  return NULL;
1302 }
1303 
1313 void command_mark(object *op, const char *params) {
1314  char name[MAX_BUF];
1315 
1316  if (!op->contr)
1317  return;
1318  if (*params == '\0') {
1319  object *mark = find_marked_object(op);
1320  if (!mark)
1322  "You have no marked object.");
1323  else {
1324  query_name(mark, name, MAX_BUF);
1326  "%s is marked.",
1327  name);
1328  }
1329  } else {
1330  object *mark1 = find_best_object_match(op, params);
1331 
1332  if (!mark1) {
1334  "Could not find an object that matches %s",
1335  params);
1336  return;
1337  } else {
1338  op->contr->mark = mark1;
1339  op->contr->mark_count = mark1->count;
1340  query_name(mark1, name, MAX_BUF);
1342  "Marked item %s",
1343  name);
1344  return;
1345  }
1346  }
1347  /*shouldnt get here */
1348 }
1349 
1360 void examine_monster(object *op, object *tmp, int level) {
1361  object *mon = HEAD(tmp), *probe;
1362 
1363  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1365  "It is an undead force.");
1366  if (mon->level > op->level)
1368  "It is likely more powerful than you.");
1369  else if (mon->level < op->level)
1371  "It is likely less powerful than you.");
1372  else
1374  "It is probably as powerful as you.");
1375 
1376  if (mon->attacktype&AT_ACID)
1378  "You smell an acrid odor.");
1379 
1380  /* Anyone know why this used to use the clone value instead of the
1381  * maxhp field? This seems that it should give more accurate results.
1382  */
1383  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1384  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1385  case 0:
1387  "It is critically wounded.");
1388  break;
1389 
1390  case 1:
1392  "It is in a bad shape.");
1393  break;
1394 
1395  case 2:
1397  "It is hurt.");
1398  break;
1399 
1400  case 3:
1402  "It is somewhat hurt.");
1403  break;
1404 
1405  default:
1407  "It is in excellent shape.");
1408  break;
1409  }
1410  if (object_present_in_ob(POISONING, mon) != NULL)
1412  "It looks very ill.");
1413 
1414  if (level < 10)
1415  return;
1417 
1418  if (level < 15)
1419  return;
1420 
1421  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1422  if (probe != NULL && probe->level > level)
1423  return;
1424 
1425  if (probe == NULL) {
1427  free_string(probe->name);
1428  probe->name = add_string("probe_force");
1431  object_insert_in_ob(probe, mon);
1432  fix_object(mon);
1433  }
1434  probe->level = level;
1435  if (level / 10 > probe->duration)
1436  probe->duration = level / 10;
1437 }
1438 
1448 void examine(object *op, object *tmp) {
1449  char buf[VERY_BIG_BUF];
1450  int in_shop;
1451  int i, exp = 0, conn;
1452 
1453  /* we use this to track how far along we got with trying to identify an item,
1454  * so that we can give the appropriate message to the player */
1455  int id_attempted = 0;
1456  char prefix[MAX_BUF] = "That is";
1457  const typedata *tmptype;
1458  object *skill;
1459 
1460  buf[0] = '\0';
1461 
1462  if (tmp == NULL || tmp->type == CLOSE_CON)
1463  return;
1464  tmptype = get_typedata(tmp->type);
1465  if (!tmptype) {
1466  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid", tmp->count, tmp->type);
1467  return;
1468  }
1469  /* first of all check whether this is an item we need to identify, and identify it as best we can.*/
1470  if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
1471  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1472  skill = find_skill_by_number(op, SK_DET_MAGIC);
1473  if (skill && (object_can_pick(op, tmp))) {
1474  exp = detect_magic_on_item(op, tmp, skill);
1475  if (exp) {
1476  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1478  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1479  }
1480  }
1481  skill = find_skill_by_number(op, SK_DET_CURSE);
1482  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1483  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1484  exp = detect_curse_on_item(op, tmp, skill);
1485  if (exp) {
1486  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1488  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1489  }
1490  }
1491  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1492 
1493  id_attempted = 1;
1494  skill = find_skill_by_number(op, tmptype->identifyskill);
1495  if (skill) {
1496  id_attempted = 2;
1497 
1498  /* identify_object_with_skill() may merge tmp with another
1499  * object, so once that happens, we really can not do
1500  * any further processing with tmp. It would be possible
1501  * to modify identify_object_with_skill() to return
1502  * the merged object, but it is currently set to return
1503  * exp, so it would have to do it via modifying the
1504  * passed in value, but many other consumers would
1505  * need to be modified for that.
1506  */
1507  exp = identify_object_with_skill(tmp, op, skill, 1);
1508  if (exp) {
1509  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1510  return;
1511  }
1512  }
1513  if(!exp) {
1514  /* The primary id skill didn't work, let's try the secondary one */
1515  skill = find_skill_by_number(op, tmptype->identifyskill2);
1516  if (skill) {
1517  /* if we've reached here, then the first skill will have been attempted
1518  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1519  * that now, and try with the secondary ID skill, if it fails, then the
1520  * flag will be reset anyway, if it succeeds, it won't matter.*/
1522  id_attempted = 2;
1523  exp = identify_object_with_skill(tmp, op, skill, 1);
1524  if (exp) {
1525  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1526  return;
1527  }
1528  }
1529  }
1530  }
1531  }
1532  if (!exp) {
1533  /* if we did get exp we'll already have propulated prefix */
1534  if (tmptype->identifyskill || tmptype->identifyskill2) {
1535  switch (id_attempted) {
1536  case 1:
1537  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1538  break;
1539  case 2:
1540  snprintf(prefix, MAX_BUF, "You fail to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1541  break;
1542  default:
1543  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1544  }
1545  } else snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1546  }
1547  /* now we need to get the rest of the object description */
1548  ob_describe(tmp, op, buf, sizeof(buf));
1549 
1551  "%s %s", prefix, buf);
1552  buf[0] = '\0';
1553  if (tmp->custom_name) {
1555  "You name it %s",
1556  tmp->custom_name);
1557  }
1558 
1559  switch (tmp->type) {
1560  case SPELLBOOK:
1561  if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) && tmp->inv) {
1562  char level[100];
1563 
1564  get_levelnumber(tmp->inv->level, level, 100);
1565  snprintf(buf, sizeof(buf), "%s is a %s level %s spell", tmp->inv->name, level, tmp->inv->skill);
1566  }
1567  break;
1568 
1569  case BOOK:
1570  if (tmp->msg != NULL)
1571  snprintf(buf, sizeof(buf), "Something is written in it.");
1572  break;
1573 
1574  case CONTAINER:
1575  if (tmp->race != NULL) {
1576  if (tmp->weight_limit && tmp->stats.Str < 100)
1577  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)));
1578  else
1579  snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
1580  } else
1581  if (tmp->weight_limit && tmp->stats.Str < 100)
1582  snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
1583  break;
1584 
1585  case WAND:
1586  if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
1587  snprintf(buf, sizeof(buf), "It has %d charges left.", tmp->stats.food);
1588  break;
1589  }
1590 
1591  if (buf[0] != '\0')
1593  buf);
1594 
1595  if (tmp->materialname != NULL && !tmp->msg) {
1597  "It is made of: %s.",
1598  tmp->materialname);
1599  }
1600  /* Where to wear this item */
1601  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1602  if (tmp->body_info[i] < -1) {
1603  if (op->body_info[i])
1605  "It goes %s (%d)",
1606  body_locations[i].use_name, -tmp->body_info[i]);
1607  else
1609  "It goes %s",
1610  body_locations[i].nonuse_name);
1611  } else if (tmp->body_info[i]) {
1612  if (op->body_info[i])
1614  "It goes %s",
1615  body_locations[i].use_name);
1616  else
1618  "It goes %s",
1619  body_locations[i].nonuse_name);
1620  }
1621  }
1622 
1623  if (tmp->weight) {
1624  snprintf(buf, sizeof(buf), tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", tmp->weight*((float)(tmp->nrof ? tmp->nrof : 1)/1000.0));
1626  buf);
1627  }
1628 
1629  in_shop = shop_contains(op);
1630 
1631  if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
1632  char *value = cost_approx_str(tmp, op);
1633  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
1634  free(value);
1636  buf);
1637  if (in_shop) {
1638  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1639  value = cost_str(shop_price_buy(tmp, op));
1640  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
1641  free(value);
1642  } else {
1643  value = cost_str(shop_price_sell(tmp, op));
1644  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
1645  free(value);
1646  }
1648  buf);
1649  }
1650  }
1651 
1652  if (QUERY_FLAG(tmp, FLAG_MONSTER))
1653  examine_monster(op, tmp, 0);
1654 
1655  /* Is this item buildable? */
1656  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
1658  "This is a buildable item.");
1659  if (QUERY_FLAG(tmp, FLAG_IS_LINKED)){
1660  conn = get_button_value(tmp);
1661  if (conn) {
1662  FOR_INV_PREPARE(op, tmp_inv) {
1663  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
1664  && strcmp(tmp_inv->slaying, op->map->path) == 0
1665  && tmp_inv->msg != NULL
1666  && tmp_inv->path_attuned == (uint32_t) conn) {
1667 
1669  MSG_TYPE_COMMAND_EXAMINE, "Connected with: %s",
1670  tmp_inv->msg);
1671 
1672  break;
1673  }
1674  } FOR_INV_FINISH();
1675  }
1676  }
1677  }
1678 
1679  /* Does the object have a message? Don't show message for all object
1680  * types - especially if the first entry is a match
1681  */
1682  if (tmp->msg
1683  && tmp->type != EXIT
1684  && tmp->type != BOOK
1685  && tmp->type != CORPSE
1686  && !tmp->move_on
1687  && strncasecmp(tmp->msg, "@match", 6)) {
1688  /* This is just a hack so when identifying the items, we print
1689  * out the extra message
1690  *
1691  * Also, don't print the message for the object unless it has been identified
1692  * -- SilverNexus 2015-05-20
1693  */
1694  if (need_identify(tmp) && QUERY_FLAG(tmp, FLAG_IDENTIFIED)){
1696  "The object has a story:");
1697 
1699  tmp->msg);
1700  }
1701  }
1703  " "); /* Blank line */
1704 
1705  if (!need_identify(tmp) || QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
1707  }
1708 }
1709 
1718 void inventory(object *op, object *inv) {
1719  const char *in;
1720  int items = 0, length;
1721  char weight[MAX_BUF], name[MAX_BUF];
1722 
1723  if (inv == NULL && op == NULL) {
1725  "Inventory of what object?");
1726  return;
1727  }
1728  FOR_INV_PREPARE(inv ? inv : op, tmp)
1729  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
1730  || !op || QUERY_FLAG(op, FLAG_WIZ))
1731  items++;
1732  FOR_INV_FINISH();
1733  if (inv == NULL) { /* player's inventory */
1734  if (items == 0) {
1736  "You carry nothing.");
1737  return;
1738  } else {
1739  length = 28;
1740  in = "";
1742  "Inventory:");
1743  }
1744  } else {
1745  if (items == 0)
1746  return;
1747  else {
1748  length = 28;
1749  in = " ";
1750  }
1751  }
1752  FOR_INV_PREPARE(inv ? inv : op, tmp) {
1753  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
1754  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
1755  continue;
1756  query_weight(tmp, weight, MAX_BUF);
1757  query_name(tmp, name, MAX_BUF);
1758  if (!op || QUERY_FLAG(op, FLAG_WIZ))
1760  "[fixed]%s- %-*.*s (%5d) %-8s",
1761  in, length, length, name, tmp->count, weight);
1762  else
1764  "[fixed]%s- %-*.*s %-8s",
1765  in, length+8, length+8, name, weight);
1766  } FOR_INV_FINISH();
1767  if (!inv && op) {
1768  query_weight(op, weight, MAX_BUF);
1770  "[fixed]%-*s %-8s",
1771  41, "Total weight :", weight);
1772  }
1773 }
1774 
1783 static void display_new_pickup(const object *op, int old) {
1784  int i = op->contr->mode;
1785 
1786  esrv_send_pickup(op->contr);
1787 
1788  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
1789  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
1791  "Pickup is %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
1792  }
1793  return;
1794  }
1795 
1797  "%d NEWMODE",
1798  i&PU_NEWMODE ? 1 : 0);
1800  "%d DEBUG",
1801  i&PU_DEBUG ? 1 : 0);
1803  "%d INHIBIT",
1804  i&PU_INHIBIT ? 1 : 0);
1806  "%d STOP",
1807  i&PU_STOP ? 1 : 0);
1808 
1810  "%d <= x pickup weight/value RATIO (0==off)",
1811  (i&PU_RATIO)*5);
1812 
1814  "%d FOOD",
1815  i&PU_FOOD ? 1 : 0);
1817  "%d DRINK",
1818  i&PU_DRINK ? 1 : 0);
1820  "%d VALUABLES",
1821  i&PU_VALUABLES ? 1 : 0);
1822 
1824  "%d BOW",
1825  i&PU_BOW ? 1 : 0);
1827  "%d ARROW",
1828  i&PU_ARROW ? 1 : 0);
1829 
1831  "%d HELMET",
1832  i&PU_HELMET ? 1 : 0);
1834  "%d SHIELD",
1835  i&PU_SHIELD ? 1 : 0);
1837  "%d ARMOUR",
1838  i&PU_ARMOUR ? 1 : 0);
1839 
1841  "%d BOOTS",
1842  i&PU_BOOTS ? 1 : 0);
1844  "%d GLOVES",
1845  i&PU_GLOVES ? 1 : 0);
1847  "%d CLOAK",
1848  i&PU_CLOAK ? 1 : 0);
1850  "%d KEY",
1851  i&PU_KEY ? 1 : 0);
1852 
1854  "%d MISSILEWEAPON",
1855  i&PU_MISSILEWEAPON ? 1 : 0);
1857  "%d MELEEWEAPON",
1858  i&PU_MELEEWEAPON ? 1 : 0);
1860  "%d MAGICAL",
1861  i&PU_MAGICAL ? 1 : 0);
1863  "%d POTION",
1864  i&PU_POTION ? 1 : 0);
1865 
1867  "%d SPELLBOOK",
1868  i&PU_SPELLBOOK ? 1 : 0);
1870  "%d SKILLSCROLL",
1871  i&PU_SKILLSCROLL ? 1 : 0);
1873  "%d READABLES",
1874  i&PU_READABLES ? 1 : 0);
1876  "%d MAGICDEVICE",
1877  i&PU_MAGIC_DEVICE ? 1 : 0);
1878 
1880  "%d NOT CURSED",
1881  i&PU_NOT_CURSED ? 1 : 0);
1882 
1884  "%d JEWELS",
1885  i&PU_JEWELS ? 1 : 0);
1886 
1888  "%d FLESH",
1889  i&PU_FLESH ? 1 : 0);
1890 
1892  "%d CONTAINER",
1893  i&PU_CONTAINER ? 1 : 0);
1894 
1896  "");
1897 }
1898 
1908 void command_pickup(object *op, const char *params) {
1909  uint32_t i;
1910  static const char *names[] = {
1911  "debug", "inhibit", "stop", "food", "drink",
1912  "valuables", "bow", "arrow", "helmet", "shield",
1913  "armour", "boots", "gloves", "cloak", "key",
1914  "missile", "melee", "magical", "potion", "spellbook",
1915  "skillscroll", "readables", "magicdevice", "notcursed", "jewels",
1916  "flesh", "container", NULL
1917  };
1918  static const uint32_t modes[] = {
1923  };
1924 
1925  if (*params == '\0') {
1926  /* if the new mode is used, just print the settings */
1927  if (op->contr->mode&PU_NEWMODE) {
1928  display_new_pickup(op, op->contr->mode);
1929  return;
1930  }
1931  if (1)
1932  LOG(llevDebug, "command_pickup: !params\n");
1933  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
1934  return;
1935  }
1936 
1937  while (*params == ' ')
1938  params++;
1939 
1940  if (*params == '+' || *params == '-' || *params == '!') {
1941  int mode;
1942 
1943  for (mode = 0; names[mode]; mode++) {
1944  if (!strcmp(names[mode], params+1)) {
1945  int old = op->contr->mode;
1946  i = op->contr->mode;
1947  if (!(i&PU_NEWMODE))
1948  i = PU_NEWMODE;
1949  if (*params == '+')
1950  i = i|modes[mode];
1951  else if (*params == '-')
1952  i = i&~modes[mode];
1953  else {
1954  if (i&modes[mode])
1955  i = i&~modes[mode];
1956  else
1957  i = i|modes[mode];
1958  }
1959  op->contr->mode = i;
1960  display_new_pickup(op, old);
1961  return;
1962  }
1963  }
1965  "Pickup: invalid item %s\n",
1966  params);
1967  return;
1968  }
1969 
1970  if (sscanf(params, "%u", &i) != 1) {
1971  if (1)
1972  LOG(llevDebug, "command_pickup: params==NULL\n");
1974  "Usage: pickup <0-7> or <value_density> .");
1975  return;
1976  }
1977  set_pickup_mode(op, i);
1978  display_new_pickup(op, op->contr->mode);
1979 }
1980 
1989 static void set_pickup_mode(const object *op, int i) {
1990  op->contr->mode = i;
1991  switch (op->contr->mode) {
1992  case 0:
1994  "Mode: Don't pick up.");
1995  break;
1996 
1997  case 1:
1999  "Mode: Pick up one item.");
2000  break;
2001 
2002  case 2:
2004  "Mode: Pick up one item and stop.");
2005  break;
2006 
2007  case 3:
2009  "Mode: Stop before picking up.");
2010  break;
2011 
2012  case 4:
2014  "Mode: Pick up all items.");
2015  break;
2016 
2017  case 5:
2019  "Mode: Pick up all items and stop.");
2020  break;
2021 
2022  case 6:
2024  "Mode: Pick up all magic items.");
2025  break;
2026 
2027  case 7:
2029  "Mode: Pick up all coins and gems");
2030  break;
2031  }
2032 }
2033 
2042 void command_search_items(object *op, const char *params) {
2043  if (settings.search_items == FALSE)
2044  return;
2045 
2046  if (*params == '\0') {
2047  if (op->contr->search_str[0] == '\0') {
2049  "Example: search magic+1 "
2050  "Would automatically pick up all "
2051  "items containing the word 'magic+1'.");
2052  return;
2053  }
2054  op->contr->search_str[0] = '\0';
2056  "Search mode turned off.");
2057  fix_object(op);
2058  return;
2059  }
2060  if ((int)strlen(params) >= MAX_BUF) {
2062  "Search string too long.");
2063  return;
2064  }
2065  strcpy(op->contr->search_str, params);
2067  "Searching for '%s'.",
2068  op->contr->search_str);
2069  fix_object(op);
2070 }
2071 
2087 void command_rename_item(object *op, const char *params) {
2088  char buf[VERY_BIG_BUF], name[MAX_BUF];
2089  tag_t itemnumber;
2090  object *item = NULL;
2091  object *tmp;
2092  char *closebrace;
2093  size_t counter;
2094 
2095  if (*params != '\0') {
2096  /* Let's skip white spaces */
2097  while (' ' == *params)
2098  params++;
2099 
2100  /* Checking the first part */
2101  itemnumber = atoi(params);
2102  if (itemnumber != 0) {
2103  int found = 0;
2104  FOR_INV_PREPARE(op, item)
2105  if (item->count == itemnumber && !item->invisible) {
2106  found = 1;
2107  break;
2108  }
2109  FOR_INV_FINISH();
2110  if (!found) {
2112  "Tried to rename an invalid item.");
2113  return;
2114  }
2115  while (isdigit(*params) || ' ' == *params)
2116  params++;
2117  } else if ('<' == *params) {
2118  /* Got old name, let's get it & find appropriate matching item */
2119  closebrace = strchr(params, '>');
2120  if (!closebrace) {
2122  "Syntax error!");
2123  return;
2124  }
2125  /* Sanity check for buffer overruns */
2126  if (closebrace-params > 127) {
2128  "Old name too long (up to 127 characters allowed)!");
2129  return;
2130  }
2131  /* Copy the old name */
2132  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2133 
2134  /* Find best matching item */
2135  item = find_best_object_match(op, buf);
2136  if (!item) {
2138  "Could not find a matching item to rename.");
2139  return;
2140  }
2141 
2142  /* Now need to move pointer to just after > */
2143  params = closebrace+1;
2144  while (' ' == *params)
2145  params++;
2146  } else {
2147  /* Use marked item */
2148  item = find_marked_object(op);
2149  if (!item) {
2151  "No marked item to rename.");
2152  return;
2153  }
2154  }
2155 
2156  /* Now let's find the new name */
2157  if (!strncmp(params, "to ", 3)) {
2158  params += 3;
2159  while (' ' == *params)
2160  params++;
2161  if ('<' != *params) {
2163  "Syntax error, expecting < at start of new name!");
2164  return;
2165  }
2166  closebrace = strchr(params+1, '>');
2167  if (!closebrace) {
2169  "Syntax error, expecting > at end of new name!");
2170  return;
2171  }
2172 
2173  /* Sanity check for buffer overruns */
2174  if (closebrace-params > 127) {
2176  "New name too long (up to 127 characters allowed)!");
2177  return;
2178  }
2179 
2180  /* Copy the new name */
2181  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2182 
2183  /* Let's check it for weird characters */
2184  for (counter = 0; counter < strlen(buf); counter++) {
2185  if (isalnum(buf[counter]))
2186  continue;
2187  if (' ' == buf[counter])
2188  continue;
2189  if ('\'' == buf[counter])
2190  continue;
2191  if ('+' == buf[counter])
2192  continue;
2193  if ('_' == buf[counter])
2194  continue;
2195  if ('-' == buf[counter])
2196  continue;
2197 
2198  /* If we come here, then the name contains an invalid character...
2199  * tell the player & exit
2200  */
2202  "Invalid new name!");
2203  return;
2204  }
2205  } else {
2206  /* If param contains something, then syntax error... */
2207  if (strlen(params)) {
2209  "Syntax error, expected 'to <' after old name!");
2210  return;
2211  }
2212  /* New name is empty */
2213  buf[0] = '\0';
2214  }
2215  } else {
2216  /* Last case: *params=='\0' */
2217  item = find_marked_object(op);
2218  if (!item) {
2220  "No marked item to rename.");
2221  return;
2222  }
2223  buf[0] = '\0';
2224  }
2225 
2226  /* Coming here, everything is fine... */
2227  if (!strlen(buf)) {
2228  /* Clear custom name */
2229  if (item->custom_name == NULL) {
2231  "This item has no custom name.");
2232  return;
2233  }
2234 
2236  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2238  "You stop calling your %s with weird names.",
2239  name);
2240  } else {
2241  if (item->custom_name != NULL && strcmp(item->custom_name, buf) == 0) {
2242  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2244  "You keep calling your %s %s.",
2245  name, buf);
2246  return;
2247  }
2248 
2249  /* Set custom name */
2250  FREE_AND_COPY(item->custom_name, buf);
2251 
2252  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2254  "Your %s will now be called %s.",
2255  name, buf);
2256  }
2257 
2258  tmp = object_merge(item, NULL);
2259  if (tmp == NULL) {
2260  /* object was not merged - if it was, object_merge() handles updating for us. */
2261  esrv_update_item(UPD_NAME, op, item);
2262  }
2263 }
2264 
2273 void command_lock_item(object *op, const char *params) {
2274  object *item;
2275  object *tmp;
2276  char name[HUGE_BUF];
2277 
2278  if (*params == '\0' || strlen(params) == 0) {
2280  "Lock what item?");
2281  return;
2282  }
2283 
2284  item = find_best_object_match(op, params);
2285  if (!item) {
2287  "Can't find any matching item.");
2288  return;
2289  }
2290 
2291  query_short_name(item, name, HUGE_BUF);
2292  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2294  "Unlocked %s.", name);
2295  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2296  } else {
2298  "Locked %s.", name);
2299  SET_FLAG(item, FLAG_INV_LOCKED);
2300  }
2301 
2302  tmp = object_merge(item, NULL);
2303  if (tmp == NULL) {
2304  /* object was not merged, if it was object_merge() handles updates for us */
2305  esrv_update_item(UPD_FLAGS, op, item);
2306  }
2307 }
2308 
2316 void command_use(object *op, const char *params) {
2317  char *with, copy[MAX_BUF];
2318  object *first, *second/*, *add*/;
2319  /*archetype *arch;*/
2320  /*int count;*/
2321  /*sstring data;*/
2322  recipe *transformation;
2323 
2324  if (!IS_PLAYER(op))
2325  return;
2326 
2327  strlcpy(copy, params, sizeof(copy));
2328  with = strstr(copy, " with ");
2329  if (!with) {
2330  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2331  return;
2332  }
2333 
2334  with[0] = '\0';
2335  with = with+strlen(" with ");
2336 
2337  first = find_best_object_match(op, copy);
2338  if (!first) {
2339  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2340  return;
2341  }
2342  second = find_best_object_match(op, with);
2343  if (!second) {
2344  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2345  return;
2346  }
2347 
2348  transformation = NULL;
2349  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2351  if (transformation->ingred_count != 1)
2352  continue;
2353 
2354 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2355  if (strcmp(second->name, transformation->ingred->name) == 0) {
2357  object *generated = create_archetype(transformation->arch_name[0]);
2358  if (transformation->yield)
2359  generated->nrof = transformation->yield;
2360  object_insert_in_ob(generated, op);
2361  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2363  return;
2364  }
2365  }
2366  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2367  return;
2368 
2369  /*
2370  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2371  data = object_get_value(second, copy);
2372  if (!data) {
2373  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2374  data = object_get_value(second, copy);
2375  if (!data) {
2376  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2377  data = object_get_value(second, copy);
2378  if (!data) {
2379  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2380  return 1;
2381  }
2382  }
2383  }
2384 
2385  while (data != NULL) {
2386  if (strncmp(data, "add ", 4) == 0) {
2387  data += 4;
2388  if (isdigit(*data)) {
2389  count = atol(data);
2390  data = strchr(data, ' ')+1;
2391  } else
2392  count = 1;
2393  with = strchr(data, ' ');
2394  if (!with) {
2395  strncpy(copy, data, sizeof(copy));
2396  data = NULL;
2397  } else {
2398  *with = '\0';
2399  strncpy(copy, data, sizeof(copy));
2400  data += strlen(copy)+1;
2401  }
2402  arch = find_archetype(copy);
2403  if (!arch) {
2404  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2405  return 1;
2406  }
2407  add = object_create_arch(arch);
2408  add->nrof = count;
2409  object_insert_in_ob(add, op);
2410  } else if (strncmp(data, "remove $", 8) == 0) {
2411  data += 8;
2412  if (*data == '1') {
2413  if (first)
2414  first = object_decrease_nrof_by_one(first);
2415  data += 2;
2416  } else if (*data == '2') {
2417  if (second)
2418  second = object_decrease_nrof_by_one(second);
2419  data += 2;
2420  } else {
2421  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2422  return 1;
2423  }
2424  } else {
2425  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2426  return 1;
2427  }
2428  }
2429 
2430  return 1;
2431  */
2432 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:316
#define AP_UNAPPLY
Definition: define.h:613
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.c:4018
char path[HUGE_BUF]
Definition: map.h:365
void apply_by_living_below(object *pl)
Definition: apply.c:614
void sell_item(object *op, object *pl)
Definition: shop.c:953
static object * find_best_object_match(object *pl, const char *params)
Definition: c_object.c:86
#define FLAG_NO_DROP
Definition: define.h:289
#define NUM_BODY_LOCATIONS
Definition: object.h:13
Definition: player.h:92
int apply_special(object *who, object *op, int aflags)
Definition: apply.c:1078
#define FLAG_IS_FLOOR
Definition: define.h:303
#define FLAG_UNPAID
Definition: define.h:236
static void do_skill_by_number(object *op, int skill_subtype, const char *params, const char *missing_message)
Definition: c_object.c:142
int32_t weight_limit
Definition: object.h:367
#define MSG_TYPE_COMMAND_INVENTORY
Definition: newclient.h:513
#define FLAG_IS_LINKED
Definition: define.h:316
MoveType move_type
Definition: object.h:426
#define INS_BELOW_ORIGINATOR
Definition: object.h:572
int change_skill(object *who, object *new_skill, int flag)
Definition: skill_util.c:340
void command_search_items(object *op, const char *params)
Definition: c_object.c:2042
Definition: object.h:127
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.c:688
void pick_up(object *op, object *alt)
Definition: c_object.c:456
MoveType move_on
Definition: object.h:429
Definition: object.h:185
bool shop_contains(object *ob)
Definition: shop.c:1271
uint8_t max_stat
Definition: global.h:327
const char * race
Definition: object.h:318
#define PU_CONTAINER
Definition: define.h:143
#define SET_FLAG(xyz, p)
Definition: define.h:223
#define PU_DEBUG
Definition: define.h:108
Definition: object.h:221
int identifyskill
Definition: define.h:93
void command_lock_item(object *op, const char *params)
Definition: c_object.c:2273
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:511
void get_levelnumber(int i, char *buf, size_t size)
Definition: item.c:447
void command_take(object *op, const char *params)
Definition: c_object.c:595
Definition: object.h:204
Definition: object.h:112
struct obj * container
Definition: object.h:291
#define PU_STOP
Definition: define.h:110
Definition: object.h:117
#define PU_SHIELD
Definition: define.h:122
int yield
Definition: recipe.h:21
object * mon
Definition: comet_perf.c:74
int identify_object_with_skill(object *tmp, object *pl, object *skill, int print_on_success)
Definition: skills.c:797
#define FLAG_NO_FIX_PLAYER
Definition: define.h:277
#define LOOK_OBJ(ob)
Definition: object.h:507
int save_player(object *op, int flag)
Definition: login.c:212
void inventory(object *op, object *inv)
Definition: c_object.c:1718
void free_string(sstring str)
Definition: shstr.c:280
#define PU_KEY
Definition: define.h:128
#define HUGE_BUF
Definition: define.h:37
#define MSG_TYPE_COMMAND_EXAMINE
Definition: newclient.h:512
void esrv_update_item(int flags, object *pl, object *op)
Definition: main.c:343
Definition: object.h:137
static uint32_t NROF(const object *const ob)
Definition: object.h:612
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:720
socket_struct socket
Definition: player.h:94
linked_char * ingred
Definition: recipe.h:22
int16_t invisible
Definition: object.h:361
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Definition: recipe.c:832
void command_throw(object *op, const char *params)
Definition: c_object.c:193
void query_weight(const object *op, char *buf, size_t size)
Definition: item.c:427
Definition: object.h:119
Definition: object.h:136
const char * slaying
Definition: object.h:319
#define MSG_TYPE_SKILL_MISSING
Definition: newclient.h:582
Definition: object.h:109
uint32_t mark_count
Definition: player.h:193
struct obj * above
Definition: object.h:288
Definition: object.h:157
#define object_was_destroyed(op, old_tag)
Definition: object.h:68
Definition: object.h:223
#define PU_FLESH
Definition: define.h:142
#define PU_FOOD
Definition: define.h:115
body_locations_struct body_locations[NUM_BODY_LOCATIONS]
Definition: item.c:54
object * stop_item(object *op)
Definition: time.c:450
Definition: object.h:139
#define FALSE
Definition: compat.h:11
uint32_t get_weight_limit(int stat)
Definition: living.c:2355
Definition: object.h:187
static void pick_up_object(object *pl, object *op, object *tmp, int nrof)
Definition: c_object.c:325
Definition: object.h:212
#define SCRIPT_FIX_ALL
Definition: global.h:367
#define AP_APPLY
Definition: define.h:612
#define PU_NEWMODE
Definition: define.h:111
void command_dropall(object *op, const char *params)
Definition: c_object.c:982
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:311
void command_rskill(object *pl, const char *params)
Definition: c_object.c:115
#define PU_MISSILEWEAPON
Definition: define.h:130
Definition: object.h:220
#define FOR_OB_AND_BELOW_FINISH()
Definition: define.h:791
#define PU_CLOAK
Definition: define.h:127
#define MIN(x, y)
Definition: compat.h:17
void command_empty(object *op, const char *params)
Definition: c_object.c:1196
#define FLAG_REMOVED
Definition: define.h:232
int16_t hp
Definition: living.h:40
void command_rename_item(object *op, const char *params)
Definition: c_object.c:2087
int ingred_count
Definition: recipe.h:23
const typedata * get_typedata(int itemtype)
Definition: item.c:335
#define FLAG_UNDEAD
Definition: define.h:270
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Definition: spell_effect.c:684
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Definition: knowledge.c:1339
uint32_t update_look
Definition: newserver.h:104
void object_free_drop_inventory(object *ob)
Definition: object.c:1389
int16_t y
Definition: object.h:326
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1933
void command_examine(object *op, const char *params)
Definition: c_object.c:1235
int16_t maxhp
Definition: living.h:41
#define MSG_TYPE_COMMAND
Definition: newclient.h:379
#define PU_BOOTS
Definition: define.h:125
Definition: object.h:118
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Definition: apply.c:553
void examine(object *op, object *tmp)
Definition: c_object.c:1448
void command_search(object *op, const char *params)
Definition: c_object.c:166
Definition: object.h:114
Definition: object.h:181
object * create_archetype(const char *name)
Definition: arch.c:620
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Definition: skills.c:696
char ** arch_name
Definition: recipe.h:13
uint64_t shop_price_buy(const object *obj, object *who)
Definition: shop.c:193
int object_can_pick(const object *who, const object *item)
Definition: object.c:3809
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2707
char * cost_approx_str(const object *obj, object *who)
Definition: shop.c:425
#define MSG_TYPE_COMMAND_SUCCESS
Definition: newclient.h:510
#define MSG_TYPE_COMMAND_ERROR
Definition: newclient.h:509
#define PU_SKILLSCROLL
Definition: define.h:136
signed short int16_t
Definition: win32.h:160
uint8_t search_items
Definition: global.h:269
const char * materialname
Definition: object.h:347
int32_t weight
Definition: object.h:366
static bool IS_PLAYER(object *op)
Definition: object.h:596
#define PU_ARROW
Definition: define.h:120
struct mapdef * map
Definition: object.h:297
char search_str[MAX_BUF]
Definition: player.h:192
#define snprintf
Definition: win32.h:46
#define FLAG_IDENTIFIED
Definition: define.h:261
#define FOR_INV_FINISH()
Definition: define.h:714
#define MOVE_FLYING
Definition: define.h:410
void command_drop(object *op, const char *params)
Definition: c_object.c:1106
#define FLAG_PROBE
Definition: define.h:257
int32_t carrying
Definition: object.h:368
const char * name
Definition: object.h:311
#define PU_INHIBIT
Definition: define.h:109
struct obj * env
Definition: object.h:293
#define EVENT_PICKUP
Definition: plugin.h:69
#define PU_BOW
Definition: define.h:118
#define AP_NULL
Definition: define.h:611
struct obj * below
Definition: object.h:287
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.c:3017
#define PU_RATIO
Definition: define.h:113
char * cost_str(uint64_t cost)
Definition: shop.c:421
uint32_t nrof
Definition: object.h:333
#define UPD_FLAGS
Definition: newclient.h:290
void command_apply(object *op, const char *params)
Definition: c_object.c:205
#define FLAG_IS_CAULDRON
Definition: define.h:339
MoveType move_off
Definition: object.h:430
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.c:412
uint8_t real_wiz
Definition: global.h:273
Definition: object.h:111
struct pl * contr
Definition: object.h:276
#define PU_DRINK
Definition: define.h:116
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
Definition: object.c:2200
static void empty_container(object *container, object *pl)
Definition: c_object.c:1158
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:206
#define UPD_WEIGHT
Definition: newclient.h:291
uint32_t tag_t
Definition: object.h:12
void knowledge_show_monster_detail(object *op, const char *name)
Definition: knowledge.c:1533
static void set_pickup_mode(const object *op, int i)
Definition: c_object.c:1989
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define HEAD(op)
Definition: object.h:594
#define FLAG_WIZ
Definition: define.h:231
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Definition: living.c:2162
#define MAX_BUF
Definition: define.h:35
char * ob_describe(const object *op, const object *observer, char *buf, size_t size)
Definition: ob_methods.c:91
#define PU_READABLES
Definition: define.h:137
int16_t x
Definition: object.h:326
int strncasecmp(const char *s1, const char *s2, int n)
Definition: porting.c:224
const char * skill
Definition: object.h:321
uint64_t shop_price_sell(const object *obj, object *who)
Definition: shop.c:251
#define EVENT_DROP
Definition: plugin.h:68
int identifyskill2
Definition: define.h:94
int8_t Str
Definition: living.h:36
void command_pickup(object *op, const char *params)
Definition: c_object.c:1908
int need_identify(const object *op)
Definition: item.c:1326
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
#define AP_NO_MERGE
Definition: define.h:618
int set_object_face_main(object *op)
Definition: apply.c:149
Definition: object.h:135
const char * name
Definition: global.h:87
#define PU_MELEEWEAPON
Definition: define.h:131
int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof)
Definition: c_object.c:267
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:374
uint32_t attacktype
Definition: object.h:343
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2478
#define INS_NO_MERGE
Definition: object.h:568
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Definition: skills.c:745
#define object_decrease_nrof_by_one(xyz)
Definition: compat.h:28
#define VERY_BIG_BUF
Definition: define.h:36
#define FREE_AND_COPY(sv, nv)
Definition: global.h:211
Definition: object.h:243
const char * custom_name
Definition: object.h:434
int get_button_value(const object *button)
Definition: button.c:754
void command_use(object *op, const char *params)
Definition: c_object.c:2316
tag_t count
Definition: object.h:299
living stats
Definition: object.h:369
struct archt * arch
Definition: object.h:414
#define FLAG_IS_BUILDABLE
Definition: define.h:376
uint8_t type
Definition: object.h:339
uint32_t mode
Definition: player.h:110
struct Settings settings
Definition: init.c:39
static void display_new_pickup(const object *op, int old)
Definition: c_object.c:1783
#define MSG_TYPE_COMMAND_INFO
Definition: newclient.h:506
int transport_can_hold(const object *transport, const object *op, int nrof)
Definition: apply.c:54
#define FLAG_APPLIED
Definition: define.h:235
object * object_merge(object *op, object *top)
Definition: object.c:1881
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:548
#define PU_SPELLBOOK
Definition: define.h:135
object * object_get_player_container(object *op)
Definition: object.c:384
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: main.c:365
signed int int32_t
Definition: win32.h:159
#define UPD_NAME
Definition: newclient.h:293
const char * msg
Definition: object.h:322
int object_matches_string(object *pl, object *op, const char *name)
Definition: object.c:4472
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:787
#define FLAG_STARTEQUIP
Definition: define.h:268
void command_disarm(object *op, const char *params)
Definition: c_object.c:178
#define FORCE_NAME
Definition: spells.h:169
#define PU_VALUABLES
Definition: define.h:117
#define PU_MAGICAL
Definition: define.h:132
sstring add_string(const char *str)
Definition: shstr.c:124
#define PU_JEWELS
Definition: define.h:141
#define FLAG_MONSTER
Definition: define.h:245
void esrv_send_pickup(player *pl)
Definition: request.c:1653
#define MSG_TYPE_SKILL
Definition: newclient.h:383
struct obj * inv
Definition: object.h:290
#define NDI_UNIQUE
Definition: newclient.h:245
Definition: object.h:213
static object * find_best_apply_object_match(object *start, object *pl, const char *params, int aflag)
Definition: c_object.c:55
void LOG(LogLevel logLevel, const char *format,...)
Definition: logger.c:51
#define PU_GLOVES
Definition: define.h:126
object * mark
Definition: player.h:194
#define FLAG_WAS_WIZ
Definition: define.h:234
object * find_marked_object(object *op)
Definition: c_object.c:1266
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:623
#define PU_ARMOUR
Definition: define.h:123
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.c:824
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:741
#define SK_SUBTRACT_SKILL_EXP
Definition: skills.h:81
object * find_skill_by_number(object *who, int skillno)
Definition: main.c:352
Definition: map.h:325
int use_skill(object *op, const char *string)
Definition: skill_util.c:943
Definition: object.h:167
#define FLAG_NO_PICK
Definition: define.h:239
#define PU_POTION
Definition: define.h:133
#define FLAG_NO_SKILL_IDENT
Definition: define.h:336
Definition: object.h:120
#define PU_HELMET
Definition: define.h:121
int16_t level
Definition: object.h:352
int8_t facing
Definition: object.h:336
#define AT_ACID
Definition: attack.h:82
void command_uskill(object *pl, const char *params)
Definition: c_object.c:98
#define FLAG_INV_LOCKED
Definition: define.h:330
void fix_object(object *op)
Definition: living.c:1120
#define PU_NOT_CURSED
Definition: define.h:140
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:192
int32_t value
Definition: object.h:351
const char * name
Definition: object.h:468
size_t strlcpy(char *dst, const char *src, size_t size)
Definition: porting.c:366
#define FOR_BELOW_FINISH()
Definition: define.h:748
void command_mark(object *op, const char *params)
Definition: c_object.c:1313
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:707
void object_remove(object *op)
Definition: object.c:1666
void examine_monster(object *op, object *tmp, int level)
Definition: c_object.c:1360
#define PU_MAGIC_DEVICE
Definition: define.h:138
int32_t food
Definition: living.h:48
#define FLAG_FREED
Definition: define.h:233
uint32_t count
Definition: player.h:109
Definition: object.h:224
void drop(object *op, object *tmp)
Definition: c_object.c:920