ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.135
Committed: Sun Nov 18 00:37:11 2018 UTC (5 years, 6 months ago) by root
Content type: text/plain
Branch: MAIN
CVS Tags: HEAD
Changes since 1.134: +2 -2 lines
Log Message:
some range based for loops

File Contents

# User Rev Content
1 elmex 1.1 /*
2 root 1.60 * This file is part of Deliantra, the Roguelike Realtime MMORPG.
3 root 1.129 *
4 root 1.134 * Copyright (©) 2017,2018 Marc Alexander Lehmann / the Deliantra team
5 root 1.132 * Copyright (©) 2005,2006,2007,2008,2009,2010,2011,2012,2013,2014,2015,2016 Marc Alexander Lehmann / Robin Redeker / the Deliantra team
6 root 1.110 * Copyright (©) 2002 Mark Wedel & Crossfire Development Team
7     * Copyright (©) 1992 Frank Tore Johansen
8 root 1.129 *
9 root 1.97 * Deliantra is free software: you can redistribute it and/or modify it under
10     * the terms of the Affero GNU General Public License as published by the
11     * Free Software Foundation, either version 3 of the License, or (at your
12     * option) any later version.
13 root 1.129 *
14 root 1.57 * This program is distributed in the hope that it will be useful,
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17     * GNU General Public License for more details.
18 root 1.129 *
19 root 1.97 * You should have received a copy of the Affero GNU General Public License
20     * and the GNU General Public License along with this program. If not, see
21     * <http://www.gnu.org/licenses/>.
22 root 1.129 *
23 root 1.60 * The authors can be reached via e-mail to <support@deliantra.net>
24 pippijn 1.37 */
25 elmex 1.1
26 pippijn 1.37 /*
27     * Object (handling) commands
28     */
29 elmex 1.1
30     #include <global.h>
31     #include <skills.h>
32 root 1.32 #include <sproto.h>
33 elmex 1.1 #include <living.h>
34 root 1.14
35 elmex 1.1 /*
36     * Object id parsing functions
37     */
38    
39     #define ADD_ITEM(NEW,COUNT)\
40 root 1.10 if(!first) {\
41 root 1.21 first = new objectlink;\
42 root 1.10 last=first;\
43     } else {\
44 root 1.21 last->next = new objectlink;\
45 root 1.10 last=last->next;\
46     }\
47 root 1.21 last->next=0;\
48 root 1.10 last->ob=(NEW);\
49 elmex 1.1 last->id=(COUNT);
50    
51     /**
52     * Search the inventory of 'pl' for what matches best with params.
53     * we use item_matched_string above - this gives us consistent behaviour
54     * between many commands. Return the best match, or NULL if no match.
55     * aflag is used with apply -u , and apply -a to
56     * only unapply applied, or apply unapplied objects
57     **/
58 root 1.14 static object *
59     find_best_apply_object_match (object *pl, const char *params, enum apply_flag aflag)
60 elmex 1.1 {
61 root 1.52 object *best = 0;
62     int match_val = 0;
63 elmex 1.1
64 root 1.52 for (object *tmp = pl->inv; tmp; tmp = tmp->below)
65 root 1.14 {
66     if (tmp->invisible)
67     continue;
68 root 1.52
69     int tmpmatch = item_matched_string (pl, tmp, params);
70    
71     if (tmpmatch > match_val)
72 root 1.14 {
73 root 1.120 if ((aflag == AP_APPLY) && (tmp->flag [FLAG_APPLIED]))
74 root 1.14 continue;
75 root 1.52
76 root 1.120 if ((aflag == AP_UNAPPLY) && (!tmp->flag [FLAG_APPLIED]))
77 root 1.14 continue;
78 root 1.52
79 root 1.14 match_val = tmpmatch;
80     best = tmp;
81 elmex 1.1 }
82     }
83 root 1.52
84 root 1.14 return best;
85 elmex 1.1 }
86    
87     /**
88     * Shortcut to find_best_apply_object_match(pl, params, AF_NULL);
89     **/
90 root 1.14 object *
91     find_best_object_match (object *pl, const char *params)
92 elmex 1.1 {
93 root 1.54 return find_best_apply_object_match (pl, params, AP_TOGGLE);
94 elmex 1.1 }
95    
96 root 1.66 static bool
97     can_split (object *pl, object *&op, sint32 nrof)
98     {
99 root 1.69 if (object *tmp = op->split (nrof ? nrof : op->number_of ()))
100 root 1.66 {
101     op = tmp;
102     return true;
103     }
104     else
105     {
106 root 1.67 if (op->nrof > 1)
107     new_draw_info_format (NDI_UNIQUE, 0, pl, "There are only %d %s.", op->nrof, &op->name_pl);
108     else
109     new_draw_info_format (NDI_UNIQUE, 0, pl, "There is only one %s.", &op->name);
110    
111 root 1.66 return false;
112     }
113     }
114    
115 root 1.14 int
116     command_uskill (object *pl, char *params)
117     {
118     if (!params)
119     {
120     new_draw_info (NDI_UNIQUE, 0, pl, "Usage: use_skill <skill name>");
121     return 0;
122     }
123 root 1.47
124 root 1.14 return use_skill (pl, params);
125 elmex 1.1 }
126    
127 root 1.14 int
128     command_rskill (object *pl, char *params)
129     {
130     object *skill;
131 elmex 1.1
132 root 1.14 if (!params)
133     {
134     new_draw_info (NDI_UNIQUE, 0, pl, "Usage: ready_skill <skill name>");
135     return 0;
136 elmex 1.1 }
137 root 1.47
138 root 1.87 skill = find_skill_by_name_fuzzy (pl, params);
139 elmex 1.1
140 root 1.14 if (!skill)
141     {
142 root 1.114 new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no knowledge of the %s skill.", params);
143 root 1.14 return 0;
144 elmex 1.1 }
145 root 1.47
146 root 1.112 pl->apply (skill);
147 root 1.54 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.122 if (object *skop = find_skill_by_name (op, shstr_throwing))
157 root 1.14 return do_skill (op, op, skop, op->facing, params);
158     else
159 root 1.114 new_draw_info (NDI_UNIQUE, 0, op, "You have no knowledge of the throwing skill.");
160 root 1.51
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 root 1.117 op->apply (inv, aflag);
196 root 1.14 else
197 root 1.119 op->failmsgf ("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 root 1.120 if (!sack->flag [FLAG_APPLIED])
216 root 1.14 {
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.130 if (sack->weight_limit
240     && weight_t (sack->carrying
241     + sack->number_of ()
242     * (op->weight + (op->type == CONTAINER ? (op->carrying * op->stats.Str) : 0))
243     * (100 - sack->stats.Str) / 100)
244     > sack->weight_limit)
245 root 1.14 {
246     new_draw_info_format (NDI_UNIQUE, 0, pl, "That won't fit in the %s!", query_name (sack));
247     return 0;
248 elmex 1.1 }
249 root 1.66
250 root 1.14 /* All other checks pass, must be OK */
251     return 1;
252 elmex 1.1 }
253    
254     /* Pick up commands follow */
255 root 1.14
256 elmex 1.1 /* pl = player (not always - monsters can use this now)
257 root 1.130 * op is the object to put tmp into,
258 elmex 1.1 * tmp is the object to pick up, nrof is the number to
259     * pick up (0 means all of them)
260     */
261 root 1.14 static void
262     pick_up_object (object *pl, object *op, object *tmp, int nrof)
263 elmex 1.1 {
264 root 1.130 weight_t weight, effective_weight_limit;
265 root 1.66 int tmp_nrof = tmp->number_of ();
266 root 1.14
267 root 1.130 /* IF the player is flying & trying to take the item out of a container
268     * that is in his inventory, let him. tmp->env points to the container
269     * (sack, luggage, etc), tmp->env->env then points to the player (nested
270 root 1.14 * containers not allowed as of now)
271     */
272 root 1.120 if ((pl->move_type & MOVE_FLYING) && !pl->flag [FLAG_WIZ] && tmp->in_player () != pl)
273 root 1.14 {
274 root 1.72 pl->failmsg ("You are levitating, you can't reach the ground! "
275     "H<You have to stop levitating first, if you can, either by using your levitation skill, "
276     "or waiting till the levitation effect wears off.>");
277 root 1.14 return;
278     }
279 root 1.18
280 root 1.120 if (tmp->flag [FLAG_NO_DROP])
281 root 1.14 return;
282 root 1.18
283 root 1.67 if (nrof > tmp_nrof || nrof <= 0)
284 root 1.14 nrof = tmp_nrof;
285 root 1.18
286 root 1.14 /* Figure out how much weight this object will add to the player */
287     weight = tmp->weight * nrof;
288     if (tmp->inv)
289     weight += tmp->carrying * (100 - tmp->stats.Str) / 100;
290 root 1.18
291 root 1.64 effective_weight_limit = weight_limit [min (MAX_STAT, pl->stats.Str)];
292 root 1.18
293 root 1.14 if ((pl->weight + pl->carrying + weight) > effective_weight_limit)
294     {
295     new_draw_info (0, 0, pl, "That item is too heavy for you to pick up.");
296     return;
297 elmex 1.1 }
298 root 1.18
299 root 1.66 if (!can_split (pl, tmp, nrof))
300     return;
301 root 1.39
302 root 1.120 if (tmp->flag [FLAG_UNPAID])
303 root 1.69 {
304     tmp->flag.reset (FLAG_UNPAID);
305     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));
306     tmp->flag.set (FLAG_UNPAID);
307     }
308 root 1.14 else
309 root 1.64 new_draw_info_format (NDI_UNIQUE, 0, pl, "You pick up the %s.", query_name (tmp));
310 root 1.14
311 root 1.69 op->insert (tmp);
312 elmex 1.1 }
313    
314 root 1.18 /* modified slightly to allow monsters use this -b.t. 5-31-95 */
315 root 1.14 void
316     pick_up (object *op, object *alt)
317 elmex 1.1 {
318 root 1.14 int need_fix_tmp = 0;
319     object *tmp = NULL;
320 root 1.19 maptile *tmp_map = NULL;
321 root 1.14 int count;
322    
323     /* Decide which object to pick. */
324     if (alt)
325     {
326     if (!can_pick (op, alt))
327     {
328     new_draw_info_format (NDI_UNIQUE, 0, op, "You can't pick up the %s.", &alt->name);
329     goto leave;
330     }
331 root 1.64
332 root 1.14 tmp = alt;
333     }
334     else
335     {
336     if (op->below == NULL || !can_pick (op, op->below))
337     {
338     new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up here.");
339     goto leave;
340 elmex 1.1 }
341 root 1.18
342 root 1.14 tmp = op->below;
343     }
344    
345     /* Try to catch it. */
346     tmp_map = tmp->map;
347     tmp = stop_item (tmp);
348     if (tmp == NULL)
349     goto leave;
350 root 1.64
351 root 1.14 need_fix_tmp = 1;
352     if (!can_pick (op, tmp))
353     goto leave;
354    
355     if (op->type == PLAYER)
356     {
357     count = op->contr->count;
358     if (count == 0)
359     count = tmp->nrof;
360 elmex 1.1 }
361 root 1.14 else
362     count = tmp->nrof;
363 elmex 1.1
364 root 1.14 /* container is open, so use it */
365 root 1.64 if (tmp->flag [FLAG_STARTEQUIP])
366     alt = op;
367 root 1.100 else if ((alt = op->container_ ()))
368 root 1.14 {
369     if (alt != tmp->env && !sack_can_hold (op, alt, tmp, count))
370 elmex 1.1 goto leave;
371 root 1.14 }
372     else
373     { /* non container pickup */
374     for (alt = op->inv; alt; alt = alt->below)
375 root 1.120 if (alt->type == CONTAINER && alt->flag [FLAG_APPLIED] &&
376 root 1.14 alt->race && alt->race == tmp->race && sack_can_hold (NULL, alt, tmp, count))
377     break; /* perfect match */
378    
379     if (!alt)
380     for (alt = op->inv; alt; alt = alt->below)
381 root 1.120 if (alt->type == CONTAINER && alt->flag [FLAG_APPLIED] && sack_can_hold (NULL, alt, tmp, count))
382 root 1.14 break; /* General container comes next */
383 root 1.39
384 root 1.14 if (!alt)
385     alt = op; /* No free containers */
386     }
387 root 1.21
388 root 1.14 if (tmp->env == alt)
389     {
390     /* here it could be possible to check rent,
391     * if someone wants to implement it
392     */
393     alt = op;
394 elmex 1.1 }
395 root 1.64
396 elmex 1.1 #ifdef PICKUP_DEBUG
397 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);
398 elmex 1.1 #endif
399    
400 root 1.14 /* startequip items are not allowed to be put into containers: */
401 root 1.120 if (op->type == PLAYER && alt->type == CONTAINER && tmp->flag [FLAG_STARTEQUIP])
402 elmex 1.1 {
403 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This object cannot be put into containers!");
404     goto leave;
405 elmex 1.1 }
406    
407 root 1.14 pick_up_object (op, alt, tmp, count);
408 root 1.18
409     if (tmp->destroyed () || tmp->env)
410 root 1.14 need_fix_tmp = 0;
411 root 1.18
412 root 1.14 if (op->type == PLAYER)
413     op->contr->count = 0;
414 root 1.18
415 root 1.14 goto leave;
416 elmex 1.1
417 root 1.14 leave:
418     if (need_fix_tmp)
419     fix_stopped_item (tmp, tmp_map, op);
420 elmex 1.1 }
421    
422     /* This takes (picks up) and item. op is the player
423     * who issued the command. params is a string to
424     * match against the item name. Basically, always
425     * returns zero, but that should be improved.
426     */
427 root 1.14 int
428     command_take (object *op, char *params)
429 elmex 1.1 {
430 root 1.14 object *tmp, *next;
431 elmex 1.1
432 root 1.100 if (op->container_ ())
433     tmp = op->container_ ()->inv;
434 root 1.14 else
435     {
436     tmp = op->above;
437     if (tmp)
438     while (tmp->above)
439 root 1.21 tmp = tmp->above;
440    
441 root 1.14 if (!tmp)
442     tmp = op->below;
443 elmex 1.1 }
444    
445 root 1.39 if (!tmp)
446 root 1.14 {
447     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to take!");
448     return 0;
449 elmex 1.1 }
450    
451 root 1.14 /* Makes processing easier */
452     if (params && *params == '\0')
453 root 1.39 params = 0;
454 elmex 1.1
455 root 1.103 int cnt = MAX_ITEM_PER_ACTION;
456 elmex 1.62
457 root 1.14 while (tmp)
458     {
459     next = tmp->below;
460 elmex 1.1
461 root 1.14 if (tmp->invisible)
462     {
463     tmp = next;
464     continue;
465     }
466 root 1.35
467 root 1.14 /* This following two if and else if could be merged into line
468     * but that probably will make it more difficult to read, and
469     * not make it any more efficient
470     */
471     if (params && item_matched_string (op, tmp, params))
472 elmex 1.62 {
473 root 1.74 if (--cnt < 0) break;
474 elmex 1.62 pick_up (op, tmp);
475     }
476 root 1.14 else if (can_pick (op, tmp) && !params)
477     {
478 root 1.74 if (--cnt < 0) break;
479 root 1.14 pick_up (op, tmp);
480     break;
481 root 1.10 }
482 root 1.35
483 root 1.14 tmp = next;
484     }
485 root 1.35
486 root 1.73 if (cnt < 0)
487 elmex 1.62 {
488     op->failmsg ("Couldn't pick up so many items at once.");
489     return 0;
490     }
491    
492 root 1.14 if (!params && !tmp)
493     {
494 root 1.35 for (tmp = op->below; tmp; tmp = tmp->below)
495 root 1.14 if (!tmp->invisible)
496     {
497 root 1.64 new_draw_info_format (NDI_UNIQUE, 0, op, "You can't pick up a %s.", &tmp->name);
498 root 1.10 break;
499 root 1.14 }
500 root 1.35
501 root 1.14 if (!tmp)
502     new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up.");
503 elmex 1.1 }
504 root 1.35
505 root 1.14 return 0;
506 elmex 1.1 }
507    
508     /*
509 root 1.133 * This function was part of drop, now is own function.
510     * Player 'op' tries to put object 'tmp' into sack 'sack',
511     * if nrof is non zero, then nrof objects is tried to put into sack.
512 root 1.83 *
513 elmex 1.1 * Note that the 'sack' in question can now be a transport,
514     * so this function isn't named very good anymore.
515     */
516 root 1.14 void
517     put_object_in_sack (object *op, object *sack, object *tmp, uint32 nrof)
518 elmex 1.1 {
519 root 1.128 object *tmp2;
520 root 1.14 char buf[MAX_BUF];
521    
522     if (sack == tmp)
523     return; /* Can't put an object in itself */
524 root 1.18
525 root 1.120 if (tmp->flag [FLAG_STARTEQUIP] || tmp->flag [FLAG_NO_DROP])
526 root 1.14 {
527     new_draw_info_format (NDI_UNIQUE, 0, op, "You cannot put the %s in the %s.", query_name (tmp), query_name (sack));
528     return;
529 elmex 1.1 }
530 root 1.18
531 root 1.14 if (tmp->type == CONTAINER && tmp->inv)
532     {
533     /* Eneq(@csd.uu.se): If the object to be dropped is a container
534     * we instead move the contents of that container into the active
535     * container, this is only done if the object has something in it.
536     */
537     new_draw_info_format (NDI_UNIQUE, 0, op, "You move the items from %s into %s.", query_name (tmp), query_name (sack));
538 root 1.18
539 root 1.14 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp)
540     {
541     tmp = tmp2->below;
542 root 1.18
543 root 1.100 if ((sack->type == CONTAINER && sack_can_hold (op, op->container_ (), tmp2, tmp2->nrof)))
544 root 1.69 put_object_in_sack (op, sack, tmp2, 0);
545 root 1.14 else
546     {
547     sprintf (buf, "Your %s fills up.", query_name (sack));
548     new_draw_info (NDI_UNIQUE, 0, op, buf);
549     break;
550 root 1.10 }
551     }
552 root 1.18
553 root 1.14 return;
554     }
555    
556     /* Don't worry about this for containers - our caller should have
557     * already checked this.
558     */
559     if ((sack->type == CONTAINER) && !sack_can_hold (op, sack, tmp, (nrof ? nrof : tmp->nrof)))
560     return;
561    
562 root 1.120 if (tmp->flag [FLAG_APPLIED])
563 root 1.118 if (!op->apply (tmp, AP_UNAPPLY | AP_NO_MERGE))
564 root 1.18 return;
565 elmex 1.1
566 root 1.14 /* we want to put some portion of the item into the container */
567 root 1.69 if (!can_split (op, tmp, nrof))
568     return;
569 root 1.14
570     new_draw_info_format (NDI_UNIQUE, 0, op, "You put the %s in %s.", query_name (tmp), query_name (sack));
571 root 1.69 sack->insert (tmp);
572 elmex 1.1 }
573    
574 elmex 1.81 /* In contrast to drop_object (op, tmp, nrof) above this function takes the
575     * already split off object, and feeds it to the event handlers and does
576     * other magic with it.
577     *
578     * <droppper> is the object that dropped this object and <obj> is the
579     * object that was dropped.
580     *
581     * Make sure to check what happened with <obj> after this function returns!
582     * Otherwise you may leak this object.
583     */
584     void
585     drop_object (object *dropper, object *obj)
586     {
587     if (INVOKE_OBJECT (DROP, obj, ARG_OBJECT (dropper)))
588 elmex 1.2 return;
589 elmex 1.81
590 elmex 1.82 if (obj->destroyed () || obj->is_inserted ())
591     return;
592 elmex 1.1
593 root 1.120 if (obj->flag [FLAG_STARTEQUIP])
594 elmex 1.2 {
595 elmex 1.81 dropper->statusmsg (format ("You drop the %s.", query_name (obj)));
596     dropper->statusmsg ("The god who lent it to you retrieves it.");
597 root 1.28
598 elmex 1.81 obj->destroy ();
599     dropper->update_stats ();
600 elmex 1.1 return;
601     }
602    
603 elmex 1.81 for (object *floor = GET_MAP_OB (dropper->map, dropper->x, dropper->y);
604     floor;
605     floor = floor->above)
606     if (INVOKE_OBJECT (DROP_ON, floor, ARG_OBJECT (obj), ARG_OBJECT (dropper)))
607 elmex 1.5 return;
608 elmex 1.1
609 elmex 1.82 if (obj->destroyed () || obj->is_inserted ())
610     return;
611 elmex 1.1
612 root 1.120 if (dropper->is_in_shop () && !obj->flag [FLAG_UNPAID] && obj->type != MONEY)
613 elmex 1.81 if (!sell_item (obj, dropper))
614 root 1.131 return;
615 elmex 1.1
616 root 1.103 if (!obj->can_drop_at (dropper->map, dropper->x, dropper->y, dropper))
617     return;
618    
619 elmex 1.81 /* If nothing special happened with this object, the default action is to
620     * insert it below the dropper:
621     */
622    
623     obj->x = dropper->x;
624     obj->y = dropper->y;
625    
626     insert_ob_in_map (obj, dropper->map, dropper, INS_BELOW_ORIGINATOR);
627 elmex 1.1 }
628    
629 root 1.103 /*
630     * This function was part of drop, now is own function.
631     * Player 'op' tries to drop object 'tmp', if tmp is non zero, then
632     * nrof objects are tried to drop.
633     * This is used when dropping objects onto the floor.
634     */
635     void
636     drop_object (object *op, object *tmp, uint32 nrof)
637     {
638 root 1.120 if (tmp->flag [FLAG_NO_DROP])
639 root 1.103 return;
640    
641 root 1.120 if (tmp->flag [FLAG_APPLIED])
642 root 1.118 if (!op->apply (tmp, AP_UNAPPLY | AP_NO_MERGE))
643 root 1.103 return; /* can't unapply it */
644    
645     /* We are only dropping some of the items. We split the current object
646     * off
647     */
648     if (!can_split (op, tmp, nrof))
649     return;
650    
651     drop_object (op, tmp);
652    
653     if (!tmp->destroyed () && !tmp->is_inserted ())
654     {
655     // if nothing happened with the object we give it back
656     op->insert (tmp);
657     }
658     }
659    
660 root 1.69 void
661 root 1.14 drop (object *op, object *tmp)
662 elmex 1.1 {
663 root 1.14 /* Hopeful fix for disappearing objects when dropping from a container -
664     * somehow, players get an invisible object in the container, and the
665     * old logic would skip over invisible objects - works fine for the
666     * playes inventory, but drop inventory wants to use the next value.
667     */
668     if (tmp->invisible)
669     {
670     /* if the following is the case, it must be in an container. */
671     if (tmp->env && tmp->env->type != PLAYER)
672     {
673     /* Just toss the object - probably shouldn't be hanging
674     * around anyways
675     */
676 root 1.79 tmp->destroy ();
677 root 1.14 return;
678     }
679     else
680 root 1.103 while (tmp && tmp->invisible)
681     tmp = tmp->below;
682 elmex 1.1 }
683    
684 root 1.103 if (!tmp)
685 root 1.14 {
686     new_draw_info (NDI_UNIQUE, 0, op, "You don't have anything to drop.");
687 elmex 1.1 return;
688     }
689 root 1.70
690 root 1.120 if (tmp->flag [FLAG_INV_LOCKED])
691 root 1.14 {
692     new_draw_info (NDI_UNIQUE, 0, op, "This item is locked");
693 elmex 1.1 return;
694     }
695 root 1.70
696 root 1.120 if (tmp->flag [FLAG_NO_DROP])
697 root 1.14 {
698 elmex 1.1 #if 0
699     /* Eneq(@csd.uu.se): Objects with NO_DROP defined can't be dropped. */
700 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This item can't be dropped.");
701 elmex 1.1 #endif
702     return;
703     }
704    
705 root 1.26 if (op->type == PLAYER && op->contr->last_used == tmp)
706     op->contr->last_used = tmp->below ? tmp->below
707     : tmp->above ? tmp->above
708 root 1.91 : (object *)0;
709 elmex 1.1
710 root 1.100 if (op->container_ ())
711 root 1.14 {
712     if (op->type == PLAYER)
713 root 1.100 put_object_in_sack (op, op->container_ (), tmp, op->contr->count);
714 root 1.14 else
715 root 1.100 put_object_in_sack (op, op->container_ (), tmp, 0);
716 root 1.14 }
717     else
718     {
719     if (op->type == PLAYER)
720 root 1.26 drop_object (op, tmp, op->contr->count);
721 root 1.14 else
722 root 1.26 drop_object (op, tmp, 0);
723 elmex 1.1 }
724 root 1.26
725 root 1.14 if (op->type == PLAYER)
726     op->contr->count = 0;
727 elmex 1.1 }
728    
729     /* Command will drop all items that have not been locked */
730 root 1.14 int
731     command_dropall (object *op, char *params)
732     {
733    
734     if (op->inv == NULL)
735     {
736     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop!");
737     return 0;
738     }
739 elmex 1.1
740 root 1.70 object *curinv = op->inv;
741     object *nextinv;
742 elmex 1.1
743 root 1.133 /*
744 root 1.14 This is the default. Drops everything not locked or considered
745     not something that should be dropped.
746     */
747 elmex 1.1 /*
748 root 1.14 Care must be taken that the next item pointer is not to money as
749     the drop() routine will do unknown things to it when dropping
750     in a shop. --Tero.Pelander@utu.fi
751     */
752 root 1.103 int cnt = MAX_ITEM_PER_ACTION;
753 elmex 1.61
754 root 1.70 if (!params)
755 root 1.14 {
756 root 1.70 while (curinv)
757 root 1.14 {
758     nextinv = curinv->below;
759 root 1.70
760 root 1.14 while (nextinv && nextinv->type == MONEY)
761     nextinv = nextinv->below;
762 root 1.70
763 root 1.120 if (!curinv->flag [FLAG_INV_LOCKED]
764 root 1.125 && !curinv->invisible
765 root 1.103 && curinv->type != MONEY
766     && curinv->type != FOOD
767     && curinv->type != KEY
768     && curinv->type != SPECIAL_KEY
769     && curinv->type != GEM
770 root 1.125 && curinv->type != CONTAINER)
771 root 1.14 {
772     drop (op, curinv);
773 elmex 1.61 if (--cnt <= 0) break;
774 root 1.14 }
775 root 1.70
776 root 1.14 curinv = nextinv;
777     }
778     }
779     else if (strcmp (params, "weapons") == 0)
780     {
781 root 1.70 while (curinv)
782 root 1.14 {
783     nextinv = curinv->below;
784 root 1.70
785 root 1.14 while (nextinv && nextinv->type == MONEY)
786     nextinv = nextinv->below;
787 root 1.70
788 root 1.120 if (!curinv->flag [FLAG_INV_LOCKED] && ((curinv->type == WEAPON) || (curinv->type == BOW) || (curinv->type == ARROW)))
789 root 1.14 {
790     drop (op, curinv);
791 elmex 1.61 if (--cnt <= 0) break;
792 root 1.14 }
793 root 1.70
794 root 1.14 curinv = nextinv;
795     }
796     }
797     else if (strcmp (params, "armor") == 0 || strcmp (params, "armour") == 0)
798     {
799 root 1.70 while (curinv)
800 root 1.14 {
801     nextinv = curinv->below;
802 root 1.70
803 root 1.14 while (nextinv && nextinv->type == MONEY)
804     nextinv = nextinv->below;
805 root 1.70
806 root 1.120 if (!curinv->flag [FLAG_INV_LOCKED] && ((curinv->type == ARMOUR) || curinv->type == SHIELD || curinv->type == HELMET))
807 root 1.14 {
808     drop (op, curinv);
809 elmex 1.61 if (--cnt <= 0) break;
810 root 1.14 }
811 root 1.70
812 root 1.10 curinv = nextinv;
813 root 1.14 }
814     }
815     else if (strcmp (params, "misc") == 0)
816     {
817 root 1.70 while (curinv)
818 root 1.14 {
819     nextinv = curinv->below;
820 root 1.70
821 root 1.14 while (nextinv && nextinv->type == MONEY)
822     nextinv = nextinv->below;
823 root 1.70
824 root 1.120 if (!curinv->flag [FLAG_INV_LOCKED] && !curinv->flag [FLAG_APPLIED])
825 root 1.14 {
826     switch (curinv->type)
827     {
828 root 1.15 case HORN:
829     case BOOK:
830     case SPELLBOOK:
831     case GIRDLE:
832     case AMULET:
833     case RING:
834     case CLOAK:
835     case BOOTS:
836     case GLOVES:
837     case BRACERS:
838     case SCROLL:
839     case ARMOUR_IMPROVER:
840     case WEAPON_IMPROVER:
841     case WAND:
842     case ROD:
843     case POTION:
844     drop (op, curinv);
845     curinv = nextinv;
846     break;
847     default:
848     curinv = nextinv;
849     break;
850 root 1.14 }
851 root 1.70
852 elmex 1.61 if (--cnt <= 0) break;
853 root 1.14 }
854 root 1.70
855 root 1.10 curinv = nextinv;
856     }
857 elmex 1.1 }
858 root 1.28
859 elmex 1.61 if (cnt <= 0)
860 elmex 1.62 op->failmsg ("Only dropped some items, can't drop that many items at once.");
861 elmex 1.61
862 elmex 1.1 /* draw_look(op);*/
863     return 0;
864     }
865    
866 elmex 1.81
867     /* This function tries to drop all objects in the <objs> vector.
868     * <dropper> is the object that wants to drop them.
869     * <cnt> can be a 0 pointer or a pointer to the maximum number of
870     * drop operations to perform.
871     *
872     * Returns true if at least one item was dropped.
873     */
874 root 1.101 static bool
875 elmex 1.81 drop_vector (object *dropper, vector<object *> &objs, int *cnt)
876     {
877     vector<object *>::iterator i;
878    
879     bool did_one = false;
880    
881 root 1.135 for (auto &&op : objs)
882 elmex 1.81 {
883 root 1.135 drop (dropper, op);
884 elmex 1.81 if (cnt && --*cnt <= 0) break;
885     did_one = true;
886     }
887    
888     return did_one;
889     }
890    
891 elmex 1.1 /* Object op wants to drop object(s) params. params can be a
892     * comma seperated list.
893     */
894 root 1.14 int
895     command_drop (object *op, char *params)
896 elmex 1.1 {
897 root 1.14 object *tmp, *next;
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 root 1.120 if (tmp->flag [FLAG_NO_DROP] || tmp->invisible)
912 root 1.14 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 root 1.42 std::string
957     object::describe_monster (object *who)
958 root 1.14 {
959 root 1.42 dynbuf_text buf (512, 512);
960    
961     object *mon = head ? head : this;
962 root 1.14
963 root 1.120 if (mon->flag [FLAG_UNDEAD])
964 root 1.77 buf << "It is an undead force.\r";
965 root 1.42
966     if (mon->level > who->level)
967 root 1.77 buf << "It is likely more powerful than you.\r";
968 root 1.42 else if (mon->level < who->level)
969 root 1.77 buf << "It is likely less powerful than you.\r";
970 root 1.14 else
971 root 1.77 buf << "It is probably as powerful as you.\r";
972 root 1.42
973 root 1.14 if (mon->attacktype & AT_ACID)
974 root 1.77 buf << "You seem to smell an acrid odor.\r";
975 elmex 1.1
976 root 1.14 /* Anyone know why this used to use the clone value instead of the
977     * maxhp field? This seems that it should give more accurate results.
978     */
979     switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
980     { /* From 1-4 */
981 root 1.15 case 1:
982 root 1.77 buf << "It is in a bad shape.\r";
983 root 1.15 break;
984     case 2:
985 root 1.77 buf << "It is hurt.\r";
986 root 1.15 break;
987     case 3:
988 root 1.77 buf << "It is somewhat hurt.\r";
989 root 1.15 break;
990     case 4:
991 root 1.77 buf << "It is in excellent shape.\r";
992 root 1.15 break;
993 elmex 1.1 }
994 root 1.42
995     if (present_in_ob (POISONING, mon))
996 root 1.77 buf << "It looks very ill.\r";
997    
998     buf << '\n';
999 root 1.42
1000     return buf;
1001 elmex 1.1 }
1002    
1003     /* tmp is the object being described, pl is who is examing it. */
1004 root 1.41 const char *
1005 root 1.14 long_desc (object *tmp, object *pl)
1006     {
1007 root 1.46 static std::string s;
1008    
1009     return (s = tmp->long_desc (pl)).c_str ();
1010 root 1.42 }
1011 elmex 1.1
1012 root 1.42 std::string
1013     object::long_desc (object *who)
1014     {
1015 root 1.88 std::string buf (query_name ());
1016 elmex 1.1
1017 root 1.42 switch (type)
1018 root 1.14 {
1019 root 1.15 case RING:
1020     case SKILL:
1021     case WEAPON:
1022     case ARMOUR:
1023     case BRACERS:
1024     case HELMET:
1025     case SHIELD:
1026     case BOOTS:
1027     case GLOVES:
1028     case AMULET:
1029     case GIRDLE:
1030 root 1.123 case RANGED:
1031 root 1.15 case BOW:
1032     case ARROW:
1033     case CLOAK:
1034     case FOOD:
1035     case DRINK:
1036     case FLESH:
1037     case SKILL_TOOL:
1038 elmex 1.89 case LAMP:
1039 root 1.15 case POWER_CRYSTAL:
1040 root 1.42 {
1041     const char *cp = ::describe_item (this, who);
1042 root 1.14
1043 root 1.42 if (*cp)
1044     {
1045     buf.append (" ");
1046     buf.append (cp);
1047     }
1048     }
1049 elmex 1.1 }
1050 root 1.15
1051 root 1.14 return buf;
1052 elmex 1.1 }
1053    
1054 root 1.42 /* op is the player
1055     * tmp is the monster being examined.
1056     */
1057 root 1.14 void
1058 root 1.42 examine_monster (object *op, object *tmp)
1059 root 1.14 {
1060 root 1.42 new_draw_info (NDI_UNIQUE, 0, op, tmp->describe_monster (op).c_str ());
1061     }
1062 root 1.14
1063 root 1.95 static void
1064 root 1.14 display_new_pickup (object *op)
1065     {
1066     int i = op->contr->mode;
1067 elmex 1.1
1068 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d DEBUG", i & PU_DEBUG ? 1 : 0);
1069     new_draw_info_format (NDI_UNIQUE, 0, op, "%d INHIBIT", i & PU_INHIBIT ? 1 : 0);
1070     new_draw_info_format (NDI_UNIQUE, 0, op, "%d STOP", i & PU_STOP ? 1 : 0);
1071 elmex 1.1
1072 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d <= x pickup weight/value RATIO (0==off)", (i & PU_RATIO) * 5);
1073 elmex 1.1
1074 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FOOD", i & PU_FOOD ? 1 : 0);
1075     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DRINK", i & PU_DRINK ? 1 : 0);
1076     new_draw_info_format (NDI_UNIQUE, 0, op, "%d VALUABLES", i & PU_VALUABLES ? 1 : 0);
1077 elmex 1.1
1078 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOW", i & PU_BOW ? 1 : 0);
1079     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARROW", i & PU_ARROW ? 1 : 0);
1080 elmex 1.1
1081 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d HELMET", i & PU_HELMET ? 1 : 0);
1082     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SHIELD", i & PU_SHIELD ? 1 : 0);
1083     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARMOUR", i & PU_ARMOUR ? 1 : 0);
1084 elmex 1.1
1085 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOOTS", i & PU_BOOTS ? 1 : 0);
1086     new_draw_info_format (NDI_UNIQUE, 0, op, "%d GLOVES", i & PU_GLOVES ? 1 : 0);
1087     new_draw_info_format (NDI_UNIQUE, 0, op, "%d CLOAK", i & PU_CLOAK ? 1 : 0);
1088     new_draw_info_format (NDI_UNIQUE, 0, op, "%d KEY", i & PU_KEY ? 1 : 0);
1089 elmex 1.1
1090 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d MISSILEWEAPON", i & PU_MISSILEWEAPON ? 1 : 0);
1091     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ALLWEAPON", i & PU_ALLWEAPON ? 1 : 0);
1092     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICAL", i & PU_MAGICAL ? 1 : 0);
1093     new_draw_info_format (NDI_UNIQUE, 0, op, "%d POTION", i & PU_POTION ? 1 : 0);
1094 elmex 1.1
1095 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d SPELLBOOK", i & PU_SPELLBOOK ? 1 : 0);
1096     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SKILLSCROLL", i & PU_SKILLSCROLL ? 1 : 0);
1097     new_draw_info_format (NDI_UNIQUE, 0, op, "%d READABLES", i & PU_READABLES ? 1 : 0);
1098     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICDEVICE", i & PU_MAGIC_DEVICE ? 1 : 0);
1099 elmex 1.1
1100 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NOT CURSED", i & PU_NOT_CURSED ? 1 : 0);
1101 elmex 1.1
1102 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d JEWELS", i & PU_JEWELS ? 1 : 0);
1103 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FLESH", i & PU_FLESH ? 1 : 0);
1104 elmex 1.1
1105 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "");
1106     }
1107 elmex 1.1
1108 root 1.14 int
1109     command_pickup (object *op, char *params)
1110 elmex 1.1 {
1111     uint32 i;
1112 root 1.14 static const char *names[] = {
1113     "debug", "inhibit", "stop", "food", "drink", "valuables", "bow", "arrow", "helmet",
1114     "shield", "armour", "boots", "gloves", "cloak", "key", "missile", "allweapon",
1115 root 1.22 "magical", "potion", "spellbook", "skillscroll", "readables", "magicdevice", "notcursed",
1116     "jewels", "flesh", NULL
1117 root 1.14 };
1118     static uint32 modes[] = {
1119     PU_DEBUG, PU_INHIBIT, PU_STOP, PU_FOOD, PU_DRINK, PU_VALUABLES, PU_BOW, PU_ARROW, PU_HELMET,
1120     PU_SHIELD, PU_ARMOUR, PU_BOOTS, PU_GLOVES, PU_CLOAK, PU_KEY, PU_MISSILEWEAPON, PU_ALLWEAPON,
1121 root 1.22 PU_MAGICAL, PU_POTION, PU_SPELLBOOK, PU_SKILLSCROLL, PU_READABLES, PU_MAGIC_DEVICE, PU_NOT_CURSED,
1122     PU_JEWELS, PU_FLESH, 0
1123 root 1.14 };
1124    
1125     if (!params)
1126     {
1127     /* if the new mode is used, just print the settings */
1128 root 1.85 display_new_pickup (op);
1129 root 1.14 return 0;
1130     }
1131 elmex 1.1
1132 root 1.14 while (*params == ' ' && *params)
1133     params++;
1134 elmex 1.1
1135 root 1.14 if (*params == '+' || *params == '-')
1136     {
1137 elmex 1.1 int mode;
1138 root 1.14
1139     for (mode = 0; names[mode]; mode++)
1140     {
1141     if (!strcmp (names[mode], params + 1))
1142     {
1143 elmex 1.1 i = op->contr->mode;
1144 root 1.85
1145 root 1.14 if (*params == '+')
1146     i = i | modes[mode];
1147 elmex 1.1 else
1148 root 1.14 i = i & ~modes[mode];
1149 root 1.85
1150 elmex 1.1 op->contr->mode = i;
1151 root 1.14 display_new_pickup (op);
1152 elmex 1.1 return 1;
1153 root 1.14 }
1154     }
1155     new_draw_info_format (NDI_UNIQUE, 0, op, "Pickup: invalid item %s\n", params);
1156 elmex 1.1 return 1;
1157 root 1.14 }
1158 elmex 1.1
1159 root 1.14 if (sscanf (params, "%u", &i) != 1)
1160     {
1161 root 1.86 new_draw_info (NDI_UNIQUE, 0, op, "Usage: pickup <value_density> or [+-]type.");
1162 root 1.14 return 1;
1163     }
1164 root 1.85
1165 root 1.86 if (i <= PU_RATIO)
1166     i |= op->contr->mode & ~PU_RATIO;
1167    
1168 root 1.85 op->contr->mode = i;
1169 elmex 1.1
1170     return 1;
1171     }
1172    
1173 root 1.14 int
1174     command_search_items (object *op, char *params)
1175 elmex 1.1 {
1176 root 1.14 if (params == NULL)
1177     {
1178     if (op->contr->search_str[0] == '\0')
1179     {
1180 root 1.85 new_draw_info (NDI_UNIQUE, 0, op, "Example: search-items magic+1");
1181 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1182     new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1183 root 1.10 return 1;
1184     }
1185 root 1.42
1186 root 1.14 op->contr->search_str[0] = '\0';
1187     new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1188 root 1.106 op->contr->queue_stats_update ();
1189 elmex 1.1 return 1;
1190 root 1.14 }
1191 root 1.42
1192 root 1.106 if (strlen (params) >= sizeof (op->contr->search_str))
1193 root 1.14 {
1194     new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1195     return 1;
1196     }
1197 root 1.42
1198 root 1.14 strcpy (op->contr->search_str, params);
1199 root 1.106 new_draw_info (NDI_UNIQUE, 0, op, format ("Now searching for '%s'.", op->contr->search_str));
1200     op->contr->queue_stats_update ();
1201 root 1.85
1202 root 1.14 return 1;
1203 elmex 1.1 }
1204    
1205 elmex 1.107 int
1206     command_unlock (object *op, char *params)
1207     {
1208     /* if the unlock command typed with nothing, unlock everything,
1209     * this might be bad
1210     */
1211     if (params == NULL)
1212     {
1213     for (object *item = op->inv; item; item = item->below)
1214     {
1215 root 1.120 item->clr_flag (FLAG_INV_LOCKED);
1216 elmex 1.107 //d// new_draw_info (NDI_UNIQUE, 0, op, "unlocked items with null param.");
1217     esrv_update_item (UPD_FLAGS, op, item);
1218     }
1219     return 0;
1220     }
1221    
1222     /* if the unlock command is used with a param,
1223     * unlock what matches. i.e. unlock material, should unlock all the materials
1224     */
1225     for (object *item = op->inv; item; item = item->below)
1226     if (item->name.contains (params))
1227     {
1228 root 1.120 item->clr_flag (FLAG_INV_LOCKED);
1229 elmex 1.107 //d// new_draw_info (NDI_UNIQUE, 0, op, "unlocked items with a param.");
1230     esrv_update_item (UPD_FLAGS, op, item);
1231     }
1232    
1233     return 0;
1234     }
1235    
1236     int
1237     command_lock (object *op, char *params)
1238     {
1239     /* if the lock command is typed by itself, lock everything
1240     */
1241     if (params == NULL)
1242     {
1243     for (object *item = op->inv; item; item = item->below)
1244     {
1245 root 1.120 item->set_flag (FLAG_INV_LOCKED);
1246 elmex 1.107 //d// new_draw_info (NDI_UNIQUE, 0, op, "locked items with null param.");
1247     esrv_update_item (UPD_FLAGS, op, item);
1248     }
1249     return 0;
1250     }
1251    
1252     /* if the lock command is used with a param, lock what matches.
1253     * i.e. lock material, should lock all the materials
1254     */
1255     for (object *item = op->inv; item; item = item->below)
1256     if (item->name.contains (params))
1257     {
1258 root 1.120 item->set_flag (FLAG_INV_LOCKED);
1259 elmex 1.107 //d// new_draw_info (NDI_UNIQUE, 0, op, "locked items with param.");
1260     esrv_update_item (UPD_FLAGS, op, item);
1261     }
1262    
1263     return 0;
1264     }
1265 root 1.116
1266     /* op should be a player, params is any params.
1267     * If no params given, we print out the currently marked object.
1268     * otherwise, try to find a matching object - try best match first.
1269     */
1270     int
1271     command_mark (object *op, char *params)
1272     {
1273     if (!params)
1274     {
1275 root 1.121 if (object *mark = op->mark ())
1276 root 1.116 op->statusmsg (format ("%s is marked.", query_name (mark)));
1277     else
1278     op->failmsg ("You have no marked object.");
1279     }
1280     else
1281     {
1282     if (object *mark = find_best_object_match (op, params))
1283     {
1284     op->contr->mark = mark;
1285     op->statusmsg (format ("Marked item %s", query_name (mark)));
1286     }
1287     else
1288 root 1.119 op->failmsgf ("Could not find an object that matches %s", params);
1289 root 1.116 }
1290    
1291     return 0; /*shouldnt get here */
1292     }
1293