ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.62
Committed: Mon Nov 26 12:54:32 2007 UTC (16 years, 6 months ago) by elmex
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_32
Changes since 1.61: +41 -31 lines
Log Message:
moved update_stats from the inner drop/put loop to the callers. and converted
some old messages. also hard limited pick_up now.

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 elmex 1.62 int cnt = MAX_ITEM_PER_DROP;
498    
499 root 1.14 while (tmp)
500     {
501     next = tmp->below;
502 elmex 1.1
503 root 1.14 if (tmp->invisible)
504     {
505     tmp = next;
506     continue;
507     }
508 root 1.35
509 root 1.14 /* This following two if and else if could be merged into line
510     * but that probably will make it more difficult to read, and
511     * not make it any more efficient
512     */
513     if (params && item_matched_string (op, tmp, params))
514 elmex 1.62 {
515     pick_up (op, tmp);
516     if (--cnt <= 0) break;
517     }
518 root 1.14 else if (can_pick (op, tmp) && !params)
519     {
520     pick_up (op, tmp);
521     break;
522 root 1.10 }
523 root 1.35
524 root 1.14 tmp = next;
525     }
526 root 1.35
527 elmex 1.62 if (cnt <= 0)
528     {
529     op->failmsg ("Couldn't pick up so many items at once.");
530     return 0;
531     }
532    
533 root 1.14 if (!params && !tmp)
534     {
535 root 1.35 for (tmp = op->below; tmp; tmp = tmp->below)
536 root 1.14 if (!tmp->invisible)
537     {
538     char buf[MAX_BUF];
539    
540     sprintf (buf, "You can't pick up a %s.", &tmp->name);
541     new_draw_info (NDI_UNIQUE, 0, op, buf);
542 root 1.10 break;
543 root 1.14 }
544 root 1.35
545 root 1.14 if (!tmp)
546     new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up.");
547 elmex 1.1 }
548 root 1.35
549 root 1.14 return 0;
550 elmex 1.1 }
551    
552    
553     /*
554     * This function was part of drop, now is own function.
555     * Player 'op' tries to put object 'tmp' into sack 'sack',
556     * if nrof is non zero, then nrof objects is tried to put into sack.
557     * Note that the 'sack' in question can now be a transport,
558     * so this function isn't named very good anymore.
559     */
560 root 1.14 void
561     put_object_in_sack (object *op, object *sack, object *tmp, uint32 nrof)
562 elmex 1.1 {
563 root 1.14 object *tmp2, *sack2;
564     char buf[MAX_BUF];
565    
566     if (sack == tmp)
567     return; /* Can't put an object in itself */
568 root 1.18
569 root 1.14 if (QUERY_FLAG (tmp, FLAG_STARTEQUIP))
570     {
571     new_draw_info_format (NDI_UNIQUE, 0, op, "You cannot put the %s in the %s.", query_name (tmp), query_name (sack));
572     return;
573 elmex 1.1 }
574 root 1.18
575 root 1.14 if (tmp->type == CONTAINER && tmp->inv)
576     {
577 elmex 1.1
578 root 1.14 /* Eneq(@csd.uu.se): If the object to be dropped is a container
579     * we instead move the contents of that container into the active
580     * container, this is only done if the object has something in it.
581     */
582     sack2 = tmp;
583     new_draw_info_format (NDI_UNIQUE, 0, op, "You move the items from %s into %s.", query_name (tmp), query_name (sack));
584 root 1.18
585 root 1.14 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp)
586     {
587     tmp = tmp2->below;
588 root 1.18
589 root 1.14 if ((sack->type == CONTAINER && sack_can_hold (op, op->container, tmp2, tmp2->nrof)))
590     {
591     put_object_in_sack (op, sack, tmp2, 0);
592     }
593     else
594     {
595     sprintf (buf, "Your %s fills up.", query_name (sack));
596     new_draw_info (NDI_UNIQUE, 0, op, buf);
597     break;
598 root 1.10 }
599     }
600 root 1.18
601 root 1.14 esrv_update_item (UPD_WEIGHT, op, sack2);
602     return;
603     }
604    
605     /* Don't worry about this for containers - our caller should have
606     * already checked this.
607     */
608     if ((sack->type == CONTAINER) && !sack_can_hold (op, sack, tmp, (nrof ? nrof : tmp->nrof)))
609     return;
610    
611     if (QUERY_FLAG (tmp, FLAG_APPLIED))
612 root 1.18 if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
613     return;
614 elmex 1.1
615 root 1.14 /* we want to put some portion of the item into the container */
616     if (nrof && tmp->nrof != nrof)
617     {
618     object *tmp2 = tmp;
619    
620     tmp = get_split_ob (tmp, nrof);
621    
622     if (!tmp)
623     {
624     new_draw_info (NDI_UNIQUE, 0, op, errmsg);
625     return;
626     }
627     /* Tell a client what happened other objects */
628 root 1.18 if (tmp2->destroyed ())
629     esrv_del_item (op->contr, tmp2->count);
630 root 1.14 else /* this can proably be replaced with an update */
631     esrv_send_item (op, tmp2);
632     }
633     else
634 root 1.24 tmp->remove ();
635 root 1.14
636     new_draw_info_format (NDI_UNIQUE, 0, op, "You put the %s in %s.", query_name (tmp), query_name (sack));
637     tmp2 = insert_ob_in_ob (tmp, sack);
638 elmex 1.62
639     // elmex: 2007-11-26: removed update_stats and replaced
640     // it by update_after_inventory_change () in the caller
641     // of this function
642 elmex 1.1
643 root 1.14 /* If an object merged (and thus, different object), we need to
644     * delete the original.
645     */
646     if (tmp2 != tmp)
647 root 1.18 esrv_del_item (op->contr, tmp->count);
648 elmex 1.1
649 root 1.14 esrv_send_item (op, tmp2);
650 elmex 1.1
651 root 1.14 /* update the sacks weight */
652     esrv_update_item (UPD_WEIGHT, op, sack);
653 elmex 1.1 }
654    
655     /*
656     * This function was part of drop, now is own function.
657     * Player 'op' tries to drop object 'tmp', if tmp is non zero, then
658     * nrof objects is tried to dropped.
659     * This is used when dropping objects onto the floor.
660     */
661 elmex 1.2 void
662 root 1.14 drop_object (object *op, object *tmp, uint32 nrof)
663 elmex 1.1 {
664 elmex 1.2 object *floor;
665 elmex 1.1
666 elmex 1.2 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
667     return;
668 elmex 1.1
669 elmex 1.2 if (QUERY_FLAG (tmp, FLAG_APPLIED))
670     if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
671 root 1.14 return; /* can't unapply it */
672 elmex 1.2
673 root 1.38 //fprintf (stderr, "ui, on space is %ld\n", op->ms ().volume ());//D
674    
675 root 1.23 /* We are only dropping some of the items. We split the current object
676 elmex 1.2 * off
677     */
678     if (nrof && tmp->nrof != nrof)
679     {
680     object *tmp2 = tmp;
681 root 1.14
682 elmex 1.2 tmp = get_split_ob (tmp, nrof);
683     if (!tmp)
684     {
685     new_draw_info (NDI_UNIQUE, 0, op, errmsg);
686     return;
687     }
688     /* Tell a client what happened rest of objects. tmp2 is now the
689     * original object
690     */
691     if (op->type == PLAYER)
692     {
693 root 1.18 if (tmp2->destroyed ())
694     esrv_del_item (op->contr, tmp2->count);
695 elmex 1.2 else
696     esrv_send_item (op, tmp2);
697     }
698 elmex 1.1 }
699 elmex 1.2 else
700 root 1.24 tmp->remove ();
701 elmex 1.1
702 root 1.7 if (INVOKE_OBJECT (DROP, tmp, ARG_OBJECT (op)))
703 elmex 1.2 return;
704 elmex 1.1
705 elmex 1.2 if (QUERY_FLAG (tmp, FLAG_STARTEQUIP))
706     {
707 elmex 1.62 op->statusmsg (format ("You drop the %s.", query_name (tmp)));
708     op->statusmsg ("The gods who lent it to you retrieves it.");
709 root 1.28
710 elmex 1.2 if (op->type == PLAYER)
711     esrv_del_item (op->contr, tmp->count);
712 root 1.28
713 root 1.25 tmp->destroy ();
714 root 1.31 op->update_stats ();
715 elmex 1.1 return;
716     }
717    
718 elmex 1.2 if (op->type == PLAYER)
719     esrv_del_item (op->contr, tmp->count);
720 elmex 1.1
721 elmex 1.2 /* Call this before we update the various windows/players. At least
722     * that we, we know the weight is correct.
723     */
724 elmex 1.62 // 2007-11-26: moved op->update_stats away and calling it later after
725     // all items of a drop command have been processed.
726 elmex 1.1
727 root 1.29 for (floor = GET_MAP_OB (op->map, op->x, op->y); floor; floor = floor->above)
728 root 1.7 if (INVOKE_OBJECT (DROP_ON, floor, ARG_OBJECT (tmp), ARG_OBJECT (op)))
729 elmex 1.5 return;
730 elmex 1.1
731 root 1.14 if (is_in_shop (op) && !QUERY_FLAG (tmp, FLAG_UNPAID) && tmp->type != MONEY)
732 elmex 1.2 sell_item (tmp, op);
733 elmex 1.1
734 elmex 1.2 tmp->x = op->x;
735     tmp->y = op->y;
736 elmex 1.1
737 elmex 1.2 insert_ob_in_map (tmp, op->map, op, INS_BELOW_ORIGINATOR);
738 elmex 1.1 }
739    
740 elmex 1.62 void update_after_inventory_change (object *op)
741     {
742     /* Call this before we update the various windows/players. At least
743     * that we, we know the weight is correct.
744     */
745     op->update_stats ();
746    
747     // elmex: kept this for now, i have no idea what happens when i remove it:
748     if (op->type == PLAYER)
749     {
750     /* Need to update the weight for the player */
751     esrv_send_item (op, op);
752     op->contr->ns->floorbox_update ();
753     }
754     }
755    
756 root 1.14 void
757     drop (object *op, object *tmp)
758 elmex 1.1 {
759 root 1.14 /* Hopeful fix for disappearing objects when dropping from a container -
760     * somehow, players get an invisible object in the container, and the
761     * old logic would skip over invisible objects - works fine for the
762     * playes inventory, but drop inventory wants to use the next value.
763     */
764     if (tmp->invisible)
765     {
766     /* if the following is the case, it must be in an container. */
767     if (tmp->env && tmp->env->type != PLAYER)
768     {
769     /* Just toss the object - probably shouldn't be hanging
770     * around anyways
771     */
772 root 1.24 tmp->remove ();
773 root 1.25 tmp->destroy ();
774 root 1.14 return;
775     }
776     else
777     {
778     while (tmp != NULL && tmp->invisible)
779     tmp = tmp->below;
780 root 1.10 }
781 elmex 1.1 }
782    
783 root 1.14 if (tmp == NULL)
784     {
785     new_draw_info (NDI_UNIQUE, 0, op, "You don't have anything to drop.");
786 elmex 1.1 return;
787     }
788 root 1.14 if (QUERY_FLAG (tmp, FLAG_INV_LOCKED))
789     {
790     new_draw_info (NDI_UNIQUE, 0, op, "This item is locked");
791 elmex 1.1 return;
792     }
793 root 1.14 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
794     {
795 elmex 1.1 #if 0
796     /* Eneq(@csd.uu.se): Objects with NO_DROP defined can't be dropped. */
797 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This item can't be dropped.");
798 elmex 1.1 #endif
799     return;
800     }
801    
802 root 1.26 if (op->type == PLAYER && op->contr->last_used == tmp)
803     op->contr->last_used = tmp->below ? tmp->below
804     : tmp->above ? tmp->above
805     : 0;
806 elmex 1.1
807 root 1.14 if (op->container)
808     {
809     if (op->type == PLAYER)
810 root 1.26 put_object_in_sack (op, op->container, tmp, op->contr->count);
811 root 1.14 else
812 root 1.26 put_object_in_sack (op, op->container, tmp, 0);
813 root 1.14 }
814     else
815     {
816     if (op->type == PLAYER)
817 root 1.26 drop_object (op, tmp, op->contr->count);
818 root 1.14 else
819 root 1.26 drop_object (op, tmp, 0);
820 elmex 1.1 }
821 root 1.26
822 root 1.14 if (op->type == PLAYER)
823     op->contr->count = 0;
824 elmex 1.1 }
825    
826    
827    
828     /* Command will drop all items that have not been locked */
829 root 1.14 int
830     command_dropall (object *op, char *params)
831     {
832    
833     object *curinv, *nextinv;
834 elmex 1.1
835 root 1.14 if (op->inv == NULL)
836     {
837     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop!");
838     return 0;
839     }
840 elmex 1.1
841     curinv = op->inv;
842    
843     /*
844 root 1.14 This is the default. Drops everything not locked or considered
845     not something that should be dropped.
846     */
847 elmex 1.1 /*
848 root 1.14 Care must be taken that the next item pointer is not to money as
849     the drop() routine will do unknown things to it when dropping
850     in a shop. --Tero.Pelander@utu.fi
851     */
852    
853 elmex 1.61 int cnt = MAX_ITEM_PER_DROP;
854    
855 root 1.14 if (params == NULL)
856     {
857     while (curinv != NULL)
858     {
859     nextinv = curinv->below;
860     while (nextinv && nextinv->type == MONEY)
861     nextinv = nextinv->below;
862     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && curinv->type != MONEY &&
863     curinv->type != FOOD && curinv->type != KEY &&
864     curinv->type != SPECIAL_KEY && curinv->type != GEM &&
865     !curinv->invisible && (curinv->type != CONTAINER || op->container != curinv))
866     {
867     drop (op, curinv);
868 elmex 1.61 if (--cnt <= 0) break;
869 root 1.14 }
870     curinv = nextinv;
871     }
872     }
873    
874     else if (strcmp (params, "weapons") == 0)
875     {
876     while (curinv != NULL)
877     {
878     nextinv = curinv->below;
879     while (nextinv && nextinv->type == MONEY)
880     nextinv = nextinv->below;
881     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && ((curinv->type == WEAPON) || (curinv->type == BOW) || (curinv->type == ARROW)))
882     {
883     drop (op, curinv);
884 elmex 1.61 if (--cnt <= 0) break;
885 root 1.14 }
886     curinv = nextinv;
887     }
888     }
889    
890     else if (strcmp (params, "armor") == 0 || strcmp (params, "armour") == 0)
891     {
892     while (curinv != NULL)
893     {
894     nextinv = curinv->below;
895     while (nextinv && nextinv->type == MONEY)
896     nextinv = nextinv->below;
897     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && ((curinv->type == ARMOUR) || curinv->type == SHIELD || curinv->type == HELMET))
898     {
899     drop (op, curinv);
900 elmex 1.61 if (--cnt <= 0) break;
901 root 1.14 }
902 root 1.10 curinv = nextinv;
903 root 1.14 }
904     }
905    
906     else if (strcmp (params, "misc") == 0)
907     {
908     while (curinv != NULL)
909     {
910     nextinv = curinv->below;
911     while (nextinv && nextinv->type == MONEY)
912     nextinv = nextinv->below;
913     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && !QUERY_FLAG (curinv, FLAG_APPLIED))
914     {
915     switch (curinv->type)
916     {
917 root 1.15 case HORN:
918     case BOOK:
919     case SPELLBOOK:
920     case GIRDLE:
921     case AMULET:
922     case RING:
923     case CLOAK:
924     case BOOTS:
925     case GLOVES:
926     case BRACERS:
927     case SCROLL:
928     case ARMOUR_IMPROVER:
929     case WEAPON_IMPROVER:
930     case WAND:
931     case ROD:
932     case POTION:
933     drop (op, curinv);
934     curinv = nextinv;
935     break;
936     default:
937     curinv = nextinv;
938     break;
939 root 1.14 }
940 elmex 1.61 if (--cnt <= 0) break;
941 root 1.14 }
942 root 1.10 curinv = nextinv;
943     }
944 elmex 1.1 }
945 root 1.28
946 elmex 1.61 if (cnt <= 0)
947 elmex 1.62 op->failmsg ("Only dropped some items, can't drop that many items at once.");
948 elmex 1.61
949 elmex 1.62 update_after_inventory_change (op);
950 root 1.14
951 elmex 1.1 /* draw_look(op);*/
952     return 0;
953     }
954    
955     /* Object op wants to drop object(s) params. params can be a
956     * comma seperated list.
957     */
958    
959 root 1.14 int
960     command_drop (object *op, char *params)
961 elmex 1.1 {
962 root 1.14 object *tmp, *next;
963     int did_one = 0;
964 elmex 1.1
965 root 1.14 if (!params)
966     {
967     new_draw_info (NDI_UNIQUE, 0, op, "Drop what?");
968     return 0;
969     }
970     else
971     {
972 elmex 1.61 int cnt = MAX_ITEM_PER_DROP;
973    
974 root 1.14 for (tmp = op->inv; tmp; tmp = next)
975     {
976     next = tmp->below;
977     if (QUERY_FLAG (tmp, FLAG_NO_DROP) || tmp->invisible)
978     continue;
979 elmex 1.61
980 root 1.14 if (item_matched_string (op, tmp, params))
981     {
982     drop (op, tmp);
983 elmex 1.61 if (--cnt <= 0) break;
984 root 1.14 did_one = 1;
985 root 1.10 }
986     }
987 elmex 1.61
988 root 1.14 if (!did_one)
989     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop.");
990 elmex 1.61
991     if (cnt <= 0)
992 elmex 1.62 op->failmsg ("Only dropped some items, can't drop that many items at once.");
993    
994     update_after_inventory_change (op);
995 elmex 1.1 }
996 root 1.14
997     return 0;
998 elmex 1.1 }
999    
1000 root 1.14 int
1001     command_examine (object *op, char *params)
1002 elmex 1.1 {
1003 root 1.14 if (!params)
1004     {
1005     object *tmp = op->below;
1006    
1007 root 1.36 while (tmp && !tmp->client_visible ())
1008 root 1.14 tmp = tmp->below;
1009     if (tmp)
1010     examine (op, tmp);
1011     }
1012     else
1013     {
1014     object *tmp = find_best_object_match (op, params);
1015    
1016     if (tmp)
1017     examine (op, tmp);
1018     else
1019     new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find an object that matches %s", params);
1020     }
1021 elmex 1.1 return 0;
1022     }
1023    
1024     /* op should be a player.
1025     * we return the object the player has marked with the 'mark' command
1026     * below. If no match is found (or object has changed), we return
1027     * NULL. We leave it up to the calling function to print messages if
1028     * nothing is found.
1029     */
1030 root 1.14 object *
1031     find_marked_object (object *op)
1032 elmex 1.1 {
1033 root 1.14 object *tmp;
1034    
1035     if (!op || !op->contr)
1036     return NULL;
1037 root 1.20
1038 root 1.14 if (!op->contr->mark)
1039     {
1040 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
1041 root 1.20 return 0;
1042 elmex 1.1 }
1043 root 1.20
1044 root 1.14 /* This may seem like overkill, but we need to make sure that they
1045     * player hasn't dropped the item. We use count on the off chance that
1046     * an item got reincarnated at some point.
1047     */
1048     for (tmp = op->inv; tmp; tmp = tmp->below)
1049     {
1050     if (tmp->invisible)
1051     continue;
1052 root 1.20
1053 root 1.14 if (tmp == op->contr->mark)
1054     {
1055 root 1.20 if (!tmp->destroyed ())
1056 root 1.14 return tmp;
1057     else
1058     {
1059 root 1.20 op->contr->mark = 0;
1060 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
1061 root 1.20 return 0;
1062 root 1.10 }
1063     }
1064 elmex 1.1 }
1065 root 1.20
1066     return 0;
1067 elmex 1.1 }
1068 root 1.14
1069 root 1.42 std::string
1070     object::describe_monster (object *who)
1071 root 1.14 {
1072 root 1.42 dynbuf_text buf (512, 512);
1073    
1074     object *mon = head ? head : this;
1075 root 1.14
1076     if (QUERY_FLAG (mon, FLAG_UNDEAD))
1077 root 1.42 buf << "It is an undead force.\n";
1078    
1079     if (mon->level > who->level)
1080     buf << "It is likely more powerful than you.\n";
1081     else if (mon->level < who->level)
1082     buf << "It is likely less powerful than you.\n";
1083 root 1.14 else
1084 root 1.42 buf << "It is probably as powerful as you.\n";
1085    
1086 root 1.14 if (mon->attacktype & AT_ACID)
1087 root 1.42 buf << "You seem to smell an acrid odor.\n";
1088 elmex 1.1
1089 root 1.14 /* Anyone know why this used to use the clone value instead of the
1090     * maxhp field? This seems that it should give more accurate results.
1091     */
1092     switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
1093     { /* From 1-4 */
1094 root 1.15 case 1:
1095 root 1.42 buf << "It is in a bad shape.\n";
1096 root 1.15 break;
1097     case 2:
1098 root 1.42 buf << "It is hurt.\n";
1099 root 1.15 break;
1100     case 3:
1101 root 1.42 buf << "It is somewhat hurt.\n";
1102 root 1.15 break;
1103     case 4:
1104 root 1.42 buf << "It is in excellent shape.\n";
1105 root 1.15 break;
1106 elmex 1.1 }
1107 root 1.42
1108     if (present_in_ob (POISONING, mon))
1109     buf << "It looks very ill.\n";
1110    
1111     return buf;
1112 elmex 1.1 }
1113    
1114     /* tmp is the object being described, pl is who is examing it. */
1115 root 1.41 const char *
1116 root 1.14 long_desc (object *tmp, object *pl)
1117     {
1118 root 1.46 static std::string s;
1119    
1120     return (s = tmp->long_desc (pl)).c_str ();
1121 root 1.42 }
1122 elmex 1.1
1123 root 1.42 std::string
1124     object::long_desc (object *who)
1125     {
1126     std::string buf (query_name (this));
1127 elmex 1.1
1128 root 1.42 switch (type)
1129 root 1.14 {
1130 root 1.15 case RING:
1131     case SKILL:
1132     case WEAPON:
1133     case ARMOUR:
1134     case BRACERS:
1135     case HELMET:
1136     case SHIELD:
1137     case BOOTS:
1138     case GLOVES:
1139     case AMULET:
1140     case GIRDLE:
1141     case BOW:
1142     case ARROW:
1143     case CLOAK:
1144     case FOOD:
1145     case DRINK:
1146     case FLESH:
1147     case SKILL_TOOL:
1148     case POWER_CRYSTAL:
1149 root 1.42 {
1150     const char *cp = ::describe_item (this, who);
1151 root 1.14
1152 root 1.42 if (*cp)
1153     {
1154     buf.append (" ");
1155     buf.append (cp);
1156     }
1157     }
1158 elmex 1.1 }
1159 root 1.15
1160 root 1.14 return buf;
1161 elmex 1.1 }
1162    
1163 root 1.42 /* op is the player
1164     * tmp is the monster being examined.
1165     */
1166 root 1.14 void
1167 root 1.42 examine_monster (object *op, object *tmp)
1168 root 1.14 {
1169 root 1.42 new_draw_info (NDI_UNIQUE, 0, op, tmp->describe_monster (op).c_str ());
1170     }
1171 root 1.14
1172 root 1.42 std::string
1173     object::describe (object *who)
1174     {
1175     dynbuf_text buf (1024, 1024);
1176 root 1.14
1177 root 1.44 buf.printf ("That is: %s.\n", long_desc (who).c_str ());
1178 elmex 1.1
1179 root 1.42 if (custom_name)
1180 root 1.58 buf.printf ("You call it %s\n", &custom_name);
1181 elmex 1.1
1182 root 1.42 switch (type)
1183 root 1.14 {
1184 root 1.15 case SPELLBOOK:
1185 root 1.42 if (flag [FLAG_IDENTIFIED] && inv)
1186     buf.printf ("%s is a %s %s spell\n", &inv->name, get_levelnumber (inv->level), &inv->skill);
1187 root 1.15 break;
1188 root 1.10
1189 root 1.15 case BOOK:
1190 root 1.42 if (msg)
1191     buf << "Something is written in it.\n";
1192 root 1.15 break;
1193 root 1.10
1194 root 1.15 case CONTAINER:
1195 root 1.42 if (race != NULL)
1196 root 1.15 {
1197 root 1.42 if (weight_limit && stats.Str < 100)
1198     buf.printf ("It can hold only %s and its weight limit is %.1f kg.\n",
1199     &race, weight_limit / (10.0 * (100 - stats.Str)));
1200 root 1.15 else
1201 root 1.42 buf.printf ("It can hold only %s.\n", &race);
1202 root 1.15 }
1203 root 1.42 else if (weight_limit && stats.Str < 100)
1204     buf.printf ("Its weight limit is %.1f kg.\n", weight_limit / (10.0 * (100 - stats.Str)));
1205 root 1.15 break;
1206    
1207     case WAND:
1208 root 1.42 if (flag [FLAG_IDENTIFIED])
1209 root 1.45 buf.printf ("It has %d charges left.\n", stats.food);
1210 root 1.15 break;
1211 root 1.14 }
1212    
1213 root 1.42 if (materialname && !msg)
1214     buf.printf ("It is made of: %s.\n", &materialname);
1215 root 1.14
1216 root 1.42 if (who)
1217     /* Where to wear this item */
1218     for (int i = 0; i < NUM_BODY_LOCATIONS; i++)
1219 root 1.48 if (slot[i].info)
1220 root 1.14 {
1221 root 1.48 buf << (who->slot[i].info ? body_locations[i].use_name : body_locations[i].nonuse_name);
1222 root 1.42
1223 root 1.48 if (slot[i].info < -1 && who->slot[i].info)
1224     buf.printf ("(%d)", -slot[i].info);
1225 root 1.42
1226     buf << ".\n";
1227 root 1.14 }
1228    
1229 root 1.42 if (weight)
1230     buf.printf (nrof > 1 ? "They weigh %3.3f kg.\n" : "It weighs %3.3f kg.\n", weight * (nrof ? nrof : 1) / 1000.0);
1231    
1232     if (value && !flag [FLAG_STARTEQUIP] && !flag [FLAG_NO_PICK] && who)
1233 root 1.14 {
1234 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));
1235 root 1.14
1236 root 1.42 if (is_in_shop (who))
1237 root 1.14 {
1238 root 1.42 if (flag [FLAG_UNPAID])
1239     buf.printf ("%s would cost you %s.\n", nrof > 1 ? "They" : "It", query_cost_string (this, who, F_BUY | F_SHOP));
1240 root 1.14 else
1241 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");
1242 root 1.14 }
1243 elmex 1.1 }
1244    
1245 root 1.42 if (flag [FLAG_MONSTER])
1246     buf << describe_monster (who);
1247 root 1.14
1248     /* Is this item buildable? */
1249 root 1.42 if (flag [FLAG_IS_BUILDABLE])
1250     buf << "This is a buildable item.\n";
1251 root 1.14
1252     /* Does the object have a message? Don't show message for all object
1253     * types - especially if the first entry is a match
1254     */
1255 root 1.42 if (msg && type != EXIT && type != BOOK && type != CORPSE && !move_on && strncasecmp (msg, "@match", 7))
1256 root 1.14 {
1257     /* This is just a hack so when identifying the items, we print
1258     * out the extra message
1259     */
1260 root 1.42 if (need_identify (this) && flag [FLAG_IDENTIFIED])
1261     buf << "The object has a story:\n";
1262 elmex 1.1
1263 root 1.42 buf << msg << '\n';
1264 elmex 1.1 }
1265 root 1.42
1266     buf << '\n';
1267    
1268     return std::string (buf.linearise (), buf.size ());
1269     }
1270    
1271 root 1.14 static void
1272     display_new_pickup (object *op)
1273     {
1274     int i = op->contr->mode;
1275 elmex 1.1
1276 root 1.14 if (!(i & PU_NEWMODE))
1277     return;
1278 elmex 1.1
1279 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NEWMODE", i & PU_NEWMODE ? 1 : 0);
1280     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DEBUG", i & PU_DEBUG ? 1 : 0);
1281     new_draw_info_format (NDI_UNIQUE, 0, op, "%d INHIBIT", i & PU_INHIBIT ? 1 : 0);
1282     new_draw_info_format (NDI_UNIQUE, 0, op, "%d STOP", i & PU_STOP ? 1 : 0);
1283 elmex 1.1
1284 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d <= x pickup weight/value RATIO (0==off)", (i & PU_RATIO) * 5);
1285 elmex 1.1
1286 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FOOD", i & PU_FOOD ? 1 : 0);
1287     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DRINK", i & PU_DRINK ? 1 : 0);
1288     new_draw_info_format (NDI_UNIQUE, 0, op, "%d VALUABLES", i & PU_VALUABLES ? 1 : 0);
1289 elmex 1.1
1290 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOW", i & PU_BOW ? 1 : 0);
1291     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARROW", i & PU_ARROW ? 1 : 0);
1292 elmex 1.1
1293 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d HELMET", i & PU_HELMET ? 1 : 0);
1294     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SHIELD", i & PU_SHIELD ? 1 : 0);
1295     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARMOUR", i & PU_ARMOUR ? 1 : 0);
1296 elmex 1.1
1297 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOOTS", i & PU_BOOTS ? 1 : 0);
1298     new_draw_info_format (NDI_UNIQUE, 0, op, "%d GLOVES", i & PU_GLOVES ? 1 : 0);
1299     new_draw_info_format (NDI_UNIQUE, 0, op, "%d CLOAK", i & PU_CLOAK ? 1 : 0);
1300     new_draw_info_format (NDI_UNIQUE, 0, op, "%d KEY", i & PU_KEY ? 1 : 0);
1301 elmex 1.1
1302 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d MISSILEWEAPON", i & PU_MISSILEWEAPON ? 1 : 0);
1303     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ALLWEAPON", i & PU_ALLWEAPON ? 1 : 0);
1304     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICAL", i & PU_MAGICAL ? 1 : 0);
1305     new_draw_info_format (NDI_UNIQUE, 0, op, "%d POTION", i & PU_POTION ? 1 : 0);
1306 elmex 1.1
1307 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d SPELLBOOK", i & PU_SPELLBOOK ? 1 : 0);
1308     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SKILLSCROLL", i & PU_SKILLSCROLL ? 1 : 0);
1309     new_draw_info_format (NDI_UNIQUE, 0, op, "%d READABLES", i & PU_READABLES ? 1 : 0);
1310     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICDEVICE", i & PU_MAGIC_DEVICE ? 1 : 0);
1311 elmex 1.1
1312 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NOT CURSED", i & PU_NOT_CURSED ? 1 : 0);
1313 elmex 1.1
1314 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d JEWELS", i & PU_JEWELS ? 1 : 0);
1315 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FLESH", i & PU_FLESH ? 1 : 0);
1316 elmex 1.1
1317 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "");
1318     }
1319 elmex 1.1
1320 root 1.14 int
1321     command_pickup (object *op, char *params)
1322 elmex 1.1 {
1323     uint32 i;
1324 root 1.14 static const char *names[] = {
1325     "debug", "inhibit", "stop", "food", "drink", "valuables", "bow", "arrow", "helmet",
1326     "shield", "armour", "boots", "gloves", "cloak", "key", "missile", "allweapon",
1327 root 1.22 "magical", "potion", "spellbook", "skillscroll", "readables", "magicdevice", "notcursed",
1328     "jewels", "flesh", NULL
1329 root 1.14 };
1330     static uint32 modes[] = {
1331     PU_DEBUG, PU_INHIBIT, PU_STOP, PU_FOOD, PU_DRINK, PU_VALUABLES, PU_BOW, PU_ARROW, PU_HELMET,
1332     PU_SHIELD, PU_ARMOUR, PU_BOOTS, PU_GLOVES, PU_CLOAK, PU_KEY, PU_MISSILEWEAPON, PU_ALLWEAPON,
1333 root 1.22 PU_MAGICAL, PU_POTION, PU_SPELLBOOK, PU_SKILLSCROLL, PU_READABLES, PU_MAGIC_DEVICE, PU_NOT_CURSED,
1334     PU_JEWELS, PU_FLESH, 0
1335 root 1.14 };
1336    
1337     if (!params)
1338     {
1339     /* if the new mode is used, just print the settings */
1340     if (op->contr->mode & PU_NEWMODE)
1341     {
1342     display_new_pickup (op);
1343     return 1;
1344     }
1345     if (1)
1346     LOG (llevDebug, "command_pickup: !params\n");
1347     set_pickup_mode (op, (op->contr->mode > 6) ? 0 : op->contr->mode + 1);
1348     return 0;
1349     }
1350 elmex 1.1
1351 root 1.14 while (*params == ' ' && *params)
1352     params++;
1353 elmex 1.1
1354 root 1.14 if (*params == '+' || *params == '-')
1355     {
1356 elmex 1.1 int mode;
1357 root 1.14
1358     for (mode = 0; names[mode]; mode++)
1359     {
1360     if (!strcmp (names[mode], params + 1))
1361     {
1362 elmex 1.1 i = op->contr->mode;
1363 root 1.14 if (!(i & PU_NEWMODE))
1364     i = PU_NEWMODE;
1365     if (*params == '+')
1366     i = i | modes[mode];
1367 elmex 1.1 else
1368 root 1.14 i = i & ~modes[mode];
1369 elmex 1.1 op->contr->mode = i;
1370 root 1.14 display_new_pickup (op);
1371 elmex 1.1 return 1;
1372 root 1.14 }
1373     }
1374     new_draw_info_format (NDI_UNIQUE, 0, op, "Pickup: invalid item %s\n", params);
1375 elmex 1.1 return 1;
1376 root 1.14 }
1377 elmex 1.1
1378 root 1.14 if (sscanf (params, "%u", &i) != 1)
1379     {
1380     if (1)
1381     LOG (llevDebug, "command_pickup: params==NULL\n");
1382     new_draw_info (NDI_UNIQUE, 0, op, "Usage: pickup <0-7> or <value_density> .");
1383     return 1;
1384     }
1385     set_pickup_mode (op, i);
1386 elmex 1.1
1387     return 1;
1388     }
1389    
1390 root 1.14 void
1391     set_pickup_mode (object *op, int i)
1392     {
1393     switch (op->contr->mode = i)
1394     {
1395 root 1.15 case 0:
1396     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Don't pick up.");
1397     break;
1398     case 1:
1399     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item.");
1400     break;
1401     case 2:
1402     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item and stop.");
1403     break;
1404     case 3:
1405     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Stop before picking up.");
1406     break;
1407     case 4:
1408     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items.");
1409     break;
1410     case 5:
1411     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items and stop.");
1412     break;
1413     case 6:
1414     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all magic items.");
1415     break;
1416     case 7:
1417     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all coins and gems");
1418     break;
1419 elmex 1.1 }
1420     }
1421    
1422 root 1.14 int
1423     command_search_items (object *op, char *params)
1424 elmex 1.1 {
1425 root 1.14 char buf[MAX_BUF];
1426 elmex 1.1
1427 root 1.14 if (settings.search_items == FALSE)
1428     return 1;
1429 elmex 1.1
1430 root 1.14 if (params == NULL)
1431     {
1432     if (op->contr->search_str[0] == '\0')
1433     {
1434     new_draw_info (NDI_UNIQUE, 0, op, "Example: search magic+1");
1435     new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1436     new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1437 root 1.10 return 1;
1438     }
1439 root 1.42
1440 root 1.14 op->contr->search_str[0] = '\0';
1441     new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1442 root 1.31 op->update_stats ();
1443 elmex 1.1 return 1;
1444 root 1.14 }
1445 root 1.42
1446 root 1.14 if ((int) strlen (params) >= MAX_BUF)
1447     {
1448     new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1449     return 1;
1450     }
1451 root 1.42
1452 root 1.14 strcpy (op->contr->search_str, params);
1453     sprintf (buf, "Searching for '%s'.", op->contr->search_str);
1454     new_draw_info (NDI_UNIQUE, 0, op, buf);
1455 root 1.31 op->update_stats ();
1456 root 1.14 return 1;
1457 elmex 1.1 }
1458