ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.61
Committed: Mon Nov 26 11:41:02 2007 UTC (16 years, 6 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.60: +23 -0 lines
Log Message:
implemented drop item limit and fixed small performance problem in is_in_shop()

File Contents

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