ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.51
Committed: Sat May 12 16:06:42 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.50: +10 -17 lines
Log Message:
almost works

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