ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.27
Committed: Thu Dec 14 04:30:32 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.26: +3 -3 lines
Log Message:
- rewrote most of the socket loop code
- moved connection accept into tcp.ext
- no evil socket copying anymore,
  needs more cleanups

File Contents

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