ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.25
Committed: Tue Dec 12 21:39:57 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.24: +3 -6 lines
Log Message:
- more ooficiation
- removed now superfluous remove calls

File Contents

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