ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.12
Committed: Sun Sep 3 00:18:42 2006 UTC (17 years, 9 months ago) by root
Content type: text/plain
Branch: MAIN
Changes since 1.11: +12 -14 lines
Log Message:
THIS CODE WILL NOT COMPILE
use the STABLE tag instead.

- major changes in object lifetime and memory management
- replaced manual refcounting by shstr class
- removed quest system
- many optimisations
- major changes

File Contents

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