ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.128
Committed: Fri Feb 3 02:04:11 2012 UTC (12 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.127: +1 -3 lines
Log Message:
only load the highscore file once

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.126 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012 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 root 1.120 if ((aflag == AP_APPLY) && (tmp->flag [FLAG_APPLIED]))
73 root 1.14 continue;
74 root 1.52
75 root 1.120 if ((aflag == AP_UNAPPLY) && (!tmp->flag [FLAG_APPLIED]))
76 root 1.14 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 root 1.114 new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no knowledge of the %s skill.", params);
142 root 1.14 return 0;
143 elmex 1.1 }
144 root 1.47
145 root 1.112 pl->apply (skill);
146 root 1.54 return 1;
147 elmex 1.1 }
148    
149     /* A little special because we do want to pass the full params along
150     * as it includes the object to throw.
151 root 1.14 */
152     int
153     command_throw (object *op, char *params)
154 elmex 1.1 {
155 root 1.122 if (object *skop = find_skill_by_name (op, shstr_throwing))
156 root 1.14 return do_skill (op, op, skop, op->facing, params);
157     else
158 root 1.114 new_draw_info (NDI_UNIQUE, 0, op, "You have no knowledge of the throwing skill.");
159 root 1.51
160 root 1.14 return 0;
161 elmex 1.1 }
162    
163 root 1.14 int
164     command_apply (object *op, char *params)
165 elmex 1.1 {
166 root 1.14 if (!params)
167     {
168     player_apply_below (op);
169     return 0;
170     }
171     else
172     {
173 root 1.51 apply_flag aflag = (apply_flag)0;
174 root 1.14
175     while (*params == ' ')
176     params++;
177 root 1.51
178 root 1.14 if (!strncmp (params, "-a ", 3))
179     {
180     aflag = AP_APPLY;
181     params += 3;
182     }
183 root 1.51
184 root 1.14 if (!strncmp (params, "-u ", 3))
185     {
186     aflag = AP_UNAPPLY;
187     params += 3;
188     }
189 root 1.51
190 root 1.14 while (*params == ' ')
191     params++;
192 elmex 1.1
193 root 1.51 if (object *inv = find_best_apply_object_match (op, params, aflag))
194 root 1.117 op->apply (inv, aflag);
195 root 1.14 else
196 root 1.119 op->failmsgf ("Could not find any match to the %s.", params);
197 elmex 1.1 }
198 root 1.51
199 elmex 1.1 return 0;
200     }
201    
202     /*
203     * Check if an item op can be put into a sack. If pl exists then tell
204     * a player the reason of failure.
205     * returns 1 if it will fit, 0 if it will not. nrof is the number of
206     * objects (op) we want to put in. We specify it separately instead of
207     * using op->nrof because often times, a player may have specified a
208     * certain number of objects to drop, so we can pass that number, and
209     * not need to use split_ob and stuff.
210     */
211 root 1.14 int
212     sack_can_hold (object *pl, object *sack, object *op, uint32 nrof)
213     {
214 root 1.120 if (!sack->flag [FLAG_APPLIED])
215 root 1.14 {
216     new_draw_info_format (NDI_UNIQUE, 0, pl, "The %s is not active.", query_name (sack));
217     return 0;
218     }
219 root 1.66
220 root 1.14 if (sack == op)
221     {
222     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't put the %s into itself.", query_name (sack));
223     return 0;
224     }
225 root 1.66
226 root 1.14 if (sack->race && (sack->race != op->race || op->type == CONTAINER || (sack->stats.food && sack->stats.food != op->type)))
227     {
228 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));
229 root 1.14 return 0;
230     }
231 root 1.66
232 root 1.14 if (op->type == SPECIAL_KEY && sack->slaying && op->slaying)
233     {
234     new_draw_info_format (NDI_UNIQUE, 0, pl, "You can't put the key into %s.", query_name (sack));
235     return 0;
236     }
237 root 1.66
238 root 1.14 if (sack->weight_limit && (sint32) (sack->carrying + (nrof ? nrof : 1) *
239     (op->weight + (op->type == CONTAINER ? (op->carrying * op->stats.Str) : 0))
240     * (100 - sack->stats.Str) / 100) > sack->weight_limit)
241     {
242     new_draw_info_format (NDI_UNIQUE, 0, pl, "That won't fit in the %s!", query_name (sack));
243     return 0;
244 elmex 1.1 }
245 root 1.66
246 root 1.14 /* All other checks pass, must be OK */
247     return 1;
248 elmex 1.1 }
249    
250     /* Pick up commands follow */
251 root 1.14
252 elmex 1.1 /* pl = player (not always - monsters can use this now)
253     * op is the object to put tmp into,
254     * tmp is the object to pick up, nrof is the number to
255     * pick up (0 means all of them)
256     */
257 root 1.14 static void
258     pick_up_object (object *pl, object *op, object *tmp, int nrof)
259 elmex 1.1 {
260 root 1.14 uint32 weight, effective_weight_limit;
261 root 1.66 int tmp_nrof = tmp->number_of ();
262 root 1.14
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.120 if ((pl->move_type & MOVE_FLYING) && !pl->flag [FLAG_WIZ] && tmp->in_player () != pl)
269 root 1.14 {
270 root 1.72 pl->failmsg ("You are levitating, you can't reach the ground! "
271     "H<You have to stop levitating first, if you can, either by using your levitation skill, "
272     "or waiting till the levitation effect wears off.>");
273 root 1.14 return;
274     }
275 root 1.18
276 root 1.120 if (tmp->flag [FLAG_NO_DROP])
277 root 1.14 return;
278 root 1.18
279 root 1.67 if (nrof > tmp_nrof || nrof <= 0)
280 root 1.14 nrof = tmp_nrof;
281 root 1.18
282 root 1.14 /* Figure out how much weight this object will add to the player */
283     weight = tmp->weight * nrof;
284     if (tmp->inv)
285     weight += tmp->carrying * (100 - tmp->stats.Str) / 100;
286 root 1.18
287 root 1.64 effective_weight_limit = weight_limit [min (MAX_STAT, pl->stats.Str)];
288 root 1.18
289 root 1.14 if ((pl->weight + pl->carrying + weight) > effective_weight_limit)
290     {
291     new_draw_info (0, 0, pl, "That item is too heavy for you to pick up.");
292     return;
293 elmex 1.1 }
294 root 1.18
295 root 1.66 if (!can_split (pl, tmp, nrof))
296     return;
297 root 1.39
298 root 1.120 if (tmp->flag [FLAG_UNPAID])
299 root 1.69 {
300     tmp->flag.reset (FLAG_UNPAID);
301     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));
302     tmp->flag.set (FLAG_UNPAID);
303     }
304 root 1.14 else
305 root 1.64 new_draw_info_format (NDI_UNIQUE, 0, pl, "You pick up the %s.", query_name (tmp));
306 root 1.14
307 root 1.69 op->insert (tmp);
308 elmex 1.1 }
309    
310 root 1.18 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
311 root 1.14 void
312     pick_up (object *op, object *alt)
313 elmex 1.1 {
314 root 1.14 int need_fix_tmp = 0;
315     object *tmp = NULL;
316 root 1.19 maptile *tmp_map = NULL;
317 root 1.14 int count;
318    
319     /* Decide which object to pick. */
320     if (alt)
321     {
322     if (!can_pick (op, alt))
323     {
324     new_draw_info_format (NDI_UNIQUE, 0, op, "You can't pick up the %s.", &alt->name);
325     goto leave;
326     }
327 root 1.64
328 root 1.14 tmp = alt;
329     }
330     else
331     {
332     if (op->below == NULL || !can_pick (op, op->below))
333     {
334     new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up here.");
335     goto leave;
336 elmex 1.1 }
337 root 1.18
338 root 1.14 tmp = op->below;
339     }
340    
341     /* Try to catch it. */
342     tmp_map = tmp->map;
343     tmp = stop_item (tmp);
344     if (tmp == NULL)
345     goto leave;
346 root 1.64
347 root 1.14 need_fix_tmp = 1;
348     if (!can_pick (op, tmp))
349     goto leave;
350    
351     if (op->type == PLAYER)
352     {
353     count = op->contr->count;
354     if (count == 0)
355     count = tmp->nrof;
356 elmex 1.1 }
357 root 1.14 else
358     count = tmp->nrof;
359 elmex 1.1
360 root 1.14 /* container is open, so use it */
361 root 1.64 if (tmp->flag [FLAG_STARTEQUIP])
362     alt = op;
363 root 1.100 else if ((alt = op->container_ ()))
364 root 1.14 {
365     if (alt != tmp->env && !sack_can_hold (op, alt, tmp, count))
366 elmex 1.1 goto leave;
367 root 1.14 }
368     else
369     { /* non container pickup */
370     for (alt = op->inv; alt; alt = alt->below)
371 root 1.120 if (alt->type == CONTAINER && alt->flag [FLAG_APPLIED] &&
372 root 1.14 alt->race && alt->race == tmp->race && sack_can_hold (NULL, alt, tmp, count))
373     break; /* perfect match */
374    
375     if (!alt)
376     for (alt = op->inv; alt; alt = alt->below)
377 root 1.120 if (alt->type == CONTAINER && alt->flag [FLAG_APPLIED] && sack_can_hold (NULL, alt, tmp, count))
378 root 1.14 break; /* General container comes next */
379 root 1.39
380 root 1.14 if (!alt)
381     alt = op; /* No free containers */
382     }
383 root 1.21
384 root 1.14 if (tmp->env == alt)
385     {
386     /* here it could be possible to check rent,
387     * if someone wants to implement it
388     */
389     alt = op;
390 elmex 1.1 }
391 root 1.64
392 elmex 1.1 #ifdef PICKUP_DEBUG
393 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);
394 elmex 1.1 #endif
395    
396 root 1.14 /* startequip items are not allowed to be put into containers: */
397 root 1.120 if (op->type == PLAYER && alt->type == CONTAINER && tmp->flag [FLAG_STARTEQUIP])
398 elmex 1.1 {
399 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This object cannot be put into containers!");
400     goto leave;
401 elmex 1.1 }
402    
403 root 1.14 pick_up_object (op, alt, tmp, count);
404 root 1.18
405     if (tmp->destroyed () || tmp->env)
406 root 1.14 need_fix_tmp = 0;
407 root 1.18
408 root 1.14 if (op->type == PLAYER)
409     op->contr->count = 0;
410 root 1.18
411 root 1.14 goto leave;
412 elmex 1.1
413 root 1.14 leave:
414     if (need_fix_tmp)
415     fix_stopped_item (tmp, tmp_map, op);
416 elmex 1.1 }
417    
418     /* This takes (picks up) and item. op is the player
419     * who issued the command. params is a string to
420     * match against the item name. Basically, always
421     * returns zero, but that should be improved.
422     */
423 root 1.14 int
424     command_take (object *op, char *params)
425 elmex 1.1 {
426 root 1.14 object *tmp, *next;
427 elmex 1.1
428 root 1.100 if (op->container_ ())
429     tmp = op->container_ ()->inv;
430 root 1.14 else
431     {
432     tmp = op->above;
433     if (tmp)
434     while (tmp->above)
435 root 1.21 tmp = tmp->above;
436    
437 root 1.14 if (!tmp)
438     tmp = op->below;
439 elmex 1.1 }
440    
441 root 1.39 if (!tmp)
442 root 1.14 {
443     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to take!");
444     return 0;
445 elmex 1.1 }
446    
447 root 1.14 /* Makes processing easier */
448     if (params && *params == '\0')
449 root 1.39 params = 0;
450 elmex 1.1
451 root 1.103 int cnt = MAX_ITEM_PER_ACTION;
452 elmex 1.62
453 root 1.14 while (tmp)
454     {
455     next = tmp->below;
456 elmex 1.1
457 root 1.14 if (tmp->invisible)
458     {
459     tmp = next;
460     continue;
461     }
462 root 1.35
463 root 1.14 /* This following two if and else if could be merged into line
464     * but that probably will make it more difficult to read, and
465     * not make it any more efficient
466     */
467     if (params && item_matched_string (op, tmp, params))
468 elmex 1.62 {
469 root 1.74 if (--cnt < 0) break;
470 elmex 1.62 pick_up (op, tmp);
471     }
472 root 1.14 else if (can_pick (op, tmp) && !params)
473     {
474 root 1.74 if (--cnt < 0) break;
475 root 1.14 pick_up (op, tmp);
476     break;
477 root 1.10 }
478 root 1.35
479 root 1.14 tmp = next;
480     }
481 root 1.35
482 root 1.73 if (cnt < 0)
483 elmex 1.62 {
484     op->failmsg ("Couldn't pick up so many items at once.");
485     return 0;
486     }
487    
488 root 1.14 if (!params && !tmp)
489     {
490 root 1.35 for (tmp = op->below; tmp; tmp = tmp->below)
491 root 1.14 if (!tmp->invisible)
492     {
493 root 1.64 new_draw_info_format (NDI_UNIQUE, 0, op, "You can't pick up a %s.", &tmp->name);
494 root 1.10 break;
495 root 1.14 }
496 root 1.35
497 root 1.14 if (!tmp)
498     new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up.");
499 elmex 1.1 }
500 root 1.35
501 root 1.14 return 0;
502 elmex 1.1 }
503    
504     /*
505 root 1.83 * This function was part of drop, now is own function.
506     * Player 'op' tries to put object 'tmp' into sack 'sack',
507     * if nrof is non zero, then nrof objects is tried to put into sack.
508     *
509 elmex 1.1 * Note that the 'sack' in question can now be a transport,
510     * so this function isn't named very good anymore.
511     */
512 root 1.14 void
513     put_object_in_sack (object *op, object *sack, object *tmp, uint32 nrof)
514 elmex 1.1 {
515 root 1.128 object *tmp2;
516 root 1.14 char buf[MAX_BUF];
517    
518     if (sack == tmp)
519     return; /* Can't put an object in itself */
520 root 1.18
521 root 1.120 if (tmp->flag [FLAG_STARTEQUIP] || tmp->flag [FLAG_NO_DROP])
522 root 1.14 {
523     new_draw_info_format (NDI_UNIQUE, 0, op, "You cannot put the %s in the %s.", query_name (tmp), query_name (sack));
524     return;
525 elmex 1.1 }
526 root 1.18
527 root 1.14 if (tmp->type == CONTAINER && tmp->inv)
528     {
529     /* Eneq(@csd.uu.se): If the object to be dropped is a container
530     * we instead move the contents of that container into the active
531     * container, this is only done if the object has something in it.
532     */
533     new_draw_info_format (NDI_UNIQUE, 0, op, "You move the items from %s into %s.", query_name (tmp), query_name (sack));
534 root 1.18
535 root 1.14 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp)
536     {
537     tmp = tmp2->below;
538 root 1.18
539 root 1.100 if ((sack->type == CONTAINER && sack_can_hold (op, op->container_ (), tmp2, tmp2->nrof)))
540 root 1.69 put_object_in_sack (op, sack, tmp2, 0);
541 root 1.14 else
542     {
543     sprintf (buf, "Your %s fills up.", query_name (sack));
544     new_draw_info (NDI_UNIQUE, 0, op, buf);
545     break;
546 root 1.10 }
547     }
548 root 1.18
549 root 1.14 return;
550     }
551    
552     /* Don't worry about this for containers - our caller should have
553     * already checked this.
554     */
555     if ((sack->type == CONTAINER) && !sack_can_hold (op, sack, tmp, (nrof ? nrof : tmp->nrof)))
556     return;
557    
558 root 1.120 if (tmp->flag [FLAG_APPLIED])
559 root 1.118 if (!op->apply (tmp, AP_UNAPPLY | AP_NO_MERGE))
560 root 1.18 return;
561 elmex 1.1
562 root 1.14 /* we want to put some portion of the item into the container */
563 root 1.69 if (!can_split (op, tmp, nrof))
564     return;
565 root 1.14
566     new_draw_info_format (NDI_UNIQUE, 0, op, "You put the %s in %s.", query_name (tmp), query_name (sack));
567 root 1.69 sack->insert (tmp);
568 elmex 1.1 }
569    
570 elmex 1.81 /* In contrast to drop_object (op, tmp, nrof) above this function takes the
571     * already split off object, and feeds it to the event handlers and does
572     * other magic with it.
573     *
574     * <droppper> is the object that dropped this object and <obj> is the
575     * object that was dropped.
576     *
577     * Make sure to check what happened with <obj> after this function returns!
578     * Otherwise you may leak this object.
579     */
580     void
581     drop_object (object *dropper, object *obj)
582     {
583     if (INVOKE_OBJECT (DROP, obj, ARG_OBJECT (dropper)))
584 elmex 1.2 return;
585 elmex 1.81
586 elmex 1.82 if (obj->destroyed () || obj->is_inserted ())
587     return;
588 elmex 1.1
589 root 1.120 if (obj->flag [FLAG_STARTEQUIP])
590 elmex 1.2 {
591 elmex 1.81 dropper->statusmsg (format ("You drop the %s.", query_name (obj)));
592     dropper->statusmsg ("The god who lent it to you retrieves it.");
593 root 1.28
594 elmex 1.81 obj->destroy ();
595     dropper->update_stats ();
596 elmex 1.1 return;
597     }
598    
599 elmex 1.81 for (object *floor = GET_MAP_OB (dropper->map, dropper->x, dropper->y);
600     floor;
601     floor = floor->above)
602     if (INVOKE_OBJECT (DROP_ON, floor, ARG_OBJECT (obj), ARG_OBJECT (dropper)))
603 elmex 1.5 return;
604 elmex 1.1
605 elmex 1.82 if (obj->destroyed () || obj->is_inserted ())
606     return;
607 elmex 1.1
608 root 1.120 if (dropper->is_in_shop () && !obj->flag [FLAG_UNPAID] && obj->type != MONEY)
609 elmex 1.81 if (!sell_item (obj, dropper))
610     return;
611 elmex 1.1
612 root 1.103 if (!obj->can_drop_at (dropper->map, dropper->x, dropper->y, dropper))
613     return;
614    
615 elmex 1.81 /* If nothing special happened with this object, the default action is to
616     * insert it below the dropper:
617     */
618    
619     obj->x = dropper->x;
620     obj->y = dropper->y;
621    
622     insert_ob_in_map (obj, dropper->map, dropper, INS_BELOW_ORIGINATOR);
623 elmex 1.1 }
624    
625 root 1.103 /*
626     * This function was part of drop, now is own function.
627     * Player 'op' tries to drop object 'tmp', if tmp is non zero, then
628     * nrof objects are tried to drop.
629     * This is used when dropping objects onto the floor.
630     */
631     void
632     drop_object (object *op, object *tmp, uint32 nrof)
633     {
634 root 1.120 if (tmp->flag [FLAG_NO_DROP])
635 root 1.103 return;
636    
637 root 1.120 if (tmp->flag [FLAG_APPLIED])
638 root 1.118 if (!op->apply (tmp, AP_UNAPPLY | AP_NO_MERGE))
639 root 1.103 return; /* can't unapply it */
640    
641     /* We are only dropping some of the items. We split the current object
642     * off
643     */
644     if (!can_split (op, tmp, nrof))
645     return;
646    
647     drop_object (op, tmp);
648    
649     if (!tmp->destroyed () && !tmp->is_inserted ())
650     {
651     // if nothing happened with the object we give it back
652     op->insert (tmp);
653     }
654     }
655    
656 root 1.69 void
657 root 1.14 drop (object *op, object *tmp)
658 elmex 1.1 {
659 root 1.14 /* Hopeful fix for disappearing objects when dropping from a container -
660     * somehow, players get an invisible object in the container, and the
661     * old logic would skip over invisible objects - works fine for the
662     * playes inventory, but drop inventory wants to use the next value.
663     */
664     if (tmp->invisible)
665     {
666     /* if the following is the case, it must be in an container. */
667     if (tmp->env && tmp->env->type != PLAYER)
668     {
669     /* Just toss the object - probably shouldn't be hanging
670     * around anyways
671     */
672 root 1.79 tmp->destroy ();
673 root 1.14 return;
674     }
675     else
676 root 1.103 while (tmp && tmp->invisible)
677     tmp = tmp->below;
678 elmex 1.1 }
679    
680 root 1.103 if (!tmp)
681 root 1.14 {
682     new_draw_info (NDI_UNIQUE, 0, op, "You don't have anything to drop.");
683 elmex 1.1 return;
684     }
685 root 1.70
686 root 1.120 if (tmp->flag [FLAG_INV_LOCKED])
687 root 1.14 {
688     new_draw_info (NDI_UNIQUE, 0, op, "This item is locked");
689 elmex 1.1 return;
690     }
691 root 1.70
692 root 1.120 if (tmp->flag [FLAG_NO_DROP])
693 root 1.14 {
694 elmex 1.1 #if 0
695     /* Eneq(@csd.uu.se): Objects with NO_DROP defined can't be dropped. */
696 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This item can't be dropped.");
697 elmex 1.1 #endif
698     return;
699     }
700    
701 root 1.26 if (op->type == PLAYER && op->contr->last_used == tmp)
702     op->contr->last_used = tmp->below ? tmp->below
703     : tmp->above ? tmp->above
704 root 1.91 : (object *)0;
705 elmex 1.1
706 root 1.100 if (op->container_ ())
707 root 1.14 {
708     if (op->type == PLAYER)
709 root 1.100 put_object_in_sack (op, op->container_ (), tmp, op->contr->count);
710 root 1.14 else
711 root 1.100 put_object_in_sack (op, op->container_ (), tmp, 0);
712 root 1.14 }
713     else
714     {
715     if (op->type == PLAYER)
716 root 1.26 drop_object (op, tmp, op->contr->count);
717 root 1.14 else
718 root 1.26 drop_object (op, tmp, 0);
719 elmex 1.1 }
720 root 1.26
721 root 1.14 if (op->type == PLAYER)
722     op->contr->count = 0;
723 elmex 1.1 }
724    
725     /* Command will drop all items that have not been locked */
726 root 1.14 int
727     command_dropall (object *op, char *params)
728     {
729    
730     if (op->inv == NULL)
731     {
732     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop!");
733     return 0;
734     }
735 elmex 1.1
736 root 1.70 object *curinv = op->inv;
737     object *nextinv;
738 elmex 1.1
739     /*
740 root 1.14 This is the default. Drops everything not locked or considered
741     not something that should be dropped.
742     */
743 elmex 1.1 /*
744 root 1.14 Care must be taken that the next item pointer is not to money as
745     the drop() routine will do unknown things to it when dropping
746     in a shop. --Tero.Pelander@utu.fi
747     */
748 root 1.103 int cnt = MAX_ITEM_PER_ACTION;
749 elmex 1.61
750 root 1.70 if (!params)
751 root 1.14 {
752 root 1.70 while (curinv)
753 root 1.14 {
754     nextinv = curinv->below;
755 root 1.70
756 root 1.14 while (nextinv && nextinv->type == MONEY)
757     nextinv = nextinv->below;
758 root 1.70
759 root 1.120 if (!curinv->flag [FLAG_INV_LOCKED]
760 root 1.125 && !curinv->invisible
761 root 1.103 && curinv->type != MONEY
762     && curinv->type != FOOD
763     && curinv->type != KEY
764     && curinv->type != SPECIAL_KEY
765     && curinv->type != GEM
766 root 1.125 && curinv->type != CONTAINER)
767 root 1.14 {
768     drop (op, curinv);
769 elmex 1.61 if (--cnt <= 0) break;
770 root 1.14 }
771 root 1.70
772 root 1.14 curinv = nextinv;
773     }
774     }
775     else if (strcmp (params, "weapons") == 0)
776     {
777 root 1.70 while (curinv)
778 root 1.14 {
779     nextinv = curinv->below;
780 root 1.70
781 root 1.14 while (nextinv && nextinv->type == MONEY)
782     nextinv = nextinv->below;
783 root 1.70
784 root 1.120 if (!curinv->flag [FLAG_INV_LOCKED] && ((curinv->type == WEAPON) || (curinv->type == BOW) || (curinv->type == ARROW)))
785 root 1.14 {
786     drop (op, curinv);
787 elmex 1.61 if (--cnt <= 0) break;
788 root 1.14 }
789 root 1.70
790 root 1.14 curinv = nextinv;
791     }
792     }
793     else if (strcmp (params, "armor") == 0 || strcmp (params, "armour") == 0)
794     {
795 root 1.70 while (curinv)
796 root 1.14 {
797     nextinv = curinv->below;
798 root 1.70
799 root 1.14 while (nextinv && nextinv->type == MONEY)
800     nextinv = nextinv->below;
801 root 1.70
802 root 1.120 if (!curinv->flag [FLAG_INV_LOCKED] && ((curinv->type == ARMOUR) || curinv->type == SHIELD || curinv->type == HELMET))
803 root 1.14 {
804     drop (op, curinv);
805 elmex 1.61 if (--cnt <= 0) break;
806 root 1.14 }
807 root 1.70
808 root 1.10 curinv = nextinv;
809 root 1.14 }
810     }
811     else if (strcmp (params, "misc") == 0)
812     {
813 root 1.70 while (curinv)
814 root 1.14 {
815     nextinv = curinv->below;
816 root 1.70
817 root 1.14 while (nextinv && nextinv->type == MONEY)
818     nextinv = nextinv->below;
819 root 1.70
820 root 1.120 if (!curinv->flag [FLAG_INV_LOCKED] && !curinv->flag [FLAG_APPLIED])
821 root 1.14 {
822     switch (curinv->type)
823     {
824 root 1.15 case HORN:
825     case BOOK:
826     case SPELLBOOK:
827     case GIRDLE:
828     case AMULET:
829     case RING:
830     case CLOAK:
831     case BOOTS:
832     case GLOVES:
833     case BRACERS:
834     case SCROLL:
835     case ARMOUR_IMPROVER:
836     case WEAPON_IMPROVER:
837     case WAND:
838     case ROD:
839     case POTION:
840     drop (op, curinv);
841     curinv = nextinv;
842     break;
843     default:
844     curinv = nextinv;
845     break;
846 root 1.14 }
847 root 1.70
848 elmex 1.61 if (--cnt <= 0) break;
849 root 1.14 }
850 root 1.70
851 root 1.10 curinv = nextinv;
852     }
853 elmex 1.1 }
854 root 1.28
855 elmex 1.61 if (cnt <= 0)
856 elmex 1.62 op->failmsg ("Only dropped some items, can't drop that many items at once.");
857 elmex 1.61
858 elmex 1.1 /* draw_look(op);*/
859     return 0;
860     }
861    
862 elmex 1.81
863     /* This function tries to drop all objects in the <objs> vector.
864     * <dropper> is the object that wants to drop them.
865     * <cnt> can be a 0 pointer or a pointer to the maximum number of
866     * drop operations to perform.
867     *
868     * Returns true if at least one item was dropped.
869     */
870 root 1.101 static bool
871 elmex 1.81 drop_vector (object *dropper, vector<object *> &objs, int *cnt)
872     {
873     vector<object *>::iterator i;
874    
875     bool did_one = false;
876    
877     for (i = objs.begin (); i != objs.end (); i++)
878     {
879     drop (dropper, *i);
880     if (cnt && --*cnt <= 0) break;
881     did_one = true;
882     }
883    
884     return did_one;
885     }
886    
887 elmex 1.1 /* Object op wants to drop object(s) params. params can be a
888     * comma seperated list.
889     */
890 root 1.14 int
891     command_drop (object *op, char *params)
892 elmex 1.1 {
893 root 1.14 object *tmp, *next;
894 elmex 1.1
895 root 1.14 if (!params)
896     {
897     new_draw_info (NDI_UNIQUE, 0, op, "Drop what?");
898     return 0;
899     }
900     else
901     {
902 elmex 1.81 vector<object *> matched_objs;
903 elmex 1.61
904 root 1.14 for (tmp = op->inv; tmp; tmp = next)
905     {
906     next = tmp->below;
907 root 1.120 if (tmp->flag [FLAG_NO_DROP] || tmp->invisible)
908 root 1.14 continue;
909 elmex 1.61
910 root 1.14 if (item_matched_string (op, tmp, params))
911 elmex 1.81 matched_objs.push_back (tmp);
912 root 1.10 }
913 elmex 1.61
914 root 1.103 int cnt = MAX_ITEM_PER_ACTION;
915 elmex 1.81
916     if (!drop_vector (op, matched_objs, &cnt))
917 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop.");
918 elmex 1.61
919     if (cnt <= 0)
920 elmex 1.62 op->failmsg ("Only dropped some items, can't drop that many items at once.");
921 elmex 1.1 }
922 root 1.14
923     return 0;
924 elmex 1.1 }
925    
926 root 1.14 int
927     command_examine (object *op, char *params)
928 elmex 1.1 {
929 root 1.14 if (!params)
930     {
931     object *tmp = op->below;
932    
933 root 1.36 while (tmp && !tmp->client_visible ())
934 root 1.14 tmp = tmp->below;
935 root 1.65
936 root 1.14 if (tmp)
937     examine (op, tmp);
938     }
939     else
940     {
941     object *tmp = find_best_object_match (op, params);
942    
943     if (tmp)
944     examine (op, tmp);
945     else
946 root 1.65 op->contr->infobox (MSG_CHANNEL ("examine"), format ("Could not find an object that matches %s", params));
947 root 1.14 }
948 root 1.65
949 elmex 1.1 return 0;
950     }
951    
952 root 1.42 std::string
953     object::describe_monster (object *who)
954 root 1.14 {
955 root 1.42 dynbuf_text buf (512, 512);
956    
957     object *mon = head ? head : this;
958 root 1.14
959 root 1.120 if (mon->flag [FLAG_UNDEAD])
960 root 1.77 buf << "It is an undead force.\r";
961 root 1.42
962     if (mon->level > who->level)
963 root 1.77 buf << "It is likely more powerful than you.\r";
964 root 1.42 else if (mon->level < who->level)
965 root 1.77 buf << "It is likely less powerful than you.\r";
966 root 1.14 else
967 root 1.77 buf << "It is probably as powerful as you.\r";
968 root 1.42
969 root 1.14 if (mon->attacktype & AT_ACID)
970 root 1.77 buf << "You seem to smell an acrid odor.\r";
971 elmex 1.1
972 root 1.14 /* Anyone know why this used to use the clone value instead of the
973     * maxhp field? This seems that it should give more accurate results.
974     */
975     switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
976     { /* From 1-4 */
977 root 1.15 case 1:
978 root 1.77 buf << "It is in a bad shape.\r";
979 root 1.15 break;
980     case 2:
981 root 1.77 buf << "It is hurt.\r";
982 root 1.15 break;
983     case 3:
984 root 1.77 buf << "It is somewhat hurt.\r";
985 root 1.15 break;
986     case 4:
987 root 1.77 buf << "It is in excellent shape.\r";
988 root 1.15 break;
989 elmex 1.1 }
990 root 1.42
991     if (present_in_ob (POISONING, mon))
992 root 1.77 buf << "It looks very ill.\r";
993    
994     buf << '\n';
995 root 1.42
996     return buf;
997 elmex 1.1 }
998    
999     /* tmp is the object being described, pl is who is examing it. */
1000 root 1.41 const char *
1001 root 1.14 long_desc (object *tmp, object *pl)
1002     {
1003 root 1.46 static std::string s;
1004    
1005     return (s = tmp->long_desc (pl)).c_str ();
1006 root 1.42 }
1007 elmex 1.1
1008 root 1.42 std::string
1009     object::long_desc (object *who)
1010     {
1011 root 1.88 std::string buf (query_name ());
1012 elmex 1.1
1013 root 1.42 switch (type)
1014 root 1.14 {
1015 root 1.15 case RING:
1016     case SKILL:
1017     case WEAPON:
1018     case ARMOUR:
1019     case BRACERS:
1020     case HELMET:
1021     case SHIELD:
1022     case BOOTS:
1023     case GLOVES:
1024     case AMULET:
1025     case GIRDLE:
1026 root 1.123 case RANGED:
1027 root 1.15 case BOW:
1028     case ARROW:
1029     case CLOAK:
1030     case FOOD:
1031     case DRINK:
1032     case FLESH:
1033     case SKILL_TOOL:
1034 elmex 1.89 case LAMP:
1035 root 1.15 case POWER_CRYSTAL:
1036 root 1.42 {
1037     const char *cp = ::describe_item (this, who);
1038 root 1.14
1039 root 1.42 if (*cp)
1040     {
1041     buf.append (" ");
1042     buf.append (cp);
1043     }
1044     }
1045 elmex 1.1 }
1046 root 1.15
1047 root 1.14 return buf;
1048 elmex 1.1 }
1049    
1050 root 1.42 /* op is the player
1051     * tmp is the monster being examined.
1052     */
1053 root 1.14 void
1054 root 1.42 examine_monster (object *op, object *tmp)
1055 root 1.14 {
1056 root 1.42 new_draw_info (NDI_UNIQUE, 0, op, tmp->describe_monster (op).c_str ());
1057     }
1058 root 1.14
1059 root 1.95 static void
1060 root 1.14 display_new_pickup (object *op)
1061     {
1062     int i = op->contr->mode;
1063 elmex 1.1
1064 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d DEBUG", i & PU_DEBUG ? 1 : 0);
1065     new_draw_info_format (NDI_UNIQUE, 0, op, "%d INHIBIT", i & PU_INHIBIT ? 1 : 0);
1066     new_draw_info_format (NDI_UNIQUE, 0, op, "%d STOP", i & PU_STOP ? 1 : 0);
1067 elmex 1.1
1068 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d <= x pickup weight/value RATIO (0==off)", (i & PU_RATIO) * 5);
1069 elmex 1.1
1070 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FOOD", i & PU_FOOD ? 1 : 0);
1071     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DRINK", i & PU_DRINK ? 1 : 0);
1072     new_draw_info_format (NDI_UNIQUE, 0, op, "%d VALUABLES", i & PU_VALUABLES ? 1 : 0);
1073 elmex 1.1
1074 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOW", i & PU_BOW ? 1 : 0);
1075     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARROW", i & PU_ARROW ? 1 : 0);
1076 elmex 1.1
1077 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d HELMET", i & PU_HELMET ? 1 : 0);
1078     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SHIELD", i & PU_SHIELD ? 1 : 0);
1079     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARMOUR", i & PU_ARMOUR ? 1 : 0);
1080 elmex 1.1
1081 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOOTS", i & PU_BOOTS ? 1 : 0);
1082     new_draw_info_format (NDI_UNIQUE, 0, op, "%d GLOVES", i & PU_GLOVES ? 1 : 0);
1083     new_draw_info_format (NDI_UNIQUE, 0, op, "%d CLOAK", i & PU_CLOAK ? 1 : 0);
1084     new_draw_info_format (NDI_UNIQUE, 0, op, "%d KEY", i & PU_KEY ? 1 : 0);
1085 elmex 1.1
1086 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d MISSILEWEAPON", i & PU_MISSILEWEAPON ? 1 : 0);
1087     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ALLWEAPON", i & PU_ALLWEAPON ? 1 : 0);
1088     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICAL", i & PU_MAGICAL ? 1 : 0);
1089     new_draw_info_format (NDI_UNIQUE, 0, op, "%d POTION", i & PU_POTION ? 1 : 0);
1090 elmex 1.1
1091 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d SPELLBOOK", i & PU_SPELLBOOK ? 1 : 0);
1092     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SKILLSCROLL", i & PU_SKILLSCROLL ? 1 : 0);
1093     new_draw_info_format (NDI_UNIQUE, 0, op, "%d READABLES", i & PU_READABLES ? 1 : 0);
1094     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICDEVICE", i & PU_MAGIC_DEVICE ? 1 : 0);
1095 elmex 1.1
1096 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NOT CURSED", i & PU_NOT_CURSED ? 1 : 0);
1097 elmex 1.1
1098 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d JEWELS", i & PU_JEWELS ? 1 : 0);
1099 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FLESH", i & PU_FLESH ? 1 : 0);
1100 elmex 1.1
1101 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "");
1102     }
1103 elmex 1.1
1104 root 1.14 int
1105     command_pickup (object *op, char *params)
1106 elmex 1.1 {
1107     uint32 i;
1108 root 1.14 static const char *names[] = {
1109     "debug", "inhibit", "stop", "food", "drink", "valuables", "bow", "arrow", "helmet",
1110     "shield", "armour", "boots", "gloves", "cloak", "key", "missile", "allweapon",
1111 root 1.22 "magical", "potion", "spellbook", "skillscroll", "readables", "magicdevice", "notcursed",
1112     "jewels", "flesh", NULL
1113 root 1.14 };
1114     static uint32 modes[] = {
1115     PU_DEBUG, PU_INHIBIT, PU_STOP, PU_FOOD, PU_DRINK, PU_VALUABLES, PU_BOW, PU_ARROW, PU_HELMET,
1116     PU_SHIELD, PU_ARMOUR, PU_BOOTS, PU_GLOVES, PU_CLOAK, PU_KEY, PU_MISSILEWEAPON, PU_ALLWEAPON,
1117 root 1.22 PU_MAGICAL, PU_POTION, PU_SPELLBOOK, PU_SKILLSCROLL, PU_READABLES, PU_MAGIC_DEVICE, PU_NOT_CURSED,
1118     PU_JEWELS, PU_FLESH, 0
1119 root 1.14 };
1120    
1121     if (!params)
1122     {
1123     /* if the new mode is used, just print the settings */
1124 root 1.85 display_new_pickup (op);
1125 root 1.14 return 0;
1126     }
1127 elmex 1.1
1128 root 1.14 while (*params == ' ' && *params)
1129     params++;
1130 elmex 1.1
1131 root 1.14 if (*params == '+' || *params == '-')
1132     {
1133 elmex 1.1 int mode;
1134 root 1.14
1135     for (mode = 0; names[mode]; mode++)
1136     {
1137     if (!strcmp (names[mode], params + 1))
1138     {
1139 elmex 1.1 i = op->contr->mode;
1140 root 1.85
1141 root 1.14 if (*params == '+')
1142     i = i | modes[mode];
1143 elmex 1.1 else
1144 root 1.14 i = i & ~modes[mode];
1145 root 1.85
1146 elmex 1.1 op->contr->mode = i;
1147 root 1.14 display_new_pickup (op);
1148 elmex 1.1 return 1;
1149 root 1.14 }
1150     }
1151     new_draw_info_format (NDI_UNIQUE, 0, op, "Pickup: invalid item %s\n", params);
1152 elmex 1.1 return 1;
1153 root 1.14 }
1154 elmex 1.1
1155 root 1.14 if (sscanf (params, "%u", &i) != 1)
1156     {
1157 root 1.86 new_draw_info (NDI_UNIQUE, 0, op, "Usage: pickup <value_density> or [+-]type.");
1158 root 1.14 return 1;
1159     }
1160 root 1.85
1161 root 1.86 if (i <= PU_RATIO)
1162     i |= op->contr->mode & ~PU_RATIO;
1163    
1164 root 1.85 op->contr->mode = i;
1165 elmex 1.1
1166     return 1;
1167     }
1168    
1169 root 1.14 int
1170     command_search_items (object *op, char *params)
1171 elmex 1.1 {
1172 root 1.14 if (params == NULL)
1173     {
1174     if (op->contr->search_str[0] == '\0')
1175     {
1176 root 1.85 new_draw_info (NDI_UNIQUE, 0, op, "Example: search-items magic+1");
1177 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1178     new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1179 root 1.10 return 1;
1180     }
1181 root 1.42
1182 root 1.14 op->contr->search_str[0] = '\0';
1183     new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1184 root 1.106 op->contr->queue_stats_update ();
1185 elmex 1.1 return 1;
1186 root 1.14 }
1187 root 1.42
1188 root 1.106 if (strlen (params) >= sizeof (op->contr->search_str))
1189 root 1.14 {
1190     new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1191     return 1;
1192     }
1193 root 1.42
1194 root 1.14 strcpy (op->contr->search_str, params);
1195 root 1.106 new_draw_info (NDI_UNIQUE, 0, op, format ("Now searching for '%s'.", op->contr->search_str));
1196     op->contr->queue_stats_update ();
1197 root 1.85
1198 root 1.14 return 1;
1199 elmex 1.1 }
1200    
1201 elmex 1.107 int
1202     command_unlock (object *op, char *params)
1203     {
1204     /* if the unlock command typed with nothing, unlock everything,
1205     * this might be bad
1206     */
1207     if (params == NULL)
1208     {
1209     for (object *item = op->inv; item; item = item->below)
1210     {
1211 root 1.120 item->clr_flag (FLAG_INV_LOCKED);
1212 elmex 1.107 //d// new_draw_info (NDI_UNIQUE, 0, op, "unlocked items with null param.");
1213     esrv_update_item (UPD_FLAGS, op, item);
1214     }
1215     return 0;
1216     }
1217    
1218     /* if the unlock command is used with a param,
1219     * unlock what matches. i.e. unlock material, should unlock all the materials
1220     */
1221     for (object *item = op->inv; item; item = item->below)
1222     if (item->name.contains (params))
1223     {
1224 root 1.120 item->clr_flag (FLAG_INV_LOCKED);
1225 elmex 1.107 //d// new_draw_info (NDI_UNIQUE, 0, op, "unlocked items with a param.");
1226     esrv_update_item (UPD_FLAGS, op, item);
1227     }
1228    
1229     return 0;
1230     }
1231    
1232     int
1233     command_lock (object *op, char *params)
1234     {
1235     /* if the lock command is typed by itself, lock everything
1236     */
1237     if (params == NULL)
1238     {
1239     for (object *item = op->inv; item; item = item->below)
1240     {
1241 root 1.120 item->set_flag (FLAG_INV_LOCKED);
1242 elmex 1.107 //d// new_draw_info (NDI_UNIQUE, 0, op, "locked items with null param.");
1243     esrv_update_item (UPD_FLAGS, op, item);
1244     }
1245     return 0;
1246     }
1247    
1248     /* if the lock command is used with a param, lock what matches.
1249     * i.e. lock material, should lock all the materials
1250     */
1251     for (object *item = op->inv; item; item = item->below)
1252     if (item->name.contains (params))
1253     {
1254 root 1.120 item->set_flag (FLAG_INV_LOCKED);
1255 elmex 1.107 //d// new_draw_info (NDI_UNIQUE, 0, op, "locked items with param.");
1256     esrv_update_item (UPD_FLAGS, op, item);
1257     }
1258    
1259     return 0;
1260     }
1261 root 1.116
1262     /* op should be a player, params is any params.
1263     * If no params given, we print out the currently marked object.
1264     * otherwise, try to find a matching object - try best match first.
1265     */
1266     int
1267     command_mark (object *op, char *params)
1268     {
1269     if (!params)
1270     {
1271 root 1.121 if (object *mark = op->mark ())
1272 root 1.116 op->statusmsg (format ("%s is marked.", query_name (mark)));
1273     else
1274     op->failmsg ("You have no marked object.");
1275     }
1276     else
1277     {
1278     if (object *mark = find_best_object_match (op, params))
1279     {
1280     op->contr->mark = mark;
1281     op->statusmsg (format ("Marked item %s", query_name (mark)));
1282     }
1283     else
1284 root 1.119 op->failmsgf ("Could not find an object that matches %s", params);
1285 root 1.116 }
1286    
1287     return 0; /*shouldnt get here */
1288     }
1289