ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.40
Committed: Fri Mar 2 12:14:57 2007 UTC (17 years, 3 months ago) by pippijn
Content type: text/plain
Branch: MAIN
CVS Tags: rel-2_0
Changes since 1.39: +0 -41 lines
Log Message:
- run, fire, mark in perl
- no more NewServerCommands

File Contents

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