Crossfire Server, Trunk  R20513
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 retrieves 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  FOR_INV_PREPARE(op, tmp) {
1265  if (tmp->invisible)
1266  continue;
1267  if (tmp == op->contr->mark) {
1268  if (tmp->count == op->contr->mark_count)
1269  return tmp;
1270  else {
1271  op->contr->mark = NULL;
1272  op->contr->mark_count = 0;
1273  return NULL;
1274  }
1275  }
1276  } FOR_INV_FINISH();
1277  return NULL;
1278 }
1279 
1289 void command_mark(object *op, const char *params) {
1290  char name[MAX_BUF];
1291 
1292  if (!op->contr)
1293  return;
1294  if (*params == '\0') {
1295  object *mark = find_marked_object(op);
1296  if (!mark)
1298  "You have no marked object.");
1299  else {
1300  query_name(mark, name, MAX_BUF);
1302  "%s is marked.",
1303  name);
1304  }
1305  } else {
1306  object *mark1 = find_best_object_match(op, params);
1307 
1308  if (!mark1) {
1310  "Could not find an object that matches %s",
1311  params);
1312  return;
1313  } else {
1314  op->contr->mark = mark1;
1315  op->contr->mark_count = mark1->count;
1316  query_name(mark1, name, MAX_BUF);
1318  "Marked item %s",
1319  name);
1320  return;
1321  }
1322  }
1323  /*shouldnt get here */
1324 }
1325 
1336 void examine_monster(object *op, object *tmp, int level) {
1337  object *mon = HEAD(tmp), *probe;
1338 
1339  if (QUERY_FLAG(mon, FLAG_UNDEAD))
1341  "It is an undead force.");
1342  if (mon->level > op->level)
1344  "It is likely more powerful than you.");
1345  else if (mon->level < op->level)
1347  "It is likely less powerful than you.");
1348  else
1350  "It is probably as powerful as you.");
1351 
1352  if (mon->attacktype&AT_ACID)
1354  "You smell an acrid odor.");
1355 
1356  /* Anyone know why this used to use the clone value instead of the
1357  * maxhp field? This seems that it should give more accurate results.
1358  */
1359  switch ((mon->stats.hp+1)*4/(mon->stats.maxhp+1)) {
1360  /* From 0-4+, since hp can be higher than maxhp if defined in map. */
1361  case 0:
1363  "It is critically wounded.");
1364  break;
1365 
1366  case 1:
1368  "It is in a bad shape.");
1369  break;
1370 
1371  case 2:
1373  "It is hurt.");
1374  break;
1375 
1376  case 3:
1378  "It is somewhat hurt.");
1379  break;
1380 
1381  default:
1383  "It is in excellent shape.");
1384  break;
1385  }
1386  if (object_present_in_ob(POISONING, mon) != NULL)
1388  "It looks very ill.");
1389 
1390  if (level < 10)
1391  return;
1393 
1394  if (level < 15)
1395  return;
1396 
1397  probe = object_find_by_type_and_name(mon, FORCE, "probe_force");
1398  if (probe != NULL && probe->level > level)
1399  return;
1400 
1401  if (probe == NULL) {
1403  free_string(probe->name);
1404  probe->name = add_string("probe_force");
1407  object_insert_in_ob(probe, mon);
1408  fix_object(mon);
1409  }
1410  probe->level = level;
1411  if (level / 10 > probe->duration)
1412  probe->duration = level / 10;
1413 }
1414 
1424 void examine(object *op, object *tmp) {
1425  char buf[VERY_BIG_BUF];
1426  int in_shop;
1427  int i, exp = 0, conn;
1428 
1429  /* we use this to track how far along we got with trying to identify an item,
1430  * so that we can give the appropriate message to the player */
1431  int id_attempted = 0;
1432  char prefix[MAX_BUF] = "That is";
1433  const typedata *tmptype;
1434  object *skill;
1435 
1436  buf[0] = '\0';
1437 
1438  if (tmp == NULL || tmp->type == CLOSE_CON)
1439  return;
1440  tmptype = get_typedata(tmp->type);
1441  if (!tmptype) {
1442  LOG(llevError, "Attempted to examine item %d with type %d, which is invalid", tmp->count, tmp->type);
1443  return;
1444  }
1445  /* first of all check whether this is an item we need to identify, and identify it as best we can.*/
1446  if (!QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
1447  /* We will look for magic status, cursed status and then try to do a full skill-based ID, in that order */
1448  skill = find_skill_by_number(op, SK_DET_MAGIC);
1449  if (skill && (object_can_pick(op, tmp))) {
1450  exp = detect_magic_on_item(op, tmp, skill);
1451  if (exp) {
1452  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1454  "You discover mystic forces on %s", tmp->nrof <= 1?"that item":"those items" );
1455  }
1456  }
1457  skill = find_skill_by_number(op, SK_DET_CURSE);
1458  /* Cauldrons are a special case of item where it should be possible to detect a curse */
1459  if (skill && (object_can_pick(op, tmp) || QUERY_FLAG(tmp, FLAG_IS_CAULDRON))) {
1460  exp = detect_curse_on_item(op, tmp, skill);
1461  if (exp) {
1462  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1464  "You have a bad feeling about %s", tmp->nrof <= 1?"that item":"those items" );
1465  }
1466  }
1467  if (!QUERY_FLAG(tmp, FLAG_NO_SKILL_IDENT)) {
1468 
1469  id_attempted = 1;
1470  skill = find_skill_by_number(op, tmptype->identifyskill);
1471  if (skill) {
1472  id_attempted = 2;
1473 
1474  /* identify_object_with_skill() may merge tmp with another
1475  * object, so once that happens, we really can not do
1476  * any further processing with tmp. It would be possible
1477  * to modify identify_object_with_skill() to return
1478  * the merged object, but it is currently set to return
1479  * exp, so it would have to do it via modifying the
1480  * passed in value, but many other consumers would
1481  * need to be modified for that.
1482  */
1483  exp = identify_object_with_skill(tmp, op, skill, 1);
1484  if (exp) {
1485  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1486  return;
1487  }
1488  }
1489  if(!exp) {
1490  /* The primary id skill didn't work, let's try the secondary one */
1491  skill = find_skill_by_number(op, tmptype->identifyskill2);
1492  if (skill) {
1493  /* if we've reached here, then the first skill will have been attempted
1494  * and failed; this will have set FLAG_NO_SKILL_IDENT we want to clear
1495  * that now, and try with the secondary ID skill, if it fails, then the
1496  * flag will be reset anyway, if it succeeds, it won't matter.*/
1498  id_attempted = 2;
1499  exp = identify_object_with_skill(tmp, op, skill, 1);
1500  if (exp) {
1501  change_exp(op, exp, skill->skill, SK_SUBTRACT_SKILL_EXP);
1502  return;
1503  }
1504  }
1505  }
1506  }
1507  }
1508  if (!exp) {
1509  /* if we did get exp we'll already have propulated prefix */
1510  if (tmptype->identifyskill || tmptype->identifyskill2) {
1511  switch (id_attempted) {
1512  case 1:
1513  snprintf(prefix, MAX_BUF, "You lack the skill to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1514  break;
1515  case 2:
1516  snprintf(prefix, MAX_BUF, "You fail to understand %s:", tmp->nrof <= 1?"that fully; it is":"those fully, they are");
1517  break;
1518  default:
1519  snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1520  }
1521  } else snprintf(prefix, MAX_BUF, "%s:", tmp->nrof <= 1?"That is":"Those are");
1522  }
1523  /* now we need to get the rest of the object description */
1524  ob_describe(tmp, op, buf, sizeof(buf));
1525 
1527  "%s %s", prefix, buf);
1528  buf[0] = '\0';
1529  if (tmp->custom_name) {
1531  "You name it %s",
1532  tmp->custom_name);
1533  }
1534 
1535  switch (tmp->type) {
1536  case SPELLBOOK:
1537  if (QUERY_FLAG(tmp, FLAG_IDENTIFIED) && tmp->inv) {
1538  char level[100];
1539 
1540  get_levelnumber(tmp->inv->level, level, 100);
1541  snprintf(buf, sizeof(buf), "%s is a %s level %s spell", tmp->inv->name, level, tmp->inv->skill);
1542  }
1543  break;
1544 
1545  case BOOK:
1546  if (tmp->msg != NULL)
1547  snprintf(buf, sizeof(buf), "Something is written in it.");
1548  break;
1549 
1550  case CONTAINER:
1551  if (tmp->race != NULL) {
1552  if (tmp->weight_limit && tmp->stats.Str < 100)
1553  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)));
1554  else
1555  snprintf(buf, sizeof(buf), "It can hold only %s.", tmp->race);
1556  } else
1557  if (tmp->weight_limit && tmp->stats.Str < 100)
1558  snprintf(buf, sizeof(buf), "Its weight limit is %.1f kg.", tmp->weight_limit/(10.0*(100-tmp->stats.Str)));
1559  break;
1560 
1561  case WAND:
1562  if (QUERY_FLAG(tmp, FLAG_IDENTIFIED))
1563  snprintf(buf, sizeof(buf), "It has %d charges left.", tmp->stats.food);
1564  break;
1565  }
1566 
1567  if (buf[0] != '\0')
1569  buf);
1570 
1571  if (tmp->materialname != NULL && !tmp->msg) {
1573  "It is made of: %s.",
1574  tmp->materialname);
1575  }
1576  /* Where to wear this item */
1577  for (i = 0; i < NUM_BODY_LOCATIONS; i++) {
1578  if (tmp->body_info[i] < -1) {
1579  if (op->body_info[i])
1581  "It goes %s (%d)",
1582  body_locations[i].use_name, -tmp->body_info[i]);
1583  else
1585  "It goes %s",
1586  body_locations[i].nonuse_name);
1587  } else if (tmp->body_info[i]) {
1588  if (op->body_info[i])
1590  "It goes %s",
1591  body_locations[i].use_name);
1592  else
1594  "It goes %s",
1595  body_locations[i].nonuse_name);
1596  }
1597  }
1598 
1599  if (tmp->weight) {
1600  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));
1602  buf);
1603  }
1604 
1605  in_shop = shop_contains(op);
1606 
1607  if (tmp->value && !QUERY_FLAG(tmp, FLAG_STARTEQUIP) && !QUERY_FLAG(tmp, FLAG_NO_PICK)) {
1608  char *value = cost_approx_str(tmp, op);
1609  snprintf(buf, sizeof(buf), "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", value);
1610  free(value);
1612  buf);
1613  if (in_shop) {
1614  if (QUERY_FLAG(tmp, FLAG_UNPAID)) {
1615  value = cost_str(shop_price_buy(tmp, op));
1616  snprintf(buf, sizeof(buf), "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", value);
1617  free(value);
1618  } else {
1619  value = cost_str(shop_price_sell(tmp, op));
1620  snprintf(buf, sizeof(buf), "You are offered %s for %s.", value, tmp->nrof > 1 ? "them" : "it");
1621  free(value);
1622  }
1624  buf);
1625  }
1626  }
1627 
1628  if (QUERY_FLAG(tmp, FLAG_MONSTER))
1629  examine_monster(op, tmp, 0);
1630 
1631  /* Is this item buildable? */
1632  if (QUERY_FLAG(tmp, FLAG_IS_BUILDABLE)) {
1634  "This is a buildable item.");
1635  if (QUERY_FLAG(tmp, FLAG_IS_LINKED)){
1636  conn = get_button_value(tmp);
1637  if (conn) {
1638  FOR_INV_PREPARE(op, tmp_inv) {
1639  if (tmp_inv->type == FORCE && tmp_inv->slaying != NULL
1640  && strcmp(tmp_inv->slaying, op->map->path) == 0
1641  && tmp_inv->msg != NULL
1642  && tmp_inv->path_attuned == (uint32_t) conn) {
1643 
1645  MSG_TYPE_COMMAND_EXAMINE, "Connected with: %s",
1646  tmp_inv->msg);
1647 
1648  break;
1649  }
1650  } FOR_INV_FINISH();
1651  }
1652  }
1653  }
1654 
1655  /* Does the object have a message? Don't show message for all object
1656  * types - especially if the first entry is a match
1657  */
1658  if (tmp->msg
1659  && tmp->type != EXIT
1660  && tmp->type != BOOK
1661  && tmp->type != CORPSE
1662  && !tmp->move_on
1663  && strncasecmp(tmp->msg, "@match", 6)) {
1664  /* This is just a hack so when identifying the items, we print
1665  * out the extra message
1666  *
1667  * Also, don't print the message for the object unless it has been identified
1668  * -- SilverNexus 2015-05-20
1669  */
1670  if (need_identify(tmp) && QUERY_FLAG(tmp, FLAG_IDENTIFIED)){
1672  "The object has a story:");
1673 
1675  tmp->msg);
1676  }
1677  }
1679  " "); /* Blank line */
1680 
1681  if (!need_identify(tmp) || QUERY_FLAG(tmp, FLAG_IDENTIFIED)) {
1683  }
1684 }
1685 
1694 void inventory(object *op, object *inv) {
1695  const char *in;
1696  int items = 0, length;
1697  char weight[MAX_BUF], name[MAX_BUF];
1698 
1699  if (inv == NULL && op == NULL) {
1701  "Inventory of what object?");
1702  return;
1703  }
1704  FOR_INV_PREPARE(inv ? inv : op, tmp)
1705  if ((!tmp->invisible && (inv == NULL || inv->type == CONTAINER || QUERY_FLAG(tmp, FLAG_APPLIED)))
1706  || !op || QUERY_FLAG(op, FLAG_WIZ))
1707  items++;
1708  FOR_INV_FINISH();
1709  if (inv == NULL) { /* player's inventory */
1710  if (items == 0) {
1712  "You carry nothing.");
1713  return;
1714  } else {
1715  length = 28;
1716  in = "";
1718  "Inventory:");
1719  }
1720  } else {
1721  if (items == 0)
1722  return;
1723  else {
1724  length = 28;
1725  in = " ";
1726  }
1727  }
1728  FOR_INV_PREPARE(inv ? inv : op, tmp) {
1729  if ((!op || !QUERY_FLAG(op, FLAG_WIZ))
1730  && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG(tmp, FLAG_APPLIED))))
1731  continue;
1732  query_weight(tmp, weight, MAX_BUF);
1733  query_name(tmp, name, MAX_BUF);
1734  if (!op || QUERY_FLAG(op, FLAG_WIZ))
1736  "[fixed]%s- %-*.*s (%5d) %-8s",
1737  in, length, length, name, tmp->count, weight);
1738  else
1740  "[fixed]%s- %-*.*s %-8s",
1741  in, length+8, length+8, name, weight);
1742  } FOR_INV_FINISH();
1743  if (!inv && op) {
1744  query_weight(op, weight, MAX_BUF);
1746  "[fixed]%-*s %-8s",
1747  41, "Total weight :", weight);
1748  }
1749 }
1750 
1759 static void display_new_pickup(const object *op, int old) {
1760  int i = op->contr->mode;
1761 
1762  esrv_send_pickup(op->contr);
1763 
1764  if (!(i&PU_NEWMODE) || !(i&PU_DEBUG)) {
1765  if ((old & PU_INHIBIT) != (op->contr->mode & PU_INHIBIT)) {
1767  "Pickup is %s.", (old & PU_INHIBIT) ? "active" : "inhibited");
1768  }
1769  return;
1770  }
1771 
1773  "%d NEWMODE",
1774  i&PU_NEWMODE ? 1 : 0);
1776  "%d DEBUG",
1777  i&PU_DEBUG ? 1 : 0);
1779  "%d INHIBIT",
1780  i&PU_INHIBIT ? 1 : 0);
1782  "%d STOP",
1783  i&PU_STOP ? 1 : 0);
1784 
1786  "%d <= x pickup weight/value RATIO (0==off)",
1787  (i&PU_RATIO)*5);
1788 
1790  "%d FOOD",
1791  i&PU_FOOD ? 1 : 0);
1793  "%d DRINK",
1794  i&PU_DRINK ? 1 : 0);
1796  "%d VALUABLES",
1797  i&PU_VALUABLES ? 1 : 0);
1798 
1800  "%d BOW",
1801  i&PU_BOW ? 1 : 0);
1803  "%d ARROW",
1804  i&PU_ARROW ? 1 : 0);
1805 
1807  "%d HELMET",
1808  i&PU_HELMET ? 1 : 0);
1810  "%d SHIELD",
1811  i&PU_SHIELD ? 1 : 0);
1813  "%d ARMOUR",
1814  i&PU_ARMOUR ? 1 : 0);
1815 
1817  "%d BOOTS",
1818  i&PU_BOOTS ? 1 : 0);
1820  "%d GLOVES",
1821  i&PU_GLOVES ? 1 : 0);
1823  "%d CLOAK",
1824  i&PU_CLOAK ? 1 : 0);
1826  "%d KEY",
1827  i&PU_KEY ? 1 : 0);
1828 
1830  "%d MISSILEWEAPON",
1831  i&PU_MISSILEWEAPON ? 1 : 0);
1833  "%d MELEEWEAPON",
1834  i&PU_MELEEWEAPON ? 1 : 0);
1836  "%d MAGICAL",
1837  i&PU_MAGICAL ? 1 : 0);
1839  "%d POTION",
1840  i&PU_POTION ? 1 : 0);
1841 
1843  "%d SPELLBOOK",
1844  i&PU_SPELLBOOK ? 1 : 0);
1846  "%d SKILLSCROLL",
1847  i&PU_SKILLSCROLL ? 1 : 0);
1849  "%d READABLES",
1850  i&PU_READABLES ? 1 : 0);
1852  "%d MAGICDEVICE",
1853  i&PU_MAGIC_DEVICE ? 1 : 0);
1854 
1856  "%d NOT CURSED",
1857  i&PU_NOT_CURSED ? 1 : 0);
1858 
1860  "%d JEWELS",
1861  i&PU_JEWELS ? 1 : 0);
1862 
1864  "%d FLESH",
1865  i&PU_FLESH ? 1 : 0);
1866 
1868  "%d CONTAINER",
1869  i&PU_CONTAINER ? 1 : 0);
1870 
1872  "");
1873 }
1874 
1884 void command_pickup(object *op, const char *params) {
1885  uint32_t i;
1886  static const char *names[] = {
1887  "debug", "inhibit", "stop", "food", "drink",
1888  "valuables", "bow", "arrow", "helmet", "shield",
1889  "armour", "boots", "gloves", "cloak", "key",
1890  "missile", "melee", "magical", "potion", "spellbook",
1891  "skillscroll", "readables", "magicdevice", "notcursed", "jewels",
1892  "flesh", "container", NULL
1893  };
1894  static const uint32_t modes[] = {
1899  };
1900 
1901  if (*params == '\0') {
1902  /* if the new mode is used, just print the settings */
1903  if (op->contr->mode&PU_NEWMODE) {
1904  display_new_pickup(op, op->contr->mode);
1905  return;
1906  }
1907  if (1)
1908  LOG(llevDebug, "command_pickup: !params\n");
1909  set_pickup_mode(op, op->contr->mode > 6 ? 0 : op->contr->mode+1);
1910  return;
1911  }
1912 
1913  while (*params == ' ')
1914  params++;
1915 
1916  if (*params == '+' || *params == '-' || *params == '!') {
1917  int mode;
1918 
1919  for (mode = 0; names[mode]; mode++) {
1920  if (!strcmp(names[mode], params+1)) {
1921  int old = op->contr->mode;
1922  i = op->contr->mode;
1923  if (!(i&PU_NEWMODE))
1924  i = PU_NEWMODE;
1925  if (*params == '+')
1926  i = i|modes[mode];
1927  else if (*params == '-')
1928  i = i&~modes[mode];
1929  else {
1930  if (i&modes[mode])
1931  i = i&~modes[mode];
1932  else
1933  i = i|modes[mode];
1934  }
1935  op->contr->mode = i;
1936  display_new_pickup(op, old);
1937  return;
1938  }
1939  }
1941  "Pickup: invalid item %s\n",
1942  params);
1943  return;
1944  }
1945 
1946  if (sscanf(params, "%u", &i) != 1) {
1947  if (1)
1948  LOG(llevDebug, "command_pickup: params==NULL\n");
1950  "Usage: pickup <0-7> or <value_density> .");
1951  return;
1952  }
1953  set_pickup_mode(op, i);
1954  display_new_pickup(op, op->contr->mode);
1955 }
1956 
1965 static void set_pickup_mode(const object *op, int i) {
1966  op->contr->mode = i;
1967  switch (op->contr->mode) {
1968  case 0:
1970  "Mode: Don't pick up.");
1971  break;
1972 
1973  case 1:
1975  "Mode: Pick up one item.");
1976  break;
1977 
1978  case 2:
1980  "Mode: Pick up one item and stop.");
1981  break;
1982 
1983  case 3:
1985  "Mode: Stop before picking up.");
1986  break;
1987 
1988  case 4:
1990  "Mode: Pick up all items.");
1991  break;
1992 
1993  case 5:
1995  "Mode: Pick up all items and stop.");
1996  break;
1997 
1998  case 6:
2000  "Mode: Pick up all magic items.");
2001  break;
2002 
2003  case 7:
2005  "Mode: Pick up all coins and gems");
2006  break;
2007  }
2008 }
2009 
2018 void command_search_items(object *op, const char *params) {
2019  if (settings.search_items == FALSE)
2020  return;
2021 
2022  if (*params == '\0') {
2023  if (op->contr->search_str[0] == '\0') {
2025  "Example: search magic+1 "
2026  "Would automatically pick up all "
2027  "items containing the word 'magic+1'.");
2028  return;
2029  }
2030  op->contr->search_str[0] = '\0';
2032  "Search mode turned off.");
2033  fix_object(op);
2034  return;
2035  }
2036  if ((int)strlen(params) >= MAX_BUF) {
2038  "Search string too long.");
2039  return;
2040  }
2041  strcpy(op->contr->search_str, params);
2043  "Searching for '%s'.",
2044  op->contr->search_str);
2045  fix_object(op);
2046 }
2047 
2063 void command_rename_item(object *op, const char *params) {
2064  char buf[VERY_BIG_BUF], name[MAX_BUF];
2065  tag_t itemnumber;
2066  object *item = NULL;
2067  object *tmp;
2068  char *closebrace;
2069  size_t counter;
2070 
2071  if (*params != '\0') {
2072  /* Let's skip white spaces */
2073  while (' ' == *params)
2074  params++;
2075 
2076  /* Checking the first part */
2077  itemnumber = atoi(params);
2078  if (itemnumber != 0) {
2079  int found = 0;
2080  FOR_INV_PREPARE(op, item)
2081  if (item->count == itemnumber && !item->invisible) {
2082  found = 1;
2083  break;
2084  }
2085  FOR_INV_FINISH();
2086  if (!found) {
2088  "Tried to rename an invalid item.");
2089  return;
2090  }
2091  while (isdigit(*params) || ' ' == *params)
2092  params++;
2093  } else if ('<' == *params) {
2094  /* Got old name, let's get it & find appropriate matching item */
2095  closebrace = strchr(params, '>');
2096  if (!closebrace) {
2098  "Syntax error!");
2099  return;
2100  }
2101  /* Sanity check for buffer overruns */
2102  if (closebrace-params > 127) {
2104  "Old name too long (up to 127 characters allowed)!");
2105  return;
2106  }
2107  /* Copy the old name */
2108  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2109 
2110  /* Find best matching item */
2111  item = find_best_object_match(op, buf);
2112  if (!item) {
2114  "Could not find a matching item to rename.");
2115  return;
2116  }
2117 
2118  /* Now need to move pointer to just after > */
2119  params = closebrace+1;
2120  while (' ' == *params)
2121  params++;
2122  } else {
2123  /* Use marked item */
2124  item = find_marked_object(op);
2125  if (!item) {
2127  "No marked item to rename.");
2128  return;
2129  }
2130  }
2131 
2132  /* Now let's find the new name */
2133  if (!strncmp(params, "to ", 3)) {
2134  params += 3;
2135  while (' ' == *params)
2136  params++;
2137  if ('<' != *params) {
2139  "Syntax error, expecting < at start of new name!");
2140  return;
2141  }
2142  closebrace = strchr(params+1, '>');
2143  if (!closebrace) {
2145  "Syntax error, expecting > at end of new name!");
2146  return;
2147  }
2148 
2149  /* Sanity check for buffer overruns */
2150  if (closebrace-params > 127) {
2152  "New name too long (up to 127 characters allowed)!");
2153  return;
2154  }
2155 
2156  /* Copy the new name */
2157  snprintf(buf, sizeof(buf), "%.*s", (int)(closebrace-(params+1)), params+1);
2158 
2159  /* Let's check it for weird characters */
2160  for (counter = 0; counter < strlen(buf); counter++) {
2161  if (isalnum(buf[counter]))
2162  continue;
2163  if (' ' == buf[counter])
2164  continue;
2165  if ('\'' == buf[counter])
2166  continue;
2167  if ('+' == buf[counter])
2168  continue;
2169  if ('_' == buf[counter])
2170  continue;
2171  if ('-' == buf[counter])
2172  continue;
2173 
2174  /* If we come here, then the name contains an invalid character...
2175  * tell the player & exit
2176  */
2178  "Invalid new name!");
2179  return;
2180  }
2181  } else {
2182  /* If param contains something, then syntax error... */
2183  if (strlen(params)) {
2185  "Syntax error, expected 'to <' after old name!");
2186  return;
2187  }
2188  /* New name is empty */
2189  buf[0] = '\0';
2190  }
2191  } else {
2192  /* Last case: *params=='\0' */
2193  item = find_marked_object(op);
2194  if (!item) {
2196  "No marked item to rename.");
2197  return;
2198  }
2199  buf[0] = '\0';
2200  }
2201 
2202  /* Coming here, everything is fine... */
2203  if (!strlen(buf)) {
2204  /* Clear custom name */
2205  if (item->custom_name == NULL) {
2207  "This item has no custom name.");
2208  return;
2209  }
2210 
2212  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2214  "You stop calling your %s with weird names.",
2215  name);
2216  } else {
2217  if (item->custom_name != NULL && strcmp(item->custom_name, buf) == 0) {
2218  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2220  "You keep calling your %s %s.",
2221  name, buf);
2222  return;
2223  }
2224 
2225  /* Set custom name */
2226  FREE_AND_COPY(item->custom_name, buf);
2227 
2228  query_base_name(item, item->nrof > 1 ? 1 : 0, name, MAX_BUF);
2230  "Your %s will now be called %s.",
2231  name, buf);
2232  }
2233 
2234  tmp = object_merge(item, NULL);
2235  if (tmp == NULL) {
2236  /* object was not merged - if it was, object_merge() handles updating for us. */
2237  esrv_update_item(UPD_NAME, op, item);
2238  }
2239 }
2240 
2249 void command_lock_item(object *op, const char *params) {
2250  object *item;
2251  object *tmp;
2252  char name[HUGE_BUF];
2253 
2254  if (*params == '\0' || strlen(params) == 0) {
2256  "Lock what item?");
2257  return;
2258  }
2259 
2260  item = find_best_object_match(op, params);
2261  if (!item) {
2263  "Can't find any matching item.");
2264  return;
2265  }
2266 
2267  query_short_name(item, name, HUGE_BUF);
2268  if (QUERY_FLAG(item, FLAG_INV_LOCKED)) {
2270  "Unlocked %s.", name);
2271  CLEAR_FLAG(item, FLAG_INV_LOCKED);
2272  } else {
2274  "Locked %s.", name);
2275  SET_FLAG(item, FLAG_INV_LOCKED);
2276  }
2277 
2278  tmp = object_merge(item, NULL);
2279  if (tmp == NULL) {
2280  /* object was not merged, if it was object_merge() handles updates for us */
2281  esrv_update_item(UPD_FLAGS, op, item);
2282  }
2283 }
2284 
2292 void command_use(object *op, const char *params) {
2293  char *with, copy[MAX_BUF];
2294  object *first, *second/*, *add*/;
2295  /*archetype *arch;*/
2296  /*int count;*/
2297  /*sstring data;*/
2298  recipe *transformation;
2299 
2300  if (!op->type == PLAYER)
2301  return;
2302 
2303  snprintf(copy, sizeof(copy), "%s", params);
2304  with = strstr(copy, " with ");
2305  if (!with) {
2306  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Syntax is use <item> with <item>.");
2307  return;
2308  }
2309 
2310  with[0] = '\0';
2311  with = with+strlen(" with ");
2312 
2313  first = find_best_object_match(op, copy);
2314  if (!first) {
2315  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", copy);
2316  return;
2317  }
2318  second = find_best_object_match(op, with);
2319  if (!second) {
2320  draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "No match for %s.", with);
2321  return;
2322  }
2323 
2324  transformation = NULL;
2325  while ((transformation = find_recipe_for_tool(first->arch->name, transformation))) {
2327  if (transformation->ingred_count != 1)
2328  continue;
2329 
2330 /* LOG(llevDebug, "use: check %s\n", transformation->title);*/
2331  if (strcmp(second->name, transformation->ingred->name) == 0) {
2333  object *generated = create_archetype(transformation->arch_name[0]);
2334  if (transformation->yield)
2335  generated->nrof = transformation->yield;
2336  object_insert_in_ob(generated, op);
2337  /*draw_ext_info_format(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Found recipe %s", transformation->title);*/
2339  return;
2340  }
2341  }
2342  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2343  return;
2344 
2345  /*
2346  snprintf(copy, sizeof(copy), "on_use_with_%s", first->arch->name);
2347  data = object_get_value(second, copy);
2348  if (!data) {
2349  snprintf(copy, sizeof(copy), "on_use_with_%d_%d", first->type, first->subtype);
2350  data = object_get_value(second, copy);
2351  if (!data) {
2352  snprintf(copy, sizeof(copy), "on_use_with_%d", first->type);
2353  data = object_get_value(second, copy);
2354  if (!data) {
2355  draw_ext_info(NDI_UNIQUE, 0, op, MSG_TYPE_COMMAND, MSG_TYPE_COMMAND_FAILURE, "Nothing happens.");
2356  return 1;
2357  }
2358  }
2359  }
2360 
2361  while (data != NULL) {
2362  if (strncmp(data, "add ", 4) == 0) {
2363  data += 4;
2364  if (isdigit(*data)) {
2365  count = atol(data);
2366  data = strchr(data, ' ')+1;
2367  } else
2368  count = 1;
2369  with = strchr(data, ' ');
2370  if (!with) {
2371  strncpy(copy, data, sizeof(copy));
2372  data = NULL;
2373  } else {
2374  *with = '\0';
2375  strncpy(copy, data, sizeof(copy));
2376  data += strlen(copy)+1;
2377  }
2378  arch = find_archetype(copy);
2379  if (!arch) {
2380  LOG(llevError, "Use: invalid archetype %s in %s.\n", copy, second->name);
2381  return 1;
2382  }
2383  add = object_create_arch(arch);
2384  add->nrof = count;
2385  object_insert_in_ob(add, op);
2386  } else if (strncmp(data, "remove $", 8) == 0) {
2387  data += 8;
2388  if (*data == '1') {
2389  if (first)
2390  first = object_decrease_nrof_by_one(first);
2391  data += 2;
2392  } else if (*data == '2') {
2393  if (second)
2394  second = object_decrease_nrof_by_one(second);
2395  data += 2;
2396  } else {
2397  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2398  return 1;
2399  }
2400  } else {
2401  LOG(llevError, "Use: invalid use string %s in %s\n", data, second->name);
2402  return 1;
2403  }
2404  }
2405 
2406  return 1;
2407  */
2408 }
void draw_ext_info_format(int flags, int pri, const object *pl, uint8_t type, uint8_t subtype, const char *format,...)
Sends message to player(s).
Definition: main.c:315
Error, serious thing.
Definition: logger.h:11
#define AP_UNAPPLY
Item is to be remvoed.
Definition: define.h:611
object * object_find_by_type_and_name(const object *who, int type, const char *name)
Find object in inventory by type and name.
Definition: object.c:3999
char path[HUGE_BUF]
Filename of the map.
Definition: map.h:365
void apply_by_living_below(object *pl)
Attempt to apply the object &#39;below&#39; the player.
Definition: apply.c:618
void sell_item(object *op, object *pl)
Player is selling an item.
Definition: shop.c:921
static object * find_best_object_match(object *pl, const char *params)
Shortcut to find_best_apply_object_match(pl->inv, pl, params, AF_NULL);.
Definition: c_object.c:86
#define FLAG_NO_DROP
Object can&#39;t be dropped.
Definition: define.h:289
#define NUM_BODY_LOCATIONS
Number of body locations.
Definition: object.h:13
One player.
Definition: player.h:92
int apply_special(object *who, object *op, int aflags)
Apply an object.
Definition: apply.c:1082
#define FLAG_IS_FLOOR
Can&#39;t see what&#39;s underneath this object.
Definition: define.h:303
#define FLAG_UNPAID
Object hasn&#39;t been paid for yet.
Definition: define.h:236
int32_t weight_limit
Weight-limit of object.
Definition: object.h:366
#define MSG_TYPE_COMMAND_INVENTORY
Inventory listing.
Definition: newclient.h:513
#define FLAG_IS_LINKED
The object is linked with other objects.
Definition: define.h:316
MoveType move_type
Type of movement this object uses.
Definition: object.h:424
see doc/Developers/objects
Definition: object.h:108
#define INS_BELOW_ORIGINATOR
Insert new object immediately below originator.
Definition: object.h:572
int change_skill(object *who, object *new_skill, int flag)
This changes the object&#39;s skill to new_skill.
Definition: skill_util.c:356
void command_search_items(object *op, const char *params)
&#39;search-items&#39; command.
Definition: c_object.c:2018
See Key.
Definition: object.h:127
void put_object_in_sack(object *op, object *sack, object *tmp, uint32_t nrof)
Something tries to put an object into another.
Definition: c_object.c:678
void pick_up(object *op, object *alt)
Try to pick up an item.
Definition: c_object.c:446
MoveType move_on
Move types affected moving on to this space.
Definition: object.h:427
See Ring.
Definition: object.h:185
bool shop_contains(object *ob)
Check if an object is in a shop.
Definition: shop.c:1239
uint8_t max_stat
Maximum stat value - 255 should be sufficient.
Definition: global.h:322
const char * race
Human, goblin, dragon, etc.
Definition: object.h:318
#define PU_CONTAINER
Definition: define.h:143
Eneq((at)csd.uu.se): Id for close_container archetype.
Definition: object.h:229
#define SET_FLAG(xyz, p)
Definition: define.h:223
See Bracers.
Definition: object.h:217
#define PU_DEBUG
Definition: define.h:108
See Scroll.
Definition: object.h:221
int identifyskill
Skill used to identify this object class.
Definition: define.h:93
void command_lock_item(object *op, const char *params)
Alternate way to lock/unlock items (command line).
Definition: c_object.c:2249
#define MSG_TYPE_COMMAND_FAILURE
Failed result from command.
Definition: newclient.h:511
void get_levelnumber(int i, char *buf, size_t size)
Formats a level.
Definition: item.c:446
void command_take(object *op, const char *params)
This takes (picks up) and item.
Definition: c_object.c:585
See Cloak.
Definition: object.h:204
See Food.
Definition: object.h:112
struct obj * container
Current container being used.
Definition: object.h:291
#define PU_STOP
Definition: define.h:110
See Projectile.
Definition: object.h:117
#define PU_SHIELD
Definition: define.h:122
int yield
Maximum number of items produced by the recipe.
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)
Helper function for do_skill_ident, so that we can loop over inventory AND objects on the ground conv...
Definition: skills.c:796
#define FLAG_NO_FIX_PLAYER
fix_object() won&#39;t be called
Definition: define.h:277
#define LOOK_OBJ(ob)
This returns TRUE if the object is something that should be displayed in the look window...
Definition: object.h:507
int save_player(object *op, int flag)
Saves a player to disk.
Definition: login.c:211
void inventory(object *op, object *inv)
Prints object&#39;s inventory.
Definition: c_object.c:1694
void free_string(sstring str)
This will reduce the refcount, and if it has reached 0, str will be freed.
Definition: shstr.c:280
#define PU_KEY
Definition: define.h:128
#define HUGE_BUF
Used for messages - some can be quite long.
Definition: define.h:37
#define MSG_TYPE_COMMAND_EXAMINE
Player examining something.
Definition: newclient.h:512
void esrv_update_item(int flags, object *pl, object *op)
Updates object *op for player *pl.
Definition: main.c:342
See Spellbook.
Definition: object.h:203
See Money.
Definition: object.h:137
void query_base_name(const object *op, int plural, char *buf, size_t size)
Query a short name for the item.
Definition: item.c:722
socket_struct socket
Socket information for this player.
Definition: player.h:94
linked_char * ingred
List of ingredients.
Definition: recipe.h:22
int16_t invisible
How much longer the object will be invis.
Definition: object.h:360
recipe * find_recipe_for_tool(const char *tool, recipe *from)
Find a recipe for a specified tool.
Definition: recipe.c:828
Detect curse.
Definition: skills.h:33
void command_throw(object *op, const char *params)
&#39;throw&#39; command.
Definition: c_object.c:174
void query_weight(const object *op, char *buf, size_t size)
Formats the item&#39;s weight.
Definition: item.c:426
See Weapon.
Definition: object.h:119
See Helmet.
Definition: object.h:136
const char * slaying
Which race to do double damage to.
Definition: object.h:319
const char * skill_names[NUM_SKILLS]
Will contain a number-name mapping for skills, initialized by init_skills().
Definition: skill_util.c:57
#define MSG_TYPE_SKILL_MISSING
Don&#39;t have the skill.
Definition: newclient.h:582
See Rod.
Definition: object.h:109
uint32_t mark_count
Count of marked object.
Definition: player.h:193
struct obj * above
Pointer to the object stacked above this one.
Definition: object.h:288
See Drink.
Definition: object.h:157
#define object_was_destroyed(op, old_tag)
Checks if an object still exists.
Definition: object.h:68
See Girdle.
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]
The ordering of this is actually doesn&#39;t make a difference However, for ease of use, new entries should go at the end so those people that debug the code that get used to something being in the location 4 don&#39;t get confused.
Definition: item.c:54
object * stop_item(object *op)
An item (ARROW or such) stops moving.
Definition: time.c:450
See Amulet.
Definition: object.h:139
#define FALSE
Definition: compat.h:11
uint32_t get_weight_limit(int stat)
Definition: living.c:2255
animal &#39;body parts&#39; -b.t.
Definition: object.h:187
Global type definitions and header inclusions.
Link an object type with skill needed to identify, and general name.
Definition: define.h:89
static void pick_up_object(object *pl, object *op, object *tmp, int nrof)
Try to pick up some item.
Definition: c_object.c:315
See Boots.
Definition: object.h:212
#define SCRIPT_FIX_ALL
Definition: global.h:361
#define AP_APPLY
Item is to be applied.
Definition: define.h:610
#define PU_NEWMODE
Definition: define.h:111
void command_dropall(object *op, const char *params)
Command to drop all items that have not been locked.
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)
Sends message to player(s).
Definition: main.c:310
void command_rskill(object *pl, const char *params)
&#39;ready_skill&#39; command.
Definition: c_object.c:115
#define PU_MISSILEWEAPON
Definition: define.h:130
See Wand & Staff.
Definition: object.h:220
#define FOR_OB_AND_BELOW_FINISH()
Finishes FOR_OB_AND_BELOW_PREPARE().
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)
&#39;empty&#39; command.
Definition: c_object.c:1186
#define FLAG_REMOVED
Object is not in any map or invenory.
Definition: define.h:232
int16_t hp
Hit Points.
Definition: living.h:39
void command_rename_item(object *op, const char *params)
Changing the custom name of an item.
Definition: c_object.c:2063
int ingred_count
Number of items in ingred.
Definition: recipe.h:23
const typedata * get_typedata(int itemtype)
Definition: item.c:334
Throwing.
Definition: skills.h:44
#define FLAG_UNDEAD
Monster is undead.
Definition: define.h:270
int probe(object *op, object *caster, object *spell_ob, int dir, int level)
Try to get information about a living thing.
Definition: spell_effect.c:683
void knowledge_item_can_be_used_alchemy(object *op, const object *item)
Displays known alchemy recipes an item can be used in.
Definition: knowledge.c:1342
uint32_t update_look
If true, we need to send the look window.
Definition: newserver.h:115
void object_free_drop_inventory(object *ob)
Frees everything allocated by an object, removes it from the list of used objects, and puts it on the list of free objects.
Definition: object.c:1368
int16_t y
Position in the map for this object.
Definition: object.h:326
object * object_insert_in_map_at(object *op, mapstruct *m, object *originator, int flag, int x, int y)
Same as object_insert_in_map() except it handle separate coordinates and do a clean job preparing mul...
Definition: object.c:1921
void command_examine(object *op, const char *params)
&#39;examine&#39; command.
Definition: c_object.c:1225
int16_t maxhp
Max hit points.
Definition: living.h:40
#define MSG_TYPE_COMMAND
Responses to commands, eg, who.
Definition: newclient.h:379
#define PU_BOOTS
Definition: define.h:125
See Shooting Weapon.
Definition: object.h:118
int apply_by_living(object *pl, object *op, int aflag, int quiet)
Living thing is applying an object.
Definition: apply.c:557
void examine(object *op, object *tmp)
Player examines some object.
Definition: c_object.c:1424
Disarm traps.
Definition: skills.h:46
void command_search(object *op, const char *params)
&#39;search&#39; command.
Definition: c_object.c:147
See Book.
Definition: object.h:114
See Exit.
Definition: object.h:181
object * create_archetype(const char *name)
Finds which archetype matches the given name, and returns a new object containing a copy of the arche...
Definition: arch.c:620
int detect_curse_on_item(object *pl, object *tmp, object *skill)
Runs a &#39;detect curse&#39; check on a given item.
Definition: skills.c:695
char ** arch_name
Possible archetypes of the final product made.
Definition: recipe.h:13
uint64_t shop_price_buy(const object *obj, object *who)
Adjust the value of an item to be bought based on the player&#39;s bargaining skill and charisma...
Definition: shop.c:171
int object_can_pick(const object *who, const object *item)
Finds out if an object can be picked up.
Definition: object.c:3793
object * object_insert_in_ob(object *op, object *where)
This function inserts the object op in the linked list inside the object environment.
Definition: object.c:2690
char * cost_approx_str(const object *obj, object *who)
Return a textual cost approximation in a newly-allocated string.
Definition: shop.c:398
#define MSG_TYPE_COMMAND_SUCCESS
Successful result from command.
Definition: newclient.h:510
#define MSG_TYPE_COMMAND_ERROR
Bad syntax/can&#39;t use command.
Definition: newclient.h:509
Defines for loader.l / loader.c.
#define PU_SKILLSCROLL
Definition: define.h:136
signed short int16_t
Definition: win32.h:160
uint8_t search_items
Search_items command.
Definition: global.h:265
See Special Key.
Definition: object.h:124
const char * materialname
Specific material name.
Definition: object.h:346
int32_t weight
Attributes of the object.
Definition: object.h:365
#define PU_ARROW
Definition: define.h:120
struct mapdef * map
Pointer to the map in which this object is present.
Definition: object.h:297
char search_str[MAX_BUF]
Item we are looking for.
Definition: player.h:192
#define snprintf
Definition: win32.h:46
#define FLAG_IDENTIFIED
Player knows full info about item.
Definition: define.h:261
#define FOR_INV_FINISH()
Finishes FOR_INV_PREPARE().
Definition: define.h:712
#define MOVE_FLYING
Combo of fly_low and fly_high.
Definition: define.h:410
void command_drop(object *op, const char *params)
&#39;drop&#39; command.
Definition: c_object.c:1096
#define FLAG_PROBE
Object displays HP information to player.
Definition: define.h:257
int32_t carrying
How much weight this object contains.
Definition: object.h:367
const char * name
The name of the object, obviously...
Definition: object.h:311
#define PU_INHIBIT
Definition: define.h:109
struct obj * env
Pointer to the object which is the environment.
Definition: object.h:293
#define EVENT_PICKUP
Object picked up.
Definition: plugin.h:69
#define PU_BOW
Definition: define.h:118
#define AP_NULL
Nothing specific.
Definition: define.h:609
struct obj * below
Pointer to the object stacked below this one.
Definition: object.h:287
object * object_present_in_ob(uint8_t type, const object *op)
Searches for any objects with a matching type variable in the inventory of the given object...
Definition: object.c:3001
#define PU_RATIO
Definition: define.h:113
char * cost_str(uint64_t cost)
Definition: shop.c:394
uint32_t nrof
How many of the objects.
Definition: object.h:333
Detect magic.
Definition: skills.h:30
#define UPD_FLAGS
Definition: newclient.h:290
void command_apply(object *op, const char *params)
&#39;apply&#39; command.
Definition: c_object.c:195
#define FLAG_IS_CAULDRON
container can make alchemical stuff
Definition: define.h:339
MoveType move_off
Move types affected moving off this space.
Definition: object.h:428
int do_skill(object *op, object *part, object *skill, int dir, const char *string)
Main skills use function-similar in scope to cast_spell().
Definition: skill_util.c:429
uint8_t real_wiz
Use mud-like wizards.
Definition: global.h:269
See Potion.
Definition: object.h:111
struct pl * contr
Pointer to the player which control this object.
Definition: object.h:276
#define PU_DRINK
Definition: define.h:116
Find traps.
Definition: skills.h:34
object * object_insert_in_map(object *op, mapstruct *m, object *originator, int flag)
This function inserts the object in the two-way linked list which represents what is on a map...
Definition: object.c:2152
static void empty_container(object *container, object *pl)
Put all contents of the container on the ground below the player or in opened container, except locked items.
Definition: c_object.c:1148
#define FREE_AND_CLEAR_STR(xyz)
Release the shared string, and set it to NULL.
Definition: global.h:208
#define UPD_WEIGHT
Definition: newclient.h:291
uint32_t tag_t
Object tag, unique during the whole game.
Definition: object.h:12
void knowledge_show_monster_detail(object *op, const char *name)
Display the details of a monster if the player knows them.
Definition: knowledge.c:1536
static void set_pickup_mode(const object *op, int i)
Sets the &#39;old&#39; pickup mode.
Definition: c_object.c:1965
#define QUERY_FLAG(xyz, p)
Definition: define.h:225
#define CLEAR_FLAG(xyz, p)
Definition: define.h:224
#define HEAD(op)
Returns the head part of an object.
Definition: object.h:594
#define FLAG_WIZ
Object has special privilegies.
Definition: define.h:231
void change_exp(object *op, int64_t exp, const char *skill_name, int flag)
Changes experience to a player/monster.
Definition: living.c:2076
#define MAX_BUF
Used for all kinds of things.
Definition: define.h:35
char * ob_describe(const object *op, const object *observer, char *buf, size_t size)
Returns the description of an object, as seen by the given observer.
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)
Case-insensitive comparaison of strings.
Definition: porting.c:224
const char * skill
Name of the skill this object uses/grants.
Definition: object.h:321
Skill-related defines, including subtypes.
uint64_t shop_price_sell(const object *obj, object *who)
Adjust the value of an item to be sold based on the player&#39;s bargaining skill and charisma...
Definition: shop.c:224
#define EVENT_DROP
Object dropped on the floor.
Definition: plugin.h:68
See Container.
Definition: object.h:231
int identifyskill2
Second skill used to identify this object class.
Definition: define.h:94
int8_t Str
Definition: living.h:35
void command_pickup(object *op, const char *params)
&#39;pickup&#39; command.
Definition: c_object.c:1884
int need_identify(const object *op)
This function really should not exist - by default, any item not identified should need it...
Definition: item.c:1331
See Player.
Definition: object.h:107
unsigned int uint32_t
Definition: win32.h:162
#define AP_NO_MERGE
Don&#39;t try to merge object after (un)applying it.
Definition: define.h:616
int set_object_face_main(object *op)
Makes an object&#39;s face the main face, which is supposed to be the "closed" one.
Definition: apply.c:149
See Shield.
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)
Check if an item op can be put into a sack.
Definition: c_object.c:257
int8_t body_info[NUM_BODY_LOCATIONS]
Body info as loaded from the file.
Definition: object.h:372
uint32_t attacktype
Bitmask of attacks this object does.
Definition: object.h:342
object * object_split(object *orig_ob, uint32_t nr, char *err, size_t size)
object_split(ob,nr) splits up ob into two parts.
Definition: object.c:2463
#define INS_NO_MERGE
Don&#39;t try to merge with other items.
Definition: object.h:568
int detect_magic_on_item(object *pl, object *tmp, object *skill)
Runs a &#39;detect magic&#39; check on a given item.
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)
Release the shared string if not NULL, and make it a reference to nv.
Definition: global.h:213
Definition: object.h:243
const char * custom_name
Custom name assigned by player.
Definition: object.h:432
int get_button_value(const object *button)
Returns the first value linked to this button.
Definition: button.c:754
void command_use(object *op, const char *params)
Try to use an item on another.
Definition: c_object.c:2292
tag_t count
Unique object number for this object.
Definition: object.h:299
living stats
Str, Con, Dex, etc.
Definition: object.h:368
struct archt * arch
Pointer to archetype.
Definition: object.h:412
Only for debugging purposes.
Definition: logger.h:13
#define FLAG_IS_BUILDABLE
Can build on item.
Definition: define.h:376
uint8_t type
PLAYER, BULLET, etc.
Definition: object.h:338
uint32_t mode
Mode of player for pickup.
Definition: player.h:110
struct Settings settings
Server settings.
Definition: init.c:40
static void display_new_pickup(const object *op, int old)
Utility function to display the pickup mode for a player.
Definition: c_object.c:1759
#define MSG_TYPE_COMMAND_INFO
Generic info: resistances, etc.
Definition: newclient.h:506
int transport_can_hold(const object *transport, const object *op, int nrof)
Can transport hold object op? This is a pretty trivial function, but in the future, possible transport may have more restrictions or weight reduction like containers.
Definition: apply.c:54
#define FLAG_APPLIED
Object is ready for use by living.
Definition: define.h:235
object * object_merge(object *op, object *top)
This function goes through all objects below and including top, and merges op to the first matching o...
Definition: object.c:1869
void query_short_name(const object *op, char *buf, size_t size)
query_short_name(object) is similar to query_name(), but doesn&#39;t contain any information about object...
Definition: item.c:547
#define PU_SPELLBOOK
Definition: define.h:135
object * object_get_player_container(object *op)
Finds the player carrying an object.
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
If this is a book/sign/magic mouth/etc.
Definition: object.h:322
int object_matches_string(object *pl, object *op, const char *name)
This is a subset of the parse_id command.
Definition: object.c:4453
#define FOR_OB_AND_BELOW_PREPARE(op_)
Constructs a loop iterating over an object and all objects below it in the same pile.
Definition: define.h:785
#define FLAG_STARTEQUIP
Object was given to player at start.
Definition: define.h:268
void command_disarm(object *op, const char *params)
&#39;disarm&#39; command.
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)
This will add &#39;str&#39; to the hash table.
Definition: shstr.c:124
#define PU_JEWELS
Definition: define.h:141
#define FLAG_MONSTER
Will attack players.
Definition: define.h:245
void esrv_send_pickup(player *pl)
Sends the "pickup" state to pl if client wants it requested.
Definition: request.c:1625
#define MSG_TYPE_SKILL
Messages related to skill use.
Definition: newclient.h:383
struct obj * inv
Pointer to the first object in the inventory.
Definition: object.h:290
#define NDI_UNIQUE
Print immediately, don&#39;t buffer.
Definition: newclient.h:245
See Gloves.
Definition: object.h:213
static object * find_best_apply_object_match(object *start, object *pl, const char *params, int aflag)
Search from start and through below for what matches best with params.
Definition: c_object.c:55
void LOG(LogLevel logLevel, const char *format,...)
Logs a message to stderr, or to file.
Definition: logger.c:51
#define PU_GLOVES
Definition: define.h:126
object * mark
Marked object.
Definition: player.h:194
#define FLAG_WAS_WIZ
Player was once a wiz.
Definition: define.h:234
object * find_marked_object(object *op)
Return the object the player has marked with the &#39;mark&#39; command below.
Definition: c_object.c:1256
Structure containing object statistics.
void query_name(const object *op, char *buf, size_t size)
Describes an item.
Definition: item.c:625
#define PU_ARMOUR
Definition: define.h:123
object * drop_object(object *op, object *tmp, uint32_t nrof)
Try to drop an object on the floor.
Definition: c_object.c:814
#define FOR_BELOW_PREPARE(op_, it_)
Constructs a loop iterating over all objects below an object.
Definition: define.h:739
#define SK_SUBTRACT_SKILL_EXP
Used when removing exp.
Definition: skills.h:82
object * find_skill_by_number(object *who, int skillno)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: main.c:351
This is a game-map.
Definition: map.h:325
int use_skill(object *op, const char *string)
Similar to invoke command, it executes the skill in the direction that the user is facing...
Definition: skill_util.c:924
See Jewel.
Definition: object.h:167
#define FLAG_NO_PICK
Object can&#39;t be picked up.
Definition: define.h:239
#define PU_POTION
Definition: define.h:133
#define FLAG_NO_SKILL_IDENT
If set, item cannot be identified w/ a skill.
Definition: define.h:336
See Breastplate Armor.
Definition: object.h:120
#define PU_HELMET
Definition: define.h:121
int16_t level
Level of creature or object.
Definition: object.h:351
int8_t facing
Object is oriented/facing that way.
Definition: object.h:335
#define AT_ACID
Definition: attack.h:82
void command_uskill(object *pl, const char *params)
&#39;use_skill&#39; command.
Definition: c_object.c:98
#define FLAG_INV_LOCKED
Item will not be dropped from inventory.
Definition: define.h:330
void fix_object(object *op)
Updates all abilities given by applied objects in the inventory of the given object.
Definition: living.c:1120
#define PU_NOT_CURSED
Definition: define.h:140
object * find_skill_by_name(object *who, const char *name)
This returns the skill pointer of the given name (the one that accumulates exp, has the level...
Definition: skill_util.c:213
int32_t value
How much money it is worth (or contains)
Definition: object.h:350
const char * name
More definite name, like "generate_kobold".
Definition: object.h:466
#define FOR_BELOW_FINISH()
Finishes FOR_BELOW_PREPARE().
Definition: define.h:746
void command_mark(object *op, const char *params)
&#39;mark&#39; command, to mark an item for some effects (enchant armor, ...).
Definition: c_object.c:1289
#define FOR_INV_PREPARE(op_, it_)
Constructs a loop iterating over the inventory of an object.
Definition: define.h:705
void object_remove(object *op)
This function removes the object op from the linked list of objects which it is currently tied to...
Definition: object.c:1654
One alchemy recipe.
Definition: recipe.h:10
void examine_monster(object *op, object *tmp, int level)
Player examine a monster.
Definition: c_object.c:1336
#define PU_MAGIC_DEVICE
Definition: define.h:138
int32_t food
How much food in stomach.
Definition: living.h:47
#define FLAG_FREED
Object is in the list of free objects.
Definition: define.h:233
uint32_t count
Any numbers typed before a command.
Definition: player.h:109
Definition: object.h:224
void drop(object *op, object *tmp)
Drop an item, either on the floor or in a container.
Definition: c_object.c:910