ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.54
Committed: Thu May 17 20:27:01 2007 UTC (17 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_1
Changes since 1.53: +4 -2 lines
Log Message:
- more rewrite:
  change_skill now only changes the chosen_skill, nothing else.
  new flag to suppress skill tool behaviour of readying the skill
  when applying the tool, for use in find_skill.

File Contents

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