ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.98
Committed: Thu Oct 15 16:00:38 2009 UTC (14 years, 7 months ago) by sf-marcmagus
Content type: text/plain
Branch: MAIN
Changes since 1.97: +11 -0 lines
Log Message:
Add inscribable arches for other book types.
Use 'container'/weight_limit to define capacity of inscribables in characters.
Add treasures/arches to specify books with/without text.
Scorn and Navar Public Libraries use these so they don't generate inscribables.
Fix bug allowing theft of blank books from libraries.
Fix bug preventing adding an adjective to a book name if the titles are used up.
Change error message on reading empty book to be more clear.
Change error message on failed inscription [too much text] to be more informative.
Looking at an inscribable will tell you what you can do with it/what its capacity is in a hint.
Fix broken debug statements in book generation.

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.60 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 pippijn 1.37 *
4 root 1.88 * Copyright (©) 2005,2006,2007,2008,2009 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
5 root 1.55 * Copyright (©) 2002,2007 Mark Wedel & Crossfire Development Team
6     * Copyright (©) 1992,2007 Frank Tore Johansen
7 pippijn 1.37 *
8 root 1.97 * Deliantra is free software: you can redistribute it and/or modify it under
9     * the terms of the Affero GNU General Public License as published by the
10     * Free Software Foundation, either version 3 of the License, or (at your
11     * option) any later version.
12 pippijn 1.37 *
13 root 1.57 * This program is distributed in the hope that it will be useful,
14     * but WITHOUT ANY WARRANTY; without even the implied warranty of
15     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16     * GNU General Public License for more details.
17 pippijn 1.37 *
18 root 1.97 * You should have received a copy of the Affero GNU General Public License
19     * and the GNU General Public License along with this program. If not, see
20     * <http://www.gnu.org/licenses/>.
21 root 1.55 *
22 root 1.60 * The authors can be reached via e-mail to <support@deliantra.net>
23 pippijn 1.37 */
24 elmex 1.1
25 pippijn 1.37 /*
26     * Object (handling) commands
27     */
28 elmex 1.1
29     #include <global.h>
30     #include <loader.h>
31     #include <skills.h>
32 root 1.32 #include <sproto.h>
33 elmex 1.1 #include <living.h>
34     #include <math.h>
35 root 1.14
36 elmex 1.1 /*
37     * Object id parsing functions
38     */
39    
40     #define ADD_ITEM(NEW,COUNT)\
41 root 1.10 if(!first) {\
42 root 1.21 first = new objectlink;\
43 root 1.10 last=first;\
44     } else {\
45 root 1.21 last->next = new objectlink;\
46 root 1.10 last=last->next;\
47     }\
48 root 1.21 last->next=0;\
49 root 1.10 last->ob=(NEW);\
50 elmex 1.1 last->id=(COUNT);
51    
52     /**
53     * Search the inventory of 'pl' for what matches best with params.
54     * we use item_matched_string above - this gives us consistent behaviour
55     * between many commands. Return the best match, or NULL if no match.
56     * aflag is used with apply -u , and apply -a to
57     * only unapply applied, or apply unapplied objects
58     **/
59 root 1.14 static object *
60     find_best_apply_object_match (object *pl, const char *params, enum apply_flag aflag)
61 elmex 1.1 {
62 root 1.52 object *best = 0;
63     int match_val = 0;
64 elmex 1.1
65 root 1.52 for (object *tmp = pl->inv; tmp; tmp = tmp->below)
66 root 1.14 {
67     if (tmp->invisible)
68     continue;
69 root 1.52
70     int tmpmatch = item_matched_string (pl, tmp, params);
71    
72     if (tmpmatch > match_val)
73 root 1.14 {
74     if ((aflag == AP_APPLY) && (QUERY_FLAG (tmp, FLAG_APPLIED)))
75     continue;
76 root 1.52
77 root 1.14 if ((aflag == AP_UNAPPLY) && (!QUERY_FLAG (tmp, FLAG_APPLIED)))
78     continue;
79 root 1.52
80 root 1.14 match_val = tmpmatch;
81     best = tmp;
82 elmex 1.1 }
83     }
84 root 1.52
85 root 1.14 return best;
86 elmex 1.1 }
87    
88     /**
89     * Shortcut to find_best_apply_object_match(pl, params, AF_NULL);
90     **/
91 root 1.14 object *
92     find_best_object_match (object *pl, const char *params)
93 elmex 1.1 {
94 root 1.54 return find_best_apply_object_match (pl, params, AP_TOGGLE);
95 elmex 1.1 }
96    
97 root 1.66 static bool
98     can_split (object *pl, object *&op, sint32 nrof)
99     {
100 root 1.69 if (object *tmp = op->split (nrof ? nrof : op->number_of ()))
101 root 1.66 {
102     op = tmp;
103     return true;
104     }
105     else
106     {
107 root 1.67 if (op->nrof > 1)
108     new_draw_info_format (NDI_UNIQUE, 0, pl, "There are only %d %s.", op->nrof, &op->name_pl);
109     else
110     new_draw_info_format (NDI_UNIQUE, 0, pl, "There is only one %s.", &op->name);
111    
112 root 1.66 return false;
113     }
114     }
115    
116 root 1.14 int
117     command_uskill (object *pl, char *params)
118     {
119     if (!params)
120     {
121     new_draw_info (NDI_UNIQUE, 0, pl, "Usage: use_skill <skill name>");
122     return 0;
123     }
124 root 1.47
125 root 1.14 return use_skill (pl, params);
126 elmex 1.1 }
127    
128 root 1.14 int
129     command_rskill (object *pl, char *params)
130     {
131     object *skill;
132 elmex 1.1
133 root 1.14 if (!params)
134     {
135     new_draw_info (NDI_UNIQUE, 0, pl, "Usage: ready_skill <skill name>");
136     return 0;
137 elmex 1.1 }
138 root 1.47
139 root 1.87 skill = find_skill_by_name_fuzzy (pl, params);
140 elmex 1.1
141 root 1.14 if (!skill)
142     {
143     new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no knowledge of the skill %s", params);
144     return 0;
145 elmex 1.1 }
146 root 1.47
147 root 1.54 pl->change_skill (0);
148     apply_special (pl, skill, AP_APPLY);
149     return 1;
150 elmex 1.1 }
151    
152     /* A little special because we do want to pass the full params along
153     * as it includes the object to throw.
154 root 1.14 */
155     int
156     command_throw (object *op, char *params)
157 elmex 1.1 {
158 root 1.51 if (object *skop = find_skill_by_name (op, skill_names[SK_THROWING]))
159 root 1.14 return do_skill (op, op, skop, op->facing, params);
160     else
161 root 1.51 new_draw_info (NDI_UNIQUE, 0, op, "You have no knowledge of the skill throwing.");
162    
163 root 1.14 return 0;
164 elmex 1.1 }
165    
166 root 1.14 int
167     command_apply (object *op, char *params)
168 elmex 1.1 {
169 root 1.14 if (!params)
170     {
171     player_apply_below (op);
172     return 0;
173     }
174     else
175     {
176 root 1.51 apply_flag aflag = (apply_flag)0;
177 root 1.14
178     while (*params == ' ')
179     params++;
180 root 1.51
181 root 1.14 if (!strncmp (params, "-a ", 3))
182     {
183     aflag = AP_APPLY;
184     params += 3;
185     }
186 root 1.51
187 root 1.14 if (!strncmp (params, "-u ", 3))
188     {
189     aflag = AP_UNAPPLY;
190     params += 3;
191     }
192 root 1.51
193 root 1.14 while (*params == ' ')
194     params++;
195 elmex 1.1
196 root 1.51 if (object *inv = find_best_apply_object_match (op, params, aflag))
197     player_apply (op, inv, aflag, 0);
198 root 1.14 else
199     new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find any match to the %s.", params);
200 elmex 1.1 }
201 root 1.51
202 elmex 1.1 return 0;
203     }
204    
205     /*
206     * Check if an item op can be put into a sack. If pl exists then tell
207     * a player the reason of failure.
208     * returns 1 if it will fit, 0 if it will not. nrof is the number of
209     * objects (op) we want to put in. We specify it separately instead of
210     * using op->nrof because often times, a player may have specified a
211     * certain number of objects to drop, so we can pass that number, and
212     * not need to use split_ob and stuff.
213     */
214 root 1.14 int
215     sack_can_hold (object *pl, object *sack, object *op, uint32 nrof)
216     {
217     if (!QUERY_FLAG (sack, FLAG_APPLIED))
218     {
219     new_draw_info_format (NDI_UNIQUE, 0, pl, "The %s is not active.", query_name (sack));
220     return 0;
221     }
222 root 1.66
223 root 1.14 if (sack == op)
224     {
225     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't put the %s into itself.", query_name (sack));
226     return 0;
227     }
228 root 1.66
229 root 1.14 if (sack->race && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type)))
230     {
231     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can put only %s into the %s.", &sack->race, query_name (sack));
232     return 0;
233     }
234 root 1.66
235 root 1.14 if (op->type == SPECIAL_KEY && sack->slaying && op->slaying)
236     {
237     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't put the key into %s.", query_name (sack));
238     return 0;
239     }
240 root 1.66
241 root 1.14 if (sack->weight_limit && (sint32) (sack->carrying + (nrof ? nrof : 1) *
242     (op->weight + (op->type == CONTAINER ? (op->carrying * op->stats.Str) : 0))
243     * (100 - sack->stats.Str) / 100) > sack->weight_limit)
244     {
245     new_draw_info_format (NDI_UNIQUE, 0, pl, "That won't fit in the %s!", query_name (sack));
246     return 0;
247 elmex 1.1 }
248 root 1.66
249 root 1.14 /* All other checks pass, must be OK */
250     return 1;
251 elmex 1.1 }
252    
253     /* Pick up commands follow */
254 root 1.14
255 elmex 1.1 /* pl = player (not always - monsters can use this now)
256     * op is the object to put tmp into,
257     * tmp is the object to pick up, nrof is the number to
258     * pick up (0 means all of them)
259     */
260 root 1.14 static void
261     pick_up_object (object *pl, object *op, object *tmp, int nrof)
262 elmex 1.1 {
263 root 1.14 object *env = tmp->env;
264     uint32 weight, effective_weight_limit;
265 root 1.66 int tmp_nrof = tmp->number_of ();
266 root 1.14
267     /* IF the player is flying & trying to take the item out of a container
268     * that is in his inventory, let him. tmp->env points to the container
269     * (sack, luggage, etc), tmp->env->env then points to the player (nested
270     * containers not allowed as of now)
271     */
272 root 1.29 if ((pl->move_type & MOVE_FLYING) && !QUERY_FLAG (pl, FLAG_WIZ) && tmp->in_player () != pl)
273 root 1.14 {
274 root 1.72 pl->failmsg ("You are levitating, you can't reach the ground! "
275     "H<You have to stop levitating first, if you can, either by using your levitation skill, "
276     "or waiting till the levitation effect wears off.>");
277 root 1.14 return;
278     }
279 root 1.18
280 root 1.14 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
281     return;
282 root 1.18
283 root 1.67 if (nrof > tmp_nrof || nrof <= 0)
284 root 1.14 nrof = tmp_nrof;
285 root 1.18
286 root 1.14 /* Figure out how much weight this object will add to the player */
287     weight = tmp->weight * nrof;
288     if (tmp->inv)
289     weight += tmp->carrying * (100 - tmp->stats.Str) / 100;
290 root 1.18
291 root 1.64 effective_weight_limit = weight_limit [min (MAX_STAT, pl->stats.Str)];
292 root 1.18
293 root 1.14 if ((pl->weight + pl->carrying + weight) > effective_weight_limit)
294     {
295     new_draw_info (0, 0, pl, "That item is too heavy for you to pick up.");
296     return;
297 elmex 1.1 }
298 root 1.18
299 root 1.66 if (!can_split (pl, tmp, nrof))
300     return;
301 root 1.39
302 root 1.14 if (QUERY_FLAG (tmp, FLAG_UNPAID))
303 root 1.69 {
304     tmp->flag.reset (FLAG_UNPAID);
305     new_draw_info_format (NDI_UNIQUE, 0, pl, "%s will cost you %s.", query_name (tmp), query_cost_string (tmp, pl, F_BUY | F_SHOP));
306     tmp->flag.set (FLAG_UNPAID);
307     }
308 root 1.14 else
309 root 1.64 new_draw_info_format (NDI_UNIQUE, 0, pl, "You pick up the %s.", query_name (tmp));
310 root 1.14
311 root 1.69 op->insert (tmp);
312 elmex 1.1 }
313    
314 root 1.18 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
315 root 1.14 void
316     pick_up (object *op, object *alt)
317 elmex 1.1 {
318 root 1.14 int need_fix_tmp = 0;
319     object *tmp = NULL;
320 root 1.19 maptile *tmp_map = NULL;
321 root 1.14 int count;
322    
323     /* Decide which object to pick. */
324     if (alt)
325     {
326     if (!can_pick (op, alt))
327     {
328     new_draw_info_format (NDI_UNIQUE, 0, op, "You can't pick up the %s.", &alt->name);
329     goto leave;
330     }
331 root 1.64
332 root 1.14 tmp = alt;
333     }
334     else
335     {
336     if (op->below == NULL || !can_pick (op, op->below))
337     {
338     new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up here.");
339     goto leave;
340 elmex 1.1 }
341 root 1.18
342 root 1.14 tmp = op->below;
343     }
344    
345     /* Try to catch it. */
346     tmp_map = tmp->map;
347     tmp = stop_item (tmp);
348     if (tmp == NULL)
349     goto leave;
350 root 1.64
351 root 1.14 need_fix_tmp = 1;
352     if (!can_pick (op, tmp))
353     goto leave;
354    
355     if (op->type == PLAYER)
356     {
357     count = op->contr->count;
358     if (count == 0)
359     count = tmp->nrof;
360 elmex 1.1 }
361 root 1.14 else
362     count = tmp->nrof;
363 elmex 1.1
364 root 1.14 /* container is open, so use it */
365 root 1.64 if (tmp->flag [FLAG_STARTEQUIP])
366     alt = op;
367     else if (op->container)
368 root 1.14 {
369     alt = op->container;
370     if (alt != tmp->env && !sack_can_hold (op, alt, tmp, count))
371 elmex 1.1 goto leave;
372 root 1.14 }
373     else
374     { /* non container pickup */
375     for (alt = op->inv; alt; alt = alt->below)
376     if (alt->type == CONTAINER && QUERY_FLAG (alt, FLAG_APPLIED) &&
377     alt->race && alt->race == tmp->race && sack_can_hold (NULL, alt, tmp, count))
378     break; /* perfect match */
379    
380     if (!alt)
381     for (alt = op->inv; alt; alt = alt->below)
382     if (alt->type == CONTAINER && QUERY_FLAG (alt, FLAG_APPLIED) && sack_can_hold (NULL, alt, tmp, count))
383     break; /* General container comes next */
384 root 1.39
385 root 1.14 if (!alt)
386     alt = op; /* No free containers */
387     }
388 root 1.21
389 root 1.14 if (tmp->env == alt)
390     {
391     /* here it could be possible to check rent,
392     * if someone wants to implement it
393     */
394     alt = op;
395 elmex 1.1 }
396 root 1.64
397 elmex 1.1 #ifdef PICKUP_DEBUG
398 root 1.14 LOG (llevDebug, "Pick_up(): %s picks %s (%d) and inserts it %s.\n", op->name, tmp->name, op->contr->count, alt->name);
399 elmex 1.1 #endif
400    
401 root 1.14 /* startequip items are not allowed to be put into containers: */
402     if (op->type == PLAYER && alt->type == CONTAINER && QUERY_FLAG (tmp, FLAG_STARTEQUIP))
403 elmex 1.1 {
404 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This object cannot be put into containers!");
405     goto leave;
406 elmex 1.1 }
407    
408 root 1.14 pick_up_object (op, alt, tmp, count);
409 root 1.18
410     if (tmp->destroyed () || tmp->env)
411 root 1.14 need_fix_tmp = 0;
412 root 1.18
413 root 1.14 if (op->type == PLAYER)
414     op->contr->count = 0;
415 root 1.18
416 root 1.14 goto leave;
417 elmex 1.1
418 root 1.14 leave:
419     if (need_fix_tmp)
420     fix_stopped_item (tmp, tmp_map, op);
421 elmex 1.1 }
422    
423     /* This takes (picks up) and item. op is the player
424     * who issued the command. params is a string to
425     * match against the item name. Basically, always
426     * returns zero, but that should be improved.
427     */
428 root 1.14 int
429     command_take (object *op, char *params)
430 elmex 1.1 {
431 root 1.14 object *tmp, *next;
432 elmex 1.1
433 root 1.14 if (op->container)
434     tmp = op->container->inv;
435     else
436     {
437     tmp = op->above;
438     if (tmp)
439     while (tmp->above)
440 root 1.21 tmp = tmp->above;
441    
442 root 1.14 if (!tmp)
443     tmp = op->below;
444 elmex 1.1 }
445    
446 root 1.39 if (!tmp)
447 root 1.14 {
448     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to take!");
449     return 0;
450 elmex 1.1 }
451    
452 root 1.14 /* Makes processing easier */
453     if (params && *params == '\0')
454 root 1.39 params = 0;
455 elmex 1.1
456 elmex 1.62 int cnt = MAX_ITEM_PER_DROP;
457    
458 root 1.14 while (tmp)
459     {
460     next = tmp->below;
461 elmex 1.1
462 root 1.14 if (tmp->invisible)
463     {
464     tmp = next;
465     continue;
466     }
467 root 1.35
468 root 1.14 /* This following two if and else if could be merged into line
469     * but that probably will make it more difficult to read, and
470     * not make it any more efficient
471     */
472     if (params && item_matched_string (op, tmp, params))
473 elmex 1.62 {
474 root 1.74 if (--cnt < 0) break;
475 elmex 1.62 pick_up (op, tmp);
476     }
477 root 1.14 else if (can_pick (op, tmp) && !params)
478     {
479 root 1.74 if (--cnt < 0) break;
480 root 1.14 pick_up (op, tmp);
481     break;
482 root 1.10 }
483 root 1.35
484 root 1.14 tmp = next;
485     }
486 root 1.35
487 root 1.73 if (cnt < 0)
488 elmex 1.62 {
489     op->failmsg ("Couldn't pick up so many items at once.");
490     return 0;
491     }
492    
493 root 1.14 if (!params && !tmp)
494     {
495 root 1.35 for (tmp = op->below; tmp; tmp = tmp->below)
496 root 1.14 if (!tmp->invisible)
497     {
498 root 1.64 new_draw_info_format (NDI_UNIQUE, 0, op, "You can't pick up a %s.", &tmp->name);
499 root 1.10 break;
500 root 1.14 }
501 root 1.35
502 root 1.14 if (!tmp)
503     new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up.");
504 elmex 1.1 }
505 root 1.35
506 root 1.14 return 0;
507 elmex 1.1 }
508    
509     /*
510 root 1.83 * This function was part of drop, now is own function.
511     * Player 'op' tries to put object 'tmp' into sack 'sack',
512     * if nrof is non zero, then nrof objects is tried to put into sack.
513     *
514 elmex 1.1 * Note that the 'sack' in question can now be a transport,
515     * so this function isn't named very good anymore.
516     */
517 root 1.14 void
518     put_object_in_sack (object *op, object *sack, object *tmp, uint32 nrof)
519 elmex 1.1 {
520 root 1.14 object *tmp2, *sack2;
521     char buf[MAX_BUF];
522    
523     if (sack == tmp)
524     return; /* Can't put an object in itself */
525 root 1.18
526 root 1.14 if (QUERY_FLAG (tmp, FLAG_STARTEQUIP))
527     {
528     new_draw_info_format (NDI_UNIQUE, 0, op, "You cannot put the %s in the %s.", query_name (tmp), query_name (sack));
529     return;
530 elmex 1.1 }
531 root 1.18
532 root 1.14 if (tmp->type == CONTAINER && tmp->inv)
533     {
534     /* Eneq(@csd.uu.se): If the object to be dropped is a container
535     * we instead move the contents of that container into the active
536     * container, this is only done if the object has something in it.
537     */
538     sack2 = tmp;
539     new_draw_info_format (NDI_UNIQUE, 0, op, "You move the items from %s into %s.", query_name (tmp), query_name (sack));
540 root 1.18
541 root 1.14 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp)
542     {
543     tmp = tmp2->below;
544 root 1.18
545 root 1.14 if ((sack->type == CONTAINER && sack_can_hold (op, op->container, tmp2, tmp2->nrof)))
546 root 1.69 put_object_in_sack (op, sack, tmp2, 0);
547 root 1.14 else
548     {
549     sprintf (buf, "Your %s fills up.", query_name (sack));
550     new_draw_info (NDI_UNIQUE, 0, op, buf);
551     break;
552 root 1.10 }
553     }
554 root 1.18
555 root 1.14 return;
556     }
557    
558     /* Don't worry about this for containers - our caller should have
559     * already checked this.
560     */
561     if ((sack->type == CONTAINER) && !sack_can_hold (op, sack, tmp, (nrof ? nrof : tmp->nrof)))
562     return;
563    
564     if (QUERY_FLAG (tmp, FLAG_APPLIED))
565 root 1.18 if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
566     return;
567 elmex 1.1
568 root 1.14 /* we want to put some portion of the item into the container */
569 root 1.69 if (!can_split (op, tmp, nrof))
570     return;
571 root 1.14
572     new_draw_info_format (NDI_UNIQUE, 0, op, "You put the %s in %s.", query_name (tmp), query_name (sack));
573 root 1.69 sack->insert (tmp);
574 elmex 1.1 }
575    
576     /*
577     * This function was part of drop, now is own function.
578     * Player 'op' tries to drop object 'tmp', if tmp is non zero, then
579     * nrof objects is tried to dropped.
580     * This is used when dropping objects onto the floor.
581     */
582 elmex 1.2 void
583 root 1.14 drop_object (object *op, object *tmp, uint32 nrof)
584 elmex 1.1 {
585 elmex 1.2 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
586     return;
587 elmex 1.1
588 elmex 1.2 if (QUERY_FLAG (tmp, FLAG_APPLIED))
589     if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
590 root 1.14 return; /* can't unapply it */
591 elmex 1.2
592 root 1.23 /* We are only dropping some of the items. We split the current object
593 elmex 1.2 * off
594     */
595 root 1.69 if (!can_split (op, tmp, nrof))
596 elmex 1.80 return;
597 elmex 1.1
598 elmex 1.81 drop_object (op, tmp);
599    
600 elmex 1.82 if (!tmp->destroyed () && !tmp->is_inserted ())
601 elmex 1.81 {
602     // if nothing happened with the object we give it back
603     op->insert (tmp);
604     }
605     }
606    
607     /* In contrast to drop_object (op, tmp, nrof) above this function takes the
608     * already split off object, and feeds it to the event handlers and does
609     * other magic with it.
610     *
611     * <droppper> is the object that dropped this object and <obj> is the
612     * object that was dropped.
613     *
614     * Make sure to check what happened with <obj> after this function returns!
615     * Otherwise you may leak this object.
616     */
617     void
618     drop_object (object *dropper, object *obj)
619     {
620     if (INVOKE_OBJECT (DROP, obj, ARG_OBJECT (dropper)))
621 elmex 1.2 return;
622 elmex 1.81
623 elmex 1.82 if (obj->destroyed () || obj->is_inserted ())
624     return;
625 elmex 1.1
626 elmex 1.81 if (QUERY_FLAG (obj, FLAG_STARTEQUIP))
627 elmex 1.2 {
628 elmex 1.81 dropper->statusmsg (format ("You drop the %s.", query_name (obj)));
629     dropper->statusmsg ("The god who lent it to you retrieves it.");
630 root 1.28
631 elmex 1.81 obj->destroy ();
632     dropper->update_stats ();
633 elmex 1.1 return;
634     }
635    
636 elmex 1.81 for (object *floor = GET_MAP_OB (dropper->map, dropper->x, dropper->y);
637     floor;
638     floor = floor->above)
639     if (INVOKE_OBJECT (DROP_ON, floor, ARG_OBJECT (obj), ARG_OBJECT (dropper)))
640 elmex 1.5 return;
641 elmex 1.1
642 elmex 1.82 if (obj->destroyed () || obj->is_inserted ())
643     return;
644 elmex 1.1
645 elmex 1.81 if (is_in_shop (dropper) && !QUERY_FLAG (obj, FLAG_UNPAID) && obj->type != MONEY)
646     if (!sell_item (obj, dropper))
647     return;
648 elmex 1.1
649 elmex 1.81 /* If nothing special happened with this object, the default action is to
650     * insert it below the dropper:
651     */
652    
653     obj->x = dropper->x;
654     obj->y = dropper->y;
655    
656     insert_ob_in_map (obj, dropper->map, dropper, INS_BELOW_ORIGINATOR);
657 elmex 1.1 }
658    
659 root 1.69 void
660 root 1.14 drop (object *op, object *tmp)
661 elmex 1.1 {
662 root 1.14 /* Hopeful fix for disappearing objects when dropping from a container -
663     * somehow, players get an invisible object in the container, and the
664     * old logic would skip over invisible objects - works fine for the
665     * playes inventory, but drop inventory wants to use the next value.
666     */
667     if (tmp->invisible)
668     {
669     /* if the following is the case, it must be in an container. */
670     if (tmp->env && tmp->env->type != PLAYER)
671     {
672     /* Just toss the object - probably shouldn't be hanging
673     * around anyways
674     */
675 root 1.79 tmp->destroy ();
676 root 1.14 return;
677     }
678     else
679     {
680 root 1.70 while (tmp && tmp->invisible)
681 root 1.14 tmp = tmp->below;
682 root 1.10 }
683 elmex 1.1 }
684    
685 root 1.14 if (tmp == NULL)
686     {
687     new_draw_info (NDI_UNIQUE, 0, op, "You don't have anything to drop.");
688 elmex 1.1 return;
689     }
690 root 1.70
691 root 1.14 if (QUERY_FLAG (tmp, FLAG_INV_LOCKED))
692     {
693     new_draw_info (NDI_UNIQUE, 0, op, "This item is locked");
694 elmex 1.1 return;
695     }
696 root 1.70
697 root 1.14 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
698     {
699 elmex 1.1 #if 0
700     /* Eneq(@csd.uu.se): Objects with NO_DROP defined can't be dropped. */
701 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This item can't be dropped.");
702 elmex 1.1 #endif
703     return;
704     }
705    
706 root 1.26 if (op->type == PLAYER && op->contr->last_used == tmp)
707     op->contr->last_used = tmp->below ? tmp->below
708     : tmp->above ? tmp->above
709 root 1.91 : (object *)0;
710 elmex 1.1
711 root 1.14 if (op->container)
712     {
713     if (op->type == PLAYER)
714 root 1.26 put_object_in_sack (op, op->container, tmp, op->contr->count);
715 root 1.14 else
716 root 1.26 put_object_in_sack (op, op->container, tmp, 0);
717 root 1.14 }
718     else
719     {
720     if (op->type == PLAYER)
721 root 1.26 drop_object (op, tmp, op->contr->count);
722 root 1.14 else
723 root 1.26 drop_object (op, tmp, 0);
724 elmex 1.1 }
725 root 1.26
726 root 1.14 if (op->type == PLAYER)
727     op->contr->count = 0;
728 elmex 1.1 }
729    
730     /* Command will drop all items that have not been locked */
731 root 1.14 int
732     command_dropall (object *op, char *params)
733     {
734    
735     if (op->inv == NULL)
736     {
737     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop!");
738     return 0;
739     }
740 elmex 1.1
741 root 1.70 object *curinv = op->inv;
742     object *nextinv;
743 elmex 1.1
744     /*
745 root 1.14 This is the default. Drops everything not locked or considered
746     not something that should be dropped.
747     */
748 elmex 1.1 /*
749 root 1.14 Care must be taken that the next item pointer is not to money as
750     the drop() routine will do unknown things to it when dropping
751     in a shop. --Tero.Pelander@utu.fi
752     */
753    
754 elmex 1.61 int cnt = MAX_ITEM_PER_DROP;
755    
756 root 1.70 if (!params)
757 root 1.14 {
758 root 1.70 while (curinv)
759 root 1.14 {
760     nextinv = curinv->below;
761 root 1.70
762 root 1.14 while (nextinv && nextinv->type == MONEY)
763     nextinv = nextinv->below;
764 root 1.70
765 root 1.14 if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && curinv->type != MONEY &&
766     curinv->type != FOOD && curinv->type != KEY &&
767     curinv->type != SPECIAL_KEY && curinv->type != GEM &&
768     !curinv->invisible && (curinv->type != CONTAINER || op->container != curinv))
769     {
770     drop (op, curinv);
771 elmex 1.61 if (--cnt <= 0) break;
772 root 1.14 }
773 root 1.70
774 root 1.14 curinv = nextinv;
775     }
776     }
777     else if (strcmp (params, "weapons") == 0)
778     {
779 root 1.70 while (curinv)
780 root 1.14 {
781     nextinv = curinv->below;
782 root 1.70
783 root 1.14 while (nextinv && nextinv->type == MONEY)
784     nextinv = nextinv->below;
785 root 1.70
786 root 1.14 if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && ((curinv->type == WEAPON) || (curinv->type == BOW) || (curinv->type == ARROW)))
787     {
788     drop (op, curinv);
789 elmex 1.61 if (--cnt <= 0) break;
790 root 1.14 }
791 root 1.70
792 root 1.14 curinv = nextinv;
793     }
794     }
795     else if (strcmp (params, "armor") == 0 || strcmp (params, "armour") == 0)
796     {
797 root 1.70 while (curinv)
798 root 1.14 {
799     nextinv = curinv->below;
800 root 1.70
801 root 1.14 while (nextinv && nextinv->type == MONEY)
802     nextinv = nextinv->below;
803 root 1.70
804 root 1.14 if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && ((curinv->type == ARMOUR) || curinv->type == SHIELD || curinv->type == HELMET))
805     {
806     drop (op, curinv);
807 elmex 1.61 if (--cnt <= 0) break;
808 root 1.14 }
809 root 1.70
810 root 1.10 curinv = nextinv;
811 root 1.14 }
812     }
813     else if (strcmp (params, "misc") == 0)
814     {
815 root 1.70 while (curinv)
816 root 1.14 {
817     nextinv = curinv->below;
818 root 1.70
819 root 1.14 while (nextinv && nextinv->type == MONEY)
820     nextinv = nextinv->below;
821 root 1.70
822 root 1.14 if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && !QUERY_FLAG (curinv, FLAG_APPLIED))
823     {
824     switch (curinv->type)
825     {
826 root 1.15 case HORN:
827     case BOOK:
828     case SPELLBOOK:
829     case GIRDLE:
830     case AMULET:
831     case RING:
832     case CLOAK:
833     case BOOTS:
834     case GLOVES:
835     case BRACERS:
836     case SCROLL:
837     case ARMOUR_IMPROVER:
838     case WEAPON_IMPROVER:
839     case WAND:
840     case ROD:
841     case POTION:
842     drop (op, curinv);
843     curinv = nextinv;
844     break;
845     default:
846     curinv = nextinv;
847     break;
848 root 1.14 }
849 root 1.70
850 elmex 1.61 if (--cnt <= 0) break;
851 root 1.14 }
852 root 1.70
853 root 1.10 curinv = nextinv;
854     }
855 elmex 1.1 }
856 root 1.28
857 elmex 1.61 if (cnt <= 0)
858 elmex 1.62 op->failmsg ("Only dropped some items, can't drop that many items at once.");
859 elmex 1.61
860 elmex 1.1 /* draw_look(op);*/
861     return 0;
862     }
863    
864 elmex 1.81
865     /* This function tries to drop all objects in the <objs> vector.
866     * <dropper> is the object that wants to drop them.
867     * <cnt> can be a 0 pointer or a pointer to the maximum number of
868     * drop operations to perform.
869     *
870     * Returns true if at least one item was dropped.
871     */
872     bool
873     drop_vector (object *dropper, vector<object *> &objs, int *cnt)
874     {
875     vector<object *>::iterator i;
876    
877     bool did_one = false;
878    
879     for (i = objs.begin (); i != objs.end (); i++)
880     {
881     drop (dropper, *i);
882     if (cnt && --*cnt <= 0) break;
883     did_one = true;
884     }
885    
886     return did_one;
887     }
888    
889 elmex 1.1 /* Object op wants to drop object(s) params. params can be a
890     * comma seperated list.
891     */
892 root 1.14 int
893     command_drop (object *op, char *params)
894 elmex 1.1 {
895 root 1.14 object *tmp, *next;
896     int did_one = 0;
897 elmex 1.1
898 root 1.14 if (!params)
899     {
900     new_draw_info (NDI_UNIQUE, 0, op, "Drop what?");
901     return 0;
902     }
903     else
904     {
905 elmex 1.81 vector<object *> matched_objs;
906 elmex 1.61
907 root 1.14 for (tmp = op->inv; tmp; tmp = next)
908     {
909     next = tmp->below;
910     if (QUERY_FLAG (tmp, FLAG_NO_DROP) || tmp->invisible)
911     continue;
912 elmex 1.61
913 root 1.14 if (item_matched_string (op, tmp, params))
914 elmex 1.81 matched_objs.push_back (tmp);
915 root 1.10 }
916 elmex 1.61
917 elmex 1.81 int cnt = MAX_ITEM_PER_DROP;
918    
919     if (!drop_vector (op, matched_objs, &cnt))
920 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop.");
921 elmex 1.61
922     if (cnt <= 0)
923 elmex 1.62 op->failmsg ("Only dropped some items, can't drop that many items at once.");
924 elmex 1.1 }
925 root 1.14
926     return 0;
927 elmex 1.1 }
928    
929 root 1.14 int
930     command_examine (object *op, char *params)
931 elmex 1.1 {
932 root 1.14 if (!params)
933     {
934     object *tmp = op->below;
935    
936 root 1.36 while (tmp && !tmp->client_visible ())
937 root 1.14 tmp = tmp->below;
938 root 1.65
939 root 1.14 if (tmp)
940     examine (op, tmp);
941     }
942     else
943     {
944     object *tmp = find_best_object_match (op, params);
945    
946     if (tmp)
947     examine (op, tmp);
948     else
949 root 1.65 op->contr->infobox (MSG_CHANNEL ("examine"), format ("Could not find an object that matches %s", params));
950 root 1.14 }
951 root 1.65
952 elmex 1.1 return 0;
953     }
954    
955     /* op should be a player.
956     * we return the object the player has marked with the 'mark' command
957     * below. If no match is found (or object has changed), we return
958     * NULL. We leave it up to the calling function to print messages if
959     * nothing is found.
960     */
961 root 1.14 object *
962     find_marked_object (object *op)
963 elmex 1.1 {
964 root 1.14 object *tmp;
965    
966     if (!op || !op->contr)
967     return NULL;
968 root 1.20
969 root 1.14 if (!op->contr->mark)
970     {
971 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
972 root 1.20 return 0;
973 elmex 1.1 }
974 root 1.20
975 root 1.14 /* This may seem like overkill, but we need to make sure that they
976     * player hasn't dropped the item. We use count on the off chance that
977     * an item got reincarnated at some point.
978     */
979     for (tmp = op->inv; tmp; tmp = tmp->below)
980     {
981     if (tmp->invisible)
982     continue;
983 root 1.20
984 root 1.14 if (tmp == op->contr->mark)
985     {
986 root 1.20 if (!tmp->destroyed ())
987 root 1.14 return tmp;
988     else
989     {
990 root 1.20 op->contr->mark = 0;
991 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
992 root 1.20 return 0;
993 root 1.10 }
994     }
995 elmex 1.1 }
996 root 1.20
997     return 0;
998 elmex 1.1 }
999 root 1.14
1000 root 1.42 std::string
1001     object::describe_monster (object *who)
1002 root 1.14 {
1003 root 1.42 dynbuf_text buf (512, 512);
1004    
1005     object *mon = head ? head : this;
1006 root 1.14
1007     if (QUERY_FLAG (mon, FLAG_UNDEAD))
1008 root 1.77 buf << "It is an undead force.\r";
1009 root 1.42
1010     if (mon->level > who->level)
1011 root 1.77 buf << "It is likely more powerful than you.\r";
1012 root 1.42 else if (mon->level < who->level)
1013 root 1.77 buf << "It is likely less powerful than you.\r";
1014 root 1.14 else
1015 root 1.77 buf << "It is probably as powerful as you.\r";
1016 root 1.42
1017 root 1.14 if (mon->attacktype & AT_ACID)
1018 root 1.77 buf << "You seem to smell an acrid odor.\r";
1019 elmex 1.1
1020 root 1.14 /* Anyone know why this used to use the clone value instead of the
1021     * maxhp field? This seems that it should give more accurate results.
1022     */
1023     switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
1024     { /* From 1-4 */
1025 root 1.15 case 1:
1026 root 1.77 buf << "It is in a bad shape.\r";
1027 root 1.15 break;
1028     case 2:
1029 root 1.77 buf << "It is hurt.\r";
1030 root 1.15 break;
1031     case 3:
1032 root 1.77 buf << "It is somewhat hurt.\r";
1033 root 1.15 break;
1034     case 4:
1035 root 1.77 buf << "It is in excellent shape.\r";
1036 root 1.15 break;
1037 elmex 1.1 }
1038 root 1.42
1039     if (present_in_ob (POISONING, mon))
1040 root 1.77 buf << "It looks very ill.\r";
1041    
1042     buf << '\n';
1043 root 1.42
1044     return buf;
1045 elmex 1.1 }
1046    
1047     /* tmp is the object being described, pl is who is examing it. */
1048 root 1.41 const char *
1049 root 1.14 long_desc (object *tmp, object *pl)
1050     {
1051 root 1.46 static std::string s;
1052    
1053     return (s = tmp->long_desc (pl)).c_str ();
1054 root 1.42 }
1055 elmex 1.1
1056 root 1.42 std::string
1057     object::long_desc (object *who)
1058     {
1059 root 1.88 std::string buf (query_name ());
1060 elmex 1.1
1061 root 1.42 switch (type)
1062 root 1.14 {
1063 root 1.15 case RING:
1064     case SKILL:
1065     case WEAPON:
1066     case ARMOUR:
1067     case BRACERS:
1068     case HELMET:
1069     case SHIELD:
1070     case BOOTS:
1071     case GLOVES:
1072     case AMULET:
1073     case GIRDLE:
1074     case BOW:
1075     case ARROW:
1076     case CLOAK:
1077     case FOOD:
1078     case DRINK:
1079     case FLESH:
1080     case SKILL_TOOL:
1081 elmex 1.89 case LAMP:
1082 root 1.15 case POWER_CRYSTAL:
1083 root 1.42 {
1084     const char *cp = ::describe_item (this, who);
1085 root 1.14
1086 root 1.42 if (*cp)
1087     {
1088     buf.append (" ");
1089     buf.append (cp);
1090     }
1091     }
1092 elmex 1.1 }
1093 root 1.15
1094 root 1.14 return buf;
1095 elmex 1.1 }
1096    
1097 root 1.42 /* op is the player
1098     * tmp is the monster being examined.
1099     */
1100 root 1.14 void
1101 root 1.42 examine_monster (object *op, object *tmp)
1102 root 1.14 {
1103 root 1.42 new_draw_info (NDI_UNIQUE, 0, op, tmp->describe_monster (op).c_str ());
1104     }
1105 root 1.14
1106 root 1.95 static void
1107     describe_dump_object (dynbuf &buf, object *ob)
1108     {
1109     char *txt = dump_object (ob);
1110     for (char *p = txt; *p; ++p) if (*p == '\n') *p = '\r';
1111     buf << "\n" << txt << "\n";
1112    
1113     if (!ob->is_arch ())
1114     describe_dump_object (buf, ob->arch);
1115     }
1116    
1117 root 1.42 std::string
1118     object::describe (object *who)
1119     {
1120     dynbuf_text buf (1024, 1024);
1121 root 1.14
1122 root 1.77 buf.printf ("That is: %s.\r", long_desc (who).c_str ());
1123 elmex 1.1
1124 root 1.42 if (custom_name)
1125 root 1.77 buf.printf ("You call it %s.\r", &custom_name);
1126 elmex 1.1
1127 root 1.42 switch (type)
1128 root 1.14 {
1129 root 1.15 case SPELLBOOK:
1130 root 1.42 if (flag [FLAG_IDENTIFIED] && inv)
1131 root 1.84 buf.printf ("%s is a level %s %s spell.\r", &inv->name, get_levelnumber (inv->level), &inv->skill);
1132 root 1.15 break;
1133 root 1.10
1134 root 1.15 case BOOK:
1135 root 1.42 if (msg)
1136 root 1.77 buf << "Something is written in it.\r";
1137 root 1.15 break;
1138 root 1.10
1139 root 1.15 case CONTAINER:
1140 root 1.77 if (race)
1141 root 1.15 {
1142 root 1.42 if (weight_limit && stats.Str < 100)
1143 root 1.77 buf.printf ("It can hold only %s and its weight limit is %.1f kg.\r",
1144 root 1.42 &race, weight_limit / (10.0 * (100 - stats.Str)));
1145 root 1.15 else
1146 root 1.77 buf.printf ("It can hold only %s.\r", &race);
1147 root 1.15 }
1148 root 1.42 else if (weight_limit && stats.Str < 100)
1149 root 1.77 buf.printf ("Its weight limit is %.1f kg.\r", weight_limit / (10.0 * (100 - stats.Str)));
1150 root 1.15 break;
1151    
1152     case WAND:
1153 root 1.42 if (flag [FLAG_IDENTIFIED])
1154 root 1.77 buf.printf ("It has %d charges left.\r", stats.food);
1155 root 1.15 break;
1156 root 1.14 }
1157    
1158 root 1.42 if (materialname && !msg)
1159 root 1.90 buf << (nrof > 1 ? "They are made of " : "It is made of ")
1160     << materialname
1161     << '\r';
1162 root 1.14
1163 root 1.42 if (who)
1164     /* Where to wear this item */
1165     for (int i = 0; i < NUM_BODY_LOCATIONS; i++)
1166 root 1.48 if (slot[i].info)
1167 root 1.14 {
1168 root 1.48 buf << (who->slot[i].info ? body_locations[i].use_name : body_locations[i].nonuse_name);
1169 root 1.42
1170 root 1.48 if (slot[i].info < -1 && who->slot[i].info)
1171     buf.printf ("(%d)", -slot[i].info);
1172 root 1.42
1173 root 1.77 buf << ".\r";
1174 root 1.14 }
1175    
1176 root 1.42 if (weight)
1177 root 1.77 buf.printf ("%s %3.3f kg.\r", nrof > 1 ? "They weigh" : "It weighs", weight * (nrof ? nrof : 1) / 1000.0);
1178 root 1.42
1179     if (value && !flag [FLAG_STARTEQUIP] && !flag [FLAG_NO_PICK] && who)
1180 root 1.14 {
1181 root 1.77 buf.printf ("You reckon %s worth %s.\r", nrof > 1 ? "they are" : "it is", query_cost_string (this, who, F_TRUE | F_APPROX));
1182 root 1.14
1183 root 1.42 if (is_in_shop (who))
1184 root 1.14 {
1185 root 1.42 if (flag [FLAG_UNPAID])
1186 root 1.77 buf.printf ("%s would cost you %s.\r", nrof > 1 ? "They" : "It", query_cost_string (this, who, F_BUY | F_SHOP));
1187 root 1.14 else
1188 root 1.77 buf.printf ("You are offered %s for %s.\r", query_cost_string (this, who, F_SELL + F_SHOP), nrof > 1 ? "them" : "it");
1189 root 1.14 }
1190 elmex 1.1 }
1191    
1192 root 1.42 if (flag [FLAG_MONSTER])
1193     buf << describe_monster (who);
1194 root 1.14
1195     /* Is this item buildable? */
1196 root 1.42 if (flag [FLAG_IS_BUILDABLE])
1197 root 1.77 buf << "This is a buildable item.\r";
1198 root 1.14
1199     /* Does the object have a message? Don't show message for all object
1200     * types - especially if the first entry is a match
1201     */
1202 root 1.93 if (msg)
1203 root 1.14 {
1204 root 1.93 if (type != EXIT && type != BOOK && type != CORPSE && !move_on && !has_dialogue ())
1205     {
1206     buf << '\r';
1207 root 1.90
1208 root 1.93 /* This is just a hack so when identifying the items, we print
1209     * out the extra message
1210     */
1211     if (need_identify (this) && flag [FLAG_IDENTIFIED])
1212     buf << "The object has a story:\r";
1213 elmex 1.1
1214 root 1.93 buf << msg << '\n';
1215     }
1216 elmex 1.1 }
1217 root 1.93 else if (inv && inv->type == SPELL && flag [FLAG_IDENTIFIED]
1218     && (type == SPELLBOOK || type == ROD || type == WAND
1219     || type == ROD || type == POTION || type == SCROLL))
1220 root 1.95 // for spellbooks and other stuff that contains spells, print the spell message,
1221     // unless the object has a custom message handled above.
1222 root 1.93 buf << '\r' << inv->msg << '\n';
1223 root 1.42
1224 root 1.95 // try to display the duration for some potions and scrolls
1225     // this includes change ability potions and group spells,
1226     // but does not handle protection potions
1227     if (inv && inv->type == SPELL && flag [FLAG_IDENTIFIED]
1228     && (type == POTION || type == SCROLL))
1229     {
1230     object *spell = inv;
1231    
1232     if (spell->subtype == SP_PARTY_SPELL)
1233     spell = spell->other_arch;
1234    
1235     if (spell->subtype == SP_CHANGE_ABILITY)
1236     buf.printf ("\nH<The effect will last about %.10g seconds.>",
1237     TICK2TIME (change_ability_duration (spell, this)));
1238     }
1239    
1240 sf-marcmagus 1.98 // Display a hint about inscribable items [empty books]
1241     // This includes the amount of text they can hold.
1242     if (type == INSCRIBABLE)
1243     {
1244     if (other_arch && other_arch->type == SCROLL)
1245     buf.printf ("\nH<You can use the inscription skill to inscribe a spell into it.>");
1246     else
1247     buf.printf ("\nH<You can use the inscription skill to inscribe text into it. It has room for up to %d characters.>",
1248     weight_limit);
1249     }
1250    
1251 root 1.42 buf << '\n';
1252    
1253 root 1.95 // the dungeon master additionally gets a complete dump
1254 root 1.96 if (who && who->flag [FLAG_WIZLOOK])
1255 root 1.94 {
1256 root 1.95 buf << "\nT<Object>\n";
1257     describe_dump_object (buf, this);
1258    
1259     if (inv)
1260     {
1261     buf << "\nT<Top Inventory>\n";
1262     describe_dump_object (buf, inv);
1263     }
1264 root 1.94 }
1265    
1266 root 1.42 return std::string (buf.linearise (), buf.size ());
1267     }
1268    
1269 root 1.14 static void
1270     display_new_pickup (object *op)
1271     {
1272     int i = op->contr->mode;
1273 elmex 1.1
1274 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d DEBUG", i & PU_DEBUG ? 1 : 0);
1275     new_draw_info_format (NDI_UNIQUE, 0, op, "%d INHIBIT", i & PU_INHIBIT ? 1 : 0);
1276     new_draw_info_format (NDI_UNIQUE, 0, op, "%d STOP", i & PU_STOP ? 1 : 0);
1277 elmex 1.1
1278 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d <= x pickup weight/value RATIO (0==off)", (i & PU_RATIO) * 5);
1279 elmex 1.1
1280 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FOOD", i & PU_FOOD ? 1 : 0);
1281     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DRINK", i & PU_DRINK ? 1 : 0);
1282     new_draw_info_format (NDI_UNIQUE, 0, op, "%d VALUABLES", i & PU_VALUABLES ? 1 : 0);
1283 elmex 1.1
1284 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOW", i & PU_BOW ? 1 : 0);
1285     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARROW", i & PU_ARROW ? 1 : 0);
1286 elmex 1.1
1287 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d HELMET", i & PU_HELMET ? 1 : 0);
1288     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SHIELD", i & PU_SHIELD ? 1 : 0);
1289     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARMOUR", i & PU_ARMOUR ? 1 : 0);
1290 elmex 1.1
1291 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOOTS", i & PU_BOOTS ? 1 : 0);
1292     new_draw_info_format (NDI_UNIQUE, 0, op, "%d GLOVES", i & PU_GLOVES ? 1 : 0);
1293     new_draw_info_format (NDI_UNIQUE, 0, op, "%d CLOAK", i & PU_CLOAK ? 1 : 0);
1294     new_draw_info_format (NDI_UNIQUE, 0, op, "%d KEY", i & PU_KEY ? 1 : 0);
1295 elmex 1.1
1296 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d MISSILEWEAPON", i & PU_MISSILEWEAPON ? 1 : 0);
1297     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ALLWEAPON", i & PU_ALLWEAPON ? 1 : 0);
1298     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICAL", i & PU_MAGICAL ? 1 : 0);
1299     new_draw_info_format (NDI_UNIQUE, 0, op, "%d POTION", i & PU_POTION ? 1 : 0);
1300 elmex 1.1
1301 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d SPELLBOOK", i & PU_SPELLBOOK ? 1 : 0);
1302     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SKILLSCROLL", i & PU_SKILLSCROLL ? 1 : 0);
1303     new_draw_info_format (NDI_UNIQUE, 0, op, "%d READABLES", i & PU_READABLES ? 1 : 0);
1304     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICDEVICE", i & PU_MAGIC_DEVICE ? 1 : 0);
1305 elmex 1.1
1306 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NOT CURSED", i & PU_NOT_CURSED ? 1 : 0);
1307 elmex 1.1
1308 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d JEWELS", i & PU_JEWELS ? 1 : 0);
1309 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FLESH", i & PU_FLESH ? 1 : 0);
1310 elmex 1.1
1311 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "");
1312     }
1313 elmex 1.1
1314 root 1.14 int
1315     command_pickup (object *op, char *params)
1316 elmex 1.1 {
1317     uint32 i;
1318 root 1.14 static const char *names[] = {
1319     "debug", "inhibit", "stop", "food", "drink", "valuables", "bow", "arrow", "helmet",
1320     "shield", "armour", "boots", "gloves", "cloak", "key", "missile", "allweapon",
1321 root 1.22 "magical", "potion", "spellbook", "skillscroll", "readables", "magicdevice", "notcursed",
1322     "jewels", "flesh", NULL
1323 root 1.14 };
1324     static uint32 modes[] = {
1325     PU_DEBUG, PU_INHIBIT, PU_STOP, PU_FOOD, PU_DRINK, PU_VALUABLES, PU_BOW, PU_ARROW, PU_HELMET,
1326     PU_SHIELD, PU_ARMOUR, PU_BOOTS, PU_GLOVES, PU_CLOAK, PU_KEY, PU_MISSILEWEAPON, PU_ALLWEAPON,
1327 root 1.22 PU_MAGICAL, PU_POTION, PU_SPELLBOOK, PU_SKILLSCROLL, PU_READABLES, PU_MAGIC_DEVICE, PU_NOT_CURSED,
1328     PU_JEWELS, PU_FLESH, 0
1329 root 1.14 };
1330    
1331     if (!params)
1332     {
1333     /* if the new mode is used, just print the settings */
1334 root 1.85 display_new_pickup (op);
1335 root 1.14 return 0;
1336     }
1337 elmex 1.1
1338 root 1.14 while (*params == ' ' && *params)
1339     params++;
1340 elmex 1.1
1341 root 1.14 if (*params == '+' || *params == '-')
1342     {
1343 elmex 1.1 int mode;
1344 root 1.14
1345     for (mode = 0; names[mode]; mode++)
1346     {
1347     if (!strcmp (names[mode], params + 1))
1348     {
1349 elmex 1.1 i = op->contr->mode;
1350 root 1.85
1351 root 1.14 if (*params == '+')
1352     i = i | modes[mode];
1353 elmex 1.1 else
1354 root 1.14 i = i & ~modes[mode];
1355 root 1.85
1356 elmex 1.1 op->contr->mode = i;
1357 root 1.14 display_new_pickup (op);
1358 elmex 1.1 return 1;
1359 root 1.14 }
1360     }
1361     new_draw_info_format (NDI_UNIQUE, 0, op, "Pickup: invalid item %s\n", params);
1362 elmex 1.1 return 1;
1363 root 1.14 }
1364 elmex 1.1
1365 root 1.14 if (sscanf (params, "%u", &i) != 1)
1366     {
1367 root 1.86 new_draw_info (NDI_UNIQUE, 0, op, "Usage: pickup <value_density> or [+-]type.");
1368 root 1.14 return 1;
1369     }
1370 root 1.85
1371 root 1.86 if (i <= PU_RATIO)
1372     i |= op->contr->mode & ~PU_RATIO;
1373    
1374 root 1.85 op->contr->mode = i;
1375 elmex 1.1
1376     return 1;
1377     }
1378    
1379 root 1.14 int
1380     command_search_items (object *op, char *params)
1381 elmex 1.1 {
1382 root 1.14 char buf[MAX_BUF];
1383 elmex 1.1
1384 root 1.14 if (params == NULL)
1385     {
1386     if (op->contr->search_str[0] == '\0')
1387     {
1388 root 1.85 new_draw_info (NDI_UNIQUE, 0, op, "Example: search-items magic+1");
1389 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1390     new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1391 root 1.10 return 1;
1392     }
1393 root 1.42
1394 root 1.14 op->contr->search_str[0] = '\0';
1395     new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1396 root 1.31 op->update_stats ();
1397 elmex 1.1 return 1;
1398 root 1.14 }
1399 root 1.42
1400 root 1.85 if (strlen (params) >= MAX_BUF)
1401 root 1.14 {
1402     new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1403     return 1;
1404     }
1405 root 1.42
1406 root 1.14 strcpy (op->contr->search_str, params);
1407 root 1.85 sprintf (buf, "Now searching for '%s'.", op->contr->search_str);
1408 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, buf);
1409 root 1.31 op->update_stats ();
1410 root 1.85
1411 root 1.14 return 1;
1412 elmex 1.1 }
1413