ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.36
Committed: Tue Jan 9 21:32:42 2007 UTC (17 years, 4 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.35: +1 -1 lines
Log Message:
- added $cf::WAIT_FOR_TICK*
- tuned map-scheduler and player-scheduler
- added $op->inv_recursive
- added objects_size/objects($index) and actives_size/actives($index)
  for access to the object and actives vector.
- more robust player loader
- removed _perl_data attribute support
- SIGINT/TERM/HUP are now safe as they are handled synchronously.
- replaced LOOK_OBJ by client_visible
- cleanups

File Contents

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