ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.39
Committed: Sat Feb 10 21:01:10 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.38: +30 -31 lines
Log Message:
- avoid floorbox updates when client has container open, this
  completely confused gcfclient, although completely valid by
  the protocol (and of course, cfplus didn't even notice it).

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
1047     /* op should be a player, params is any params.
1048     * If no params given, we print out the currently marked object.
1049     * otherwise, try to find a matching object - try best match first.
1050     */
1051 root 1.14 int
1052     command_mark (object *op, char *params)
1053 elmex 1.1 {
1054 root 1.14 if (!op->contr)
1055     return 1;
1056 root 1.20
1057 root 1.14 if (!params)
1058     {
1059     object *mark = find_marked_object (op);
1060    
1061     if (!mark)
1062     new_draw_info (NDI_UNIQUE, 0, op, "You have no marked object.");
1063     else
1064     new_draw_info_format (NDI_UNIQUE, 0, op, "%s is marked.", query_name (mark));
1065     }
1066     else
1067     {
1068     object *mark1 = find_best_object_match (op, params);
1069    
1070     if (!mark1)
1071     {
1072     new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find an object that matches %s", params);
1073     return 1;
1074     }
1075     else
1076     {
1077     op->contr->mark = mark1;
1078     new_draw_info_format (NDI_UNIQUE, 0, op, "Marked item %s", query_name (mark1));
1079     return 0;
1080 root 1.10 }
1081 elmex 1.1 }
1082 root 1.20
1083 root 1.14 return 0; /*shouldnt get here */
1084 elmex 1.1 }
1085    
1086    
1087     /* op is the player
1088     * tmp is the monster being examined.
1089     */
1090 root 1.14 void
1091     examine_monster (object *op, object *tmp)
1092     {
1093     object *mon = tmp->head ? tmp->head : tmp;
1094    
1095     if (QUERY_FLAG (mon, FLAG_UNDEAD))
1096     new_draw_info (NDI_UNIQUE, 0, op, "It is an undead force.");
1097     if (mon->level > op->level)
1098     new_draw_info (NDI_UNIQUE, 0, op, "It is likely more powerful than you.");
1099     else if (mon->level < op->level)
1100     new_draw_info (NDI_UNIQUE, 0, op, "It is likely less powerful than you.");
1101     else
1102     new_draw_info (NDI_UNIQUE, 0, op, "It is probably as powerful as you.");
1103     if (mon->attacktype & AT_ACID)
1104     new_draw_info (NDI_UNIQUE, 0, op, "You seem to smell an acrid odor.");
1105 elmex 1.1
1106 root 1.14 /* Anyone know why this used to use the clone value instead of the
1107     * maxhp field? This seems that it should give more accurate results.
1108     */
1109     switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
1110     { /* From 1-4 */
1111 root 1.15 case 1:
1112     new_draw_info (NDI_UNIQUE, 0, op, "It is in a bad shape.");
1113     break;
1114     case 2:
1115     new_draw_info (NDI_UNIQUE, 0, op, "It is hurt.");
1116     break;
1117     case 3:
1118     new_draw_info (NDI_UNIQUE, 0, op, "It is somewhat hurt.");
1119     break;
1120     case 4:
1121     new_draw_info (NDI_UNIQUE, 0, op, "It is in excellent shape.");
1122     break;
1123 elmex 1.1 }
1124 root 1.14 if (present_in_ob (POISONING, mon) != NULL)
1125     new_draw_info (NDI_UNIQUE, 0, op, "It looks very ill.");
1126 elmex 1.1 }
1127    
1128    
1129     /* tmp is the object being described, pl is who is examing it. */
1130 root 1.14 char *
1131     long_desc (object *tmp, object *pl)
1132     {
1133     static char buf[VERY_BIG_BUF];
1134     char *cp;
1135 elmex 1.1
1136 root 1.14 if (tmp == NULL)
1137     return "";
1138 elmex 1.1
1139 root 1.14 buf[0] = '\0';
1140     switch (tmp->type)
1141     {
1142 root 1.15 case RING:
1143     case SKILL:
1144     case WEAPON:
1145     case ARMOUR:
1146     case BRACERS:
1147     case HELMET:
1148     case SHIELD:
1149     case BOOTS:
1150     case GLOVES:
1151     case AMULET:
1152     case GIRDLE:
1153     case BOW:
1154     case ARROW:
1155     case CLOAK:
1156     case FOOD:
1157     case DRINK:
1158     case FLESH:
1159     case SKILL_TOOL:
1160     case POWER_CRYSTAL:
1161     if (*(cp = describe_item (tmp, pl)) != '\0')
1162     {
1163     int len;
1164 root 1.14
1165 root 1.15 assign (buf, query_name (tmp));
1166     len = strlen (buf);
1167     if (len < VERY_BIG_BUF - 5)
1168     {
1169     /* Since we know the length, we save a few cpu cycles by using
1170     * it instead of calling strcat */
1171     strcpy (buf + len, " ");
1172     len++;
1173     assign (buf + len, cp, VERY_BIG_BUF - len - 1);
1174     }
1175     }
1176 elmex 1.1 }
1177 root 1.15
1178 root 1.14 if (buf[0] == '\0')
1179 root 1.15 assign (buf, query_name (tmp));
1180 elmex 1.1
1181 root 1.14 return buf;
1182 elmex 1.1 }
1183    
1184 root 1.14 void
1185     examine (object *op, object *tmp)
1186     {
1187     char buf[VERY_BIG_BUF];
1188     int i;
1189    
1190     if (tmp == NULL || tmp->type == CLOSE_CON)
1191     return;
1192    
1193     strcpy (buf, "That is ");
1194     strncat (buf, long_desc (tmp, op), VERY_BIG_BUF - strlen (buf) - 1);
1195     buf[VERY_BIG_BUF - 1] = 0;
1196 elmex 1.1
1197 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, buf);
1198     buf[0] = '\0';
1199 elmex 1.1
1200 root 1.14 if (tmp->custom_name)
1201     {
1202     strcpy (buf, "You call it ");
1203     strncat (buf, tmp->custom_name, VERY_BIG_BUF - strlen (buf) - 1);
1204     buf[VERY_BIG_BUF - 1] = 0;
1205     new_draw_info (NDI_UNIQUE, 0, op, buf);
1206     buf[0] = '\0';
1207 elmex 1.1 }
1208    
1209 root 1.14 switch (tmp->type)
1210     {
1211 root 1.15 case SPELLBOOK:
1212     if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) && tmp->inv)
1213     {
1214     sprintf (buf, "%s is a %s level %s spell", &tmp->inv->name, get_levelnumber (tmp->inv->level), &tmp->inv->skill);
1215     }
1216     break;
1217 root 1.10
1218 root 1.15 case BOOK:
1219     if (tmp->msg != NULL)
1220     strcpy (buf, "Something is written in it.");
1221     break;
1222 root 1.10
1223 root 1.15 case CONTAINER:
1224     if (tmp->race != NULL)
1225     {
1226     if (tmp->weight_limit && tmp->stats.Str < 100)
1227     sprintf (buf, "It can hold only %s and its weight limit is %.1f kg.",
1228     &tmp->race, tmp->weight_limit / (10.0 * (100 - tmp->stats.Str)));
1229     else
1230     sprintf (buf, "It can hold only %s.", &tmp->race);
1231     }
1232     else if (tmp->weight_limit && tmp->stats.Str < 100)
1233     sprintf (buf, "Its weight limit is %.1f kg.", tmp->weight_limit / (10.0 * (100 - tmp->stats.Str)));
1234     break;
1235    
1236     case WAND:
1237     if (QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1238     sprintf (buf, "It has %d charges left.", tmp->stats.food);
1239     break;
1240 root 1.14 }
1241    
1242     if (buf[0] != '\0')
1243     new_draw_info (NDI_UNIQUE, 0, op, buf);
1244    
1245     if (tmp->materialname != NULL && !tmp->msg)
1246     {
1247     sprintf (buf, "It is made of: %s.", &tmp->materialname);
1248     new_draw_info (NDI_UNIQUE, 0, op, buf);
1249     }
1250     /* Where to wear this item */
1251     for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1252     {
1253     if (tmp->body_info[i] < -1)
1254     {
1255     if (op->body_info[i])
1256     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s (%d)", body_locations[i].use_name, -tmp->body_info[i]);
1257     else
1258     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].nonuse_name);
1259     }
1260     else if (tmp->body_info[i])
1261     {
1262     if (op->body_info[i])
1263     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].use_name);
1264     else
1265     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].nonuse_name);
1266     }
1267     }
1268    
1269     if (tmp->weight)
1270     {
1271     sprintf (buf, tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", tmp->weight * (tmp->nrof ? tmp->nrof : 1) / 1000.0);
1272     new_draw_info (NDI_UNIQUE, 0, op, buf);
1273     }
1274    
1275     if (tmp->value && !QUERY_FLAG (tmp, FLAG_STARTEQUIP) && !QUERY_FLAG (tmp, FLAG_NO_PICK))
1276     {
1277     sprintf (buf, "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", query_cost_string (tmp, op, F_TRUE | F_APPROX));
1278     new_draw_info (NDI_UNIQUE, 0, op, buf);
1279     if (is_in_shop (op))
1280     {
1281     if (QUERY_FLAG (tmp, FLAG_UNPAID))
1282     sprintf (buf, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string (tmp, op, F_BUY | F_SHOP));
1283     else
1284     sprintf (buf, "You are offered %s for %s.", query_cost_string (tmp, op, F_SELL + F_SHOP), tmp->nrof > 1 ? "them" : "it");
1285     new_draw_info (NDI_UNIQUE, 0, op, buf);
1286     }
1287 elmex 1.1 }
1288    
1289 root 1.14 if (QUERY_FLAG (tmp, FLAG_MONSTER))
1290     examine_monster (op, tmp);
1291    
1292     /* Is this item buildable? */
1293     if (QUERY_FLAG (tmp, FLAG_IS_BUILDABLE))
1294     new_draw_info (NDI_UNIQUE, 0, op, "This is a buildable item.");
1295    
1296     /* Does the object have a message? Don't show message for all object
1297     * types - especially if the first entry is a match
1298     */
1299     if (tmp->msg && tmp->type != EXIT && tmp->type != BOOK && tmp->type != CORPSE && !tmp->move_on && strncasecmp (tmp->msg, "@match", 7))
1300     {
1301 elmex 1.1
1302 root 1.14 /* This is just a hack so when identifying the items, we print
1303     * out the extra message
1304     */
1305     if (need_identify (tmp) && QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1306     new_draw_info (NDI_UNIQUE, 0, op, "The object has a story:");
1307 elmex 1.1
1308 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, tmp->msg);
1309 elmex 1.1 }
1310 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, " "); /* Blank line */
1311 elmex 1.1 }
1312    
1313     /*
1314     * inventory prints object's inventory. If inv==NULL then print player's
1315     * inventory.
1316     * [ Only items which are applied are showed. Tero.Haatanen@lut.fi ]
1317     */
1318 root 1.14 void
1319     inventory (object *op, object *inv)
1320     {
1321 elmex 1.1 object *tmp;
1322     char *in;
1323     int items = 0, length;
1324    
1325 root 1.14 if (inv == NULL && op == NULL)
1326     {
1327     new_draw_info (NDI_UNIQUE, 0, op, "Inventory of what object?");
1328     return;
1329     }
1330 elmex 1.1 tmp = inv ? inv->inv : op->inv;
1331    
1332 root 1.14 while (tmp)
1333     {
1334     if ((!tmp->invisible &&
1335     (inv == NULL || inv->type == CONTAINER || QUERY_FLAG (tmp, FLAG_APPLIED))) || (!op || QUERY_FLAG (op, FLAG_WIZ)))
1336     items++;
1337     tmp = tmp->below;
1338     }
1339     if (inv == NULL)
1340     { /* player's inventory */
1341     if (items == 0)
1342     {
1343     new_draw_info (NDI_UNIQUE, 0, op, "You carry nothing.");
1344     return;
1345     }
1346     else
1347     {
1348     length = 28;
1349     in = "";
1350     if (op)
1351     clear_win_info (op);
1352     new_draw_info (NDI_UNIQUE, 0, op, "Inventory:");
1353     }
1354     }
1355     else
1356     {
1357     if (items == 0)
1358     return;
1359     else
1360     {
1361     length = 28;
1362     in = " ";
1363     }
1364     }
1365     for (tmp = inv ? inv->inv : op->inv; tmp; tmp = tmp->below)
1366     {
1367     if ((!op || !QUERY_FLAG (op, FLAG_WIZ)) && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG (tmp, FLAG_APPLIED))))
1368     continue;
1369     if ((!op || QUERY_FLAG (op, FLAG_WIZ)))
1370     new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s (%5d) %-8s", in, length, length,
1371     query_name (tmp), tmp->count, query_weight (tmp));
1372     else
1373     new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s %-8s", in, length + 8, length + 8, query_name (tmp), query_weight (tmp));
1374 elmex 1.1 }
1375 root 1.14 if (!inv && op)
1376     {
1377     new_draw_info_format (NDI_UNIQUE, 0, op, "%-*s %-8s", 41, "Total weight :", query_weight (op));
1378 elmex 1.1 }
1379     }
1380    
1381 root 1.14 static void
1382     display_new_pickup (object *op)
1383     {
1384     int i = op->contr->mode;
1385 elmex 1.1
1386 root 1.14 if (!(i & PU_NEWMODE))
1387     return;
1388 elmex 1.1
1389 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NEWMODE", i & PU_NEWMODE ? 1 : 0);
1390     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DEBUG", i & PU_DEBUG ? 1 : 0);
1391     new_draw_info_format (NDI_UNIQUE, 0, op, "%d INHIBIT", i & PU_INHIBIT ? 1 : 0);
1392     new_draw_info_format (NDI_UNIQUE, 0, op, "%d STOP", i & PU_STOP ? 1 : 0);
1393 elmex 1.1
1394 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d <= x pickup weight/value RATIO (0==off)", (i & PU_RATIO) * 5);
1395 elmex 1.1
1396 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FOOD", i & PU_FOOD ? 1 : 0);
1397     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DRINK", i & PU_DRINK ? 1 : 0);
1398     new_draw_info_format (NDI_UNIQUE, 0, op, "%d VALUABLES", i & PU_VALUABLES ? 1 : 0);
1399 elmex 1.1
1400 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOW", i & PU_BOW ? 1 : 0);
1401     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARROW", i & PU_ARROW ? 1 : 0);
1402 elmex 1.1
1403 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d HELMET", i & PU_HELMET ? 1 : 0);
1404     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SHIELD", i & PU_SHIELD ? 1 : 0);
1405     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARMOUR", i & PU_ARMOUR ? 1 : 0);
1406 elmex 1.1
1407 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOOTS", i & PU_BOOTS ? 1 : 0);
1408     new_draw_info_format (NDI_UNIQUE, 0, op, "%d GLOVES", i & PU_GLOVES ? 1 : 0);
1409     new_draw_info_format (NDI_UNIQUE, 0, op, "%d CLOAK", i & PU_CLOAK ? 1 : 0);
1410     new_draw_info_format (NDI_UNIQUE, 0, op, "%d KEY", i & PU_KEY ? 1 : 0);
1411 elmex 1.1
1412 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d MISSILEWEAPON", i & PU_MISSILEWEAPON ? 1 : 0);
1413     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ALLWEAPON", i & PU_ALLWEAPON ? 1 : 0);
1414     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICAL", i & PU_MAGICAL ? 1 : 0);
1415     new_draw_info_format (NDI_UNIQUE, 0, op, "%d POTION", i & PU_POTION ? 1 : 0);
1416 elmex 1.1
1417 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d SPELLBOOK", i & PU_SPELLBOOK ? 1 : 0);
1418     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SKILLSCROLL", i & PU_SKILLSCROLL ? 1 : 0);
1419     new_draw_info_format (NDI_UNIQUE, 0, op, "%d READABLES", i & PU_READABLES ? 1 : 0);
1420     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICDEVICE", i & PU_MAGIC_DEVICE ? 1 : 0);
1421 elmex 1.1
1422 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NOT CURSED", i & PU_NOT_CURSED ? 1 : 0);
1423 elmex 1.1
1424 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d JEWELS", i & PU_JEWELS ? 1 : 0);
1425 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FLESH", i & PU_FLESH ? 1 : 0);
1426 elmex 1.1
1427 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "");
1428     }
1429 elmex 1.1
1430 root 1.14 int
1431     command_pickup (object *op, char *params)
1432 elmex 1.1 {
1433     uint32 i;
1434 root 1.14 static const char *names[] = {
1435     "debug", "inhibit", "stop", "food", "drink", "valuables", "bow", "arrow", "helmet",
1436     "shield", "armour", "boots", "gloves", "cloak", "key", "missile", "allweapon",
1437 root 1.22 "magical", "potion", "spellbook", "skillscroll", "readables", "magicdevice", "notcursed",
1438     "jewels", "flesh", NULL
1439 root 1.14 };
1440     static uint32 modes[] = {
1441     PU_DEBUG, PU_INHIBIT, PU_STOP, PU_FOOD, PU_DRINK, PU_VALUABLES, PU_BOW, PU_ARROW, PU_HELMET,
1442     PU_SHIELD, PU_ARMOUR, PU_BOOTS, PU_GLOVES, PU_CLOAK, PU_KEY, PU_MISSILEWEAPON, PU_ALLWEAPON,
1443 root 1.22 PU_MAGICAL, PU_POTION, PU_SPELLBOOK, PU_SKILLSCROLL, PU_READABLES, PU_MAGIC_DEVICE, PU_NOT_CURSED,
1444     PU_JEWELS, PU_FLESH, 0
1445 root 1.14 };
1446    
1447     if (!params)
1448     {
1449     /* if the new mode is used, just print the settings */
1450     if (op->contr->mode & PU_NEWMODE)
1451     {
1452     display_new_pickup (op);
1453     return 1;
1454     }
1455     if (1)
1456     LOG (llevDebug, "command_pickup: !params\n");
1457     set_pickup_mode (op, (op->contr->mode > 6) ? 0 : op->contr->mode + 1);
1458     return 0;
1459     }
1460 elmex 1.1
1461 root 1.14 while (*params == ' ' && *params)
1462     params++;
1463 elmex 1.1
1464 root 1.14 if (*params == '+' || *params == '-')
1465     {
1466 elmex 1.1 int mode;
1467 root 1.14
1468     for (mode = 0; names[mode]; mode++)
1469     {
1470     if (!strcmp (names[mode], params + 1))
1471     {
1472 elmex 1.1 i = op->contr->mode;
1473 root 1.14 if (!(i & PU_NEWMODE))
1474     i = PU_NEWMODE;
1475     if (*params == '+')
1476     i = i | modes[mode];
1477 elmex 1.1 else
1478 root 1.14 i = i & ~modes[mode];
1479 elmex 1.1 op->contr->mode = i;
1480 root 1.14 display_new_pickup (op);
1481 elmex 1.1 return 1;
1482 root 1.14 }
1483     }
1484     new_draw_info_format (NDI_UNIQUE, 0, op, "Pickup: invalid item %s\n", params);
1485 elmex 1.1 return 1;
1486 root 1.14 }
1487 elmex 1.1
1488 root 1.14 if (sscanf (params, "%u", &i) != 1)
1489     {
1490     if (1)
1491     LOG (llevDebug, "command_pickup: params==NULL\n");
1492     new_draw_info (NDI_UNIQUE, 0, op, "Usage: pickup <0-7> or <value_density> .");
1493     return 1;
1494     }
1495     set_pickup_mode (op, i);
1496 elmex 1.1
1497     return 1;
1498     }
1499    
1500 root 1.14 void
1501     set_pickup_mode (object *op, int i)
1502     {
1503     switch (op->contr->mode = i)
1504     {
1505 root 1.15 case 0:
1506     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Don't pick up.");
1507     break;
1508     case 1:
1509     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item.");
1510     break;
1511     case 2:
1512     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item and stop.");
1513     break;
1514     case 3:
1515     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Stop before picking up.");
1516     break;
1517     case 4:
1518     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items.");
1519     break;
1520     case 5:
1521     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items and stop.");
1522     break;
1523     case 6:
1524     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all magic items.");
1525     break;
1526     case 7:
1527     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all coins and gems");
1528     break;
1529 elmex 1.1 }
1530     }
1531    
1532 root 1.14 int
1533     command_search_items (object *op, char *params)
1534 elmex 1.1 {
1535 root 1.14 char buf[MAX_BUF];
1536 elmex 1.1
1537 root 1.14 if (settings.search_items == FALSE)
1538     return 1;
1539 elmex 1.1
1540 root 1.14 if (params == NULL)
1541     {
1542     if (op->contr->search_str[0] == '\0')
1543     {
1544     new_draw_info (NDI_UNIQUE, 0, op, "Example: search magic+1");
1545     new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1546     new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1547 root 1.10 return 1;
1548     }
1549 root 1.14 op->contr->search_str[0] = '\0';
1550     new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1551 root 1.31 op->update_stats ();
1552 elmex 1.1 return 1;
1553 root 1.14 }
1554     if ((int) strlen (params) >= MAX_BUF)
1555     {
1556     new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1557     return 1;
1558     }
1559     strcpy (op->contr->search_str, params);
1560     sprintf (buf, "Searching for '%s'.", op->contr->search_str);
1561     new_draw_info (NDI_UNIQUE, 0, op, buf);
1562 root 1.31 op->update_stats ();
1563 root 1.14 return 1;
1564 elmex 1.1 }
1565