ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.41
Committed: Sun Mar 18 03:05:40 2007 UTC (17 years, 3 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.40: +9 -8 lines
Log Message:
- reduce default output-sync to less than a second
- output-sync command now uses seconds as unit, not
  something users cannot even know.
- lots of useless const adjustments.

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