Crossfire Server, Trunk  R20911
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 
134 
135 /* These functions (command_search, command_disarm) are really juse wrappers for
136  * things like 'use_skill ...'). In fact, they should really be obsoleted
137  * and replaced with those.
138  */
147 void command_search(object *op, const char *params) {
149 }
150 
159 void command_disarm(object *op, const char *params) {
161 }
162 
174 void command_throw(object *op, const char *params) {
175  object *skop;
176 
178  if (skop) {
179  do_skill(op, op, skop, op->facing, *params == '\0' ? NULL : params);
180  return;
181  }
182 
184  "You have no knowledge of the skill throwing.");
185 }
186 
195 void command_apply(object *op, const char *params) {
196  int aflag = 0;
197  object *inv = op->inv;
198  object *item;
199 
200  if (*params == '\0') {
202  return;
203  }
204 
205  while (*params == ' ')
206  params++;
207  if (!strncmp(params, "-a ", 3)) {
208  aflag = AP_APPLY;
209  params += 3;
210  }
211  if (!strncmp(params, "-u ", 3)) {
212  aflag = AP_UNAPPLY;
213  params += 3;
214  }
215  if (!strncmp(params, "-b ", 3)) {
216  params += 3;
217  if (op->container)
218  inv = op->container->inv;
219  else {
220  inv = op;
221  while (inv->above)
222  inv = inv->above;
223  }
224  }
225  while (*params == ' ')
226  params++;
227 
228  item = find_best_apply_object_match(inv, op, params, aflag);
229  if (item == NULL)
230  item = find_best_apply_object_match(inv, op, params, AP_NULL);
231  if (item) {
232  apply_by_living(op, item, aflag, 0);
233  } else
235  "Could not find any match to the %s.",
236  params);
237 }
238 
257 int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof) {
258  char name[MAX_BUF];
259  query_name(sack, name, MAX_BUF);
260 
261  if (!QUERY_FLAG(sack, FLAG_APPLIED)) {
263  "The %s is not active.",
264  name);
265  return 0;
266  }
267  if (sack == op) {
269  "You can't put the %s into itself.",
270  name);
271  return 0;
272  }
273  if (sack->race
274  && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type))) {
276  "You can put only %s into the %s.",
277  sack->race, name);
278  return 0;
279  }
280  if (op->type == SPECIAL_KEY && sack->slaying && op->slaying) {
282  "You can't put the key into %s.",
283  name);
284  return 0;
285  }
286  if (sack->weight_limit) {
287  int32_t new_weight;
288 
289  new_weight = sack->carrying+(nrof ? nrof : 1)
290  *(op->weight+(op->type == CONTAINER ? op->carrying*op->stats.Str : 0))
291  *(100-sack->stats.Str)/100;
292  if (new_weight > sack->weight_limit) {
294  "That won't fit in the %s!",
295  name);
296  return 0;
297  }
298  }
299  /* All other checks pass, must be OK */
300  return 1;
301 }
302 
315 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
316  /* buf needs to be big (more than 256 chars) because you can get
317  * very long item names.
318  */
319  char buf[HUGE_BUF], name[MAX_BUF];
320  object *env = tmp->env;
321  uint32_t weight, effective_weight_limit;
322  int tmp_nrof = tmp->nrof ? tmp->nrof : 1;
323  tag_t tag;
324  mapstruct* map = tmp->map;
325  int16_t x = tmp->x, y = tmp->y;
326 
327  /* IF the player is flying & trying to take the item out of a container
328  * that is in his inventory, let him. tmp->env points to the container
329  * (sack, luggage, etc), tmp->env->env then points to the player (nested
330  * containers not allowed as of now)
331  */
332  if ((pl->move_type&MOVE_FLYING)
333  && !QUERY_FLAG(pl, FLAG_WIZ)
334  && object_get_player_container(tmp) != pl) {
336  "You are levitating, you can't reach the ground!");
337  return;
338  }
339  if (QUERY_FLAG(tmp, FLAG_NO_DROP))
340  return;
341 
342  if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
344  "The object disappears in a puff of smoke! It must have been an illusion.");
345  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
346  object_remove(tmp);
348  return;
349  }
350 
351  if (nrof > tmp_nrof || nrof == 0)
352  nrof = tmp_nrof;
353 
354  /* Figure out how much weight this object will add to the player */
355  weight = tmp->weight*nrof;
356  if (tmp->inv)
357  weight += tmp->carrying*(100-tmp->stats.Str)/100;
358 
359  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
360 
361  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
363  "That item is too heavy for you to pick up.");
364  return;
365  }
366 
368  SET_FLAG(tmp, FLAG_WAS_WIZ);
369 
370  if (nrof != tmp_nrof) {
371  char failure[MAX_BUF];
372 
373  tmp = object_split(tmp, nrof, failure, sizeof(failure));
374  if (!tmp) {
376  failure);
377  return;
378  }
379  } else {
380  /* If the object is in a container, send a delete to the client.
381  * - we are moving all the items from the container to elsewhere,
382  * so it needs to be deleted.
383  */
384  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
385  object_remove(tmp); /* Unlink it */
386  }
387  }
388  query_name(tmp, name, MAX_BUF);
389 
390  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
391  char *value = cost_str(shop_price_buy(tmp, pl));
392  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
393  free(value);
394  } else
395  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
396 
397  /* Now item is about to be picked. */
398  tag = tmp->count;
399  if (execute_event(tmp, EVENT_PICKUP, pl, op, NULL, SCRIPT_FIX_ALL) != 0) {
400  /* put item back, if it still exists */
401  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
402  if (env != NULL) {
403  object_insert_in_ob(tmp, env);
404  } else {
405  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
406  }
407  }
408  return;
409  }
410 
412  buf);
413 
414  tmp = object_insert_in_ob(tmp, op);
415 
416  /* All the stuff below deals with client/server code, and is only
417  * usable by players
418  */
419  if (pl->type != PLAYER)
420  return;
421 
422  /* Additional weight changes speed, etc */
423  fix_object(pl);
424 
425  /* These are needed to update the weight for the container we
426  * are putting the object in.
427  */
428  if (op != pl) {
429  esrv_update_item(UPD_WEIGHT, pl, op);
430  esrv_update_item(UPD_WEIGHT, pl, pl);
431  }
432 
433  /* Update the container the object was in */
434  if (env && env != pl && env != op)
435  esrv_update_item(UPD_WEIGHT, pl, env);
436 }
437 
446 void pick_up(object *op, object *alt) {
447 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
448  object *tmp = NULL, *tmp1;
449  mapstruct *tmp_map = NULL;
450  int count;
451 
452  /* Decide which object to pick. */
453  if (alt) {
454  if (!object_can_pick(op, alt)) {
456  "You can't pick up the %s.",
457  alt->name);
458  return;
459  }
460  tmp = alt;
461  } else {
462  if (op->below == NULL || !object_can_pick(op, op->below)) {
464  "There is nothing to pick up here.");
465  return;
466  }
467  tmp = op->below;
468  }
469 
470  /* it is possible that the object is a thrown object and is flying about.
471  * in that case, what we want to pick up is the payload. Objects
472  * that are thrown are encapsulated into a thrown object.
473  * stop_item() returns the payload (unlinked from map) and gets rid of the
474  * container object. If this object isn't picked up, we need to insert
475  * it back on the map.
476  * A bug here is that even attempting to pick up one of these objects will
477  * result in this logic being called even if player is unable to pick it
478  * up.
479  */
480 
481  tmp_map = tmp->map;
482  tmp1 = stop_item(tmp);
483  if (tmp1 == NULL)
484  return;
485 
486  /* If it is a thrown object, insert it back into the map here.
487  * makes life easier further along. Do no merge so pick up code
488  * behaves more sanely.
489  */
490  if (tmp1 != tmp) {
491  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
492  }
493 
494  if (tmp == NULL)
495  return;
496 
497  if (!object_can_pick(op, tmp))
498  return;
499 
500  /* Establish how many of the object we are picking up */
501  if (op->type == PLAYER) {
502  count = op->contr->count;
503  if (count == 0)
504  count = tmp->nrof;
505  } else
506  count = tmp->nrof;
507 
508  /* container is open, so use it */
509  if (op->container) {
510  alt = op->container;
511  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
512  return;
513  } else {
514  /* non container pickup. See if player has any
515  * active containers.
516  */
517  object *container = NULL;
518 
519  /* Look for any active containers that can hold this item.
520  * we cover two cases here - the perfect match case, where we
521  * break out of the loop, and the general case (have a container),
522  * Moved this into a single loop - reduces redundant code, is
523  * more efficient and easier to follow. MSW 2009-04-06
524  */
525  alt = op->inv;
527  if (alt->type == CONTAINER
528  && QUERY_FLAG(alt, FLAG_APPLIED)
529  && sack_can_hold(NULL, alt, tmp, count)) {
530  if (alt->race && alt->race == tmp->race) {
531  break; /* perfect match */
532  } else if (!container) {
533  container = alt;
534  }
535  }
537  /* Note container could be null, but no reason to check for it */
538  if (!alt)
539  alt = container;
540 
541  if (!alt)
542  alt = op; /* No free containers */
543  }
544  /* see if this object is already in this container. If so,
545  * move it to player inventory from this container.
546  */
547  if (tmp->env == alt) {
548  alt = op;
549  }
550 
551  /* Don't allow players to be put into containers. Instead,
552  * just put them in the players inventory.
553  */
554  if (tmp->type == CONTAINER && alt->type==CONTAINER) {
555  alt = op;
556  }
557 #ifdef PICKUP_DEBUG
558  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
559 #endif
560 
561  /* startequip items are not allowed to be put into containers
562  * Not sure why we have this limitation
563  */
564  if (op->type == PLAYER
565  && alt->type == CONTAINER
566  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
568  "This object cannot be put into containers!");
569  return;
570  }
571 
572  pick_up_object(op, alt, tmp, count);
573  if (op->type == PLAYER)
574  op->contr->count = 0;
575 }
576 
585 void command_take(object *op, const char *params) {
586  object *tmp;
587  int ival;
588  int missed = 0;
589 
590  if (op->container)
591  tmp = op->container->inv;
592  else {
593  tmp = op->above;
594  if (tmp)
595  while (tmp->above) {
596  tmp = tmp->above;
597  }
598  if (!tmp)
599  tmp = op->below;
600  }
601 
602  if (tmp == NULL) {
604  "Nothing to take!");
605  return;
606  }
607 
608  /* Makes processing easier */
609  if (*params == '\0')
610  params = NULL;
611 
613  if (tmp->invisible) {
614  continue;
615  }
616  /* This following two if and else if could be merged into line
617  * but that probably will make it more difficult to read, and
618  * not make it any more efficient
619  */
620  if (params) {
621  ival = object_matches_string(op, tmp, params);
622  if (ival > 0) {
623  if (ival <= 2 && !object_can_pick(op, tmp)) {
624  if (!QUERY_FLAG(tmp, FLAG_IS_FLOOR))/* don't count floor tiles */
625  missed++;
626  } else
627  pick_up(op, tmp);
628  }
629  } else {
630  if (object_can_pick(op, tmp)) {
631  pick_up(op, tmp);
632  break;
633  }
634  }
636  if (!params && !tmp) {
637  int found = 0;
638  FOR_BELOW_PREPARE(op, tmp)
639  if (!tmp->invisible) {
641  "You can't pick up a %s.",
642  tmp->name ? tmp->name : "null");
643  found = 1;
644  break;
645  }
647  if (!found)
649  "There is nothing to pick up.");
650  }
651  if (missed == 1)
653  "You were unable to take one of the items.");
654  else if (missed > 1)
656  "You were unable to take %d of the items.",
657  missed);
658 }
659 
678 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
679  object *sack2, *orig = sack;
680  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
681 
682  if (sack == tmp)
683  return; /* Can't put an object in itself */
684  query_name(sack, name_sack, MAX_BUF);
685  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
687  "The %s is not a container.",
688  name_sack);
689  return;
690  }
691  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
692  query_name(tmp, name_tmp, MAX_BUF);
694  "You cannot put the %s in the %s.",
695  name_tmp, name_sack);
696  return;
697  }
698  if (tmp->type == CONTAINER) {
699  if (tmp->inv) {
700  if (tmp->slaying)
701  return;
702  /* Eneq(@csd.uu.se): If the object to be dropped is a container
703  * and does not require a key to be opened,
704  * we instead move the contents of that container into the active
705  * container, this is only done if the object has something in it.
706  * If object is container but need a key, just don't do anything
707  */
708  sack2 = tmp;
709  query_name(tmp, name_tmp, MAX_BUF);
711  "You move the items from %s into %s.",
712  name_tmp, name_sack);
713 
714  FOR_INV_PREPARE(tmp, tmp2) {
715  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
716  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
717  put_object_in_sack(op, sack, tmp2, 0);
718  } else {
721  "Your %s fills up.",
722  name_sack);
723  break;
724  }
725  } FOR_INV_FINISH();
726  esrv_update_item(UPD_WEIGHT, op, sack2);
727  return;
728  } else {
729  query_name(tmp, name_tmp, MAX_BUF);
731  "You can not put a %s into a %s",
732  name_tmp,
733  name_sack);
734  return;
735  }
736  }
737 
738  /* Don't worry about this for containers - our caller should have
739  * already checked this.
740  */
741  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
742  return;
743 
744  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
745  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
746  return;
747  }
748 
749  /* we want to put some portion of the item into the container */
750  if (nrof && tmp->nrof != nrof) {
751  char failure[MAX_BUF];
752 
753  tmp = object_split(tmp, nrof, failure, sizeof(failure));
754 
755  if (!tmp) {
757  failure);
758  return;
759  }
760  } else
761  object_remove(tmp);
762 
763  if (sack->nrof > 1) {
764  orig = object_split(sack, sack->nrof-1, NULL, 0);
765  set_object_face_main(orig);
766  CLEAR_FLAG(orig, FLAG_APPLIED);
767  if (sack->env) {
768  object_insert_in_ob(orig, sack->env);
769  } else {
770  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
771  orig->move_off = 0;
772  }
773  }
774 
775  query_name(tmp, name_tmp, MAX_BUF);
777  "You put the %s in %s.",
778  name_tmp, name_sack);
779 
780  object_insert_in_ob(tmp, sack);
781  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
782  fix_object(op); /* This is overkill, fix_player() is called somewhere */
783  /* in object.c */
784 
785  /* If a transport, need to update all the players in the transport
786  * the view of what is in it.
787  */
788  if (sack->type == TRANSPORT) {
789  FOR_INV_PREPARE(sack, tmp)
790  if (tmp->type == PLAYER)
791  tmp->contr->socket.update_look = 1;
792  FOR_INV_FINISH();
793  } else {
794  /* update the sacks weight */
795  esrv_update_item(UPD_WEIGHT, op, sack);
796  }
797 }
798 
814 object *drop_object(object *op, object *tmp, uint32_t nrof) {
815  tag_t tmp_tag;
816 
817  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
818  return NULL;
819  }
820 
821  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
822  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
823  return NULL; /* can't unapply it */
824  }
825 
826  /* Lauwenmark: Handle for plugin drop event */
827  if (execute_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
828  return NULL;
829 
830  /* ensure the plugin didn't destroy the object */
831  if (QUERY_FLAG(tmp, FLAG_REMOVED))
832  return NULL;
833 
834  /* We are only dropping some of the items. We split the current objec
835  * off
836  */
837  if (nrof && tmp->nrof != nrof) {
838  char failure[MAX_BUF];
839 
840  tmp = object_split(tmp, nrof, failure, sizeof(failure));
841  if (!tmp) {
843  failure);
844  return NULL;
845  }
846  } else
847  object_remove(tmp);
848 
849  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
850  char name[MAX_BUF];
851 
852  query_name(tmp, name, MAX_BUF);
854  "You drop the %s. The gods who lent it to you retrieve it.",
855  name);
857 
858  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
859  fix_object(op);
860 
861  return NULL;
862  }
863 
864  /* If SAVE_INTERVAL is commented out, we never want to save
865  * the player here.
866  */
867 #ifdef SAVE_INTERVAL
868  /* I'm not sure why there is a value check - since the save
869  * is done every SAVE_INTERVAL seconds, why care the value
870  * of what he is dropping?
871  */
872  if (op->type == PLAYER
873  && !QUERY_FLAG(tmp, FLAG_UNPAID)
874  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
875  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
876  save_player(op, 1);
877  op->contr->last_save_time = time(NULL);
878  }
879 #endif /* SAVE_INTERVAL */
880 
881 
882  tmp_tag = tmp->count;
883  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
884  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
885  sell_item(tmp, op);
886  }
887 
888  /* Call this before we update the various windows/players. At least
889  * that we, we know the weight is correct.
890  */
891  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
892  fix_object(op); /* This is overkill, fix_player() is called somewhere */
893  /* in object.c */
894 
895  /* Need to update weight of player */
896  if (op->type == PLAYER)
897  esrv_update_item(UPD_WEIGHT, op, op);
898  }
899  return tmp;
900 }
901 
910 void drop(object *op, object *tmp) {
911  /* Hopeful fix for disappearing objects when dropping from a container -
912  * somehow, players get an invisible object in the container, and the
913  * old logic would skip over invisible objects - works fine for the
914  * playes inventory, but drop inventory wants to use the next value.
915  */
916  if (tmp->invisible) {
917  /* if the following is the case, it must be in an container. */
918  if (tmp->env && tmp->env->type != PLAYER) {
919  /* Just toss the object - probably shouldn't be hanging
920  * around anyways
921  */
922  object_remove(tmp);
924  return;
925  } else {
927  if (!tmp->invisible)
928  break;
930  }
931  }
932 
933  if (tmp == NULL) {
935  "You don't have anything to drop.");
936  return;
937  }
938  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
940  "This item is locked");
941  return;
942  }
943  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
944  return;
945  }
946 
947  if (op->container) {
948  if (op->type == PLAYER) {
949  put_object_in_sack(op, op->container, tmp, op->contr->count);
950  } else {
951  put_object_in_sack(op, op->container, tmp, 0);
952  };
953  } else {
954  if (op->type == PLAYER) {
955  drop_object(op, tmp, op->contr->count);
956  } else {
957  drop_object(op, tmp, 0);
958  };
959  }
960  if (op->type == PLAYER)
961  op->contr->count = 0;
962 }
963 
972 void command_dropall(object *op, const char *params) {
973  int count = 0;
974 
975  if (op->inv == NULL) {
976  draw_ext_info(NDI_UNIQUE, 0, op,
978  "Nothing to drop!");
979  return;
980  }
981 
982  if (op->contr)
983  count = op->contr->count;
984 
985  /* Set this so we don't call it for _every_ object that
986  * is dropped.
987  */
989 
990  /*
991  * This is the default. Drops everything not locked or considered
992  * not something that should be dropped.
993  * Care must be taken that the next item pointer is not to money as
994  * the drop() routine will do unknown things to it when dropping
995  * in a shop. --Tero.Pelander@utu.fi
996  */
997  if (*params == '\0') {
998  FOR_INV_PREPARE(op, curinv) {
999  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1000  && curinv->type != MONEY
1001  && curinv->type != FOOD
1002  && curinv->type != KEY
1003  && curinv->type != SPECIAL_KEY
1004  && curinv->type != GEM
1005  && !curinv->invisible
1006  && (curinv->type != CONTAINER || op->container != curinv)) {
1007  drop(op, curinv);
1008  if (op->contr)
1009  op->contr->count = count;
1010  }
1011  } FOR_INV_FINISH();
1012  } else if (strcmp(params, "weapons") == 0) {
1013  FOR_INV_PREPARE(op, curinv) {
1014  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1015  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1016  drop(op, curinv);
1017  if (op->contr)
1018  op->contr->count = count;
1019  }
1020  } FOR_INV_FINISH();
1021  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1022  FOR_INV_PREPARE(op, curinv) {
1023  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1024  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1025  drop(op, curinv);
1026  if (op->contr)
1027  op->contr->count = count;
1028  }
1029  } FOR_INV_FINISH();
1030  } else if (strcmp(params, "food") == 0) {
1031  FOR_INV_PREPARE(op, curinv) {
1032  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1033  && (curinv->type == FOOD || curinv->type == DRINK)) {
1034  drop(op, curinv);
1035  if (op->contr)
1036  op->contr->count = count;
1037  }
1038  } FOR_INV_FINISH();
1039  } else if (strcmp(params, "flesh") == 0) {
1040  FOR_INV_PREPARE(op, curinv) {
1041  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1042  && (curinv->type == FLESH)) {
1043  drop(op, curinv);
1044  if (op->contr)
1045  op->contr->count = count;
1046  }
1047  } FOR_INV_FINISH();
1048  } else if (strcmp(params, "misc") == 0) {
1049  FOR_INV_PREPARE(op, curinv) {
1050  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1051  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1052  switch (curinv->type) {
1053  case BOOK:
1054  case SPELLBOOK:
1055  case GIRDLE:
1056  case AMULET:
1057  case RING:
1058  case CLOAK:
1059  case BOOTS:
1060  case GLOVES:
1061  case BRACERS:
1062  case SCROLL:
1063  case ARMOUR_IMPROVER:
1064  case WEAPON_IMPROVER:
1065  case WAND:
1066  case ROD:
1067  case POTION:
1068  drop(op, curinv);
1069  if (op->contr)
1070  op->contr->count = count;
1071  break;
1072 
1073  default:
1074  break;
1075  }
1076  }
1077  } FOR_INV_FINISH();
1078  }
1079  op->contr->socket.update_look = 1;
1081  /* call it now, once */
1082  fix_object(op);
1083  /* Need to update weight of player. Likewise, only do it once */
1084  if (op->type == PLAYER)
1085  esrv_update_item(UPD_WEIGHT, op, op);
1086 }
1087 
1096 void command_drop(object *op, const char *params) {
1097  int did_one = 0;
1098  int ival = 0;
1099  int missed = 0;
1100 
1101  if (*params == '\0') {
1103  "Drop what?");
1104  return;
1105  } else {
1106  FOR_INV_PREPARE(op, tmp) {
1107  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1108  continue;
1109  ival = object_matches_string(op, tmp, params);
1110  if (ival > 0) {
1111  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED) && (ival == 1 || ival == 2))
1112  missed++;
1113  else
1114  drop(op, tmp);
1115  did_one = 1;
1116  }
1117  } FOR_INV_FINISH();
1118  if (!did_one)
1120  "Nothing to drop.");
1121  if (missed == 1)
1123  "One item couldn't be dropped because it was locked.");
1124  else if (missed > 1)
1126  "%d items couldn't be dropped because they were locked.",
1127  missed);
1128  }
1129  if (op->type == PLAYER) {
1130  op->contr->count = 0;
1131  /*
1132  * Don't force a whole look update, items were transferred during their move.
1133  * Also this would send a 'delinv 0' to the client, which would make it appear
1134  * an opened container was closed.
1135  */
1136  /*op->contr->socket.update_look = 1;*/
1137  }
1138 }
1139 
1148 static void empty_container(object *container, object *pl) {
1149  int left = 0;
1150  char name[MAX_BUF];
1151 
1152  if (!container->inv)
1153  return;
1154 
1155  FOR_INV_PREPARE(container, inv) {
1156  object *next;
1157 
1158  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1159  /* you can have locked items in container. */
1160  left++;
1161  continue;
1162  }
1163  next = inv->below;
1164  drop(pl, inv);
1165  if (inv->below == next)
1166  /* item couldn't be dropped for some reason. */
1167  left++;
1168  } FOR_INV_FINISH();
1169  esrv_update_item(UPD_WEIGHT, pl, container);
1170 
1171  query_name(container, name, sizeof(name));
1172  if (left)
1173  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1174  else
1175  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s.", name);
1176 }
1177 
1186 void command_empty(object *op, const char *params) {
1187  object *container;
1188 
1189  if (*params == '\0') {
1191  "Empty what?");
1192  return;
1193  }
1194 
1195  if (strcmp(params, "all") == 0) {
1196  FOR_INV_PREPARE(op, inv)
1197  if (inv->type == CONTAINER)
1198  empty_container(inv, op);
1199  FOR_INV_FINISH();
1200  return;
1201  }
1202 
1203  container = find_best_object_match(op, params);
1204  if (!container) {
1206  "No such item.");
1207  return;
1208  }
1209  if (container->type != CONTAINER) {
1211  "This is not a container!");
1212  return;
1213  }
1214  empty_container(container, op);
1215 }
1216 
1225 void command_examine(object *op, const char *params) {
1226  if (*params == '\0') {
1227  FOR_BELOW_PREPARE(op, tmp)
1228  if (LOOK_OBJ(tmp)) {
1229  examine(op, tmp);
1230  break;
1231  }
1232  FOR_BELOW_FINISH();
1233  } else {
1234  object *tmp = find_best_object_match(op, params);
1235 
1236  if (tmp)
1237  examine(op, tmp);
1238  else
1240  "Could not find an object that matches %s",
1241  params);
1242  }
1243 }
1244 
1256 object *find_marked_object(object *op) {
1257  if (!op || !op->contr || !op->contr->mark)
1258  return NULL;
1259 
1260  /* This may seem like overkill, but we need to make sure that they
1261  * player hasn't dropped the item. We use count on the off chance that
1262  * an item got reincarnated at some point.
1263  */
1264  /*
1265  FOR_INV_PREPARE(op, tmp) {
1266  if (tmp->invisible)
1267  continue;
1268  if (tmp == op->contr->mark) {
1269  if (tmp->count == op->contr->mark_count)
1270  return tmp;
1271  else {
1272  op->contr->mark = NULL;
1273  op->contr->mark_count = 0;
1274  return NULL;
1275  }
1276  }
1277  } FOR_INV_FINISH();
1278  */
1279  /* Try a different way of doing this
1280  * We check the environment of the marked object
1281  * to make sure it is still in the player's inventory.
1282  * In addition, we ensure there is the correct quantity of that item.
1283  *
1284  * Daniel Hawkins 2018-10-23
1285  */
1286  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1287  return op->contr->mark;
1288  // Otherwise reset the mark, since it is no longer valid.
1289  op->contr->mark = NULL;
1290  op->contr->mark_count = 0;
1291  return NULL;
1292 }
1293 
1303 void command_mark(object *op, const char *params) {
1304  char name[MAX_BUF];
1305 
1306  if (!op->contr)
1307  return;
1308  if (*params == '\0') {
1309  object *mark = find_marked_object(op);
1310  if (!mark)
1312  "You have no marked object.");
1313  else {
1314  query_name(mark, name, MAX_BUF);
1316  "%s is marked.",
1317  name);
1318  }
1319  } else {
1320  object *mark1 = find_best_object_match(op, params);
1321 
1322  if (!mark1) {
1324  "Could not find an object that matches %s",
1325  params);
1326  return;
1327  } else {
1328  op->contr->mark = mark1;
1329  op->contr->mark_count = mark1->count;
1330  query_name(mark1, name, MAX_BUF);
1332  "Marked item %s",
1333  name);
1334  return;
1335  }
1336  }
1337  /*shouldnt get here */
1338 }
1339 
1350 void examine_monster(object *op, object *tmp, int level) {
1351  object *mon = HEAD(tmp), *probe;
1352 
1353  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1355  "It is an undead force.");
1356  if (mon->level > op->level)
1358  "It is likely more powerful than you.");
1359  else if (mon->level < op->level)
1361  "It is likely less powerful than you.");
1362  else
1364  "It is probably as powerful as you.");
1365 
1366  if (mon->attacktype&AT_ACID)
1368  "You smell an acrid odor.");
1369 
1370  /* Anyone know why this used to use the clone value instead of the
1371  * maxhp field? This seems that it should give more accurate results.
1372  */
1373  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1374  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1375  case 0:
1377  "It is critically wounded.");
1378  break;
1379 
1380  case 1:
1382  "It is in a bad shape.");
1383  break;
1384 
1385  case 2:
1387  "It is hurt.");
1388  break;
1389 
1390  case 3:
1392  "It is somewhat hurt.");
1393  break;
1394 
1395  default:
1397  "It is in excellent shape.");
1398  break;
1399  }
1400  if (object_present_in_ob(POISONING, mon) != NULL)
1402  "It looks very ill.");
1403 
1404  if (level < 10)
1405  return;
1407 
1408  if (level < 15)
1409  return;
1410 
1411  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1412  if (probe != NULL && probe->level > level)
1413  return;
1414 
1415  if (probe == NULL) {
1417  free_string(probe->name);
1418  probe->name = add_string("probe_force");
1421  object_insert_in_ob(probe, mon);
1422  fix_object(mon);
1423  }
1424  probe->level = level;
1425  if (level / 10 > probe->duration)
1426  probe->duration = level / 10;
1427 }
1428 
1438 void examine(object *op, object *tmp) {
1439  char buf[VERY_BIG_BUF];
1440  int in_shop;
1441  int i, exp = 0, conn;
1442 
1443  /* we use this to track how far along we got with trying to identify an item,
1444  * so that we can give the appropriate message to the player */
1445  int id_attempted = 0;
1446  char prefix[MAX_BUF] = "That is";
1447  const typedata *tmptype;
1448  object *skill;
1449 
1450  buf[0] = '\0';
1451 
1452  if (tmp == NULL || tmp->type == CLOSE_CON)
1453  return;
1454  tmptype = get_typedata(tmp->type);
1455  if (!tmptype) {
1456  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid", tmp->count, tmp->type);
1457  return;
1458  }
1459  /* first of all check whether this is an item we need to identify, and identify it as best we can.*/
1460  if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
1461  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1462  skill = find_skill_by_number(op, SK_DET_MAGIC);
1463  if (skill && (object_can_pick(op, tmp))) {
1464  exp = detect_magic_on_item(op, tmp, skill);
1465  if (exp) {
1466  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1468  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1469  }
1470  }
1471  skill = find_skill_by_number(op, SK_DET_CURSE);
1472  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1473  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1474  exp = detect_curse_on_item(op, tmp, skill);
1475  if (exp) {
1476  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1478  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1479  }
1480  }
1481  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1482 
1483  id_attempted = 1;
1484  skill = find_skill_by_number(op, tmptype->identifyskill);
1485  if (skill) {
1486  id_attempted = 2;
1487 
1488  /* identify_object_with_skill() may merge tmp with another
1489  * object, so once that happens, we really can not do
1490  * any further processing with tmp. It would be possible
1491  * to modify identify_object_with_skill() to return
1492  * the merged object, but it is currently set to return
1493  * exp, so it would have to do it via modifying the
1494  * passed in value, but many other consumers would
1495  * need to be modified for that.
1496  */
1497  exp = identify_object_with_skill(tmp, op, skill, 1);
1498  if (exp) {
1499  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1500  return;
1501  }
1502  }
1503  if(!exp) {
1504  /* The primary id skill didn't work, let's try the secondary one */
1505  skill = find_skill_by_number(op, tmptype->identifyskill2);
1506  if (skill) {
1507  /* if we've reached here, then the first skill will have been attempted
1508  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1509  * that now, and try with the secondary ID skill, if it fails, then the
1510  * flag will be reset anyway, if it succeeds, it won't matter.*/
1512  id_attempted = 2;
1513  exp = identify_object_with_skill(tmp, op, skill, 1);
1514  if (exp) {
1515  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1516  return;
1517  }
1518  }
1519  }
1520  }
1521  }
1522  if (!exp) {
1523  /* if we did get exp we'll already have propulated prefix */
1524  if (tmptype->identifyskill || tmptype->identifyskill2) {
1525  switch (id_attempted) {
1526  case 1:
1527  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1528  break;
1529  case 2:
1530  snprintf(prefix, MAX_BUF, "You fail to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1531  break;
1532  default:
1533  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1534  }
1535  } else snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1536  }
1537  /* now we need to get the rest of the object description */
1538  ob_describe(tmp, op, buf, sizeof(buf));
1539 
1541  "%s %s", prefix, buf);
1542  buf[0] = '\0';
1543  if (tmp->custom_name) {
1545  "You name it %s",
1546  tmp->custom_name);
1547  }
1548 
1549  switch (tmp->type) {
1550  case SPELLBOOK:
1551  if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) && tmp->inv) {
1552  char level[100];
1553 
1554  get_levelnumber(tmp->inv->level, level, 100);
1555  snprintf(buf, sizeof(buf), "%s is a %s level %s spell", tmp->inv->name, level, tmp->inv->skill);
1556  }
1557  break;
1558 
1559  case BOOK:
1560  if (tmp->msg != NULL)
1561  snprintf(buf, sizeof(buf), "Something is written in it.");
1562  break;
1563 
1564  case CONTAINER:
1565  if (tmp->race != NULL) {
1566  if (tmp->weight_limit && tmp->stats.Str < 100)
1567  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)));
1568  else
1569  snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
1570  } else
1571  if (tmp->weight_limit && tmp->stats.Str < 100)
1572  snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
1573  break;
1574 
1575  case WAND:
1576  if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
1577  snprintf(buf, sizeof(buf), "It has %d charges left.", tmp->stats.food);
1578  break;
1579  }
1580 
1581  if (buf[0] != '\0')
1583  buf);
1584 
1585  if (tmp->materialname != NULL && !tmp->msg) {
1587  "It is made of: %s.",
1588  tmp->materialname);
1589  }
1590  /* Where to wear this item */
1591  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1592  if (tmp->body_info[i] < -1) {
1593  if (op->body_info[i])
1595  "It goes %s (%d)",
1596  body_locations[i].use_name, -tmp->body_info[i]);
1597  else
1599  "It goes %s",
1600  body_locations[i].nonuse_name);
1601  } else if (tmp->body_info[i]) {
1602  if (op->body_info[i])
1604  "It goes %s",
1605  body_locations[i].use_name);
1606  else
1608  "It goes %s",
1609  body_locations[i].nonuse_name);
1610  }
1611  }
1612 
1613  if (tmp->weight) {
1614  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));
1616  buf);
1617  }
1618 
1619  in_shop = shop_contains(op);
1620 
1621  if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
1622  char *value = cost_approx_str(tmp, op);
1623  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
1624  free(value);
1626  buf);
1627  if (in_shop) {
1628  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1629  value = cost_str(shop_price_buy(tmp, op));
1630  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
1631  free(value);
1632  } else {
1633  value = cost_str(shop_price_sell(tmp, op));
1634  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
1635  free(value);
1636  }
1638  buf);
1639  }
1640  }
1641 
1642  if (QUERY_FLAG(tmp, FLAG_MONSTER))
1643  examine_monster(op, tmp, 0);
1644 
1645  /* Is this item buildable? */
1646  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
1648  "This is a buildable item.");
1649  if (QUERY_FLAG(tmp, FLAG_IS_LINKED)){
1650  conn = get_button_value(tmp);
1651  if (conn) {
1652  FOR_INV_PREPARE(op, tmp_inv) {
1653  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
1654  && strcmp(tmp_inv->slaying, op->map->path) == 0
1655  && tmp_inv->msg != NULL
1656  && tmp_inv->path_attuned == (uint32_t) conn) {
1657 
1659  MSG_TYPE_COMMAND_EXAMINE, "Connected with: %s",
1660  tmp_inv->msg);
1661 
1662  break;
1663  }
1664  } FOR_INV_FINISH();
1665  }
1666  }
1667  }
1668 
1669  /* Does the object have a message? Don't show message for all object
1670  * types - especially if the first entry is a match
1671  */
1672  if (tmp->msg
1673  && tmp->type != EXIT
1674  && tmp->type != BOOK
1675  && tmp->type != CORPSE
1676  && !tmp->move_on
1677  && strncasecmp(tmp->msg, "@match", 6)) {
1678  /* This is just a hack so when identifying the items, we print
1679  * out the extra message
1680  *
1681  * Also, don't print the message for the object unless it has been identified
1682  * -- SilverNexus 2015-05-20
1683  */
1684  if (need_identify(tmp) && QUERY_FLAG(tmp, FLAG_IDENTIFIED)){
1686  "The object has a story:");
1687 
1689  tmp->msg);
1690  }
1691  }
1693  " "); /* Blank line */
1694 
1695  if (!need_identify(tmp) || QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
1697  }
1698 }
1699 
1708 void inventory(object *op, object *inv) {
1709  const char *in;
1710  int items = 0, length;
1711  char weight[MAX_BUF], name[MAX_BUF];
1712 
1713  if (inv == NULL && op == NULL) {
1715  "Inventory of what object?");
1716  return;
1717  }
1718  FOR_INV_PREPARE(inv ? inv : op, tmp)
1719  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
1720  || !op || QUERY_FLAG(op, FLAG_WIZ))
1721  items++;
1722  FOR_INV_FINISH();
1723  if (inv == NULL) { /* player's inventory */
1724  if (items == 0) {
1726  "You carry nothing.");
1727  return;
1728  } else {
1729  length = 28;
1730  in = "";
1732  "Inventory:");
1733  }
1734  } else {
1735  if (items == 0)
1736  return;
1737  else {
1738  length = 28;
1739  in = " ";
1740  }
1741  }
1742  FOR_INV_PREPARE(inv ? inv : op, tmp) {
1743  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
1744  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
1745  continue;
1746  query_weight(tmp, weight, MAX_BUF);
1747  query_name(tmp, name, MAX_BUF);
1748  if (!op || QUERY_FLAG(op, FLAG_WIZ))
1750  "[fixed]%s- %-*.*s (%5d) %-8s",
1751  in, length, length, name, tmp->count, weight);
1752  else
1754  "[fixed]%s- %-*.*s %-8s",
1755  in, length+8, length+8, name, weight);
1756  } FOR_INV_FINISH();
1757  if (!inv && op) {
1758  query_weight(op, weight, MAX_BUF);
1760  "[fixed]%-*s %-8s",
1761  41, "Total weight :", weight);
1762  }
1763 }
1764 
1773 static void display_new_pickup(const object *op, int old) {
1774  int i = op->contr->mode;
1775 
1776  esrv_send_pickup(op->contr);
1777 
1778  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
1779  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
1781  "Pickup is %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
1782  }
1783  return;
1784  }
1785 
1787  "%d NEWMODE",
1788  i&PU_NEWMODE ? 1 : 0);
1790  "%d DEBUG",
1791  i&PU_DEBUG ? 1 : 0);
1793  "%d INHIBIT",
1794  i&PU_INHIBIT ? 1 : 0);
1796  "%d STOP",
1797  i&PU_STOP ? 1 : 0);
1798 
1800  "%d <= x pickup weight/value RATIO (0==off)",
1801  (i&PU_RATIO)*5);
1802 
1804  "%d FOOD",
1805  i&PU_FOOD ? 1 : 0);
1807  "%d DRINK",
1808  i&PU_DRINK ? 1 : 0);
1810  "%d VALUABLES",
1811  i&PU_VALUABLES ? 1 : 0);
1812 
1814  "%d BOW",
1815  i&PU_BOW ? 1 : 0);
1817  "%d ARROW",
1818  i&PU_ARROW ? 1 : 0);
1819 
1821  "%d HELMET",
1822  i&PU_HELMET ? 1 : 0);
1824  "%d SHIELD",
1825  i&PU_SHIELD ? 1 : 0);
1827  "%d ARMOUR",
1828  i&PU_ARMOUR ? 1 : 0);
1829 
1831  "%d BOOTS",
1832  i&PU_BOOTS ? 1 : 0);
1834  "%d GLOVES",
1835  i&PU_GLOVES ? 1 : 0);
1837  "%d CLOAK",
1838  i&PU_CLOAK ? 1 : 0);
1840  "%d KEY",
1841  i&PU_KEY ? 1 : 0);
1842 
1844  "%d MISSILEWEAPON",
1845  i&PU_MISSILEWEAPON ? 1 : 0);
1847  "%d MELEEWEAPON",
1848  i&PU_MELEEWEAPON ? 1 : 0);
1850  "%d MAGICAL",
1851  i&PU_MAGICAL ? 1 : 0);
1853  "%d POTION",
1854  i&PU_POTION ? 1 : 0);
1855 
1857  "%d SPELLBOOK",
1858  i&PU_SPELLBOOK ? 1 : 0);
1860  "%d SKILLSCROLL",
1861  i&PU_SKILLSCROLL ? 1 : 0);
1863  "%d READABLES",
1864  i&PU_READABLES ? 1 : 0);
1866  "%d MAGICDEVICE",
1867  i&PU_MAGIC_DEVICE ? 1 : 0);
1868 
1870  "%d NOT CURSED",
1871  i&PU_NOT_CURSED ? 1 : 0);
1872 
1874  "%d JEWELS",
1875  i&PU_JEWELS ? 1 : 0);
1876 
1878  "%d FLESH",
1879  i&PU_FLESH ? 1 : 0);
1880 
1882  "%d CONTAINER",
1883  i&PU_CONTAINER ? 1 : 0);
1884 
1886  "");
1887 }
1888 
1898 void command_pickup(object *op, const char *params) {
1899  uint32_t i;
1900  static const char *names[] = {
1901  "debug", "inhibit", "stop", "food", "drink",
1902  "valuables", "bow", "arrow", "helmet", "shield",
1903  "armour", "boots", "gloves", "cloak", "key",
1904  "missile", "melee", "magical", "potion", "spellbook",
1905  "skillscroll", "readables", "magicdevice", "notcursed", "jewels",
1906  "flesh", "container", NULL
1907  };
1908  static const uint32_t modes[] = {
1913  };
1914 
1915  if (*params == '\0') {
1916  /* if the new mode is used, just print the settings */
1917  if (op->contr->mode&PU_NEWMODE) {
1918  display_new_pickup(op, op->contr->mode);
1919  return;
1920  }
1921  if (1)
1922  LOG(llevDebug, "command_pickup: !params\n");
1923  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
1924  return;
1925  }
1926 
1927  while (*params == ' ')
1928  params++;
1929 
1930  if (*params == '+' || *params == '-' || *params == '!') {
1931  int mode;
1932 
1933  for (mode = 0; names[mode]; mode++) {
1934  if (!strcmp(names[mode], params+1)) {
1935  int old = op->contr->mode;
1936  i = op->contr->mode;
1937  if (!(i&PU_NEWMODE))
1938  i = PU_NEWMODE;
1939  if (*params == '+')
1940  i = i|modes[mode];
1941  else if (*params == '-')
1942  i = i&~modes[mode];
1943  else {
1944  if (i&modes[mode])
1945  i = i&~modes[mode];
1946  else
1947  i = i|modes[mode];
1948  }
1949  op->contr->mode = i;
1950  display_new_pickup(op, old);
1951  return;
1952  }
1953  }
1955  "Pickup: invalid item %s\n",
1956  params);
1957  return;
1958  }
1959 
1960  if (sscanf(params, "%u", &i) != 1) {
1961  if (1)
1962  LOG(llevDebug, "command_pickup: params==NULL\n");
1964  "Usage: pickup <0-7> or <value_density> .");
1965  return;
1966  }
1967  set_pickup_mode(op, i);
1968  display_new_pickup(op, op->contr->mode);
1969 }
1970 
1979 static void set_pickup_mode(const object *op, int i) {
1980  op->contr->mode = i;
1981  switch (op->contr->mode) {
1982  case 0:
1984  "Mode: Don't pick up.");
1985  break;
1986 
1987  case 1:
1989  "Mode: Pick up one item.");
1990  break;
1991 
1992  case 2:
1994  "Mode: Pick up one item and stop.");
1995  break;
1996 
1997  case 3:
1999  "Mode: Stop before picking up.");
2000  break;
2001 
2002  case 4:
2004  "Mode: Pick up all items.");
2005  break;
2006 
2007  case 5:
2009  "Mode: Pick up all items and stop.");
2010  break;
2011 
2012  case 6:
2014  "Mode: Pick up all magic items.");
2015  break;
2016 
2017  case 7:
2019  "Mode: Pick up all coins and gems");
2020  break;
2021  }
2022 }
2023 
2032 void command_search_items(object *op, const char *params) {
2033  if (settings.search_items == FALSE)
2034  return;
2035 
2036  if (*params == '\0') {
2037  if (op->contr->search_str[0] == '\0') {
2039  "Example: search magic+1 "
2040  "Would automatically pick up all "
2041  "items containing the word 'magic+1'.");
2042  return;
2043  }
2044  op->contr->search_str[0] = '\0';
2046  "Search mode turned off.");
2047  fix_object(op);
2048  return;
2049  }
2050  if ((int)strlen(params) >= MAX_BUF) {
2052  "Search string too long.");
2053  return;
2054  }
2055  strcpy(op->contr->search_str, params);
2057  "Searching for '%s'.",
2058  op->contr->search_str);
2059  fix_object(op);
2060 }
2061 
2077 void command_rename_item(object *op, const char *params) {
2078  char buf[VERY_BIG_BUF], name[MAX_BUF];
2079  tag_t itemnumber;
2080  object *item = NULL;
2081  object *tmp;
2082  char *closebrace;
2083  size_t counter;
2084 
2085  if (*params != '\0') {
2086  /* Let's skip white spaces */
2087  while (' ' == *params)
2088  params++;
2089 
2090  /* Checking the first part */
2091  itemnumber = atoi(params);
2092  if (itemnumber != 0) {
2093  int found = 0;
2094  FOR_INV_PREPARE(op, item)
2095  if (item->count == itemnumber && !item->invisible) {
2096  found = 1;
2097  break;
2098  }
2099  FOR_INV_FINISH();
2100  if (!found) {
2102  "Tried to rename an invalid item.");
2103  return;
2104  }
2105  while (isdigit(*params) || ' ' == *params)
2106  params++;
2107  } else if ('<' == *params) {
2108  /* Got old name, let's get it & find appropriate matching item */
2109  closebrace = strchr(params, '>');
2110  if (!closebrace) {
2112  "Syntax error!");
2113  return;
2114  }
2115  /* Sanity check for buffer overruns */
2116  if (closebrace-params > 127) {
2118  "Old name too long (up to 127 characters allowed)!");
2119  return;
2120  }
2121  /* Copy the old name */
2122  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2123 
2124  /* Find best matching item */
2125  item = find_best_object_match(op, buf);
2126  if (!item) {
2128  "Could not find a matching item to rename.");
2129  return;
2130  }
2131 
2132  /* Now need to move pointer to just after > */
2133  params = closebrace+1;
2134  while (' ' == *params)
2135  params++;
2136  } else {
2137  /* Use marked item */
2138  item = find_marked_object(op);
2139  if (!item) {
2141  "No marked item to rename.");
2142  return;
2143  }
2144  }
2145 
2146  /* Now let's find the new name */
2147  if (!strncmp(params, "to ", 3)) {
2148  params += 3;
2149  while (' ' == *params)
2150  params++;
2151  if ('<' != *params) {
2153  "Syntax error, expecting < at start of new name!");
2154  return;
2155  }
2156  closebrace = strchr(params+1, '>');
2157  if (!closebrace) {
2159  "Syntax error, expecting > at end of new name!");
2160  return;
2161  }
2162 
2163  /* Sanity check for buffer overruns */
2164  if (closebrace-params > 127) {
2166  "New name too long (up to 127 characters allowed)!");
2167  return;
2168  }
2169 
2170  /* Copy the new name */
2171  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2172 
2173  /* Let's check it for weird characters */
2174  for (counter = 0; counter < strlen(buf); counter++) {
2175  if (isalnum(buf[counter]))
2176  continue;
2177  if (' ' == buf[counter])
2178  continue;
2179  if ('\'' == buf[counter])
2180  continue;
2181  if ('+' == buf[counter])
2182  continue;
2183  if ('_' == buf[counter])
2184  continue;
2185  if ('-' == buf[counter])
2186  continue;
2187 
2188  /* If we come here, then the name contains an invalid character...
2189  * tell the player & exit
2190  */
2192  "Invalid new name!");
2193  return;
2194  }
2195  } else {
2196  /* If param contains something, then syntax error... */
2197  if (strlen(params)) {
2199  "Syntax error, expected 'to <' after old name!");
2200  return;
2201  }
2202  /* New name is empty */
2203  buf[0] = '\0';
2204  }
2205  } else {
2206  /* Last case: *params=='\0' */
2207  item = find_marked_object(op);
2208  if (!item) {
2210  "No marked item to rename.");
2211  return;
2212  }
2213  buf[0] = '\0';
2214  }
2215 
2216  /* Coming here, everything is fine... */
2217  if (!strlen(buf)) {
2218  /* Clear custom name */
2219  if (item->custom_name == NULL) {
2221  "This item has no custom name.");
2222  return;
2223  }
2224 
2226  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2228  "You stop calling your %s with weird names.",
2229  name);
2230  } else {
2231  if (item->custom_name != NULL && strcmp(item->custom_name, buf) == 0) {
2232  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2234  "You keep calling your %s %s.",
2235  name, buf);
2236  return;
2237  }
2238 
2239  /* Set custom name */
2240  FREE_AND_COPY(item->custom_name, buf);
2241 
2242  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2244  "Your %s will now be called %s.",
2245  name, buf);
2246  }
2247 
2248  tmp = object_merge(item, NULL);
2249  if (tmp == NULL) {
2250  /* object was not merged - if it was, object_merge() handles updating for us. */
2251  esrv_update_item(UPD_NAME, op, item);
2252  }
2253 }
2254 
2263 void command_lock_item(object *op, const char *params) {
2264  object *item;
2265  object *tmp;
2266  char name[HUGE_BUF];
2267 
2268  if (*params == '\0' || strlen(params) == 0) {
2270  "Lock what item?");
2271  return;
2272  }
2273 
2274  item = find_best_object_match(op, params);
2275  if (!item) {
2277  "Can't find any matching item.");
2278  return;
2279  }
2280 
2281  query_short_name(item, name, HUGE_BUF);
2282  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2284  "Unlocked %s.", name);
2285  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2286  } else {
2288  "Locked %s.", name);
2289  SET_FLAG(item, FLAG_INV_LOCKED);
2290  }
2291 
2292  tmp = object_merge(item, NULL);
2293  if (tmp == NULL) {
2294  /* object was not merged, if it was object_merge() handles updates for us */
2295  esrv_update_item(UPD_FLAGS, op, item);
2296  }
2297 }
2298 
2306 void command_use(object *op, const char *params) {
2307  char *with, copy[MAX_BUF];
2308  object *first, *second/*, *add*/;
2309  /*archetype *arch;*/
2310  /*int count;*/
2311  /*sstring data;*/
2312  recipe *transformation;
2313 
2314  if (!IS_PLAYER(op))
2315  return;
2316 
2317  snprintf(copy, sizeof(copy), "%s", params);
2318  with = strstr(copy, " with ");
2319  if (!with) {
2320  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2321  return;
2322  }
2323 
2324  with[0] = '\0';
2325  with = with+strlen(" with ");
2326 
2327  first = find_best_object_match(op, copy);
2328  if (!first) {
2329  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2330  return;
2331  }
2332  second = find_best_object_match(op, with);
2333  if (!second) {
2334  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2335  return;
2336  }
2337 
2338  transformation = NULL;
2339  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2341  if (transformation->ingred_count != 1)
2342  continue;
2343 
2344 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2345  if (strcmp(second->name, transformation->ingred->name) == 0) {
2347  object *generated = create_archetype(transformation->arch_name[0]);
2348  if (transformation->yield)
2349  generated->nrof = transformation->yield;
2350  object_insert_in_ob(generated, op);
2351  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2353  return;
2354  }
2355  }
2356  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2357  return;
2358 
2359  /*
2360  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2361  data = object_get_value(second, copy);
2362  if (!data) {
2363  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2364  data = object_get_value(second, copy);
2365  if (!data) {
2366  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2367  data = object_get_value(second, copy);
2368  if (!data) {
2369  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2370  return 1;
2371  }
2372  }
2373  }
2374 
2375  while (data != NULL) {
2376  if (strncmp(data, "add ", 4) == 0) {
2377  data += 4;
2378  if (isdigit(*data)) {
2379  count = atol(data);
2380  data = strchr(data, ' ')+1;
2381  } else
2382  count = 1;
2383  with = strchr(data, ' ');
2384  if (!with) {
2385  strncpy(copy, data, sizeof(copy));
2386  data = NULL;
2387  } else {
2388  *with = '\0';
2389  strncpy(copy, data, sizeof(copy));
2390  data += strlen(copy)+1;
2391  }
2392  arch = find_archetype(copy);
2393  if (!arch) {
2394  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2395  return 1;
2396  }
2397  add = object_create_arch(arch);
2398  add->nrof = count;
2399  object_insert_in_ob(add, op);
2400  } else if (strncmp(data, "remove $", 8) == 0) {
2401  data += 8;
2402  if (*data == '1') {
2403  if (first)
2404  first = object_decrease_nrof_by_one(first);
2405  data += 2;
2406  } else if (*data == '2') {
2407  if (second)
2408  second = object_decrease_nrof_by_one(second);
2409  data += 2;
2410  } else {
2411  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2412  return 1;
2413  }
2414  } else {
2415  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2416  return 1;
2417  }
2418  }
2419 
2420  return 1;
2421  */
2422 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Definition: main.c:315
#define AP_UNAPPLY
Definition: define.h:611
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.c:4002
char path[HUGE_BUF]
Definition: map.h:365
void apply_by_living_below(object *pl)
Definition: apply.c:618
void sell_item(object *op, object *pl)
Definition: shop.c:943
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:1082
#define FLAG_IS_FLOOR
Definition: define.h:303
#define FLAG_UNPAID
Definition: define.h:236
int32_t weight_limit
Definition: object.h:366
#define MSG_TYPE_COMMAND_INVENTORY
Definition: newclient.h:513
#define FLAG_IS_LINKED
Definition: define.h:316
MoveType move_type
Definition: object.h:424
#define INS_BELOW_ORIGINATOR
Definition: object.h:572
int change_skill(object *who, object *new_skill, int flag)
Definition: skill_util.c:356
void command_search_items(object *op, const char *params)
Definition: c_object.c:2032
Definition: object.h:127
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.c:678
void pick_up(object *op, object *alt)
Definition: c_object.c:446
MoveType move_on
Definition: object.h:427
Definition: object.h:185
bool shop_contains(object *ob)
Definition: shop.c:1261
uint8_t max_stat
Definition: global.h:321
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:2263
#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:585
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:796
#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:211
void inventory(object *op, object *inv)
Definition: c_object.c:1708
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:342
Definition: object.h:137
void query_base_name(const object *op, int plural, char *buf, size_t size)
Definition: item.c:723
socket_struct socket
Definition: player.h:94
linked_char * ingred
Definition: recipe.h:22
int16_t invisible
Definition: object.h:360
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Definition: recipe.c:810
void command_throw(object *op, const char *params)
Definition: c_object.c:174
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
const char * skill_names[NUM_SKILLS]
Definition: skill_util.c:57
#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:2279
Definition: object.h:187
static void pick_up_object(object *pl, object *op, object *tmp, int nrof)
Definition: c_object.c:315
Definition: object.h:212
#define SCRIPT_FIX_ALL
Definition: global.h:361
#define AP_APPLY
Definition: define.h:610
#define PU_NEWMODE
Definition: define.h:111
void command_dropall(object *op, const char *params)
Definition: c_object.c:972
void draw_ext_info(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *message)
Definition: main.c:310
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:789
#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:1186
#define FLAG_REMOVED
Definition: define.h:232
int16_t hp
Definition: living.h:39
void command_rename_item(object *op, const char *params)
Definition: c_object.c:2077
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:683
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Definition: knowledge.c:1342
uint32_t update_look
Definition: newserver.h:115
void object_free_drop_inventory(object *ob)
Definition: object.c:1368
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:1921
void command_examine(object *op, const char *params)
Definition: c_object.c:1225
int16_t maxhp
Definition: living.h:40
#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:557
void examine(object *op, object *tmp)
Definition: c_object.c:1438
void command_search(object *op, const char *params)
Definition: c_object.c:147
Definition: object.h:114
Definition: object.h:181
object * create_archetype(const char *name)
Definition: arch.c:617
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Definition: skills.c:695
char ** arch_name
Definition: recipe.h:13
uint64_t shop_price_buy(const object *obj, object *who)
Definition: shop.c:188
int object_can_pick(const object *who, const object *item)
Definition: object.c:3793
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2690
char * cost_approx_str(const object *obj, object *who)
Definition: shop.c:420
#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:263
const char * materialname
Definition: object.h:346
int32_t weight
Definition: object.h:365
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:712
#define MOVE_FLYING
Definition: define.h:410
void command_drop(object *op, const char *params)
Definition: c_object.c:1096
#define FLAG_PROBE
Definition: define.h:257
int32_t carrying
Definition: object.h:367
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:609
struct obj * below
Definition: object.h:287
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.c:3001
#define PU_RATIO
Definition: define.h:113
char * cost_str(uint64_t cost)
Definition: shop.c:416
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:195
#define FLAG_IS_CAULDRON
Definition: define.h:339
MoveType move_off
Definition: object.h:428
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Definition: skill_util.c:428
uint8_t real_wiz
Definition: global.h:267
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:2152
static void empty_container(object *container, object *pl)
Definition: c_object.c:1148
#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:1536
static void set_pickup_mode(const object *op, int i)
Definition: c_object.c:1979
#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:2100
#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:85
#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:246
#define EVENT_DROP
Definition: plugin.h:68
int identifyskill2
Definition: define.h:94
int8_t Str
Definition: living.h:35
void command_pickup(object *op, const char *params)
Definition: c_object.c:1898
int need_identify(const object *op)
Definition: item.c:1332
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
#define AP_NO_MERGE
Definition: define.h:616
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:257
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:372
uint32_t attacktype
Definition: object.h:342
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2463
#define INS_NO_MERGE
Definition: object.h:568
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Definition: skills.c:744
#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:432
int get_button_value(const object *button)
Definition: button.c:754
void command_use(object *op, const char *params)
Definition: c_object.c:2306
tag_t count
Definition: object.h:299
living stats
Definition: object.h:368
struct archt * arch
Definition: object.h:412
#define FLAG_IS_BUILDABLE
Definition: define.h:376
uint8_t type
Definition: object.h:338
uint32_t mode
Definition: player.h:110
struct Settings settings
Definition: init.c:40
static void display_new_pickup(const object *op, int old)
Definition: c_object.c:1773
#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:1869
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:353
int execute_event(object *op, int eventcode, object *activator, object *third, const char *message, int fix)
Definition: main.c:364
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:4456
#define FOR_OB_AND_BELOW_PREPARE(op_)
Definition: define.h:785
#define FLAG_STARTEQUIP
Definition: define.h:268
void command_disarm(object *op, const char *params)
Definition: c_object.c:159
#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:1637
#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:1256
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:626
#define PU_ARMOUR
Definition: define.h:123
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.c:814
#define FOR_BELOW_PREPARE(op_, it_)
Definition: define.h:739
#define SK_SUBTRACT_SKILL_EXP
Definition: skills.h:82
object * find_skill_by_number(object *who, int skillno)
Definition: main.c:351
Definition: map.h:325
int use_skill(object *op, const char *string)
Definition: skill_util.c:923
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:351
int8_t facing
Definition: object.h:335
#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:1118
#define PU_NOT_CURSED
Definition: define.h:140
object * find_skill_by_name(object *who, const char *name)
Definition: skill_util.c:213
int32_t value
Definition: object.h:350
const char * name
Definition: object.h:466
#define FOR_BELOW_FINISH()
Definition: define.h:746
void command_mark(object *op, const char *params)
Definition: c_object.c:1303
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:705
void object_remove(object *op)
Definition: object.c:1654
void examine_monster(object *op, object *tmp, int level)
Definition: c_object.c:1350
#define PU_MAGIC_DEVICE
Definition: define.h:138
int32_t food
Definition: living.h:47
#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:910