ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.56
Committed: Tue Jun 5 13:05:02 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.55: +0 -2 lines
Log Message:
- improve observe
- remove more cruft code
- archetype loading almost works again, reloading probbaly still borked.

File Contents

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