ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.64
Committed: Sun Apr 20 00:44:13 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.63: +10 -17 lines
Log Message:
reloadable archetypes, maybe

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