ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.54
Committed: Thu May 17 20:27:01 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_1
Changes since 1.53: +4 -2 lines
Log Message:
- more rewrite:
  change_skill now only changes the chosen_skill, nothing else.
  new flag to suppress skill tool behaviour of readying the skill
  when applying the tool, for use in find_skill.

File Contents

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