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