ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.23
Committed: Mon Dec 11 23:35:37 2006 UTC (17 years, 5 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.22: +1 -1 lines
Log Message:
reduced dependencies on old plug-in api, fixed some bugs and renamed
some methods while I was at it.

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