ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.110
Committed: Fri Mar 26 00:59:22 2010 UTC (14 years, 2 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.109: +2 -2 lines
Log Message:
remove bogus 2007 copyright that was added wrongly by the script, update to affero license

File Contents

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