ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.34
Committed: Sat Jan 6 14:42:30 2007 UTC (17 years, 5 months ago) by pippijn
Content type: text/plain
Branch: MAIN
Changes since 1.33: +1 -0 lines
Log Message:
added some copyrights

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     /* This following two if and else if could be merged into line
515     * but that probably will make it more difficult to read, and
516     * not make it any more efficient
517     */
518     if (params && item_matched_string (op, tmp, params))
519     {
520     pick_up (op, tmp);
521 root 1.10 }
522 root 1.14 else if (can_pick (op, tmp) && !params)
523     {
524     pick_up (op, tmp);
525     break;
526 root 1.10 }
527 root 1.14 tmp = next;
528     /* Might as well just skip over the player immediately -
529     * we know it can't be picked up
530     */
531     if (tmp == op)
532     tmp = tmp->below;
533     }
534     if (!params && !tmp)
535     {
536     for (tmp = op->below; tmp != NULL; tmp = tmp->next)
537     if (!tmp->invisible)
538     {
539     char buf[MAX_BUF];
540    
541     sprintf (buf, "You can't pick up a %s.", &tmp->name);
542     new_draw_info (NDI_UNIQUE, 0, op, buf);
543 root 1.10 break;
544 root 1.14 }
545     if (!tmp)
546     new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up.");
547 elmex 1.1 }
548 root 1.14 return 0;
549 elmex 1.1 }
550    
551    
552     /*
553     * This function was part of drop, now is own function.
554     * Player 'op' tries to put object 'tmp' into sack 'sack',
555     * if nrof is non zero, then nrof objects is tried to put into sack.
556     * Note that the 'sack' in question can now be a transport,
557     * so this function isn't named very good anymore.
558     */
559 root 1.14 void
560     put_object_in_sack (object *op, object *sack, object *tmp, uint32 nrof)
561 elmex 1.1 {
562 root 1.14 object *tmp2, *sack2;
563     char buf[MAX_BUF];
564    
565     if (sack == tmp)
566     return; /* Can't put an object in itself */
567 root 1.18
568 root 1.14 if (QUERY_FLAG (tmp, FLAG_STARTEQUIP))
569     {
570     new_draw_info_format (NDI_UNIQUE, 0, op, "You cannot put the %s in the %s.", query_name (tmp), query_name (sack));
571     return;
572 elmex 1.1 }
573 root 1.18
574 root 1.14 if (tmp->type == CONTAINER && tmp->inv)
575     {
576 elmex 1.1
577 root 1.14 /* Eneq(@csd.uu.se): If the object to be dropped is a container
578     * we instead move the contents of that container into the active
579     * container, this is only done if the object has something in it.
580     */
581     sack2 = tmp;
582     new_draw_info_format (NDI_UNIQUE, 0, op, "You move the items from %s into %s.", query_name (tmp), query_name (sack));
583 root 1.18
584 root 1.14 for (tmp2 = tmp->inv; tmp2; tmp2 = tmp)
585     {
586     tmp = tmp2->below;
587 root 1.18
588 root 1.14 if ((sack->type == CONTAINER && sack_can_hold (op, op->container, tmp2, tmp2->nrof)))
589     {
590     put_object_in_sack (op, sack, tmp2, 0);
591     }
592     else
593     {
594     sprintf (buf, "Your %s fills up.", query_name (sack));
595     new_draw_info (NDI_UNIQUE, 0, op, buf);
596     break;
597 root 1.10 }
598     }
599 root 1.18
600 root 1.14 esrv_update_item (UPD_WEIGHT, op, sack2);
601     return;
602     }
603    
604     /* Don't worry about this for containers - our caller should have
605     * already checked this.
606     */
607     if ((sack->type == CONTAINER) && !sack_can_hold (op, sack, tmp, (nrof ? nrof : tmp->nrof)))
608     return;
609    
610     if (QUERY_FLAG (tmp, FLAG_APPLIED))
611 root 1.18 if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
612     return;
613 elmex 1.1
614 root 1.14 /* we want to put some portion of the item into the container */
615     if (nrof && tmp->nrof != nrof)
616     {
617     object *tmp2 = tmp;
618    
619     tmp = get_split_ob (tmp, nrof);
620    
621     if (!tmp)
622     {
623     new_draw_info (NDI_UNIQUE, 0, op, errmsg);
624     return;
625     }
626     /* Tell a client what happened other objects */
627 root 1.18 if (tmp2->destroyed ())
628     esrv_del_item (op->contr, tmp2->count);
629 root 1.14 else /* this can proably be replaced with an update */
630     esrv_send_item (op, tmp2);
631     }
632     else
633 root 1.24 tmp->remove ();
634 root 1.14
635     new_draw_info_format (NDI_UNIQUE, 0, op, "You put the %s in %s.", query_name (tmp), query_name (sack));
636     tmp2 = insert_ob_in_ob (tmp, sack);
637 root 1.31 op->update_stats (); /* This is overkill, fix_player() is called somewhere */
638 root 1.14 /* in object.c */
639 elmex 1.1
640 root 1.14 /* If an object merged (and thus, different object), we need to
641     * delete the original.
642     */
643     if (tmp2 != tmp)
644 root 1.18 esrv_del_item (op->contr, tmp->count);
645 elmex 1.1
646 root 1.14 esrv_send_item (op, tmp2);
647 elmex 1.1
648 root 1.14 /* update the sacks weight */
649     esrv_update_item (UPD_WEIGHT, op, sack);
650 elmex 1.1 }
651    
652     /*
653     * This function was part of drop, now is own function.
654     * Player 'op' tries to drop object 'tmp', if tmp is non zero, then
655     * nrof objects is tried to dropped.
656     * This is used when dropping objects onto the floor.
657     */
658 elmex 1.2 void
659 root 1.14 drop_object (object *op, object *tmp, uint32 nrof)
660 elmex 1.1 {
661 elmex 1.2 char buf[MAX_BUF];
662     object *floor;
663 elmex 1.1
664 elmex 1.2 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
665     return;
666 elmex 1.1
667 elmex 1.2 if (QUERY_FLAG (tmp, FLAG_APPLIED))
668     if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
669 root 1.14 return; /* can't unapply it */
670 elmex 1.2
671 root 1.23 /* We are only dropping some of the items. We split the current object
672 elmex 1.2 * off
673     */
674     if (nrof && tmp->nrof != nrof)
675     {
676     object *tmp2 = tmp;
677 root 1.14
678 elmex 1.2 tmp = get_split_ob (tmp, nrof);
679     if (!tmp)
680     {
681     new_draw_info (NDI_UNIQUE, 0, op, errmsg);
682     return;
683     }
684     /* Tell a client what happened rest of objects. tmp2 is now the
685     * original object
686     */
687     if (op->type == PLAYER)
688     {
689 root 1.18 if (tmp2->destroyed ())
690     esrv_del_item (op->contr, tmp2->count);
691 elmex 1.2 else
692     esrv_send_item (op, tmp2);
693     }
694 elmex 1.1 }
695 elmex 1.2 else
696 root 1.24 tmp->remove ();
697 elmex 1.1
698 root 1.7 if (INVOKE_OBJECT (DROP, tmp, ARG_OBJECT (op)))
699 elmex 1.2 return;
700 elmex 1.1
701 elmex 1.2 if (QUERY_FLAG (tmp, FLAG_STARTEQUIP))
702     {
703     sprintf (buf, "You drop the %s.", query_name (tmp));
704     new_draw_info (NDI_UNIQUE, 0, op, buf);
705 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "The gods who lent it to you retrieves it.");
706 root 1.28
707 elmex 1.2 if (op->type == PLAYER)
708     esrv_del_item (op->contr, tmp->count);
709 root 1.28
710 root 1.25 tmp->destroy ();
711 root 1.31 op->update_stats ();
712 elmex 1.1 return;
713     }
714    
715 elmex 1.2 if (op->type == PLAYER)
716     esrv_del_item (op->contr, tmp->count);
717 elmex 1.1
718 elmex 1.2 /* Call this before we update the various windows/players. At least
719     * that we, we know the weight is correct.
720     */
721 root 1.31 op->update_stats (); /* This is overkill, fix_player() is called somewhere */
722 root 1.14 /* in object.c */
723 elmex 1.1
724 elmex 1.2 if (op->type == PLAYER)
725     {
726     /* Need to update the weight for the player */
727     esrv_send_item (op, op);
728 root 1.30 op->contr->ns->floorbox_update ();
729 elmex 1.2 }
730 elmex 1.1
731 root 1.29 for (floor = GET_MAP_OB (op->map, op->x, op->y); floor; floor = floor->above)
732 root 1.7 if (INVOKE_OBJECT (DROP_ON, floor, ARG_OBJECT (tmp), ARG_OBJECT (op)))
733 elmex 1.5 return;
734 elmex 1.1
735 root 1.14 if (is_in_shop (op) && !QUERY_FLAG (tmp, FLAG_UNPAID) && tmp->type != MONEY)
736 elmex 1.2 sell_item (tmp, op);
737 elmex 1.1
738 elmex 1.2 tmp->x = op->x;
739     tmp->y = op->y;
740 elmex 1.1
741 elmex 1.2 insert_ob_in_map (tmp, op->map, op, INS_BELOW_ORIGINATOR);
742 elmex 1.1 }
743    
744 root 1.14 void
745     drop (object *op, object *tmp)
746 elmex 1.1 {
747 root 1.14 /* Hopeful fix for disappearing objects when dropping from a container -
748     * somehow, players get an invisible object in the container, and the
749     * old logic would skip over invisible objects - works fine for the
750     * playes inventory, but drop inventory wants to use the next value.
751     */
752     if (tmp->invisible)
753     {
754     /* if the following is the case, it must be in an container. */
755     if (tmp->env && tmp->env->type != PLAYER)
756     {
757     /* Just toss the object - probably shouldn't be hanging
758     * around anyways
759     */
760 root 1.24 tmp->remove ();
761 root 1.25 tmp->destroy ();
762 root 1.14 return;
763     }
764     else
765     {
766     while (tmp != NULL && tmp->invisible)
767     tmp = tmp->below;
768 root 1.10 }
769 elmex 1.1 }
770    
771 root 1.14 if (tmp == NULL)
772     {
773     new_draw_info (NDI_UNIQUE, 0, op, "You don't have anything to drop.");
774 elmex 1.1 return;
775     }
776 root 1.14 if (QUERY_FLAG (tmp, FLAG_INV_LOCKED))
777     {
778     new_draw_info (NDI_UNIQUE, 0, op, "This item is locked");
779 elmex 1.1 return;
780     }
781 root 1.14 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
782     {
783 elmex 1.1 #if 0
784     /* Eneq(@csd.uu.se): Objects with NO_DROP defined can't be dropped. */
785 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, "This item can't be dropped.");
786 elmex 1.1 #endif
787     return;
788     }
789    
790 root 1.26 if (op->type == PLAYER && op->contr->last_used == tmp)
791     op->contr->last_used = tmp->below ? tmp->below
792     : tmp->above ? tmp->above
793     : 0;
794 elmex 1.1
795 root 1.14 if (op->container)
796     {
797     if (op->type == PLAYER)
798 root 1.26 put_object_in_sack (op, op->container, tmp, op->contr->count);
799 root 1.14 else
800 root 1.26 put_object_in_sack (op, op->container, tmp, 0);
801 root 1.14 }
802     else
803     {
804     if (op->type == PLAYER)
805 root 1.26 drop_object (op, tmp, op->contr->count);
806 root 1.14 else
807 root 1.26 drop_object (op, tmp, 0);
808 elmex 1.1 }
809 root 1.26
810 root 1.14 if (op->type == PLAYER)
811     op->contr->count = 0;
812 elmex 1.1 }
813    
814    
815    
816     /* Command will drop all items that have not been locked */
817 root 1.14 int
818     command_dropall (object *op, char *params)
819     {
820    
821     object *curinv, *nextinv;
822 elmex 1.1
823 root 1.14 if (op->inv == NULL)
824     {
825     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop!");
826     return 0;
827     }
828 elmex 1.1
829     curinv = op->inv;
830    
831     /*
832 root 1.14 This is the default. Drops everything not locked or considered
833     not something that should be dropped.
834     */
835 elmex 1.1 /*
836 root 1.14 Care must be taken that the next item pointer is not to money as
837     the drop() routine will do unknown things to it when dropping
838     in a shop. --Tero.Pelander@utu.fi
839     */
840    
841     if (params == NULL)
842     {
843     while (curinv != NULL)
844     {
845     nextinv = curinv->below;
846     while (nextinv && nextinv->type == MONEY)
847     nextinv = nextinv->below;
848     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && curinv->type != MONEY &&
849     curinv->type != FOOD && curinv->type != KEY &&
850     curinv->type != SPECIAL_KEY && curinv->type != GEM &&
851     !curinv->invisible && (curinv->type != CONTAINER || op->container != curinv))
852     {
853     drop (op, curinv);
854     }
855     curinv = nextinv;
856     }
857     }
858    
859     else if (strcmp (params, "weapons") == 0)
860     {
861     while (curinv != NULL)
862     {
863     nextinv = curinv->below;
864     while (nextinv && nextinv->type == MONEY)
865     nextinv = nextinv->below;
866     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && ((curinv->type == WEAPON) || (curinv->type == BOW) || (curinv->type == ARROW)))
867     {
868     drop (op, curinv);
869     }
870     curinv = nextinv;
871     }
872     }
873    
874     else if (strcmp (params, "armor") == 0 || strcmp (params, "armour") == 0)
875     {
876     while (curinv != NULL)
877     {
878     nextinv = curinv->below;
879     while (nextinv && nextinv->type == MONEY)
880     nextinv = nextinv->below;
881     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && ((curinv->type == ARMOUR) || curinv->type == SHIELD || curinv->type == HELMET))
882     {
883     drop (op, curinv);
884     }
885 root 1.10 curinv = nextinv;
886 root 1.14 }
887     }
888    
889     else if (strcmp (params, "misc") == 0)
890     {
891     while (curinv != NULL)
892     {
893     nextinv = curinv->below;
894     while (nextinv && nextinv->type == MONEY)
895     nextinv = nextinv->below;
896     if (!QUERY_FLAG (curinv, FLAG_INV_LOCKED) && !QUERY_FLAG (curinv, FLAG_APPLIED))
897     {
898     switch (curinv->type)
899     {
900 root 1.15 case HORN:
901     case BOOK:
902     case SPELLBOOK:
903     case GIRDLE:
904     case AMULET:
905     case RING:
906     case CLOAK:
907     case BOOTS:
908     case GLOVES:
909     case BRACERS:
910     case SCROLL:
911     case ARMOUR_IMPROVER:
912     case WEAPON_IMPROVER:
913     case WAND:
914     case ROD:
915     case POTION:
916     drop (op, curinv);
917     curinv = nextinv;
918     break;
919     default:
920     curinv = nextinv;
921     break;
922 root 1.14 }
923     }
924 root 1.10 curinv = nextinv;
925     }
926 elmex 1.1 }
927 root 1.28
928 root 1.30 op->contr->ns->floorbox_update ();
929 root 1.14
930 elmex 1.1 /* draw_look(op);*/
931     return 0;
932     }
933    
934     /* Object op wants to drop object(s) params. params can be a
935     * comma seperated list.
936     */
937    
938 root 1.14 int
939     command_drop (object *op, char *params)
940 elmex 1.1 {
941 root 1.14 object *tmp, *next;
942     int did_one = 0;
943 elmex 1.1
944 root 1.14 if (!params)
945     {
946     new_draw_info (NDI_UNIQUE, 0, op, "Drop what?");
947     return 0;
948     }
949     else
950     {
951     for (tmp = op->inv; tmp; tmp = next)
952     {
953     next = tmp->below;
954     if (QUERY_FLAG (tmp, FLAG_NO_DROP) || tmp->invisible)
955     continue;
956     if (item_matched_string (op, tmp, params))
957     {
958     drop (op, tmp);
959     did_one = 1;
960 root 1.10 }
961     }
962 root 1.14 if (!did_one)
963     new_draw_info (NDI_UNIQUE, 0, op, "Nothing to drop.");
964 elmex 1.1 }
965 root 1.14 if (op->type == PLAYER)
966 elmex 1.1 {
967 root 1.14 op->contr->count = 0;
968 root 1.30 op->contr->ns->floorbox_update ();
969 elmex 1.1 };
970 root 1.14
971 elmex 1.1 /* draw_look(op);*/
972 root 1.14 return 0;
973 elmex 1.1 }
974    
975 root 1.14 int
976     command_examine (object *op, char *params)
977 elmex 1.1 {
978 root 1.14 if (!params)
979     {
980     object *tmp = op->below;
981    
982     while (tmp && !LOOK_OBJ (tmp))
983     tmp = tmp->below;
984     if (tmp)
985     examine (op, tmp);
986     }
987     else
988     {
989     object *tmp = find_best_object_match (op, params);
990    
991     if (tmp)
992     examine (op, tmp);
993     else
994     new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find an object that matches %s", params);
995     }
996 elmex 1.1 return 0;
997     }
998    
999     /* op should be a player.
1000     * we return the object the player has marked with the 'mark' command
1001     * below. If no match is found (or object has changed), we return
1002     * NULL. We leave it up to the calling function to print messages if
1003     * nothing is found.
1004     */
1005 root 1.14 object *
1006     find_marked_object (object *op)
1007 elmex 1.1 {
1008 root 1.14 object *tmp;
1009    
1010     if (!op || !op->contr)
1011     return NULL;
1012 root 1.20
1013 root 1.14 if (!op->contr->mark)
1014     {
1015 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
1016 root 1.20 return 0;
1017 elmex 1.1 }
1018 root 1.20
1019 root 1.14 /* This may seem like overkill, but we need to make sure that they
1020     * player hasn't dropped the item. We use count on the off chance that
1021     * an item got reincarnated at some point.
1022     */
1023     for (tmp = op->inv; tmp; tmp = tmp->below)
1024     {
1025     if (tmp->invisible)
1026     continue;
1027 root 1.20
1028 root 1.14 if (tmp == op->contr->mark)
1029     {
1030 root 1.20 if (!tmp->destroyed ())
1031 root 1.14 return tmp;
1032     else
1033     {
1034 root 1.20 op->contr->mark = 0;
1035 elmex 1.1 /* new_draw_info(NDI_UNIQUE,0,op,"You have no marked object");*/
1036 root 1.20 return 0;
1037 root 1.10 }
1038     }
1039 elmex 1.1 }
1040 root 1.20
1041     return 0;
1042 elmex 1.1 }
1043 root 1.14
1044 elmex 1.1
1045     /* op should be a player, params is any params.
1046     * If no params given, we print out the currently marked object.
1047     * otherwise, try to find a matching object - try best match first.
1048     */
1049 root 1.14 int
1050     command_mark (object *op, char *params)
1051 elmex 1.1 {
1052 root 1.14 if (!op->contr)
1053     return 1;
1054 root 1.20
1055 root 1.14 if (!params)
1056     {
1057     object *mark = find_marked_object (op);
1058    
1059     if (!mark)
1060     new_draw_info (NDI_UNIQUE, 0, op, "You have no marked object.");
1061     else
1062     new_draw_info_format (NDI_UNIQUE, 0, op, "%s is marked.", query_name (mark));
1063     }
1064     else
1065     {
1066     object *mark1 = find_best_object_match (op, params);
1067    
1068     if (!mark1)
1069     {
1070     new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find an object that matches %s", params);
1071     return 1;
1072     }
1073     else
1074     {
1075     op->contr->mark = mark1;
1076     new_draw_info_format (NDI_UNIQUE, 0, op, "Marked item %s", query_name (mark1));
1077     return 0;
1078 root 1.10 }
1079 elmex 1.1 }
1080 root 1.20
1081 root 1.14 return 0; /*shouldnt get here */
1082 elmex 1.1 }
1083    
1084    
1085     /* op is the player
1086     * tmp is the monster being examined.
1087     */
1088 root 1.14 void
1089     examine_monster (object *op, object *tmp)
1090     {
1091     object *mon = tmp->head ? tmp->head : tmp;
1092    
1093     if (QUERY_FLAG (mon, FLAG_UNDEAD))
1094     new_draw_info (NDI_UNIQUE, 0, op, "It is an undead force.");
1095     if (mon->level > op->level)
1096     new_draw_info (NDI_UNIQUE, 0, op, "It is likely more powerful than you.");
1097     else if (mon->level < op->level)
1098     new_draw_info (NDI_UNIQUE, 0, op, "It is likely less powerful than you.");
1099     else
1100     new_draw_info (NDI_UNIQUE, 0, op, "It is probably as powerful as you.");
1101     if (mon->attacktype & AT_ACID)
1102     new_draw_info (NDI_UNIQUE, 0, op, "You seem to smell an acrid odor.");
1103 elmex 1.1
1104 root 1.14 /* Anyone know why this used to use the clone value instead of the
1105     * maxhp field? This seems that it should give more accurate results.
1106     */
1107     switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
1108     { /* From 1-4 */
1109 root 1.15 case 1:
1110     new_draw_info (NDI_UNIQUE, 0, op, "It is in a bad shape.");
1111     break;
1112     case 2:
1113     new_draw_info (NDI_UNIQUE, 0, op, "It is hurt.");
1114     break;
1115     case 3:
1116     new_draw_info (NDI_UNIQUE, 0, op, "It is somewhat hurt.");
1117     break;
1118     case 4:
1119     new_draw_info (NDI_UNIQUE, 0, op, "It is in excellent shape.");
1120     break;
1121 elmex 1.1 }
1122 root 1.14 if (present_in_ob (POISONING, mon) != NULL)
1123     new_draw_info (NDI_UNIQUE, 0, op, "It looks very ill.");
1124 elmex 1.1 }
1125    
1126    
1127     /* tmp is the object being described, pl is who is examing it. */
1128 root 1.14 char *
1129     long_desc (object *tmp, object *pl)
1130     {
1131     static char buf[VERY_BIG_BUF];
1132     char *cp;
1133 elmex 1.1
1134 root 1.14 if (tmp == NULL)
1135     return "";
1136 elmex 1.1
1137 root 1.14 buf[0] = '\0';
1138     switch (tmp->type)
1139     {
1140 root 1.15 case RING:
1141     case SKILL:
1142     case WEAPON:
1143     case ARMOUR:
1144     case BRACERS:
1145     case HELMET:
1146     case SHIELD:
1147     case BOOTS:
1148     case GLOVES:
1149     case AMULET:
1150     case GIRDLE:
1151     case BOW:
1152     case ARROW:
1153     case CLOAK:
1154     case FOOD:
1155     case DRINK:
1156     case FLESH:
1157     case SKILL_TOOL:
1158     case POWER_CRYSTAL:
1159     if (*(cp = describe_item (tmp, pl)) != '\0')
1160     {
1161     int len;
1162 root 1.14
1163 root 1.15 assign (buf, query_name (tmp));
1164     len = strlen (buf);
1165     if (len < VERY_BIG_BUF - 5)
1166     {
1167     /* Since we know the length, we save a few cpu cycles by using
1168     * it instead of calling strcat */
1169     strcpy (buf + len, " ");
1170     len++;
1171     assign (buf + len, cp, VERY_BIG_BUF - len - 1);
1172     }
1173     }
1174 elmex 1.1 }
1175 root 1.15
1176 root 1.14 if (buf[0] == '\0')
1177 root 1.15 assign (buf, query_name (tmp));
1178 elmex 1.1
1179 root 1.14 return buf;
1180 elmex 1.1 }
1181    
1182 root 1.14 void
1183     examine (object *op, object *tmp)
1184     {
1185     char buf[VERY_BIG_BUF];
1186     int i;
1187    
1188     if (tmp == NULL || tmp->type == CLOSE_CON)
1189     return;
1190    
1191     strcpy (buf, "That is ");
1192     strncat (buf, long_desc (tmp, op), VERY_BIG_BUF - strlen (buf) - 1);
1193     buf[VERY_BIG_BUF - 1] = 0;
1194 elmex 1.1
1195 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, buf);
1196     buf[0] = '\0';
1197 elmex 1.1
1198 root 1.14 if (tmp->custom_name)
1199     {
1200     strcpy (buf, "You call it ");
1201     strncat (buf, tmp->custom_name, VERY_BIG_BUF - strlen (buf) - 1);
1202     buf[VERY_BIG_BUF - 1] = 0;
1203     new_draw_info (NDI_UNIQUE, 0, op, buf);
1204     buf[0] = '\0';
1205 elmex 1.1 }
1206    
1207 root 1.14 switch (tmp->type)
1208     {
1209 root 1.15 case SPELLBOOK:
1210     if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) && tmp->inv)
1211     {
1212     sprintf (buf, "%s is a %s level %s spell", &tmp->inv->name, get_levelnumber (tmp->inv->level), &tmp->inv->skill);
1213     }
1214     break;
1215 root 1.10
1216 root 1.15 case BOOK:
1217     if (tmp->msg != NULL)
1218     strcpy (buf, "Something is written in it.");
1219     break;
1220 root 1.10
1221 root 1.15 case CONTAINER:
1222     if (tmp->race != NULL)
1223     {
1224     if (tmp->weight_limit && tmp->stats.Str < 100)
1225     sprintf (buf, "It can hold only %s and its weight limit is %.1f kg.",
1226     &tmp->race, tmp->weight_limit / (10.0 * (100 - tmp->stats.Str)));
1227     else
1228     sprintf (buf, "It can hold only %s.", &tmp->race);
1229     }
1230     else if (tmp->weight_limit && tmp->stats.Str < 100)
1231     sprintf (buf, "Its weight limit is %.1f kg.", tmp->weight_limit / (10.0 * (100 - tmp->stats.Str)));
1232     break;
1233    
1234     case WAND:
1235     if (QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1236     sprintf (buf, "It has %d charges left.", tmp->stats.food);
1237     break;
1238 root 1.14 }
1239    
1240     if (buf[0] != '\0')
1241     new_draw_info (NDI_UNIQUE, 0, op, buf);
1242    
1243     if (tmp->materialname != NULL && !tmp->msg)
1244     {
1245     sprintf (buf, "It is made of: %s.", &tmp->materialname);
1246     new_draw_info (NDI_UNIQUE, 0, op, buf);
1247     }
1248     /* Where to wear this item */
1249     for (i = 0; i < NUM_BODY_LOCATIONS; i++)
1250     {
1251     if (tmp->body_info[i] < -1)
1252     {
1253     if (op->body_info[i])
1254     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s (%d)", body_locations[i].use_name, -tmp->body_info[i]);
1255     else
1256     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].nonuse_name);
1257     }
1258     else if (tmp->body_info[i])
1259     {
1260     if (op->body_info[i])
1261     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].use_name);
1262     else
1263     new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].nonuse_name);
1264     }
1265     }
1266    
1267     if (tmp->weight)
1268     {
1269     sprintf (buf, tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", tmp->weight * (tmp->nrof ? tmp->nrof : 1) / 1000.0);
1270     new_draw_info (NDI_UNIQUE, 0, op, buf);
1271     }
1272    
1273     if (tmp->value && !QUERY_FLAG (tmp, FLAG_STARTEQUIP) && !QUERY_FLAG (tmp, FLAG_NO_PICK))
1274     {
1275     sprintf (buf, "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", query_cost_string (tmp, op, F_TRUE | F_APPROX));
1276     new_draw_info (NDI_UNIQUE, 0, op, buf);
1277     if (is_in_shop (op))
1278     {
1279     if (QUERY_FLAG (tmp, FLAG_UNPAID))
1280     sprintf (buf, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string (tmp, op, F_BUY | F_SHOP));
1281     else
1282     sprintf (buf, "You are offered %s for %s.", query_cost_string (tmp, op, F_SELL + F_SHOP), tmp->nrof > 1 ? "them" : "it");
1283     new_draw_info (NDI_UNIQUE, 0, op, buf);
1284     }
1285 elmex 1.1 }
1286    
1287 root 1.14 if (QUERY_FLAG (tmp, FLAG_MONSTER))
1288     examine_monster (op, tmp);
1289    
1290     /* Is this item buildable? */
1291     if (QUERY_FLAG (tmp, FLAG_IS_BUILDABLE))
1292     new_draw_info (NDI_UNIQUE, 0, op, "This is a buildable item.");
1293    
1294     /* Does the object have a message? Don't show message for all object
1295     * types - especially if the first entry is a match
1296     */
1297     if (tmp->msg && tmp->type != EXIT && tmp->type != BOOK && tmp->type != CORPSE && !tmp->move_on && strncasecmp (tmp->msg, "@match", 7))
1298     {
1299 elmex 1.1
1300 root 1.14 /* This is just a hack so when identifying the items, we print
1301     * out the extra message
1302     */
1303     if (need_identify (tmp) && QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1304     new_draw_info (NDI_UNIQUE, 0, op, "The object has a story:");
1305 elmex 1.1
1306 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, tmp->msg);
1307 elmex 1.1 }
1308 root 1.14 new_draw_info (NDI_UNIQUE, 0, op, " "); /* Blank line */
1309 elmex 1.1 }
1310    
1311     /*
1312     * inventory prints object's inventory. If inv==NULL then print player's
1313     * inventory.
1314     * [ Only items which are applied are showed. Tero.Haatanen@lut.fi ]
1315     */
1316 root 1.14 void
1317     inventory (object *op, object *inv)
1318     {
1319 elmex 1.1 object *tmp;
1320     char *in;
1321     int items = 0, length;
1322    
1323 root 1.14 if (inv == NULL && op == NULL)
1324     {
1325     new_draw_info (NDI_UNIQUE, 0, op, "Inventory of what object?");
1326     return;
1327     }
1328 elmex 1.1 tmp = inv ? inv->inv : op->inv;
1329    
1330 root 1.14 while (tmp)
1331     {
1332     if ((!tmp->invisible &&
1333     (inv == NULL || inv->type == CONTAINER || QUERY_FLAG (tmp, FLAG_APPLIED))) || (!op || QUERY_FLAG (op, FLAG_WIZ)))
1334     items++;
1335     tmp = tmp->below;
1336     }
1337     if (inv == NULL)
1338     { /* player's inventory */
1339     if (items == 0)
1340     {
1341     new_draw_info (NDI_UNIQUE, 0, op, "You carry nothing.");
1342     return;
1343     }
1344     else
1345     {
1346     length = 28;
1347     in = "";
1348     if (op)
1349     clear_win_info (op);
1350     new_draw_info (NDI_UNIQUE, 0, op, "Inventory:");
1351     }
1352     }
1353     else
1354     {
1355     if (items == 0)
1356     return;
1357     else
1358     {
1359     length = 28;
1360     in = " ";
1361     }
1362     }
1363     for (tmp = inv ? inv->inv : op->inv; tmp; tmp = tmp->below)
1364     {
1365     if ((!op || !QUERY_FLAG (op, FLAG_WIZ)) && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG (tmp, FLAG_APPLIED))))
1366     continue;
1367     if ((!op || QUERY_FLAG (op, FLAG_WIZ)))
1368     new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s (%5d) %-8s", in, length, length,
1369     query_name (tmp), tmp->count, query_weight (tmp));
1370     else
1371     new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s %-8s", in, length + 8, length + 8, query_name (tmp), query_weight (tmp));
1372 elmex 1.1 }
1373 root 1.14 if (!inv && op)
1374     {
1375     new_draw_info_format (NDI_UNIQUE, 0, op, "%-*s %-8s", 41, "Total weight :", query_weight (op));
1376 elmex 1.1 }
1377     }
1378    
1379 root 1.14 static void
1380     display_new_pickup (object *op)
1381     {
1382     int i = op->contr->mode;
1383 elmex 1.1
1384 root 1.14 if (!(i & PU_NEWMODE))
1385     return;
1386 elmex 1.1
1387 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NEWMODE", i & PU_NEWMODE ? 1 : 0);
1388     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DEBUG", i & PU_DEBUG ? 1 : 0);
1389     new_draw_info_format (NDI_UNIQUE, 0, op, "%d INHIBIT", i & PU_INHIBIT ? 1 : 0);
1390     new_draw_info_format (NDI_UNIQUE, 0, op, "%d STOP", i & PU_STOP ? 1 : 0);
1391 elmex 1.1
1392 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d <= x pickup weight/value RATIO (0==off)", (i & PU_RATIO) * 5);
1393 elmex 1.1
1394 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FOOD", i & PU_FOOD ? 1 : 0);
1395     new_draw_info_format (NDI_UNIQUE, 0, op, "%d DRINK", i & PU_DRINK ? 1 : 0);
1396     new_draw_info_format (NDI_UNIQUE, 0, op, "%d VALUABLES", i & PU_VALUABLES ? 1 : 0);
1397 elmex 1.1
1398 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOW", i & PU_BOW ? 1 : 0);
1399     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARROW", i & PU_ARROW ? 1 : 0);
1400 elmex 1.1
1401 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d HELMET", i & PU_HELMET ? 1 : 0);
1402     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SHIELD", i & PU_SHIELD ? 1 : 0);
1403     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ARMOUR", i & PU_ARMOUR ? 1 : 0);
1404 elmex 1.1
1405 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d BOOTS", i & PU_BOOTS ? 1 : 0);
1406     new_draw_info_format (NDI_UNIQUE, 0, op, "%d GLOVES", i & PU_GLOVES ? 1 : 0);
1407     new_draw_info_format (NDI_UNIQUE, 0, op, "%d CLOAK", i & PU_CLOAK ? 1 : 0);
1408     new_draw_info_format (NDI_UNIQUE, 0, op, "%d KEY", i & PU_KEY ? 1 : 0);
1409 elmex 1.1
1410 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d MISSILEWEAPON", i & PU_MISSILEWEAPON ? 1 : 0);
1411     new_draw_info_format (NDI_UNIQUE, 0, op, "%d ALLWEAPON", i & PU_ALLWEAPON ? 1 : 0);
1412     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICAL", i & PU_MAGICAL ? 1 : 0);
1413     new_draw_info_format (NDI_UNIQUE, 0, op, "%d POTION", i & PU_POTION ? 1 : 0);
1414 elmex 1.1
1415 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d SPELLBOOK", i & PU_SPELLBOOK ? 1 : 0);
1416     new_draw_info_format (NDI_UNIQUE, 0, op, "%d SKILLSCROLL", i & PU_SKILLSCROLL ? 1 : 0);
1417     new_draw_info_format (NDI_UNIQUE, 0, op, "%d READABLES", i & PU_READABLES ? 1 : 0);
1418     new_draw_info_format (NDI_UNIQUE, 0, op, "%d MAGICDEVICE", i & PU_MAGIC_DEVICE ? 1 : 0);
1419 elmex 1.1
1420 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d NOT CURSED", i & PU_NOT_CURSED ? 1 : 0);
1421 elmex 1.1
1422 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "%d JEWELS", i & PU_JEWELS ? 1 : 0);
1423 root 1.22 new_draw_info_format (NDI_UNIQUE, 0, op, "%d FLESH", i & PU_FLESH ? 1 : 0);
1424 elmex 1.1
1425 root 1.14 new_draw_info_format (NDI_UNIQUE, 0, op, "");
1426     }
1427 elmex 1.1
1428 root 1.14 int
1429     command_pickup (object *op, char *params)
1430 elmex 1.1 {
1431     uint32 i;
1432 root 1.14 static const char *names[] = {
1433     "debug", "inhibit", "stop", "food", "drink", "valuables", "bow", "arrow", "helmet",
1434     "shield", "armour", "boots", "gloves", "cloak", "key", "missile", "allweapon",
1435 root 1.22 "magical", "potion", "spellbook", "skillscroll", "readables", "magicdevice", "notcursed",
1436     "jewels", "flesh", NULL
1437 root 1.14 };
1438     static uint32 modes[] = {
1439     PU_DEBUG, PU_INHIBIT, PU_STOP, PU_FOOD, PU_DRINK, PU_VALUABLES, PU_BOW, PU_ARROW, PU_HELMET,
1440     PU_SHIELD, PU_ARMOUR, PU_BOOTS, PU_GLOVES, PU_CLOAK, PU_KEY, PU_MISSILEWEAPON, PU_ALLWEAPON,
1441 root 1.22 PU_MAGICAL, PU_POTION, PU_SPELLBOOK, PU_SKILLSCROLL, PU_READABLES, PU_MAGIC_DEVICE, PU_NOT_CURSED,
1442     PU_JEWELS, PU_FLESH, 0
1443 root 1.14 };
1444    
1445     if (!params)
1446     {
1447     /* if the new mode is used, just print the settings */
1448     if (op->contr->mode & PU_NEWMODE)
1449     {
1450     display_new_pickup (op);
1451     return 1;
1452     }
1453     if (1)
1454     LOG (llevDebug, "command_pickup: !params\n");
1455     set_pickup_mode (op, (op->contr->mode > 6) ? 0 : op->contr->mode + 1);
1456     return 0;
1457     }
1458 elmex 1.1
1459 root 1.14 while (*params == ' ' && *params)
1460     params++;
1461 elmex 1.1
1462 root 1.14 if (*params == '+' || *params == '-')
1463     {
1464 elmex 1.1 int mode;
1465 root 1.14
1466     for (mode = 0; names[mode]; mode++)
1467     {
1468     if (!strcmp (names[mode], params + 1))
1469     {
1470 elmex 1.1 i = op->contr->mode;
1471 root 1.14 if (!(i & PU_NEWMODE))
1472     i = PU_NEWMODE;
1473     if (*params == '+')
1474     i = i | modes[mode];
1475 elmex 1.1 else
1476 root 1.14 i = i & ~modes[mode];
1477 elmex 1.1 op->contr->mode = i;
1478 root 1.14 display_new_pickup (op);
1479 elmex 1.1 return 1;
1480 root 1.14 }
1481     }
1482     new_draw_info_format (NDI_UNIQUE, 0, op, "Pickup: invalid item %s\n", params);
1483 elmex 1.1 return 1;
1484 root 1.14 }
1485 elmex 1.1
1486 root 1.14 if (sscanf (params, "%u", &i) != 1)
1487     {
1488     if (1)
1489     LOG (llevDebug, "command_pickup: params==NULL\n");
1490     new_draw_info (NDI_UNIQUE, 0, op, "Usage: pickup <0-7> or <value_density> .");
1491     return 1;
1492     }
1493     set_pickup_mode (op, i);
1494 elmex 1.1
1495     return 1;
1496     }
1497    
1498 root 1.14 void
1499     set_pickup_mode (object *op, int i)
1500     {
1501     switch (op->contr->mode = i)
1502     {
1503 root 1.15 case 0:
1504     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Don't pick up.");
1505     break;
1506     case 1:
1507     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item.");
1508     break;
1509     case 2:
1510     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up one item and stop.");
1511     break;
1512     case 3:
1513     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Stop before picking up.");
1514     break;
1515     case 4:
1516     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items.");
1517     break;
1518     case 5:
1519     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all items and stop.");
1520     break;
1521     case 6:
1522     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all magic items.");
1523     break;
1524     case 7:
1525     new_draw_info (NDI_UNIQUE, 0, op, "Mode: Pick up all coins and gems");
1526     break;
1527 elmex 1.1 }
1528     }
1529    
1530 root 1.14 int
1531     command_search_items (object *op, char *params)
1532 elmex 1.1 {
1533 root 1.14 char buf[MAX_BUF];
1534 elmex 1.1
1535 root 1.14 if (settings.search_items == FALSE)
1536     return 1;
1537 elmex 1.1
1538 root 1.14 if (params == NULL)
1539     {
1540     if (op->contr->search_str[0] == '\0')
1541     {
1542     new_draw_info (NDI_UNIQUE, 0, op, "Example: search magic+1");
1543     new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1544     new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1545 root 1.10 return 1;
1546     }
1547 root 1.14 op->contr->search_str[0] = '\0';
1548     new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1549 root 1.31 op->update_stats ();
1550 elmex 1.1 return 1;
1551 root 1.14 }
1552     if ((int) strlen (params) >= MAX_BUF)
1553     {
1554     new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1555     return 1;
1556     }
1557     strcpy (op->contr->search_str, params);
1558     sprintf (buf, "Searching for '%s'.", op->contr->search_str);
1559     new_draw_info (NDI_UNIQUE, 0, op, buf);
1560 root 1.31 op->update_stats ();
1561 root 1.14 return 1;
1562 elmex 1.1 }
1563