ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.65
Committed: Sun Apr 20 18:48:51 2008 UTC (16 years, 1 month ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.64: +3 -1 lines
Log Message:
*** empty log message ***

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 root 1.65
1003 root 1.14 if (tmp)
1004     examine (op, tmp);
1005     }
1006     else
1007     {
1008     object *tmp = find_best_object_match (op, params);
1009    
1010     if (tmp)
1011     examine (op, tmp);
1012     else
1013 root 1.65 op->contr->infobox (MSG_CHANNEL ("examine"), format ("Could not find an object that matches %s", params));
1014 root 1.14 }
1015 root 1.65
1016 elmex 1.1 return 0;
1017     }
1018    
1019     /* op should be a player.
1020     * we return the object the player has marked with the 'mark' command
1021     * below. If no match is found (or object has changed), we return
1022     * NULL. We leave it up to the calling function to print messages if
1023     * nothing is found.
1024     */
1025 root 1.14 object *
1026     find_marked_object (object *op)
1027 elmex 1.1 {
1028 root 1.14 object *tmp;
1029    
1030     if (!op || !op->contr)
1031     return NULL;
1032 root 1.20
1033 root 1.14 if (!op->contr->mark)
1034     {
1035 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
1036 root 1.20 return 0;
1037 elmex 1.1 }
1038 root 1.20
1039 root 1.14 /* This may seem like overkill, but we need to make sure that they
1040     * player hasn't dropped the item. We use count on the off chance that
1041     * an item got reincarnated at some point.
1042     */
1043     for (tmp = op->inv; tmp; tmp = tmp->below)
1044     {
1045     if (tmp->invisible)
1046     continue;
1047 root 1.20
1048 root 1.14 if (tmp == op->contr->mark)
1049     {
1050 root 1.20 if (!tmp->destroyed ())
1051 root 1.14 return tmp;
1052     else
1053     {
1054 root 1.20 op->contr->mark = 0;
1055 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
1056 root 1.20 return 0;
1057 root 1.10 }
1058     }
1059 elmex 1.1 }
1060 root 1.20
1061     return 0;
1062 elmex 1.1 }
1063 root 1.14
1064 root 1.42 std::string
1065     object::describe_monster (object *who)
1066 root 1.14 {
1067 root 1.42 dynbuf_text buf (512, 512);
1068    
1069     object *mon = head ? head : this;
1070 root 1.14
1071     if (QUERY_FLAG (mon, FLAG_UNDEAD))
1072 root 1.42 buf << "It is an undead force.\n";
1073    
1074     if (mon->level > who->level)
1075     buf << "It is likely more powerful than you.\n";
1076     else if (mon->level < who->level)
1077     buf << "It is likely less powerful than you.\n";
1078 root 1.14 else
1079 root 1.42 buf << "It is probably as powerful as you.\n";
1080    
1081 root 1.14 if (mon->attacktype & AT_ACID)
1082 root 1.42 buf << "You seem to smell an acrid odor.\n";
1083 elmex 1.1
1084 root 1.14 /* Anyone know why this used to use the clone value instead of the
1085     * maxhp field? This seems that it should give more accurate results.
1086     */
1087     switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
1088     { /* From 1-4 */
1089 root 1.15 case 1:
1090 root 1.42 buf << "It is in a bad shape.\n";
1091 root 1.15 break;
1092     case 2:
1093 root 1.42 buf << "It is hurt.\n";
1094 root 1.15 break;
1095     case 3:
1096 root 1.42 buf << "It is somewhat hurt.\n";
1097 root 1.15 break;
1098     case 4:
1099 root 1.42 buf << "It is in excellent shape.\n";
1100 root 1.15 break;
1101 elmex 1.1 }
1102 root 1.42
1103     if (present_in_ob (POISONING, mon))
1104     buf << "It looks very ill.\n";
1105    
1106     return buf;
1107 elmex 1.1 }
1108    
1109     /* tmp is the object being described, pl is who is examing it. */
1110 root 1.41 const char *
1111 root 1.14 long_desc (object *tmp, object *pl)
1112     {
1113 root 1.46 static std::string s;
1114    
1115     return (s = tmp->long_desc (pl)).c_str ();
1116 root 1.42 }
1117 elmex 1.1
1118 root 1.42 std::string
1119     object::long_desc (object *who)
1120     {
1121     std::string buf (query_name (this));
1122 elmex 1.1
1123 root 1.42 switch (type)
1124 root 1.14 {
1125 root 1.15 case RING:
1126     case SKILL:
1127     case WEAPON:
1128     case ARMOUR:
1129     case BRACERS:
1130     case HELMET:
1131     case SHIELD:
1132     case BOOTS:
1133     case GLOVES:
1134     case AMULET:
1135     case GIRDLE:
1136     case BOW:
1137     case ARROW:
1138     case CLOAK:
1139     case FOOD:
1140     case DRINK:
1141     case FLESH:
1142     case SKILL_TOOL:
1143     case POWER_CRYSTAL:
1144 root 1.42 {
1145     const char *cp = ::describe_item (this, who);
1146 root 1.14
1147 root 1.42 if (*cp)
1148     {
1149     buf.append (" ");
1150     buf.append (cp);
1151     }
1152     }
1153 elmex 1.1 }
1154 root 1.15
1155 root 1.14 return buf;
1156 elmex 1.1 }
1157    
1158 root 1.42 /* op is the player
1159     * tmp is the monster being examined.
1160     */
1161 root 1.14 void
1162 root 1.42 examine_monster (object *op, object *tmp)
1163 root 1.14 {
1164 root 1.42 new_draw_info (NDI_UNIQUE, 0, op, tmp->describe_monster (op).c_str ());
1165     }
1166 root 1.14
1167 root 1.42 std::string
1168     object::describe (object *who)
1169     {
1170     dynbuf_text buf (1024, 1024);
1171 root 1.14
1172 root 1.44 buf.printf ("That is: %s.\n", long_desc (who).c_str ());
1173 elmex 1.1
1174 root 1.42 if (custom_name)
1175 root 1.58 buf.printf ("You call it %s\n", &custom_name);
1176 elmex 1.1
1177 root 1.42 switch (type)
1178 root 1.14 {
1179 root 1.15 case SPELLBOOK:
1180 root 1.42 if (flag [FLAG_IDENTIFIED] && inv)
1181     buf.printf ("%s is a %s %s spell\n", &inv->name, get_levelnumber (inv->level), &inv->skill);
1182 root 1.15 break;
1183 root 1.10
1184 root 1.15 case BOOK:
1185 root 1.42 if (msg)
1186     buf << "Something is written in it.\n";
1187 root 1.15 break;
1188 root 1.10
1189 root 1.15 case CONTAINER:
1190 root 1.42 if (race != NULL)
1191 root 1.15 {
1192 root 1.42 if (weight_limit && stats.Str < 100)
1193     buf.printf ("It can hold only %s and its weight limit is %.1f kg.\n",
1194     &race, weight_limit / (10.0 * (100 - stats.Str)));
1195 root 1.15 else
1196 root 1.42 buf.printf ("It can hold only %s.\n", &race);
1197 root 1.15 }
1198 root 1.42 else if (weight_limit && stats.Str < 100)
1199     buf.printf ("Its weight limit is %.1f kg.\n", weight_limit / (10.0 * (100 - stats.Str)));
1200 root 1.15 break;
1201    
1202     case WAND:
1203 root 1.42 if (flag [FLAG_IDENTIFIED])
1204 root 1.45 buf.printf ("It has %d charges left.\n", stats.food);
1205 root 1.15 break;
1206 root 1.14 }
1207    
1208 root 1.42 if (materialname && !msg)
1209     buf.printf ("It is made of: %s.\n", &materialname);
1210 root 1.14
1211 root 1.42 if (who)
1212     /* Where to wear this item */
1213     for (int i = 0; i < NUM_BODY_LOCATIONS; i++)
1214 root 1.48 if (slot[i].info)
1215 root 1.14 {
1216 root 1.48 buf << (who->slot[i].info ? body_locations[i].use_name : body_locations[i].nonuse_name);
1217 root 1.42
1218 root 1.48 if (slot[i].info < -1 && who->slot[i].info)
1219     buf.printf ("(%d)", -slot[i].info);
1220 root 1.42
1221     buf << ".\n";
1222 root 1.14 }
1223    
1224 root 1.42 if (weight)
1225     buf.printf (nrof > 1 ? "They weigh %3.3f kg.\n" : "It weighs %3.3f kg.\n", weight * (nrof ? nrof : 1) / 1000.0);
1226    
1227     if (value && !flag [FLAG_STARTEQUIP] && !flag [FLAG_NO_PICK] && who)
1228 root 1.14 {
1229 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));
1230 root 1.14
1231 root 1.42 if (is_in_shop (who))
1232 root 1.14 {
1233 root 1.42 if (flag [FLAG_UNPAID])
1234     buf.printf ("%s would cost you %s.\n", nrof > 1 ? "They" : "It", query_cost_string (this, who, F_BUY | F_SHOP));
1235 root 1.14 else
1236 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");
1237 root 1.14 }
1238 elmex 1.1 }
1239    
1240 root 1.42 if (flag [FLAG_MONSTER])
1241     buf << describe_monster (who);
1242 root 1.14
1243     /* Is this item buildable? */
1244 root 1.42 if (flag [FLAG_IS_BUILDABLE])
1245     buf << "This is a buildable item.\n";
1246 root 1.14
1247     /* Does the object have a message? Don't show message for all object
1248     * types - especially if the first entry is a match
1249     */
1250 root 1.63 if (msg && type != EXIT && type != BOOK && type != CORPSE && !move_on && *msg != '@')
1251 root 1.14 {
1252     /* This is just a hack so when identifying the items, we print
1253     * out the extra message
1254     */
1255 root 1.42 if (need_identify (this) && flag [FLAG_IDENTIFIED])
1256     buf << "The object has a story:\n";
1257 elmex 1.1
1258 root 1.42 buf << msg << '\n';
1259 elmex 1.1 }
1260 root 1.42
1261     buf << '\n';
1262    
1263     return std::string (buf.linearise (), buf.size ());
1264     }
1265    
1266 root 1.14 static void
1267     display_new_pickup (object *op)
1268     {
1269     int i = op->contr->mode;
1270 elmex 1.1
1271 root 1.14 if (!(i & PU_NEWMODE))
1272     return;
1273 elmex 1.1
1274 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NEWMODE", i & PU_NEWMODE ? 1 : 0);
1275     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DEBUG", i & PU_DEBUG ? 1 : 0);
1276     new_draw_info_format (NDI_UNIQUE, 0, op, "%d INHIBIT", i & PU_INHIBIT ? 1 : 0);
1277     new_draw_info_format (NDI_UNIQUE, 0, op, "%d STOP", i & PU_STOP ? 1 : 0);
1278 elmex 1.1
1279 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d <= x pickup weight/value RATIO (0==off)", (i & PU_RATIO) * 5);
1280 elmex 1.1
1281 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FOOD", i & PU_FOOD ? 1 : 0);
1282     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DRINK", i & PU_DRINK ? 1 : 0);
1283     new_draw_info_format (NDI_UNIQUE, 0, op, "%d VALUABLES", i & PU_VALUABLES ? 1 : 0);
1284 elmex 1.1
1285 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOW", i & PU_BOW ? 1 : 0);
1286     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARROW", i & PU_ARROW ? 1 : 0);
1287 elmex 1.1
1288 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d HELMET", i & PU_HELMET ? 1 : 0);
1289     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SHIELD", i & PU_SHIELD ? 1 : 0);
1290     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARMOUR", i & PU_ARMOUR ? 1 : 0);
1291 elmex 1.1
1292 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOOTS", i & PU_BOOTS ? 1 : 0);
1293     new_draw_info_format (NDI_UNIQUE, 0, op, "%d GLOVES", i & PU_GLOVES ? 1 : 0);
1294     new_draw_info_format (NDI_UNIQUE, 0, op, "%d CLOAK", i & PU_CLOAK ? 1 : 0);
1295     new_draw_info_format (NDI_UNIQUE, 0, op, "%d KEY", i & PU_KEY ? 1 : 0);
1296 elmex 1.1
1297 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d MISSILEWEAPON", i & PU_MISSILEWEAPON ? 1 : 0);
1298     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ALLWEAPON", i & PU_ALLWEAPON ? 1 : 0);
1299     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICAL", i & PU_MAGICAL ? 1 : 0);
1300     new_draw_info_format (NDI_UNIQUE, 0, op, "%d POTION", i & PU_POTION ? 1 : 0);
1301 elmex 1.1
1302 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d SPELLBOOK", i & PU_SPELLBOOK ? 1 : 0);
1303     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SKILLSCROLL", i & PU_SKILLSCROLL ? 1 : 0);
1304     new_draw_info_format (NDI_UNIQUE, 0, op, "%d READABLES", i & PU_READABLES ? 1 : 0);
1305     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICDEVICE", i & PU_MAGIC_DEVICE ? 1 : 0);
1306 elmex 1.1
1307 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NOT CURSED", i & PU_NOT_CURSED ? 1 : 0);
1308 elmex 1.1
1309 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d JEWELS", i & PU_JEWELS ? 1 : 0);
1310 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FLESH", i & PU_FLESH ? 1 : 0);
1311 elmex 1.1
1312 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "");
1313     }
1314 elmex 1.1
1315 root 1.14 int
1316     command_pickup (object *op, char *params)
1317 elmex 1.1 {
1318     uint32 i;
1319 root 1.14 static const char *names[] = {
1320     "debug", "inhibit", "stop", "food", "drink", "valuables", "bow", "arrow", "helmet",
1321     "shield", "armour", "boots", "gloves", "cloak", "key", "missile", "allweapon",
1322 root 1.22 "magical", "potion", "spellbook", "skillscroll", "readables", "magicdevice", "notcursed",
1323     "jewels", "flesh", NULL
1324 root 1.14 };
1325     static uint32 modes[] = {
1326     PU_DEBUG, PU_INHIBIT, PU_STOP, PU_FOOD, PU_DRINK, PU_VALUABLES, PU_BOW, PU_ARROW, PU_HELMET,
1327     PU_SHIELD, PU_ARMOUR, PU_BOOTS, PU_GLOVES, PU_CLOAK, PU_KEY, PU_MISSILEWEAPON, PU_ALLWEAPON,
1328 root 1.22 PU_MAGICAL, PU_POTION, PU_SPELLBOOK, PU_SKILLSCROLL, PU_READABLES, PU_MAGIC_DEVICE, PU_NOT_CURSED,
1329     PU_JEWELS, PU_FLESH, 0
1330 root 1.14 };
1331    
1332     if (!params)
1333     {
1334     /* if the new mode is used, just print the settings */
1335     if (op->contr->mode & PU_NEWMODE)
1336     {
1337     display_new_pickup (op);
1338     return 1;
1339     }
1340     if (1)
1341     LOG (llevDebug, "command_pickup: !params\n");
1342     set_pickup_mode (op, (op->contr->mode > 6) ? 0 : op->contr->mode + 1);
1343     return 0;
1344     }
1345 elmex 1.1
1346 root 1.14 while (*params == ' ' && *params)
1347     params++;
1348 elmex 1.1
1349 root 1.14 if (*params == '+' || *params == '-')
1350     {
1351 elmex 1.1 int mode;
1352 root 1.14
1353     for (mode = 0; names[mode]; mode++)
1354     {
1355     if (!strcmp (names[mode], params + 1))
1356     {
1357 elmex 1.1 i = op->contr->mode;
1358 root 1.14 if (!(i & PU_NEWMODE))
1359     i = PU_NEWMODE;
1360     if (*params == '+')
1361     i = i | modes[mode];
1362 elmex 1.1 else
1363 root 1.14 i = i & ~modes[mode];
1364 elmex 1.1 op->contr->mode = i;
1365 root 1.14 display_new_pickup (op);
1366 elmex 1.1 return 1;
1367 root 1.14 }
1368     }
1369     new_draw_info_format (NDI_UNIQUE, 0, op, "Pickup: invalid item %s\n", params);
1370 elmex 1.1 return 1;
1371 root 1.14 }
1372 elmex 1.1
1373 root 1.14 if (sscanf (params, "%u", &i) != 1)
1374     {
1375     if (1)
1376     LOG (llevDebug, "command_pickup: params==NULL\n");
1377     new_draw_info (NDI_UNIQUE, 0, op, "Usage: pickup <0-7> or <value_density> .");
1378     return 1;
1379     }
1380     set_pickup_mode (op, i);
1381 elmex 1.1
1382     return 1;
1383     }
1384    
1385 root 1.14 void
1386     set_pickup_mode (object *op, int i)
1387     {
1388     switch (op->contr->mode = i)
1389     {
1390 root 1.15 case 0:
1391     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Don't pick up.");
1392     break;
1393     case 1:
1394     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item.");
1395     break;
1396     case 2:
1397     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item and stop.");
1398     break;
1399     case 3:
1400     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Stop before picking up.");
1401     break;
1402     case 4:
1403     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items.");
1404     break;
1405     case 5:
1406     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items and stop.");
1407     break;
1408     case 6:
1409     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all magic items.");
1410     break;
1411     case 7:
1412     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all coins and gems");
1413     break;
1414 elmex 1.1 }
1415     }
1416    
1417 root 1.14 int
1418     command_search_items (object *op, char *params)
1419 elmex 1.1 {
1420 root 1.14 char buf[MAX_BUF];
1421 elmex 1.1
1422 root 1.14 if (settings.search_items == FALSE)
1423     return 1;
1424 elmex 1.1
1425 root 1.14 if (params == NULL)
1426     {
1427     if (op->contr->search_str[0] == '\0')
1428     {
1429     new_draw_info (NDI_UNIQUE, 0, op, "Example: search magic+1");
1430     new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1431     new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1432 root 1.10 return 1;
1433     }
1434 root 1.42
1435 root 1.14 op->contr->search_str[0] = '\0';
1436     new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1437 root 1.31 op->update_stats ();
1438 elmex 1.1 return 1;
1439 root 1.14 }
1440 root 1.42
1441 root 1.14 if ((int) strlen (params) >= MAX_BUF)
1442     {
1443     new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1444     return 1;
1445     }
1446 root 1.42
1447 root 1.14 strcpy (op->contr->search_str, params);
1448     sprintf (buf, "Searching for '%s'.", op->contr->search_str);
1449     new_draw_info (NDI_UNIQUE, 0, op, buf);
1450 root 1.31 op->update_stats ();
1451 root 1.14 return 1;
1452 elmex 1.1 }
1453