ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.47
Committed: Thu May 3 04:50:27 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.46: +3 -0 lines
Log Message:
- skill system is looking as if it were going somewhere, slowly.
- support a regex argument to who to limit user reports.

File Contents

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