ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.14
Committed: Sun Sep 10 15:59:57 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.13: +1274 -1062 lines
Log Message:
indent

File Contents

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