ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.52
Committed: Sat May 12 20:21:54 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.51: +10 -4 lines
Log Message:
fix weapon speed to be more in line with documentation

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