ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.37
Committed: Mon Jan 15 21:06:19 2007 UTC (17 years, 5 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.36: +26 -23 lines
Log Message:
comments

File Contents

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