ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.19
Committed: Sat Sep 16 22:24:13 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.18: +1 -1 lines
Log Message:
mapstruct => maptile
removed many ytypedefs in favor of structure tags

File Contents

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