ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.52
Committed: Sat May 12 20:21:54 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.51: +10 -4 lines
Log Message:
fix weapon speed to be more in line with documentation

File Contents

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