ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.16
Committed: Thu Sep 14 19:08:39 2006 UTC (17 years, 8 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.15: +0 -191 lines
Log Message:
remove rename command and implement lots of extra perl support

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