ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.53
Committed: Thu May 17 14:14:55 2007 UTC (17 years ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.52: +0 -12 lines
Log Message:
remove superfluous/broken settings and related code

- COZY_SERVER:
  enabled most msall adjustments, changed digestion formula to the original one,
  party member treament w.r.t. pets enforced.
- PROHIBIT_PLAYERKILL: default
- real_wiz: removed and enforced
- create_home_portals: removed and enforced
- casting_time: removed and forced to be off (was crashing anyways)
- was_wiz flag removed and treated as off usually unless it was used
  in place of flag_wiz.
- do not save or restore wiz, wizcast and wizpass flags.

File Contents

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