Crossfire Server, Trunk  R21670
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, "-o ", 3)) {
226  aflag = AP_OPEN;
227  params += 3;
228  }
229  if (!strncmp(params, "-b ", 3)) {
230  params += 3;
231  if (op->container)
232  inv = op->container->inv;
233  else {
234  inv = op;
235  while (inv->above)
236  inv = inv->above;
237  }
238  }
239  while (*params == ' ')
240  params++;
241 
242  item = find_best_apply_object_match(inv, op, params, aflag);
243  if (item == NULL)
244  item = find_best_apply_object_match(inv, op, params, AP_NULL);
245  if (item) {
246  apply_by_living(op, item, aflag, 0);
247  } else
249  "Could not find any match to the %s.",
250  params);
251 }
252 
271 int sack_can_hold(const object *pl, const object *sack, const object *op, uint32_t nrof) {
272  char name[MAX_BUF];
273  query_name(sack, name, MAX_BUF);
274 
275  if (!QUERY_FLAG(sack, FLAG_APPLIED)) {
277  "The %s is not active.",
278  name);
279  return 0;
280  }
281  if (sack == op) {
283  "You can't put the %s into itself.",
284  name);
285  return 0;
286  }
287  if (sack->race
288  && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type))) {
290  "You can put only %s into the %s.",
291  sack->race, name);
292  return 0;
293  }
294  if (op->type == SPECIAL_KEY && sack->slaying && op->slaying) {
296  "You can't put the key into %s.",
297  name);
298  return 0;
299  }
300  if (sack->weight_limit) {
301  int32_t new_weight;
302 
303  new_weight = sack->carrying+(nrof ? nrof : 1)
304  *(op->weight+(op->type == CONTAINER ? op->carrying*op->stats.Str : 0))
305  *(100-sack->stats.Str)/100;
306  if (new_weight > sack->weight_limit) {
308  "That won't fit in the %s!",
309  name);
310  return 0;
311  }
312  }
313  /* All other checks pass, must be OK */
314  return 1;
315 }
316 
329 static void pick_up_object(object *pl, object *op, object *tmp, int nrof) {
330  /* buf needs to be big (more than 256 chars) because you can get
331  * very long item names.
332  */
333  char buf[HUGE_BUF], name[MAX_BUF];
334  object *env = tmp->env;
335  uint32_t weight, effective_weight_limit;
336  const int tmp_nrof = NROF(tmp);
337  tag_t tag;
338  mapstruct* map = tmp->map;
339  int16_t x = tmp->x, y = tmp->y;
340 
341  /* IF the player is flying & trying to take the item out of a container
342  * that is in his inventory, let him. tmp->env points to the container
343  * (sack, luggage, etc), tmp->env->env then points to the player (nested
344  * containers not allowed as of now)
345  */
346  if ((pl->move_type&MOVE_FLYING)
347  && !QUERY_FLAG(pl, FLAG_WIZ)
348  && object_get_player_container(tmp) != pl) {
350  "You are levitating, you can't reach the ground!");
351  return;
352  }
353  if (QUERY_FLAG(tmp, FLAG_NO_DROP))
354  return;
355 
356  if (QUERY_FLAG(tmp, FLAG_WAS_WIZ) && !QUERY_FLAG(pl, FLAG_WAS_WIZ)) {
358  "The object disappears in a puff of smoke! It must have been an illusion.");
359  if (!QUERY_FLAG(tmp, FLAG_REMOVED))
360  object_remove(tmp);
362  return;
363  }
364 
365  if (nrof > tmp_nrof || nrof == 0)
366  nrof = tmp_nrof;
367 
368  /* Figure out how much weight this object will add to the player */
369  weight = tmp->weight*nrof;
370  if (tmp->inv)
371  weight += tmp->carrying*(100-tmp->stats.Str)/100;
372 
373  effective_weight_limit = get_weight_limit(MIN(pl->stats.Str, settings.max_stat));
374 
375  if (pl->weight+pl->carrying+weight > effective_weight_limit) {
377  "That item is too heavy for you to pick up.");
378  return;
379  }
380 
382  SET_FLAG(tmp, FLAG_WAS_WIZ);
383 
384  if (nrof != tmp_nrof) {
385  char failure[MAX_BUF];
386 
387  tmp = object_split(tmp, nrof, failure, sizeof(failure));
388  if (!tmp) {
390  failure);
391  return;
392  }
393  } else {
394  /* If the object is in a container, send a delete to the client.
395  * - we are moving all the items from the container to elsewhere,
396  * so it needs to be deleted.
397  */
398  if (!QUERY_FLAG(tmp, FLAG_REMOVED)) {
399  object_remove(tmp); /* Unlink it */
400  }
401  }
402  query_name(tmp, name, MAX_BUF);
403 
404  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
405  char *value = cost_str(shop_price_buy(tmp, pl));
406  snprintf(buf, sizeof(buf), "%s will cost you %s.", name, value);
407  free(value);
408  } else
409  snprintf(buf, sizeof(buf), "You pick up the %s.", name);
410 
411  /* Now item is about to be picked. */
412  tag = tmp->count;
413  if (execute_event(tmp, EVENT_PICKUP, pl, op, NULL, SCRIPT_FIX_ALL) != 0) {
414  /* put item back, if it still exists */
415  if (tmp->count == tag && !QUERY_FLAG(tmp, FLAG_FREED)) {
416  if (env != NULL) {
417  object_insert_in_ob(tmp, env);
418  } else {
419  object_insert_in_map_at(tmp, map, NULL, 0, x, y);
420  }
421  }
422  return;
423  }
424 
426  buf);
427 
428  tmp = object_insert_in_ob(tmp, op);
429 
430  /* All the stuff below deals with client/server code, and is only
431  * usable by players
432  */
433  if (pl->type != PLAYER)
434  return;
435 
436  /* Additional weight changes speed, etc */
437  fix_object(pl);
438 
439  /* These are needed to update the weight for the container we
440  * are putting the object in.
441  */
442  if (op != pl) {
443  esrv_update_item(UPD_WEIGHT, pl, op);
444  esrv_update_item(UPD_WEIGHT, pl, pl);
445  }
446 
447  /* Update the container the object was in */
448  if (env && env != pl && env != op)
449  esrv_update_item(UPD_WEIGHT, pl, env);
450 }
451 
460 void pick_up(object *op, object *alt) {
461 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
462  object *tmp = NULL, *tmp1;
463  mapstruct *tmp_map = NULL;
464  int count;
465 
466  /* Decide which object to pick. */
467  if (alt) {
468  if (!object_can_pick(op, alt)) {
470  "You can't pick up the %s.",
471  alt->name);
472  return;
473  }
474  tmp = alt;
475  } else {
476  if (op->below == NULL || !object_can_pick(op, op->below)) {
478  "There is nothing to pick up here.");
479  return;
480  }
481  tmp = op->below;
482  }
483 
484  /* it is possible that the object is a thrown object and is flying about.
485  * in that case, what we want to pick up is the payload. Objects
486  * that are thrown are encapsulated into a thrown object.
487  * stop_item() returns the payload (unlinked from map) and gets rid of the
488  * container object. If this object isn't picked up, we need to insert
489  * it back on the map.
490  * A bug here is that even attempting to pick up one of these objects will
491  * result in this logic being called even if player is unable to pick it
492  * up.
493  */
494 
495  tmp_map = tmp->map;
496  tmp1 = stop_item(tmp);
497  if (tmp1 == NULL)
498  return;
499 
500  /* If it is a thrown object, insert it back into the map here.
501  * makes life easier further along. Do no merge so pick up code
502  * behaves more sanely.
503  */
504  if (tmp1 != tmp) {
505  tmp = object_insert_in_map(tmp1, tmp_map, op, INS_NO_MERGE);
506  }
507 
508  if (tmp == NULL)
509  return;
510 
511  if (!object_can_pick(op, tmp))
512  return;
513 
514  /* Establish how many of the object we are picking up */
515  if (op->type == PLAYER) {
516  count = op->contr->count;
517  if (count == 0)
518  count = tmp->nrof;
519  } else
520  count = tmp->nrof;
521 
522  /* container is open, so use it */
523  if (op->container) {
524  alt = op->container;
525  if (alt != tmp->env && !sack_can_hold(op, alt, tmp, count))
526  return;
527  } else {
528  /* non container pickup. See if player has any
529  * active containers.
530  */
531  object *container = NULL;
532 
533  /* Look for any active containers that can hold this item.
534  * we cover two cases here - the perfect match case, where we
535  * break out of the loop, and the general case (have a container),
536  * Moved this into a single loop - reduces redundant code, is
537  * more efficient and easier to follow. MSW 2009-04-06
538  */
539  alt = op->inv;
541  if (alt->type == CONTAINER
542  && QUERY_FLAG(alt, FLAG_APPLIED)
543  && sack_can_hold(NULL, alt, tmp, count)) {
544  if (alt->race && alt->race == tmp->race) {
545  break; /* perfect match */
546  } else if (!container) {
547  container = alt;
548  }
549  }
551  /* Note container could be null, but no reason to check for it */
552  if (!alt)
553  alt = container;
554 
555  if (!alt)
556  alt = op; /* No free containers */
557  }
558  /* see if this object is already in this container. If so,
559  * move it to player inventory from this container.
560  */
561  if (tmp->env == alt) {
562  alt = op;
563  }
564 
565  /* Don't allow players to be put into containers. Instead,
566  * just put them in the players inventory.
567  */
568  if (tmp->type == CONTAINER && alt->type==CONTAINER) {
569  alt = op;
570  }
571 #ifdef PICKUP_DEBUG
572  LOG(llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
573 #endif
574 
575  /* startequip items are not allowed to be put into containers
576  * Not sure why we have this limitation
577  */
578  if (op->type == PLAYER
579  && alt->type == CONTAINER
580  && QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
582  "This object cannot be put into containers!");
583  return;
584  }
585 
586  pick_up_object(op, alt, tmp, count);
587  if (op->type == PLAYER)
588  op->contr->count = 0;
589 }
590 
599 void command_take(object *op, const char *params) {
600  object *tmp;
601  int ival;
602  int missed = 0;
603 
604  if (op->container)
605  tmp = op->container->inv;
606  else {
607  tmp = op->above;
608  if (tmp)
609  while (tmp->above) {
610  tmp = tmp->above;
611  }
612  if (!tmp)
613  tmp = op->below;
614  }
615 
616  if (tmp == NULL) {
618  "Nothing to take!");
619  return;
620  }
621 
622  /* Makes processing easier */
623  if (*params == '\0')
624  params = NULL;
625 
627  if (tmp->invisible) {
628  continue;
629  }
630  /* This following two if and else if could be merged into line
631  * but that probably will make it more difficult to read, and
632  * not make it any more efficient
633  */
634  if (params) {
635  ival = object_matches_string(op, tmp, params);
636  if (ival > 0) {
637  if (ival <= 2 && !object_can_pick(op, tmp)) {
638  if (!QUERY_FLAG(tmp, FLAG_IS_FLOOR))/* don't count floor tiles */
639  missed++;
640  } else
641  pick_up(op, tmp);
642  }
643  } else {
644  if (object_can_pick(op, tmp)) {
645  pick_up(op, tmp);
646  break;
647  }
648  }
650  if (!params && !tmp) {
651  int found = 0;
652  FOR_BELOW_PREPARE(op, tmp)
653  if (!tmp->invisible) {
655  "You can't pick up a %s.",
656  tmp->name ? tmp->name : "null");
657  found = 1;
658  break;
659  }
661  if (!found)
663  "There is nothing to pick up.");
664  }
665  if (missed == 1)
667  "You were unable to take one of the items.");
668  else if (missed > 1)
670  "You were unable to take %d of the items.",
671  missed);
672 }
673 
692 void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof) {
693  object *sack2, *orig = sack;
694  char name_sack[MAX_BUF], name_tmp[MAX_BUF];
695 
696  if (sack == tmp)
697  return; /* Can't put an object in itself */
698  query_name(sack, name_sack, MAX_BUF);
699  if (sack->type != CONTAINER && sack->type != TRANSPORT) {
701  "The %s is not a container.",
702  name_sack);
703  return;
704  }
705  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
706  query_name(tmp, name_tmp, MAX_BUF);
708  "You cannot put the %s in the %s.",
709  name_tmp, name_sack);
710  return;
711  }
712  if (tmp->type == CONTAINER) {
713  if (tmp->inv) {
714  if (tmp->slaying)
715  return;
716  /* Eneq(@csd.uu.se): If the object to be dropped is a container
717  * and does not require a key to be opened,
718  * we instead move the contents of that container into the active
719  * container, this is only done if the object has something in it.
720  * If object is container but need a key, just don't do anything
721  */
722  sack2 = tmp;
723  query_name(tmp, name_tmp, MAX_BUF);
725  "You move the items from %s into %s.",
726  name_tmp, name_sack);
727 
728  FOR_INV_PREPARE(tmp, tmp2) {
729  if ((sack->type == CONTAINER && sack_can_hold(op, op->container, tmp2, tmp2->nrof))
730  || (sack->type == TRANSPORT && transport_can_hold(sack, tmp2, tmp2->nrof))) {
731  put_object_in_sack(op, sack, tmp2, 0);
732  } else {
735  "Your %s fills up.",
736  name_sack);
737  break;
738  }
739  } FOR_INV_FINISH();
740  esrv_update_item(UPD_WEIGHT, op, sack2);
741  return;
742  } else {
743  query_name(tmp, name_tmp, MAX_BUF);
745  "You can not put a %s into a %s",
746  name_tmp,
747  name_sack);
748  return;
749  }
750  }
751 
752  /* Don't worry about this for containers - our caller should have
753  * already checked this.
754  */
755  if (sack->type == CONTAINER && !sack_can_hold(op, sack, tmp, nrof ? nrof : tmp->nrof))
756  return;
757 
758  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
759  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
760  return;
761  }
762 
763  /* we want to put some portion of the item into the container */
764  if (nrof && tmp->nrof != nrof) {
765  char failure[MAX_BUF];
766 
767  tmp = object_split(tmp, nrof, failure, sizeof(failure));
768 
769  if (!tmp) {
771  failure);
772  return;
773  }
774  } else
775  object_remove(tmp);
776 
777  if (sack->nrof > 1) {
778  orig = object_split(sack, sack->nrof-1, NULL, 0);
779  set_object_face_main(orig);
780  CLEAR_FLAG(orig, FLAG_APPLIED);
781  if (sack->env) {
782  object_insert_in_ob(orig, sack->env);
783  } else {
784  object_insert_in_map_at(orig, sack->map, NULL, 0, sack->x, sack->y);
785  orig->move_off = 0;
786  }
787  }
788 
789  query_name(tmp, name_tmp, MAX_BUF);
791  "You put the %s in %s.",
792  name_tmp, name_sack);
793 
794  object_insert_in_ob(tmp, sack);
795  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
796  fix_object(op); /* This is overkill, fix_player() is called somewhere */
797  /* in object.c */
798 
799  /* If a transport, need to update all the players in the transport
800  * the view of what is in it.
801  */
802  if (sack->type == TRANSPORT) {
803  FOR_INV_PREPARE(sack, tmp)
804  if (tmp->type == PLAYER)
805  tmp->contr->socket.update_look = 1;
806  FOR_INV_FINISH();
807  } else {
808  /* update the sacks weight */
809  esrv_update_item(UPD_WEIGHT, op, sack);
810  }
811 }
812 
828 object *drop_object(object *op, object *tmp, uint32_t nrof) {
829  tag_t tmp_tag;
830 
831  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
832  return NULL;
833  }
834 
835  if (QUERY_FLAG(tmp, FLAG_APPLIED)) {
836  if (apply_special(op, tmp, AP_UNAPPLY|AP_NO_MERGE))
837  return NULL; /* can't unapply it */
838  }
839 
840  /* Lauwenmark: Handle for plugin drop event */
841  if (execute_event(tmp, EVENT_DROP, op, NULL, NULL, SCRIPT_FIX_ALL) != 0)
842  return NULL;
843 
844  /* ensure the plugin didn't destroy the object */
845  if (QUERY_FLAG(tmp, FLAG_REMOVED))
846  return NULL;
847 
848  /* We are only dropping some of the items. We split the current objec
849  * off
850  */
851  if (nrof && tmp->nrof != nrof) {
852  char failure[MAX_BUF];
853 
854  tmp = object_split(tmp, nrof, failure, sizeof(failure));
855  if (!tmp) {
857  failure);
858  return NULL;
859  }
860  } else
861  object_remove(tmp);
862 
863  if (QUERY_FLAG(tmp, FLAG_STARTEQUIP)) {
864  char name[MAX_BUF];
865 
866  query_name(tmp, name, MAX_BUF);
868  "You drop the %s. The gods who lent it to you retrieve it.",
869  name);
871 
872  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER))
873  fix_object(op);
874 
875  return NULL;
876  }
877 
878  /* If SAVE_INTERVAL is commented out, we never want to save
879  * the player here.
880  */
881 #ifdef SAVE_INTERVAL
882  /* I'm not sure why there is a value check - since the save
883  * is done every SAVE_INTERVAL seconds, why care the value
884  * of what he is dropping?
885  */
886  if (op->type == PLAYER
887  && !QUERY_FLAG(tmp, FLAG_UNPAID)
888  && (tmp->nrof ? tmp->value*tmp->nrof : tmp->value > 2000)
889  && op->contr->last_save_time+SAVE_INTERVAL <= time(NULL)) {
890  save_player(op, 1);
891  op->contr->last_save_time = time(NULL);
892  }
893 #endif /* SAVE_INTERVAL */
894 
895 
896  tmp_tag = tmp->count;
897  object_insert_in_map_at(tmp, op->map, op, INS_BELOW_ORIGINATOR, op->x, op->y);
898  if (!object_was_destroyed(tmp, tmp_tag) && !QUERY_FLAG(tmp, FLAG_UNPAID) && tmp->type != MONEY && shop_contains(op)) {
899  sell_item(tmp, op);
900  }
901 
902  /* Call this before we update the various windows/players. At least
903  * that we, we know the weight is correct.
904  */
905  if (!QUERY_FLAG(op, FLAG_NO_FIX_PLAYER)) {
906  fix_object(op); /* This is overkill, fix_player() is called somewhere */
907  /* in object.c */
908 
909  /* Need to update weight of player */
910  if (op->type == PLAYER)
911  esrv_update_item(UPD_WEIGHT, op, op);
912  }
913  return tmp;
914 }
915 
924 void drop(object *op, object *tmp) {
925  /* Hopeful fix for disappearing objects when dropping from a container -
926  * somehow, players get an invisible object in the container, and the
927  * old logic would skip over invisible objects - works fine for the
928  * playes inventory, but drop inventory wants to use the next value.
929  */
930  if (tmp->invisible) {
931  /* if the following is the case, it must be in an container. */
932  if (tmp->env && tmp->env->type != PLAYER) {
933  /* Just toss the object - probably shouldn't be hanging
934  * around anyways
935  */
936  object_remove(tmp);
938  return;
939  } else {
941  if (!tmp->invisible)
942  break;
944  }
945  }
946 
947  if (tmp == NULL) {
949  "You don't have anything to drop.");
950  return;
951  }
952  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED)) {
954  "This item is locked");
955  return;
956  }
957  if (QUERY_FLAG(tmp, FLAG_NO_DROP)) {
958  return;
959  }
960 
961  if (op->container) {
962  if (op->type == PLAYER) {
963  put_object_in_sack(op, op->container, tmp, op->contr->count);
964  } else {
965  put_object_in_sack(op, op->container, tmp, 0);
966  };
967  } else {
968  if (op->type == PLAYER) {
969  drop_object(op, tmp, op->contr->count);
970  } else {
971  drop_object(op, tmp, 0);
972  };
973  }
974  if (op->type == PLAYER)
975  op->contr->count = 0;
976 }
977 
986 void command_dropall(object *op, const char *params) {
987  int count = 0;
988 
989  if (op->inv == NULL) {
990  draw_ext_info(NDI_UNIQUE, 0, op,
992  "Nothing to drop!");
993  return;
994  }
995 
996  if (op->contr)
997  count = op->contr->count;
998 
999  /* Set this so we don't call it for _every_ object that
1000  * is dropped.
1001  */
1003 
1004  /*
1005  * This is the default. Drops everything not locked or considered
1006  * not something that should be dropped.
1007  * Care must be taken that the next item pointer is not to money as
1008  * the drop() routine will do unknown things to it when dropping
1009  * in a shop. --Tero.Pelander@utu.fi
1010  */
1011  if (*params == '\0') {
1012  FOR_INV_PREPARE(op, curinv) {
1013  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1014  && curinv->type != MONEY
1015  && curinv->type != FOOD
1016  && curinv->type != KEY
1017  && curinv->type != SPECIAL_KEY
1018  && curinv->type != GEM
1019  && !curinv->invisible
1020  && (curinv->type != CONTAINER || op->container != curinv)) {
1021  drop(op, curinv);
1022  if (op->contr)
1023  op->contr->count = count;
1024  }
1025  } FOR_INV_FINISH();
1026  } else if (strcmp(params, "weapons") == 0) {
1027  FOR_INV_PREPARE(op, curinv) {
1028  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1029  && (curinv->type == WEAPON || curinv->type == BOW || curinv->type == ARROW)) {
1030  drop(op, curinv);
1031  if (op->contr)
1032  op->contr->count = count;
1033  }
1034  } FOR_INV_FINISH();
1035  } else if (strcmp(params, "armor") == 0 || strcmp(params, "armour") == 0) {
1036  FOR_INV_PREPARE(op, curinv) {
1037  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1038  && (curinv->type == ARMOUR || curinv->type == SHIELD || curinv->type == HELMET)) {
1039  drop(op, curinv);
1040  if (op->contr)
1041  op->contr->count = count;
1042  }
1043  } FOR_INV_FINISH();
1044  } else if (strcmp(params, "food") == 0) {
1045  FOR_INV_PREPARE(op, curinv) {
1046  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1047  && (curinv->type == FOOD || curinv->type == DRINK)) {
1048  drop(op, curinv);
1049  if (op->contr)
1050  op->contr->count = count;
1051  }
1052  } FOR_INV_FINISH();
1053  } else if (strcmp(params, "flesh") == 0) {
1054  FOR_INV_PREPARE(op, curinv) {
1055  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1056  && (curinv->type == FLESH)) {
1057  drop(op, curinv);
1058  if (op->contr)
1059  op->contr->count = count;
1060  }
1061  } FOR_INV_FINISH();
1062  } else if (strcmp(params, "misc") == 0) {
1063  FOR_INV_PREPARE(op, curinv) {
1064  if (!QUERY_FLAG(curinv, FLAG_INV_LOCKED)
1065  && !QUERY_FLAG(curinv, FLAG_APPLIED)) {
1066  switch (curinv->type) {
1067  case BOOK:
1068  case SPELLBOOK:
1069  case GIRDLE:
1070  case AMULET:
1071  case RING:
1072  case CLOAK:
1073  case BOOTS:
1074  case GLOVES:
1075  case BRACERS:
1076  case SCROLL:
1077  case ARMOUR_IMPROVER:
1078  case WEAPON_IMPROVER:
1079  case WAND:
1080  case ROD:
1081  case POTION:
1082  drop(op, curinv);
1083  if (op->contr)
1084  op->contr->count = count;
1085  break;
1086 
1087  default:
1088  break;
1089  }
1090  }
1091  } FOR_INV_FINISH();
1092  }
1093  op->contr->socket.update_look = 1;
1095  /* call it now, once */
1096  fix_object(op);
1097  /* Need to update weight of player. Likewise, only do it once */
1098  if (op->type == PLAYER)
1099  esrv_update_item(UPD_WEIGHT, op, op);
1100 }
1101 
1110 void command_drop(object *op, const char *params) {
1111  int did_one = 0;
1112  int ival = 0;
1113  int missed = 0;
1114 
1115  if (*params == '\0') {
1117  "Drop what?");
1118  return;
1119  } else {
1120  FOR_INV_PREPARE(op, tmp) {
1121  if (QUERY_FLAG(tmp, FLAG_NO_DROP) || tmp->invisible)
1122  continue;
1123  ival = object_matches_string(op, tmp, params);
1124  if (ival > 0) {
1125  if (QUERY_FLAG(tmp, FLAG_INV_LOCKED) && (ival == 1 || ival == 2))
1126  missed++;
1127  else
1128  drop(op, tmp);
1129  did_one = 1;
1130  }
1131  } FOR_INV_FINISH();
1132  if (!did_one)
1134  "Nothing to drop.");
1135  if (missed == 1)
1137  "One item couldn't be dropped because it was locked.");
1138  else if (missed > 1)
1140  "%d items couldn't be dropped because they were locked.",
1141  missed);
1142  }
1143  if (op->type == PLAYER) {
1144  op->contr->count = 0;
1145  /*
1146  * Don't force a whole look update, items were transferred during their move.
1147  * Also this would send a 'delinv 0' to the client, which would make it appear
1148  * an opened container was closed.
1149  */
1150  /*op->contr->socket.update_look = 1;*/
1151  }
1152 }
1153 
1162 static void empty_container(object *container, object *pl) {
1163  int left = 0;
1164  char name[MAX_BUF];
1165 
1166  if (!container->inv)
1167  return;
1168 
1169  FOR_INV_PREPARE(container, inv) {
1170  object *next;
1171 
1172  if (QUERY_FLAG(inv, FLAG_INV_LOCKED)) {
1173  /* you can have locked items in container. */
1174  left++;
1175  continue;
1176  }
1177  next = inv->below;
1178  drop(pl, inv);
1179  if (inv->below == next)
1180  /* item couldn't be dropped for some reason. */
1181  left++;
1182  } FOR_INV_FINISH();
1183  esrv_update_item(UPD_WEIGHT, pl, container);
1184 
1185  query_name(container, name, sizeof(name));
1186  if (left)
1187  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s except %d items.", name, left);
1188  else
1189  draw_ext_info_format(NDI_UNIQUE, 0, pl, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_SUCCESS, "You empty the %s.", name);
1190 }
1191 
1200 void command_empty(object *op, const char *params) {
1201  object *container;
1202 
1203  if (*params == '\0') {
1205  "Empty what?");
1206  return;
1207  }
1208 
1209  if (strcmp(params, "all") == 0) {
1210  FOR_INV_PREPARE(op, inv)
1211  if (inv->type == CONTAINER)
1212  empty_container(inv, op);
1213  FOR_INV_FINISH();
1214  return;
1215  }
1216 
1217  container = find_best_object_match(op, params);
1218  if (!container) {
1220  "No such item.");
1221  return;
1222  }
1223  if (container->type != CONTAINER) {
1225  "This is not a container!");
1226  return;
1227  }
1228  empty_container(container, op);
1229 }
1230 
1239 void command_examine(object *op, const char *params) {
1240  if (*params == '\0') {
1241  FOR_BELOW_PREPARE(op, tmp)
1242  if (LOOK_OBJ(tmp)) {
1243  examine(op, tmp);
1244  break;
1245  }
1246  FOR_BELOW_FINISH();
1247  } else {
1248  object *tmp = find_best_object_match(op, params);
1249 
1250  if (tmp)
1251  examine(op, tmp);
1252  else
1254  "Could not find an object that matches %s",
1255  params);
1256  }
1257 }
1258 
1270 object *find_marked_object(object *op) {
1271  if (!op || !op->contr || !op->contr->mark)
1272  return NULL;
1273 
1274  /* This may seem like overkill, but we need to make sure that they
1275  * player hasn't dropped the item. We use count on the off chance that
1276  * an item got reincarnated at some point.
1277  */
1278  /*
1279  FOR_INV_PREPARE(op, tmp) {
1280  if (tmp->invisible)
1281  continue;
1282  if (tmp == op->contr->mark) {
1283  if (tmp->count == op->contr->mark_count)
1284  return tmp;
1285  else {
1286  op->contr->mark = NULL;
1287  op->contr->mark_count = 0;
1288  return NULL;
1289  }
1290  }
1291  } FOR_INV_FINISH();
1292  */
1293  /* Try a different way of doing this
1294  * We check the environment of the marked object
1295  * to make sure it is still in the player's inventory.
1296  * In addition, we ensure there is the correct tag for that item.
1297  *
1298  * Daniel Hawkins 2018-10-23
1299  */
1300  if (op->contr->mark->env == op && op->contr->mark->count == op->contr->mark_count)
1301  return op->contr->mark;
1302  // Otherwise reset the mark, since it is no longer valid.
1303  op->contr->mark = NULL;
1304  op->contr->mark_count = 0;
1305  return NULL;
1306 }
1307 
1317 void command_mark(object *op, const char *params) {
1318  char name[MAX_BUF];
1319 
1320  if (!op->contr)
1321  return;
1322  if (*params == '\0') {
1323  object *mark = find_marked_object(op);
1324  if (!mark)
1326  "You have no marked object.");
1327  else {
1328  query_name(mark, name, MAX_BUF);
1330  "%s is marked.",
1331  name);
1332  }
1333  } else {
1334  object *mark1 = find_best_object_match(op, params);
1335 
1336  if (!mark1) {
1338  "Could not find an object that matches %s",
1339  params);
1340  return;
1341  } else {
1342  op->contr->mark = mark1;
1343  op->contr->mark_count = mark1->count;
1344  query_name(mark1, name, MAX_BUF);
1346  "Marked item %s",
1347  name);
1348  return;
1349  }
1350  }
1351  /*shouldnt get here */
1352 }
1353 
1364 void examine_monster(object *op, object *tmp, int level) {
1365  object *mon = HEAD(tmp), *probe;
1366 
1367  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1369  "It is an undead force.");
1370  if (mon->level > op->level)
1372  "It is likely more powerful than you.");
1373  else if (mon->level < op->level)
1375  "It is likely less powerful than you.");
1376  else
1378  "It is probably as powerful as you.");
1379 
1380  if (mon->attacktype&AT_ACID)
1382  "You smell an acrid odor.");
1383 
1384  /* Anyone know why this used to use the clone value instead of the
1385  * maxhp field? This seems that it should give more accurate results.
1386  */
1387  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1388  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1389  case 0:
1391  "It is critically wounded.");
1392  break;
1393 
1394  case 1:
1396  "It is in a bad shape.");
1397  break;
1398 
1399  case 2:
1401  "It is hurt.");
1402  break;
1403 
1404  case 3:
1406  "It is somewhat hurt.");
1407  break;
1408 
1409  default:
1411  "It is in excellent shape.");
1412  break;
1413  }
1414  if (object_present_in_ob(POISONING, mon) != NULL)
1416  "It looks very ill.");
1417 
1418  if (level < 10)
1419  return;
1421 
1422  if (level < 15)
1423  return;
1424 
1425  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1426  if (probe != NULL && probe->level > level)
1427  return;
1428 
1429  if (probe == NULL) {
1431  free_string(probe->name);
1432  probe->name = add_string("probe_force");
1435  object_insert_in_ob(probe, mon);
1436  fix_object(mon);
1437  }
1438  probe->level = level;
1439  if (level / 10 > probe->duration)
1440  probe->duration = level / 10;
1441 }
1442 
1452 void examine(object *op, object *tmp) {
1453  char buf[VERY_BIG_BUF];
1454  int in_shop;
1455  int i, exp = 0, conn;
1456 
1457  /* we use this to track how far along we got with trying to identify an item,
1458  * so that we can give the appropriate message to the player */
1459  int id_attempted = 0;
1460  char prefix[MAX_BUF] = "That is";
1461  const typedata *tmptype;
1462  object *skill;
1463 
1464  buf[0] = '\0';
1465 
1466  if (tmp == NULL || tmp->type == CLOSE_CON)
1467  return;
1468  tmptype = get_typedata(tmp->type);
1469  if (!tmptype) {
1470  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid", tmp->count, tmp->type);
1471  return;
1472  }
1473  /* first of all check whether this is an item we need to identify, and identify it as best we can.*/
1474  if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
1475  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1476  skill = find_skill_by_number(op, SK_DET_MAGIC);
1477  if (skill && (object_can_pick(op, tmp))) {
1478  exp = detect_magic_on_item(op, tmp, skill);
1479  if (exp) {
1480  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1482  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1483  }
1484  }
1485  skill = find_skill_by_number(op, SK_DET_CURSE);
1486  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1487  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1488  exp = detect_curse_on_item(op, tmp, skill);
1489  if (exp) {
1490  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1492  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1493  }
1494  }
1495  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1496 
1497  id_attempted = 1;
1498  skill = find_skill_by_number(op, tmptype->identifyskill);
1499  if (skill) {
1500  id_attempted = 2;
1501 
1502  /* identify_object_with_skill() may merge tmp with another
1503  * object, so once that happens, we really can not do
1504  * any further processing with tmp. It would be possible
1505  * to modify identify_object_with_skill() to return
1506  * the merged object, but it is currently set to return
1507  * exp, so it would have to do it via modifying the
1508  * passed in value, but many other consumers would
1509  * need to be modified for that.
1510  */
1511  exp = identify_object_with_skill(tmp, op, skill, 1);
1512  if (exp) {
1513  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1514  return;
1515  }
1516  }
1517  if(!exp) {
1518  /* The primary id skill didn't work, let's try the secondary one */
1519  skill = find_skill_by_number(op, tmptype->identifyskill2);
1520  if (skill) {
1521  /* if we've reached here, then the first skill will have been attempted
1522  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1523  * that now, and try with the secondary ID skill, if it fails, then the
1524  * flag will be reset anyway, if it succeeds, it won't matter.*/
1526  id_attempted = 2;
1527  exp = identify_object_with_skill(tmp, op, skill, 1);
1528  if (exp) {
1529  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1530  return;
1531  }
1532  }
1533  }
1534  }
1535  }
1536  if (!exp) {
1537  /* if we did get exp we'll already have propulated prefix */
1538  if (tmptype->identifyskill || tmptype->identifyskill2) {
1539  switch (id_attempted) {
1540  case 1:
1541  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1542  break;
1543  case 2:
1544  snprintf(prefix, MAX_BUF, "You fail to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1545  break;
1546  default:
1547  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1548  }
1549  } else snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1550  }
1551  /* now we need to get the rest of the object description */
1552  ob_describe(tmp, op, 1, buf, sizeof(buf));
1553 
1555  "%s %s", prefix, buf);
1556  buf[0] = '\0';
1557  if (tmp->custom_name) {
1559  "You name it %s",
1560  tmp->custom_name);
1561  }
1562 
1563  switch (tmp->type) {
1564  case SKILLSCROLL:
1565  case SKILL_TOOL:
1566  // Embedded skills are stored as an archetype name and don't get reified
1567  // until the player actually reads/equips the object, so we need to
1568  // handle it differently from spells, which are stored in the inv.
1569  if (!tmp->skill) break; // Blank skill scroll, somehow.
1571  if (!skill) {
1572  // Skill name doesn't correspond to any actual skill.
1574  "Unfortunately the scroll is damaged and unreadable.");
1575  break;
1576  }
1577  // Only print the flavor text once we have identified.
1578  if (is_identified(tmp) && skill->clone.msg) {
1580  stringbuffer_append_string(sb, skill->clone.msg);
1582  char *const fluff = stringbuffer_finish(sb);
1583  // SPELL_INFO is not a perfect match here, but it should display in the
1584  // same manner as the spell descriptions below and there's no SKILL_INFO
1585  // message type.
1587  free(fluff);
1588  }
1589  break;
1590 
1591  case SPELLBOOK:
1592  case SCROLL:
1593  case WAND:
1594  case ROD:
1595  case POTION:
1596  // Only print the flavor text once we have identified.
1597  if (is_identified(tmp) && tmp->inv && tmp->inv->msg) {
1598  // If the embedded spell has a msg, display it here so that the
1599  // player knows what it does before they actually read/use the item.
1600  // Strip trailing newlines so that the output of examine() is
1601  // contiguous.
1602  // TODO: It might be better to strip the newlines in object_set_msg
1603  // and append them at print time, rather than ensuring that the msg
1604  // is newline-terminated and stripping off the newlines when we don't
1605  // want them; C string handling makes the latter a lot less convenient.
1607  stringbuffer_append_string(sb, tmp->inv->msg);
1609  char *const fluff = stringbuffer_finish(sb);
1611  free(fluff);
1612  }
1613  if (tmp->type == WAND && is_identified(tmp)) {
1614  snprintf(buf, sizeof(buf), "It has %d charges left.", tmp->stats.food);
1615  }
1616  break;
1617 
1618  case BOOK:
1619  if (tmp->msg != NULL)
1620  snprintf(buf, sizeof(buf), "Something is written in it.");
1621  break;
1622 
1623  case CONTAINER:
1624  if (tmp->race != NULL) {
1625  if (tmp->weight_limit && tmp->stats.Str < 100)
1626  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)));
1627  else
1628  snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
1629  } else
1630  if (tmp->weight_limit && tmp->stats.Str < 100)
1631  snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
1632  break;
1633  }
1634 
1635  if (buf[0] != '\0')
1637  buf);
1638 
1639  // TODO: combine with weight and properly pluralize, so you get:
1640  // It is made of stone and weighs 15.0 kg.
1641  // They are made of paper and weigh 3 kg.
1642  if (tmp->materialname != NULL && !tmp->msg) {
1644  "It is made of: %s.",
1645  tmp->materialname);
1646  }
1647  /* Where to wear this item */
1648  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1649  if (tmp->body_info[i]) {
1650  if (op->body_info[i]) {
1651  if (tmp->body_info[i] < -1) {
1653  "%s %s (%d)", tmp->nrof > 1 ? "They go" : "It goes",
1654  body_locations[i].use_name, -tmp->body_info[i]);
1655  } else {
1657  "%s %s", tmp->nrof > 1 ? "They go" : "It goes",
1659  }
1660  } else {
1662  "%s %s", tmp->nrof > 1 ? "They go" : "It goes",
1664  }
1665  }
1666  }
1667 
1668  if (tmp->weight) {
1669  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));
1671  buf);
1672  }
1673 
1674  in_shop = shop_contains(op);
1675 
1676  if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
1677  char *value = cost_approx_str(tmp, op);
1678  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
1679  free(value);
1681  buf);
1682  if (in_shop) {
1683  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1684  value = cost_str(shop_price_buy(tmp, op));
1685  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
1686  free(value);
1687  } else {
1688  value = cost_str(shop_price_sell(tmp, op));
1689  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
1690  free(value);
1691  }
1693  buf);
1694  }
1695  }
1696 
1697  if (QUERY_FLAG(tmp, FLAG_MONSTER))
1698  examine_monster(op, tmp, 0);
1699 
1700  /* Is this item buildable? */
1701  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
1703  "This is a buildable item.");
1704  if (QUERY_FLAG(tmp, FLAG_IS_LINKED)){
1705  conn = get_button_value(tmp);
1706  if (conn) {
1707  FOR_INV_PREPARE(op, tmp_inv) {
1708  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
1709  && strcmp(tmp_inv->slaying, op->map->path) == 0
1710  && tmp_inv->msg != NULL
1711  && tmp_inv->path_attuned == (uint32_t) conn) {
1712 
1714  MSG_TYPE_COMMAND_EXAMINE, "Connected with: %s",
1715  tmp_inv->msg);
1716 
1717  break;
1718  }
1719  } FOR_INV_FINISH();
1720  }
1721  }
1722  }
1723 
1724  /* Does the object have a message? Don't show message for all object
1725  * types - especially if the first entry is a match
1726  */
1727  if (tmp->msg
1728  && tmp->type != EXIT
1729  && tmp->type != BOOK
1730  && tmp->type != CORPSE
1731  && !tmp->move_on
1732  && strncasecmp(tmp->msg, "@match", 6)) {
1733  /* This is just a hack so when identifying the items, we print
1734  * out the extra message. Do this only for "identifiable types", e.g.
1735  * we don't want to print this message when the player looks at a
1736  * locked door (where msg is used to store the message they get when
1737  * trying to force it open).
1738  *
1739  * Also, don't print the message for the object unless it has been identified
1740  * -- SilverNexus 2015-05-20
1741  */
1742  if (is_identifiable_type(tmp) && is_identified(tmp)) {
1744  "The object has a story:");
1745 
1747  tmp->msg);
1748  }
1749  }
1751  " "); /* Blank line */
1752 
1753  if (is_identified(tmp)) {
1755  }
1756 }
1757 
1766 void inventory(object *op, object *inv) {
1767  const char *in;
1768  int items = 0, length;
1769  char weight[MAX_BUF], name[MAX_BUF];
1770 
1771  if (inv == NULL && op == NULL) {
1773  "Inventory of what object?");
1774  return;
1775  }
1776  FOR_INV_PREPARE(inv ? inv : op, tmp)
1777  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
1778  || !op || QUERY_FLAG(op, FLAG_WIZ))
1779  items++;
1780  FOR_INV_FINISH();
1781  if (inv == NULL) { /* player's inventory */
1782  if (items == 0) {
1784  "You carry nothing.");
1785  return;
1786  } else {
1787  length = 28;
1788  in = "";
1790  "Inventory:");
1791  }
1792  } else {
1793  if (items == 0)
1794  return;
1795  else {
1796  length = 28;
1797  in = " ";
1798  }
1799  }
1800  FOR_INV_PREPARE(inv ? inv : op, tmp) {
1801  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
1802  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
1803  continue;
1804  query_weight(tmp, weight, MAX_BUF);
1805  query_name(tmp, name, MAX_BUF);
1806  if (!op || QUERY_FLAG(op, FLAG_WIZ))
1808  "[fixed]%s- %-*.*s (%5d) %-8s",
1809  in, length, length, name, tmp->count, weight);
1810  else
1812  "[fixed]%s- %-*.*s %-8s",
1813  in, length+8, length+8, name, weight);
1814  } FOR_INV_FINISH();
1815  if (!inv && op) {
1816  query_weight(op, weight, MAX_BUF);
1818  "[fixed]%-*s %-8s",
1819  41, "Total weight :", weight);
1820  }
1821 }
1822 
1831 static void display_new_pickup(const object *op, int old) {
1832  int i = op->contr->mode;
1833 
1834  esrv_send_pickup(op->contr);
1835 
1836  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
1837  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
1839  "Pickup is %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
1840  }
1841  return;
1842  }
1843 
1845  "%d NEWMODE",
1846  i&PU_NEWMODE ? 1 : 0);
1848  "%d DEBUG",
1849  i&PU_DEBUG ? 1 : 0);
1851  "%d INHIBIT",
1852  i&PU_INHIBIT ? 1 : 0);
1854  "%d STOP",
1855  i&PU_STOP ? 1 : 0);
1856 
1858  "%d <= x pickup weight/value RATIO (0==off)",
1859  (i&PU_RATIO)*5);
1860 
1862  "%d FOOD",
1863  i&PU_FOOD ? 1 : 0);
1865  "%d DRINK",
1866  i&PU_DRINK ? 1 : 0);
1868  "%d VALUABLES",
1869  i&PU_VALUABLES ? 1 : 0);
1870 
1872  "%d BOW",
1873  i&PU_BOW ? 1 : 0);
1875  "%d ARROW",
1876  i&PU_ARROW ? 1 : 0);
1877 
1879  "%d HELMET",
1880  i&PU_HELMET ? 1 : 0);
1882  "%d SHIELD",
1883  i&PU_SHIELD ? 1 : 0);
1885  "%d ARMOUR",
1886  i&PU_ARMOUR ? 1 : 0);
1887 
1889  "%d BOOTS",
1890  i&PU_BOOTS ? 1 : 0);
1892  "%d GLOVES",
1893  i&PU_GLOVES ? 1 : 0);
1895  "%d CLOAK",
1896  i&PU_CLOAK ? 1 : 0);
1898  "%d KEY",
1899  i&PU_KEY ? 1 : 0);
1900 
1902  "%d MISSILEWEAPON",
1903  i&PU_MISSILEWEAPON ? 1 : 0);
1905  "%d MELEEWEAPON",
1906  i&PU_MELEEWEAPON ? 1 : 0);
1908  "%d MAGICAL",
1909  i&PU_MAGICAL ? 1 : 0);
1911  "%d POTION",
1912  i&PU_POTION ? 1 : 0);
1913 
1915  "%d SPELLBOOK",
1916  i&PU_SPELLBOOK ? 1 : 0);
1918  "%d SKILLSCROLL",
1919  i&PU_SKILLSCROLL ? 1 : 0);
1921  "%d READABLES",
1922  i&PU_READABLES ? 1 : 0);
1924  "%d MAGICDEVICE",
1925  i&PU_MAGIC_DEVICE ? 1 : 0);
1926 
1928  "%d NOT CURSED",
1929  i&PU_NOT_CURSED ? 1 : 0);
1930 
1932  "%d JEWELS",
1933  i&PU_JEWELS ? 1 : 0);
1934 
1936  "%d FLESH",
1937  i&PU_FLESH ? 1 : 0);
1938 
1940  "%d CONTAINER",
1941  i&PU_CONTAINER ? 1 : 0);
1942 
1944  "");
1945 }
1946 
1956 void command_pickup(object *op, const char *params) {
1957  uint32_t i;
1958  static const char *names[] = {
1959  "debug", "inhibit", "stop", "food", "drink",
1960  "valuables", "bow", "arrow", "helmet", "shield",
1961  "armour", "boots", "gloves", "cloak", "key",
1962  "missile", "melee", "magical", "potion", "spellbook",
1963  "skillscroll", "readables", "magicdevice", "notcursed", "jewels",
1964  "flesh", "container", NULL
1965  };
1966  static const uint32_t modes[] = {
1971  };
1972 
1973  if (*params == '\0') {
1974  /* if the new mode is used, just print the settings */
1975  if (op->contr->mode&PU_NEWMODE) {
1976  display_new_pickup(op, op->contr->mode);
1977  return;
1978  }
1979  if (1)
1980  LOG(llevDebug, "command_pickup: !params\n");
1981  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
1982  return;
1983  }
1984 
1985  while (*params == ' ')
1986  params++;
1987 
1988  if (*params == '+' || *params == '-' || *params == '!') {
1989  int mode;
1990 
1991  for (mode = 0; names[mode]; mode++) {
1992  if (!strcmp(names[mode], params+1)) {
1993  int old = op->contr->mode;
1994  i = op->contr->mode;
1995  if (!(i&PU_NEWMODE))
1996  i = PU_NEWMODE;
1997  if (*params == '+')
1998  i = i|modes[mode];
1999  else if (*params == '-')
2000  i = i&~modes[mode];
2001  else {
2002  if (i&modes[mode])
2003  i = i&~modes[mode];
2004  else
2005  i = i|modes[mode];
2006  }
2007  op->contr->mode = i;
2008  display_new_pickup(op, old);
2009  return;
2010  }
2011  }
2013  "Pickup: invalid item %s\n",
2014  params);
2015  return;
2016  }
2017 
2018  if (sscanf(params, "%u", &i) != 1) {
2019  if (1)
2020  LOG(llevDebug, "command_pickup: params==NULL\n");
2022  "Usage: pickup <0-7> or <value_density> .");
2023  return;
2024  }
2025  set_pickup_mode(op, i);
2026  display_new_pickup(op, op->contr->mode);
2027 }
2028 
2037 static void set_pickup_mode(const object *op, int i) {
2038  op->contr->mode = i;
2039  switch (op->contr->mode) {
2040  case 0:
2042  "Mode: Don't pick up.");
2043  break;
2044 
2045  case 1:
2047  "Mode: Pick up one item.");
2048  break;
2049 
2050  case 2:
2052  "Mode: Pick up one item and stop.");
2053  break;
2054 
2055  case 3:
2057  "Mode: Stop before picking up.");
2058  break;
2059 
2060  case 4:
2062  "Mode: Pick up all items.");
2063  break;
2064 
2065  case 5:
2067  "Mode: Pick up all items and stop.");
2068  break;
2069 
2070  case 6:
2072  "Mode: Pick up all magic items.");
2073  break;
2074 
2075  case 7:
2077  "Mode: Pick up all coins and gems");
2078  break;
2079  }
2080 }
2081 
2090 void command_search_items(object *op, const char *params) {
2091  if (settings.search_items == FALSE)
2092  return;
2093 
2094  if (*params == '\0') {
2095  if (op->contr->search_str[0] == '\0') {
2097  "Example: search magic+1 "
2098  "Would automatically pick up all "
2099  "items containing the word 'magic+1'.");
2100  return;
2101  }
2102  op->contr->search_str[0] = '\0';
2104  "Search mode turned off.");
2105  fix_object(op);
2106  return;
2107  }
2108  if ((int)strlen(params) >= MAX_BUF) {
2110  "Search string too long.");
2111  return;
2112  }
2113  strcpy(op->contr->search_str, params);
2115  "Searching for '%s'.",
2116  op->contr->search_str);
2117  fix_object(op);
2118 }
2119 
2135 void command_rename_item(object *op, const char *params) {
2136  char buf[VERY_BIG_BUF], name[MAX_BUF];
2137  tag_t itemnumber;
2138  object *item = NULL;
2139  object *tmp;
2140  char *closebrace;
2141  size_t counter;
2142 
2143  if (*params != '\0') {
2144  /* Let's skip white spaces */
2145  while (' ' == *params)
2146  params++;
2147 
2148  /* Checking the first part */
2149  itemnumber = atoi(params);
2150  if (itemnumber != 0) {
2151  int found = 0;
2152  FOR_INV_PREPARE(op, item)
2153  if (item->count == itemnumber && !item->invisible) {
2154  found = 1;
2155  break;
2156  }
2157  FOR_INV_FINISH();
2158  if (!found) {
2160  "Tried to rename an invalid item.");
2161  return;
2162  }
2163  while (isdigit(*params) || ' ' == *params)
2164  params++;
2165  } else if ('<' == *params) {
2166  /* Got old name, let's get it & find appropriate matching item */
2167  closebrace = strchr(params, '>');
2168  if (!closebrace) {
2170  "Syntax error!");
2171  return;
2172  }
2173  /* Sanity check for buffer overruns */
2174  if (closebrace-params > 127) {
2176  "Old name too long (up to 127 characters allowed)!");
2177  return;
2178  }
2179  /* Copy the old name */
2180  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2181 
2182  /* Find best matching item */
2183  item = find_best_object_match(op, buf);
2184  if (!item) {
2186  "Could not find a matching item to rename.");
2187  return;
2188  }
2189 
2190  /* Now need to move pointer to just after > */
2191  params = closebrace+1;
2192  while (' ' == *params)
2193  params++;
2194  } else {
2195  /* Use marked item */
2196  item = find_marked_object(op);
2197  if (!item) {
2199  "No marked item to rename.");
2200  return;
2201  }
2202  }
2203 
2204  /* Now let's find the new name */
2205  if (!strncmp(params, "to ", 3)) {
2206  params += 3;
2207  while (' ' == *params)
2208  params++;
2209  if ('<' != *params) {
2211  "Syntax error, expecting < at start of new name!");
2212  return;
2213  }
2214  closebrace = strchr(params+1, '>');
2215  if (!closebrace) {
2217  "Syntax error, expecting > at end of new name!");
2218  return;
2219  }
2220 
2221  /* Sanity check for buffer overruns */
2222  if (closebrace-params > 127) {
2224  "New name too long (up to 127 characters allowed)!");
2225  return;
2226  }
2227 
2228  /* Copy the new name */
2229  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2230 
2231  /* Let's check it for weird characters */
2232  for (counter = 0; counter < strlen(buf); counter++) {
2233  if (isalnum(buf[counter]))
2234  continue;
2235  if (' ' == buf[counter])
2236  continue;
2237  if ('\'' == buf[counter])
2238  continue;
2239  if ('+' == buf[counter])
2240  continue;
2241  if ('_' == buf[counter])
2242  continue;
2243  if ('-' == buf[counter])
2244  continue;
2245 
2246  /* If we come here, then the name contains an invalid character...
2247  * tell the player & exit
2248  */
2250  "Invalid new name!");
2251  return;
2252  }
2253  } else {
2254  /* If param contains something, then syntax error... */
2255  if (strlen(params)) {
2257  "Syntax error, expected 'to <' after old name!");
2258  return;
2259  }
2260  /* New name is empty */
2261  buf[0] = '\0';
2262  }
2263  } else {
2264  /* Last case: *params=='\0' */
2265  item = find_marked_object(op);
2266  if (!item) {
2268  "No marked item to rename.");
2269  return;
2270  }
2271  buf[0] = '\0';
2272  }
2273 
2274  /* Coming here, everything is fine... */
2275  if (!strlen(buf)) {
2276  /* Clear custom name */
2277  if (item->custom_name == NULL) {
2279  "This item has no custom name.");
2280  return;
2281  }
2282 
2284  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2286  "You stop calling your %s with weird names.",
2287  name);
2288  } else {
2289  if (item->custom_name != NULL && strcmp(item->custom_name, buf) == 0) {
2290  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2292  "You keep calling your %s %s.",
2293  name, buf);
2294  return;
2295  }
2296 
2297  /* Set custom name */
2298  FREE_AND_COPY(item->custom_name, buf);
2299 
2300  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2302  "Your %s will now be called %s.",
2303  name, buf);
2304  }
2305 
2306  tmp = object_merge(item, NULL);
2307  if (tmp == NULL) {
2308  /* object was not merged - if it was, object_merge() handles updating for us. */
2309  esrv_update_item(UPD_NAME, op, item);
2310  }
2311 }
2312 
2321 void command_lock_item(object *op, const char *params) {
2322  object *item;
2323  object *tmp;
2324  char name[HUGE_BUF];
2325 
2326  if (*params == '\0' || strlen(params) == 0) {
2328  "Lock what item?");
2329  return;
2330  }
2331 
2332  item = find_best_object_match(op, params);
2333  if (!item) {
2335  "Can't find any matching item.");
2336  return;
2337  }
2338 
2339  query_short_name(item, name, HUGE_BUF);
2340  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2342  "Unlocked %s.", name);
2343  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2344  } else {
2346  "Locked %s.", name);
2347  SET_FLAG(item, FLAG_INV_LOCKED);
2348  }
2349 
2350  tmp = object_merge(item, NULL);
2351  if (tmp == NULL) {
2352  /* object was not merged, if it was object_merge() handles updates for us */
2353  esrv_update_item(UPD_FLAGS, op, item);
2354  }
2355 }
2356 
2364 void command_use(object *op, const char *params) {
2365  char *with, copy[MAX_BUF];
2366  object *first, *second/*, *add*/;
2367  /*archetype *arch;*/
2368  /*int count;*/
2369  /*sstring data;*/
2370  recipe *transformation;
2371 
2372  if (!IS_PLAYER(op))
2373  return;
2374 
2375  strlcpy(copy, params, sizeof(copy));
2376  with = strstr(copy, " with ");
2377  if (!with) {
2378  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2379  return;
2380  }
2381 
2382  with[0] = '\0';
2383  with = with+strlen(" with ");
2384 
2385  first = find_best_object_match(op, copy);
2386  if (!first) {
2387  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2388  return;
2389  }
2390  second = find_best_object_match(op, with);
2391  if (!second) {
2392  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2393  return;
2394  }
2395 
2396  transformation = NULL;
2397  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2399  if (transformation->ingred_count != 1)
2400  continue;
2401 
2402 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2403  if (strcmp(second->name, transformation->ingred->name) == 0) {
2405  object *generated = create_archetype(transformation->arch_name[0]);
2406  if (transformation->yield)
2407  generated->nrof = transformation->yield;
2408  object_insert_in_ob(generated, op);
2409  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2411  return;
2412  }
2413  }
2414  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2415  return;
2416 
2417  /*
2418  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2419  data = object_get_value(second, copy);
2420  if (!data) {
2421  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2422  data = object_get_value(second, copy);
2423  if (!data) {
2424  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2425  data = object_get_value(second, copy);
2426  if (!data) {
2427  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2428  return 1;
2429  }
2430  }
2431  }
2432 
2433  while (data != NULL) {
2434  if (strncmp(data, "add ", 4) == 0) {
2435  data += 4;
2436  if (isdigit(*data)) {
2437  count = atol(data);
2438  data = strchr(data, ' ')+1;
2439  } else
2440  count = 1;
2441  with = strchr(data, ' ');
2442  if (!with) {
2443  strncpy(copy, data, sizeof(copy));
2444  data = NULL;
2445  } else {
2446  *with = '\0';
2447  strncpy(copy, data, sizeof(copy));
2448  data += strlen(copy)+1;
2449  }
2450  arch = find_archetype(copy);
2451  if (!arch) {
2452  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2453  return 1;
2454  }
2455  add = object_create_arch(arch);
2456  add->nrof = count;
2457  object_insert_in_ob(add, op);
2458  } else if (strncmp(data, "remove $", 8) == 0) {
2459  data += 8;
2460  if (*data == '1') {
2461  if (first)
2462  first = object_decrease_nrof_by_one(first);
2463  data += 2;
2464  } else if (*data == '2') {
2465  if (second)
2466  second = object_decrease_nrof_by_one(second);
2467  data += 2;
2468  } else {
2469  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2470  return 1;
2471  }
2472  } else {
2473  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2474  return 1;
2475  }
2476  }
2477 
2478  return 1;
2479  */
2480 }
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:612
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Definition: object.c:3887
char path[HUGE_BUF]
Definition: map.h:365
void apply_by_living_below(object *pl)
Definition: apply.c:696
void sell_item(object *op, object *pl)
Definition: shop.c:951
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:1157
#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:368
#define MSG_TYPE_COMMAND_INVENTORY
Definition: newclient.h:513
#define FLAG_IS_LINKED
Definition: define.h:316
MoveType move_type
Definition: object.h:427
#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:2090
Definition: object.h:127
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Definition: c_object.c:692
void pick_up(object *op, object *alt)
Definition: c_object.c:460
MoveType move_on
Definition: object.h:430
Definition: object.h:185
bool shop_contains(object *ob)
Definition: shop.c:1274
uint8_t max_stat
Definition: global.h:326
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:2321
#define MSG_TYPE_COMMAND_FAILURE
Definition: newclient.h:511
void command_take(object *op, const char *params)
Definition: c_object.c:599
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
void stringbuffer_trim_whitespace(StringBuffer *sb)
Definition: stringbuffer.c:166
#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:802
#define MSG_TYPE_SPELL
Definition: newclient.h:387
#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
StringBuffer * stringbuffer_new(void)
Definition: stringbuffer.c:57
void inventory(object *op, object *inv)
Definition: c_object.c:1766
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
#define MSG_TYPE_SPELL_INFO
Definition: newclient.h:634
#define NDI_BLUE
Definition: newclient.h:226
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:680
object clone
Definition: object.h:472
socket_struct socket
Definition: player.h:94
linked_char * ingred
Definition: recipe.h:22
int16_t invisible
Definition: object.h:362
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:410
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:2356
Definition: object.h:187
static void pick_up_object(object *pl, object *op, object *tmp, int nrof)
Definition: c_object.c:329
Definition: object.h:212
#define SCRIPT_FIX_ALL
Definition: global.h:367
#define AP_APPLY
Definition: define.h:611
#define PU_NEWMODE
Definition: define.h:111
void command_dropall(object *op, const char *params)
Definition: c_object.c:986
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
Definition: object.h:467
#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:1200
#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:2135
int ingred_count
Definition: recipe.h:23
const typedata * get_typedata(int itemtype)
Definition: item.c:318
#define FLAG_UNDEAD
Definition: define.h:270
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Definition: spell_effect.c:700
#define AP_OPEN
Definition: define.h:613
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Definition: knowledge.c:1350
uint32_t update_look
Definition: newserver.h:104
void object_free_drop_inventory(object *ob)
Definition: object.c:1316
int16_t y
Definition: object.h:327
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Definition: object.c:1838
void command_examine(object *op, const char *params)
Definition: c_object.c:1239
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:638
void examine(object *op, object *tmp)
Definition: c_object.c:1452
void command_search(object *op, const char *params)
Definition: c_object.c:166
Definition: object.h:114
int is_identified(const object *op)
Definition: item.c:1316
Definition: object.h:181
object * create_archetype(const char *name)
Definition: arch.c:620
void stringbuffer_append_string(StringBuffer *sb, const char *str)
Definition: stringbuffer.c:95
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Definition: skills.c:701
char ** arch_name
Definition: recipe.h:13
uint64_t shop_price_buy(const object *obj, object *who)
Definition: shop.c:192
int object_can_pick(const object *who, const object *item)
Definition: object.c:3646
object * object_insert_in_ob(object *op, object *where)
Definition: object.c:2591
char * cost_approx_str(const object *obj, object *who)
Definition: shop.c:421
#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:268
const char * materialname
Definition: object.h:348
int32_t weight
Definition: object.h:367
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:1110
#define FLAG_PROBE
Definition: define.h:257
int32_t carrying
Definition: object.h:369
archetype * get_archetype_by_skill_name(const char *skill, int type)
Definition: arch.c:108
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:72
#define PU_BOW
Definition: define.h:118
#define AP_NULL
Definition: define.h:610
struct obj * below
Definition: object.h:287
object * object_present_in_ob(uint8_t type, const object *op)
Definition: object.c:2889
#define PU_RATIO
Definition: define.h:113
char * cost_str(uint64_t cost)
Definition: shop.c:417
uint32_t nrof
Definition: object.h:334
#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:431
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:272
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:2099
static void empty_container(object *container, object *pl)
Definition: c_object.c:1162
#define FREE_AND_CLEAR_STR(xyz)
Definition: global.h:205
const char * use_name
Definition: object.h:22
#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:1544
static void set_pickup_mode(const object *op, int i)
Definition: c_object.c:2037
#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
#define PU_READABLES
Definition: define.h:137
const char * nonuse_name
Definition: object.h:23
int16_t x
Definition: object.h:327
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:250
#define EVENT_DROP
Definition: plugin.h:71
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:1956
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
char * ob_describe(const object *op, const object *observer, int use_media_tags, char *buf, size_t size)
Definition: ob_methods.c:92
#define AP_NO_MERGE
Definition: define.h:618
int set_object_face_main(object *op)
Definition: apply.c:146
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:271
int8_t body_info[NUM_BODY_LOCATIONS]
Definition: object.h:375
uint32_t attacktype
Definition: object.h:344
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
Definition: object.c:2371
#define INS_NO_MERGE
Definition: object.h:568
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Definition: skills.c:750
#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:210
Definition: object.h:243
Definition: object.h:143
const char * custom_name
Definition: object.h:435
int get_button_value(const object *button)
Definition: button.c:754
void command_use(object *op, const char *params)
Definition: c_object.c:2364
tag_t count
Definition: object.h:299
living stats
Definition: object.h:370
struct archt * arch
Definition: object.h:415
#define FLAG_IS_BUILDABLE
Definition: define.h:376
uint8_t type
Definition: object.h:340
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:1831
#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:1789
void query_short_name(const object *op, char *buf, size_t size)
Definition: item.c:508
#define PU_SPELLBOOK
Definition: define.h:135
object * object_get_player_container(object *op)
Definition: object.c:377
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:4323
#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:1664
#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:1270
void query_name(const object *op, char *buf, size_t size)
Definition: item.c:583
#define PU_ARMOUR
Definition: define.h:123
object * drop_object(object *op, object *tmp, uint32_t nrof)
Definition: c_object.c:828
#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
int is_identifiable_type(const object *op)
Definition: item.c:1292
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:353
int8_t facing
Definition: object.h:337
#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:352
const char * name
Definition: object.h:468
char * stringbuffer_finish(StringBuffer *sb)
Definition: stringbuffer.c:76
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:1317
#define FOR_INV_PREPARE(op_, it_)
Definition: define.h:707
void object_remove(object *op)
Definition: object.c:1577
void examine_monster(object *op, object *tmp, int level)
Definition: c_object.c:1364
#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:924