ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.29
Committed: Wed Dec 20 09:14:22 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.28: +2 -2 lines
Log Message:
- minor cleanups
- minor optimisations (in_player vs. is_player_inv)
- added P_PLAYER map flag
- some (dead) concept code

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 root 1.29 if ((pl->move_type & MOVE_FLYING) && !QUERY_FLAG (pl, FLAG_WIZ) && tmp->in_player () != pl)
265 root 1.14 {
266     new_draw_info (NDI_UNIQUE, 0, pl, "You are levitating, you can't reach the ground!");
267     return;
268     }
269 root 1.18
270 root 1.14 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
271     return;
272 root 1.18
273 root 1.14 if (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 root 1.28
708 elmex 1.2 if (op->type == PLAYER)
709     esrv_del_item (op->contr, tmp->count);
710 root 1.28
711 root 1.25 tmp->destroy ();
712 elmex 1.2 fix_player (op);
713 elmex 1.1 return;
714     }
715    
716     /* If SAVE_INTERVAL is commented out, we never want to save
717     * the player here.
718     */
719     #ifdef SAVE_INTERVAL
720 elmex 1.2 /* I'm not sure why there is a value check - since the save
721     * is done every SAVE_INTERVAL seconds, why care the value
722     * of what he is dropping?
723     */
724     if (op->type == PLAYER && !QUERY_FLAG (tmp, FLAG_UNPAID) &&
725 root 1.14 (tmp->nrof ? tmp->value * tmp->nrof : tmp->value > 2000) && (op->contr->last_save_time + SAVE_INTERVAL) <= time (NULL))
726 elmex 1.2 {
727     save_player (op, 1);
728     op->contr->last_save_time = time (NULL);
729 elmex 1.1 }
730     #endif /* SAVE_INTERVAL */
731    
732 elmex 1.2 if (op->type == PLAYER)
733     esrv_del_item (op->contr, tmp->count);
734 elmex 1.1
735 elmex 1.2 /* Call this before we update the various windows/players. At least
736     * that we, we know the weight is correct.
737     */
738 root 1.14 fix_player (op); /* This is overkill, fix_player() is called somewhere */
739     /* in object.c */
740 elmex 1.1
741 elmex 1.2 if (op->type == PLAYER)
742     {
743     /* Need to update the weight for the player */
744     esrv_send_item (op, op);
745 root 1.28 op->contr->socket->floorbox_update ();
746 elmex 1.2 }
747 elmex 1.1
748 root 1.29 for (floor = GET_MAP_OB (op->map, op->x, op->y); floor; floor = floor->above)
749 root 1.7 if (INVOKE_OBJECT (DROP_ON, floor, ARG_OBJECT (tmp), ARG_OBJECT (op)))
750 elmex 1.5 return;
751 elmex 1.1
752 root 1.14 if (is_in_shop (op) && !QUERY_FLAG (tmp, FLAG_UNPAID) && tmp->type != MONEY)
753 elmex 1.2 sell_item (tmp, op);
754 elmex 1.1
755 elmex 1.2 tmp->x = op->x;
756     tmp->y = op->y;
757 elmex 1.1
758 elmex 1.2 insert_ob_in_map (tmp, op->map, op, INS_BELOW_ORIGINATOR);
759 elmex 1.1 }
760    
761 root 1.14 void
762     drop (object *op, object *tmp)
763 elmex 1.1 {
764 root 1.14 /* Hopeful fix for disappearing objects when dropping from a container -
765     * somehow, players get an invisible object in the container, and the
766     * old logic would skip over invisible objects - works fine for the
767     * playes inventory, but drop inventory wants to use the next value.
768     */
769     if (tmp->invisible)
770     {
771     /* if the following is the case, it must be in an container. */
772     if (tmp->env && tmp->env->type != PLAYER)
773     {
774     /* Just toss the object - probably shouldn't be hanging
775     * around anyways
776     */
777 root 1.24 tmp->remove ();
778 root 1.25 tmp->destroy ();
779 root 1.14 return;
780     }
781     else
782     {
783     while (tmp != NULL && tmp->invisible)
784     tmp = tmp->below;
785 root 1.10 }
786 elmex 1.1 }
787    
788 root 1.14 if (tmp == NULL)
789     {
790     new_draw_info (NDI_UNIQUE, 0, op, "You don't have anything to drop.");
791 elmex 1.1 return;
792     }
793 root 1.14 if (QUERY_FLAG (tmp, FLAG_INV_LOCKED))
794     {
795     new_draw_info (NDI_UNIQUE, 0, op, "This item is locked");
796 elmex 1.1 return;
797     }
798 root 1.14 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
799     {
800 elmex 1.1 #if 0
801     /* Eneq(@csd.uu.se): Objects with NO_DROP defined can't be dropped. */
802 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This item can't be dropped.");
803 elmex 1.1 #endif
804     return;
805     }
806    
807 root 1.26 if (op->type == PLAYER && op->contr->last_used == tmp)
808     op->contr->last_used = tmp->below ? tmp->below
809     : tmp->above ? tmp->above
810     : 0;
811 elmex 1.1
812 root 1.14 if (op->container)
813     {
814     if (op->type == PLAYER)
815 root 1.26 put_object_in_sack (op, op->container, tmp, op->contr->count);
816 root 1.14 else
817 root 1.26 put_object_in_sack (op, op->container, tmp, 0);
818 root 1.14 }
819     else
820     {
821     if (op->type == PLAYER)
822 root 1.26 drop_object (op, tmp, op->contr->count);
823 root 1.14 else
824 root 1.26 drop_object (op, tmp, 0);
825 elmex 1.1 }
826 root 1.26
827 root 1.14 if (op->type == PLAYER)
828     op->contr->count = 0;
829 elmex 1.1 }
830    
831    
832    
833     /* Command will drop all items that have not been locked */
834 root 1.14 int
835     command_dropall (object *op, char *params)
836     {
837    
838     object *curinv, *nextinv;
839 elmex 1.1
840 root 1.14 if (op->inv == NULL)
841     {
842     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop!");
843     return 0;
844     }
845 elmex 1.1
846     curinv = op->inv;
847    
848     /*
849 root 1.14 This is the default. Drops everything not locked or considered
850     not something that should be dropped.
851     */
852 elmex 1.1 /*
853 root 1.14 Care must be taken that the next item pointer is not to money as
854     the drop() routine will do unknown things to it when dropping
855     in a shop. --Tero.Pelander@utu.fi
856     */
857    
858     if (params == NULL)
859     {
860     while (curinv != NULL)
861     {
862     nextinv = curinv->below;
863     while (nextinv && nextinv->type == MONEY)
864     nextinv = nextinv->below;
865     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && curinv->type != MONEY &&
866     curinv->type != FOOD && curinv->type != KEY &&
867     curinv->type != SPECIAL_KEY && curinv->type != GEM &&
868     !curinv->invisible && (curinv->type != CONTAINER || op->container != curinv))
869     {
870     drop (op, curinv);
871     }
872     curinv = nextinv;
873     }
874     }
875    
876     else if (strcmp (params, "weapons") == 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 == WEAPON) || (curinv->type == BOW) || (curinv->type == ARROW)))
884     {
885     drop (op, curinv);
886     }
887     curinv = nextinv;
888     }
889     }
890    
891     else if (strcmp (params, "armor") == 0 || strcmp (params, "armour") == 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) && ((curinv->type == ARMOUR) || curinv->type == SHIELD || curinv->type == HELMET))
899     {
900     drop (op, curinv);
901     }
902 root 1.10 curinv = nextinv;
903 root 1.14 }
904     }
905    
906     else if (strcmp (params, "misc") == 0)
907     {
908     while (curinv != NULL)
909     {
910     nextinv = curinv->below;
911     while (nextinv && nextinv->type == MONEY)
912     nextinv = nextinv->below;
913     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && !QUERY_FLAG (curinv, FLAG_APPLIED))
914     {
915     switch (curinv->type)
916     {
917 root 1.15 case HORN:
918     case BOOK:
919     case SPELLBOOK:
920     case GIRDLE:
921     case AMULET:
922     case RING:
923     case CLOAK:
924     case BOOTS:
925     case GLOVES:
926     case BRACERS:
927     case SCROLL:
928     case ARMOUR_IMPROVER:
929     case WEAPON_IMPROVER:
930     case WAND:
931     case ROD:
932     case POTION:
933     drop (op, curinv);
934     curinv = nextinv;
935     break;
936     default:
937     curinv = nextinv;
938     break;
939 root 1.14 }
940     }
941 root 1.10 curinv = nextinv;
942     }
943 elmex 1.1 }
944 root 1.28
945     op->contr->socket->floorbox_update ();
946 root 1.14
947 elmex 1.1 /* draw_look(op);*/
948     return 0;
949     }
950    
951     /* Object op wants to drop object(s) params. params can be a
952     * comma seperated list.
953     */
954    
955 root 1.14 int
956     command_drop (object *op, char *params)
957 elmex 1.1 {
958 root 1.14 object *tmp, *next;
959     int did_one = 0;
960 elmex 1.1
961 root 1.14 if (!params)
962     {
963     new_draw_info (NDI_UNIQUE, 0, op, "Drop what?");
964     return 0;
965     }
966     else
967     {
968     for (tmp = op->inv; tmp; tmp = next)
969     {
970     next = tmp->below;
971     if (QUERY_FLAG (tmp, FLAG_NO_DROP) || tmp->invisible)
972     continue;
973     if (item_matched_string (op, tmp, params))
974     {
975     drop (op, tmp);
976     did_one = 1;
977 root 1.10 }
978     }
979 root 1.14 if (!did_one)
980     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop.");
981 elmex 1.1 }
982 root 1.14 if (op->type == PLAYER)
983 elmex 1.1 {
984 root 1.14 op->contr->count = 0;
985 root 1.28 op->contr->socket->floorbox_update ();
986 elmex 1.1 };
987 root 1.14
988 elmex 1.1 /* draw_look(op);*/
989 root 1.14 return 0;
990 elmex 1.1 }
991    
992 root 1.14 int
993     command_examine (object *op, char *params)
994 elmex 1.1 {
995 root 1.14 if (!params)
996     {
997     object *tmp = op->below;
998    
999     while (tmp && !LOOK_OBJ (tmp))
1000     tmp = tmp->below;
1001     if (tmp)
1002     examine (op, tmp);
1003     }
1004     else
1005     {
1006     object *tmp = find_best_object_match (op, params);
1007    
1008     if (tmp)
1009     examine (op, tmp);
1010     else
1011     new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find an object that matches %s", params);
1012     }
1013 elmex 1.1 return 0;
1014     }
1015    
1016     /* op should be a player.
1017     * we return the object the player has marked with the 'mark' command
1018     * below. If no match is found (or object has changed), we return
1019     * NULL. We leave it up to the calling function to print messages if
1020     * nothing is found.
1021     */
1022 root 1.14 object *
1023     find_marked_object (object *op)
1024 elmex 1.1 {
1025 root 1.14 object *tmp;
1026    
1027     if (!op || !op->contr)
1028     return NULL;
1029 root 1.20
1030 root 1.14 if (!op->contr->mark)
1031     {
1032 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
1033 root 1.20 return 0;
1034 elmex 1.1 }
1035 root 1.20
1036 root 1.14 /* This may seem like overkill, but we need to make sure that they
1037     * player hasn't dropped the item. We use count on the off chance that
1038     * an item got reincarnated at some point.
1039     */
1040     for (tmp = op->inv; tmp; tmp = tmp->below)
1041     {
1042     if (tmp->invisible)
1043     continue;
1044 root 1.20
1045 root 1.14 if (tmp == op->contr->mark)
1046     {
1047 root 1.20 if (!tmp->destroyed ())
1048 root 1.14 return tmp;
1049     else
1050     {
1051 root 1.20 op->contr->mark = 0;
1052 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
1053 root 1.20 return 0;
1054 root 1.10 }
1055     }
1056 elmex 1.1 }
1057 root 1.20
1058     return 0;
1059 elmex 1.1 }
1060 root 1.14
1061 elmex 1.1
1062     /* op should be a player, params is any params.
1063     * If no params given, we print out the currently marked object.
1064     * otherwise, try to find a matching object - try best match first.
1065     */
1066 root 1.14 int
1067     command_mark (object *op, char *params)
1068 elmex 1.1 {
1069 root 1.14 if (!op->contr)
1070     return 1;
1071 root 1.20
1072 root 1.14 if (!params)
1073     {
1074     object *mark = find_marked_object (op);
1075    
1076     if (!mark)
1077     new_draw_info (NDI_UNIQUE, 0, op, "You have no marked object.");
1078     else
1079     new_draw_info_format (NDI_UNIQUE, 0, op, "%s is marked.", query_name (mark));
1080     }
1081     else
1082     {
1083     object *mark1 = find_best_object_match (op, params);
1084    
1085     if (!mark1)
1086     {
1087     new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find an object that matches %s", params);
1088     return 1;
1089     }
1090     else
1091     {
1092     op->contr->mark = mark1;
1093     new_draw_info_format (NDI_UNIQUE, 0, op, "Marked item %s", query_name (mark1));
1094     return 0;
1095 root 1.10 }
1096 elmex 1.1 }
1097 root 1.20
1098 root 1.14 return 0; /*shouldnt get here */
1099 elmex 1.1 }
1100    
1101    
1102     /* op is the player
1103     * tmp is the monster being examined.
1104     */
1105 root 1.14 void
1106     examine_monster (object *op, object *tmp)
1107     {
1108     object *mon = tmp->head ? tmp->head : tmp;
1109    
1110     if (QUERY_FLAG (mon, FLAG_UNDEAD))
1111     new_draw_info (NDI_UNIQUE, 0, op, "It is an undead force.");
1112     if (mon->level > op->level)
1113     new_draw_info (NDI_UNIQUE, 0, op, "It is likely more powerful than you.");
1114     else if (mon->level < op->level)
1115     new_draw_info (NDI_UNIQUE, 0, op, "It is likely less powerful than you.");
1116     else
1117     new_draw_info (NDI_UNIQUE, 0, op, "It is probably as powerful as you.");
1118     if (mon->attacktype & AT_ACID)
1119     new_draw_info (NDI_UNIQUE, 0, op, "You seem to smell an acrid odor.");
1120 elmex 1.1
1121 root 1.14 /* Anyone know why this used to use the clone value instead of the
1122     * maxhp field? This seems that it should give more accurate results.
1123     */
1124     switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
1125     { /* From 1-4 */
1126 root 1.15 case 1:
1127     new_draw_info (NDI_UNIQUE, 0, op, "It is in a bad shape.");
1128     break;
1129     case 2:
1130     new_draw_info (NDI_UNIQUE, 0, op, "It is hurt.");
1131     break;
1132     case 3:
1133     new_draw_info (NDI_UNIQUE, 0, op, "It is somewhat hurt.");
1134     break;
1135     case 4:
1136     new_draw_info (NDI_UNIQUE, 0, op, "It is in excellent shape.");
1137     break;
1138 elmex 1.1 }
1139 root 1.14 if (present_in_ob (POISONING, mon) != NULL)
1140     new_draw_info (NDI_UNIQUE, 0, op, "It looks very ill.");
1141 elmex 1.1 }
1142    
1143    
1144     /* tmp is the object being described, pl is who is examing it. */
1145 root 1.14 char *
1146     long_desc (object *tmp, object *pl)
1147     {
1148     static char buf[VERY_BIG_BUF];
1149     char *cp;
1150 elmex 1.1
1151 root 1.14 if (tmp == NULL)
1152     return "";
1153 elmex 1.1
1154 root 1.14 buf[0] = '\0';
1155     switch (tmp->type)
1156     {
1157 root 1.15 case RING:
1158     case SKILL:
1159     case WEAPON:
1160     case ARMOUR:
1161     case BRACERS:
1162     case HELMET:
1163     case SHIELD:
1164     case BOOTS:
1165     case GLOVES:
1166     case AMULET:
1167     case GIRDLE:
1168     case BOW:
1169     case ARROW:
1170     case CLOAK:
1171     case FOOD:
1172     case DRINK:
1173     case FLESH:
1174     case SKILL_TOOL:
1175     case POWER_CRYSTAL:
1176     if (*(cp = describe_item (tmp, pl)) != '\0')
1177     {
1178     int len;
1179 root 1.14
1180 root 1.15 assign (buf, query_name (tmp));
1181     len = strlen (buf);
1182     if (len < VERY_BIG_BUF - 5)
1183     {
1184     /* Since we know the length, we save a few cpu cycles by using
1185     * it instead of calling strcat */
1186     strcpy (buf + len, " ");
1187     len++;
1188     assign (buf + len, cp, VERY_BIG_BUF - len - 1);
1189     }
1190     }
1191 elmex 1.1 }
1192 root 1.15
1193 root 1.14 if (buf[0] == '\0')
1194 root 1.15 assign (buf, query_name (tmp));
1195 elmex 1.1
1196 root 1.14 return buf;
1197 elmex 1.1 }
1198    
1199 root 1.14 void
1200     examine (object *op, object *tmp)
1201     {
1202     char buf[VERY_BIG_BUF];
1203     int i;
1204    
1205     if (tmp == NULL || tmp->type == CLOSE_CON)
1206     return;
1207    
1208     strcpy (buf, "That is ");
1209     strncat (buf, long_desc (tmp, op), VERY_BIG_BUF - strlen (buf) - 1);
1210     buf[VERY_BIG_BUF - 1] = 0;
1211 elmex 1.1
1212 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, buf);
1213     buf[0] = '\0';
1214 elmex 1.1
1215 root 1.14 if (tmp->custom_name)
1216     {
1217     strcpy (buf, "You call it ");
1218     strncat (buf, tmp->custom_name, VERY_BIG_BUF - strlen (buf) - 1);
1219     buf[VERY_BIG_BUF - 1] = 0;
1220     new_draw_info (NDI_UNIQUE, 0, op, buf);
1221     buf[0] = '\0';
1222 elmex 1.1 }
1223    
1224 root 1.14 switch (tmp->type)
1225     {
1226 root 1.15 case SPELLBOOK:
1227     if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) && tmp->inv)
1228     {
1229     sprintf (buf, "%s is a %s level %s spell", &tmp->inv->name, get_levelnumber (tmp->inv->level), &tmp->inv->skill);
1230     }
1231     break;
1232 root 1.10
1233 root 1.15 case BOOK:
1234     if (tmp->msg != NULL)
1235     strcpy (buf, "Something is written in it.");
1236     break;
1237 root 1.10
1238 root 1.15 case CONTAINER:
1239     if (tmp->race != NULL)
1240     {
1241     if (tmp->weight_limit && tmp->stats.Str < 100)
1242     sprintf (buf, "It can hold only %s and its weight limit is %.1f kg.",
1243     &tmp->race, tmp->weight_limit / (10.0 * (100 - tmp->stats.Str)));
1244     else
1245     sprintf (buf, "It can hold only %s.", &tmp->race);
1246     }
1247     else if (tmp->weight_limit && tmp->stats.Str < 100)
1248     sprintf (buf, "Its weight limit is %.1f kg.", tmp->weight_limit / (10.0 * (100 - tmp->stats.Str)));
1249     break;
1250    
1251     case WAND:
1252     if (QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1253     sprintf (buf, "It has %d charges left.", tmp->stats.food);
1254     break;
1255 root 1.14 }
1256    
1257     if (buf[0] != '\0')
1258     new_draw_info (NDI_UNIQUE, 0, op, buf);
1259    
1260     if (tmp->materialname != NULL && !tmp->msg)
1261     {
1262     sprintf (buf, "It is made of: %s.", &tmp->materialname);
1263     new_draw_info (NDI_UNIQUE, 0, op, buf);
1264     }
1265     /* Where to wear this item */
1266     for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1267     {
1268     if (tmp->body_info[i] < -1)
1269     {
1270     if (op->body_info[i])
1271     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s (%d)", body_locations[i].use_name, -tmp->body_info[i]);
1272     else
1273     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].nonuse_name);
1274     }
1275     else if (tmp->body_info[i])
1276     {
1277     if (op->body_info[i])
1278     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].use_name);
1279     else
1280     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].nonuse_name);
1281     }
1282     }
1283    
1284     if (tmp->weight)
1285     {
1286     sprintf (buf, tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", tmp->weight * (tmp->nrof ? tmp->nrof : 1) / 1000.0);
1287     new_draw_info (NDI_UNIQUE, 0, op, buf);
1288     }
1289    
1290     if (tmp->value && !QUERY_FLAG (tmp, FLAG_STARTEQUIP) && !QUERY_FLAG (tmp, FLAG_NO_PICK))
1291     {
1292     sprintf (buf, "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", query_cost_string (tmp, op, F_TRUE | F_APPROX));
1293     new_draw_info (NDI_UNIQUE, 0, op, buf);
1294     if (is_in_shop (op))
1295     {
1296     if (QUERY_FLAG (tmp, FLAG_UNPAID))
1297     sprintf (buf, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string (tmp, op, F_BUY | F_SHOP));
1298     else
1299     sprintf (buf, "You are offered %s for %s.", query_cost_string (tmp, op, F_SELL + F_SHOP), tmp->nrof > 1 ? "them" : "it");
1300     new_draw_info (NDI_UNIQUE, 0, op, buf);
1301     }
1302 elmex 1.1 }
1303    
1304 root 1.14 if (QUERY_FLAG (tmp, FLAG_MONSTER))
1305     examine_monster (op, tmp);
1306    
1307     /* Is this item buildable? */
1308     if (QUERY_FLAG (tmp, FLAG_IS_BUILDABLE))
1309     new_draw_info (NDI_UNIQUE, 0, op, "This is a buildable item.");
1310    
1311     /* Does the object have a message? Don't show message for all object
1312     * types - especially if the first entry is a match
1313     */
1314     if (tmp->msg && tmp->type != EXIT && tmp->type != BOOK && tmp->type != CORPSE && !tmp->move_on && strncasecmp (tmp->msg, "@match", 7))
1315     {
1316 elmex 1.1
1317 root 1.14 /* This is just a hack so when identifying the items, we print
1318     * out the extra message
1319     */
1320     if (need_identify (tmp) && QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1321     new_draw_info (NDI_UNIQUE, 0, op, "The object has a story:");
1322 elmex 1.1
1323 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, tmp->msg);
1324 elmex 1.1 }
1325 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, " "); /* Blank line */
1326 elmex 1.1 }
1327    
1328     /*
1329     * inventory prints object's inventory. If inv==NULL then print player's
1330     * inventory.
1331     * [ Only items which are applied are showed. Tero.Haatanen@lut.fi ]
1332     */
1333 root 1.14 void
1334     inventory (object *op, object *inv)
1335     {
1336 elmex 1.1 object *tmp;
1337     char *in;
1338     int items = 0, length;
1339    
1340 root 1.14 if (inv == NULL && op == NULL)
1341     {
1342     new_draw_info (NDI_UNIQUE, 0, op, "Inventory of what object?");
1343     return;
1344     }
1345 elmex 1.1 tmp = inv ? inv->inv : op->inv;
1346    
1347 root 1.14 while (tmp)
1348     {
1349     if ((!tmp->invisible &&
1350     (inv == NULL || inv->type == CONTAINER || QUERY_FLAG (tmp, FLAG_APPLIED))) || (!op || QUERY_FLAG (op, FLAG_WIZ)))
1351     items++;
1352     tmp = tmp->below;
1353     }
1354     if (inv == NULL)
1355     { /* player's inventory */
1356     if (items == 0)
1357     {
1358     new_draw_info (NDI_UNIQUE, 0, op, "You carry nothing.");
1359     return;
1360     }
1361     else
1362     {
1363     length = 28;
1364     in = "";
1365     if (op)
1366     clear_win_info (op);
1367     new_draw_info (NDI_UNIQUE, 0, op, "Inventory:");
1368     }
1369     }
1370     else
1371     {
1372     if (items == 0)
1373     return;
1374     else
1375     {
1376     length = 28;
1377     in = " ";
1378     }
1379     }
1380     for (tmp = inv ? inv->inv : op->inv; tmp; tmp = tmp->below)
1381     {
1382     if ((!op || !QUERY_FLAG (op, FLAG_WIZ)) && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG (tmp, FLAG_APPLIED))))
1383     continue;
1384     if ((!op || QUERY_FLAG (op, FLAG_WIZ)))
1385     new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s (%5d) %-8s", in, length, length,
1386     query_name (tmp), tmp->count, query_weight (tmp));
1387     else
1388     new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s %-8s", in, length + 8, length + 8, query_name (tmp), query_weight (tmp));
1389 elmex 1.1 }
1390 root 1.14 if (!inv && op)
1391     {
1392     new_draw_info_format (NDI_UNIQUE, 0, op, "%-*s %-8s", 41, "Total weight :", query_weight (op));
1393 elmex 1.1 }
1394     }
1395    
1396 root 1.14 static void
1397     display_new_pickup (object *op)
1398     {
1399     int i = op->contr->mode;
1400 elmex 1.1
1401 root 1.14 if (!(i & PU_NEWMODE))
1402     return;
1403 elmex 1.1
1404 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NEWMODE", i & PU_NEWMODE ? 1 : 0);
1405     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DEBUG", i & PU_DEBUG ? 1 : 0);
1406     new_draw_info_format (NDI_UNIQUE, 0, op, "%d INHIBIT", i & PU_INHIBIT ? 1 : 0);
1407     new_draw_info_format (NDI_UNIQUE, 0, op, "%d STOP", i & PU_STOP ? 1 : 0);
1408 elmex 1.1
1409 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d <= x pickup weight/value RATIO (0==off)", (i & PU_RATIO) * 5);
1410 elmex 1.1
1411 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FOOD", i & PU_FOOD ? 1 : 0);
1412     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DRINK", i & PU_DRINK ? 1 : 0);
1413     new_draw_info_format (NDI_UNIQUE, 0, op, "%d VALUABLES", i & PU_VALUABLES ? 1 : 0);
1414 elmex 1.1
1415 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOW", i & PU_BOW ? 1 : 0);
1416     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARROW", i & PU_ARROW ? 1 : 0);
1417 elmex 1.1
1418 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d HELMET", i & PU_HELMET ? 1 : 0);
1419     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SHIELD", i & PU_SHIELD ? 1 : 0);
1420     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARMOUR", i & PU_ARMOUR ? 1 : 0);
1421 elmex 1.1
1422 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOOTS", i & PU_BOOTS ? 1 : 0);
1423     new_draw_info_format (NDI_UNIQUE, 0, op, "%d GLOVES", i & PU_GLOVES ? 1 : 0);
1424     new_draw_info_format (NDI_UNIQUE, 0, op, "%d CLOAK", i & PU_CLOAK ? 1 : 0);
1425     new_draw_info_format (NDI_UNIQUE, 0, op, "%d KEY", i & PU_KEY ? 1 : 0);
1426 elmex 1.1
1427 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d MISSILEWEAPON", i & PU_MISSILEWEAPON ? 1 : 0);
1428     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ALLWEAPON", i & PU_ALLWEAPON ? 1 : 0);
1429     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICAL", i & PU_MAGICAL ? 1 : 0);
1430     new_draw_info_format (NDI_UNIQUE, 0, op, "%d POTION", i & PU_POTION ? 1 : 0);
1431 elmex 1.1
1432 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d SPELLBOOK", i & PU_SPELLBOOK ? 1 : 0);
1433     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SKILLSCROLL", i & PU_SKILLSCROLL ? 1 : 0);
1434     new_draw_info_format (NDI_UNIQUE, 0, op, "%d READABLES", i & PU_READABLES ? 1 : 0);
1435     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICDEVICE", i & PU_MAGIC_DEVICE ? 1 : 0);
1436 elmex 1.1
1437 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NOT CURSED", i & PU_NOT_CURSED ? 1 : 0);
1438 elmex 1.1
1439 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d JEWELS", i & PU_JEWELS ? 1 : 0);
1440 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FLESH", i & PU_FLESH ? 1 : 0);
1441 elmex 1.1
1442 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "");
1443     }
1444 elmex 1.1
1445 root 1.14 int
1446     command_pickup (object *op, char *params)
1447 elmex 1.1 {
1448     uint32 i;
1449 root 1.14 static const char *names[] = {
1450     "debug", "inhibit", "stop", "food", "drink", "valuables", "bow", "arrow", "helmet",
1451     "shield", "armour", "boots", "gloves", "cloak", "key", "missile", "allweapon",
1452 root 1.22 "magical", "potion", "spellbook", "skillscroll", "readables", "magicdevice", "notcursed",
1453     "jewels", "flesh", NULL
1454 root 1.14 };
1455     static uint32 modes[] = {
1456     PU_DEBUG, PU_INHIBIT, PU_STOP, PU_FOOD, PU_DRINK, PU_VALUABLES, PU_BOW, PU_ARROW, PU_HELMET,
1457     PU_SHIELD, PU_ARMOUR, PU_BOOTS, PU_GLOVES, PU_CLOAK, PU_KEY, PU_MISSILEWEAPON, PU_ALLWEAPON,
1458 root 1.22 PU_MAGICAL, PU_POTION, PU_SPELLBOOK, PU_SKILLSCROLL, PU_READABLES, PU_MAGIC_DEVICE, PU_NOT_CURSED,
1459     PU_JEWELS, PU_FLESH, 0
1460 root 1.14 };
1461    
1462     if (!params)
1463     {
1464     /* if the new mode is used, just print the settings */
1465     if (op->contr->mode & PU_NEWMODE)
1466     {
1467     display_new_pickup (op);
1468     return 1;
1469     }
1470     if (1)
1471     LOG (llevDebug, "command_pickup: !params\n");
1472     set_pickup_mode (op, (op->contr->mode > 6) ? 0 : op->contr->mode + 1);
1473     return 0;
1474     }
1475 elmex 1.1
1476 root 1.14 while (*params == ' ' && *params)
1477     params++;
1478 elmex 1.1
1479 root 1.14 if (*params == '+' || *params == '-')
1480     {
1481 elmex 1.1 int mode;
1482 root 1.14
1483     for (mode = 0; names[mode]; mode++)
1484     {
1485     if (!strcmp (names[mode], params + 1))
1486     {
1487 elmex 1.1 i = op->contr->mode;
1488 root 1.14 if (!(i & PU_NEWMODE))
1489     i = PU_NEWMODE;
1490     if (*params == '+')
1491     i = i | modes[mode];
1492 elmex 1.1 else
1493 root 1.14 i = i & ~modes[mode];
1494 elmex 1.1 op->contr->mode = i;
1495 root 1.14 display_new_pickup (op);
1496 elmex 1.1 return 1;
1497 root 1.14 }
1498     }
1499     new_draw_info_format (NDI_UNIQUE, 0, op, "Pickup: invalid item %s\n", params);
1500 elmex 1.1 return 1;
1501 root 1.14 }
1502 elmex 1.1
1503 root 1.14 if (sscanf (params, "%u", &i) != 1)
1504     {
1505     if (1)
1506     LOG (llevDebug, "command_pickup: params==NULL\n");
1507     new_draw_info (NDI_UNIQUE, 0, op, "Usage: pickup <0-7> or <value_density> .");
1508     return 1;
1509     }
1510     set_pickup_mode (op, i);
1511 elmex 1.1
1512     return 1;
1513     }
1514    
1515 root 1.14 void
1516     set_pickup_mode (object *op, int i)
1517     {
1518     switch (op->contr->mode = i)
1519     {
1520 root 1.15 case 0:
1521     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Don't pick up.");
1522     break;
1523     case 1:
1524     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item.");
1525     break;
1526     case 2:
1527     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item and stop.");
1528     break;
1529     case 3:
1530     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Stop before picking up.");
1531     break;
1532     case 4:
1533     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items.");
1534     break;
1535     case 5:
1536     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items and stop.");
1537     break;
1538     case 6:
1539     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all magic items.");
1540     break;
1541     case 7:
1542     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all coins and gems");
1543     break;
1544 elmex 1.1 }
1545     }
1546    
1547 root 1.14 int
1548     command_search_items (object *op, char *params)
1549 elmex 1.1 {
1550 root 1.14 char buf[MAX_BUF];
1551 elmex 1.1
1552 root 1.14 if (settings.search_items == FALSE)
1553     return 1;
1554 elmex 1.1
1555 root 1.14 if (params == NULL)
1556     {
1557     if (op->contr->search_str[0] == '\0')
1558     {
1559     new_draw_info (NDI_UNIQUE, 0, op, "Example: search magic+1");
1560     new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1561     new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1562 root 1.10 return 1;
1563     }
1564 root 1.14 op->contr->search_str[0] = '\0';
1565     new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1566     fix_player (op);
1567 elmex 1.1 return 1;
1568 root 1.14 }
1569     if ((int) strlen (params) >= MAX_BUF)
1570     {
1571     new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1572     return 1;
1573     }
1574     strcpy (op->contr->search_str, params);
1575     sprintf (buf, "Searching for '%s'.", op->contr->search_str);
1576     new_draw_info (NDI_UNIQUE, 0, op, buf);
1577     fix_player (op);
1578     return 1;
1579 elmex 1.1 }
1580