ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.33
Committed: Tue Jan 2 11:08:36 2007 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.32: +0 -16 lines
Log Message:
add some robustness checks, add map find/load locking

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