ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
Revision: 1.4
Committed: Thu Aug 17 08:07:38 2006 UTC (17 years, 10 months ago) by elmex
Content type: text/plain
Branch: MAIN
Changes since 1.3: +6 -1 lines
Log Message:
preventing renaming of unpaid items.

File Contents

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