ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.32
Committed: Tue Dec 26 08:54:59 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.31: +1 -3 lines
Log Message:
replace update_ob_speed by ->set_speed

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