ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.51
Committed: Sat May 12 16:06:42 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.50: +10 -17 lines
Log Message:
almost works

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