ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.38
Committed: Wed Feb 7 23:50:01 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.37: +2 -0 lines
Log Message:
interim check-in for server upgrade

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