ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/deliantra/server/server/c_object.C
(Generate patch)

Comparing deliantra/server/server/c_object.C (file contents):
Revision 1.31 by root, Fri Dec 22 16:34:00 2006 UTC vs.
Revision 1.54 by root, Thu May 17 20:27:01 2007 UTC

1/* 1/*
2 CrossFire, A Multiplayer game for X-windows 2 * CrossFire, A Multiplayer game
3 3 *
4 * Copyright (C) 2005, 2006, 2007 Marc Lehmann & Crossfire+ Development Team
4 Copyright (C) 2002 Mark Wedel & Crossfire Development Team 5 * Copyright (C) 2002 Mark Wedel & Crossfire Development Team
5 Copyright (C) 1992 Frank Tore Johansen 6 * Copyright (C) 1992 Frank Tore Johansen
6 7 *
7 This program is free software; you can redistribute it and/or modify 8 * This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by 9 * it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or 10 * the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version. 11 * (at your option) any later version.
11 12 *
12 This program is distributed in the hope that it will be useful, 13 * This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details. 16 * GNU General Public License for more details.
16 17 *
17 You should have received a copy of the GNU General Public License 18 * You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software 19 * along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 21 *
21 The author can be reached via e-mail to <crossfire@schmorp.de> 22 * The author can be reached via e-mail to <crossfire@schmorp.de>
23 *
24 */
22 25
26/*
23 Object (handling) commands 27 * Object (handling) commands
24*/ 28 */
25 29
26#include <global.h> 30#include <global.h>
27#include <loader.h> 31#include <loader.h>
28#include <skills.h> 32#include <skills.h>
29#ifndef __CEXTRACT__
30# include <sproto.h> 33#include <sproto.h>
31#endif
32#include <living.h> 34#include <living.h>
33#include <math.h> 35#include <math.h>
34 36
35/* 37/*
36 * Object id parsing functions 38 * Object id parsing functions
56 * only unapply applied, or apply unapplied objects 58 * only unapply applied, or apply unapplied objects
57 **/ 59 **/
58static object * 60static object *
59find_best_apply_object_match (object *pl, const char *params, enum apply_flag aflag) 61find_best_apply_object_match (object *pl, const char *params, enum apply_flag aflag)
60{ 62{
61 object *tmp, *best = NULL; 63 object *best = 0;
62 int match_val = 0, tmpmatch; 64 int match_val = 0;
63 65
64 for (tmp = pl->inv; tmp; tmp = tmp->below) 66 for (object *tmp = pl->inv; tmp; tmp = tmp->below)
65 { 67 {
66 if (tmp->invisible) 68 if (tmp->invisible)
67 continue; 69 continue;
70
68 if ((tmpmatch = item_matched_string (pl, tmp, params)) > match_val) 71 int tmpmatch = item_matched_string (pl, tmp, params);
72
73 if (tmpmatch > match_val)
69 { 74 {
70 if ((aflag == AP_APPLY) && (QUERY_FLAG (tmp, FLAG_APPLIED))) 75 if ((aflag == AP_APPLY) && (QUERY_FLAG (tmp, FLAG_APPLIED)))
71 continue; 76 continue;
77
72 if ((aflag == AP_UNAPPLY) && (!QUERY_FLAG (tmp, FLAG_APPLIED))) 78 if ((aflag == AP_UNAPPLY) && (!QUERY_FLAG (tmp, FLAG_APPLIED)))
73 continue; 79 continue;
80
74 match_val = tmpmatch; 81 match_val = tmpmatch;
75 best = tmp; 82 best = tmp;
76 } 83 }
77 } 84 }
85
78 return best; 86 return best;
79} 87}
80 88
81/** 89/**
82 * Shortcut to find_best_apply_object_match(pl, params, AF_NULL); 90 * Shortcut to find_best_apply_object_match(pl, params, AF_NULL);
83 **/ 91 **/
84object * 92object *
85find_best_object_match (object *pl, const char *params) 93find_best_object_match (object *pl, const char *params)
86{ 94{
87 return find_best_apply_object_match (pl, params, AP_NULL); 95 return find_best_apply_object_match (pl, params, AP_TOGGLE);
88} 96}
89 97
90int 98int
91command_uskill (object *pl, char *params) 99command_uskill (object *pl, char *params)
92{ 100{
93 if (!params) 101 if (!params)
94 { 102 {
95 new_draw_info (NDI_UNIQUE, 0, pl, "Usage: use_skill <skill name>"); 103 new_draw_info (NDI_UNIQUE, 0, pl, "Usage: use_skill <skill name>");
96 return 0; 104 return 0;
97 } 105 }
106
98 return use_skill (pl, params); 107 return use_skill (pl, params);
99} 108}
100 109
101int 110int
102command_rskill (object *pl, char *params) 111command_rskill (object *pl, char *params)
106 if (!params) 115 if (!params)
107 { 116 {
108 new_draw_info (NDI_UNIQUE, 0, pl, "Usage: ready_skill <skill name>"); 117 new_draw_info (NDI_UNIQUE, 0, pl, "Usage: ready_skill <skill name>");
109 return 0; 118 return 0;
110 } 119 }
120
111 skill = find_skill_by_name (pl, params); 121 skill = find_skill_by_name (pl, params);
112 122
113 if (!skill) 123 if (!skill)
114 { 124 {
115 new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no knowledge of the skill %s", params); 125 new_draw_info_format (NDI_UNIQUE, 0, pl, "You have no knowledge of the skill %s", params);
116 return 0; 126 return 0;
117 } 127 }
118 return change_skill (pl, skill, 0);
119}
120 128
129 pl->change_skill (0);
130 apply_special (pl, skill, AP_APPLY);
131 return 1;
132}
121 133
122/* These functions (command_search, command_disarm) are really just wrappers for 134/* These functions (command_search, command_disarm) are really just wrappers for
123 * things like 'use_skill ...'). In fact, they should really be obsoleted 135 * things like 'use_skill ...'). In fact, they should really be obsoleted
124 * and replaced with those. 136 * and replaced with those.
125 */ 137 */
133command_disarm (object *op, char *params) 145command_disarm (object *op, char *params)
134{ 146{
135 return use_skill (op, skill_names[SK_DISARM_TRAPS]); 147 return use_skill (op, skill_names[SK_DISARM_TRAPS]);
136} 148}
137 149
138
139/* A little special because we do want to pass the full params along 150/* A little special because we do want to pass the full params along
140 * as it includes the object to throw. 151 * as it includes the object to throw.
141 */ 152 */
142int 153int
143command_throw (object *op, char *params) 154command_throw (object *op, char *params)
144{ 155{
145 object *skop;
146
147 skop = find_skill_by_name (op, skill_names[SK_THROWING]); 156 if (object *skop = find_skill_by_name (op, skill_names[SK_THROWING]))
148 if (skop)
149 return do_skill (op, op, skop, op->facing, params); 157 return do_skill (op, op, skop, op->facing, params);
150 else 158 else
151 {
152 new_draw_info (NDI_UNIQUE, 0, op, "You have no knowledge of the skill throwing."); 159 new_draw_info (NDI_UNIQUE, 0, op, "You have no knowledge of the skill throwing.");
153 } 160
154 return 0; 161 return 0;
155} 162}
156
157 163
158int 164int
159command_apply (object *op, char *params) 165command_apply (object *op, char *params)
160{ 166{
161 if (!params) 167 if (!params)
163 player_apply_below (op); 169 player_apply_below (op);
164 return 0; 170 return 0;
165 } 171 }
166 else 172 else
167 { 173 {
168 apply_flag aflag = (apply_flag) 0; 174 apply_flag aflag = (apply_flag)0;
169 object *inv;
170 175
171 while (*params == ' ') 176 while (*params == ' ')
172 params++; 177 params++;
178
173 if (!strncmp (params, "-a ", 3)) 179 if (!strncmp (params, "-a ", 3))
174 { 180 {
175 aflag = AP_APPLY; 181 aflag = AP_APPLY;
176 params += 3; 182 params += 3;
177 } 183 }
184
178 if (!strncmp (params, "-u ", 3)) 185 if (!strncmp (params, "-u ", 3))
179 { 186 {
180 aflag = AP_UNAPPLY; 187 aflag = AP_UNAPPLY;
181 params += 3; 188 params += 3;
182 } 189 }
190
183 while (*params == ' ') 191 while (*params == ' ')
184 params++; 192 params++;
185 193
186 inv = find_best_apply_object_match (op, params, aflag); 194 if (object *inv = find_best_apply_object_match (op, params, aflag))
187 if (inv)
188 {
189 player_apply (op, inv, aflag, 0); 195 player_apply (op, inv, aflag, 0);
190 }
191 else 196 else
192 new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find any match to the %s.", params); 197 new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find any match to the %s.", params);
193 } 198 }
199
194 return 0; 200 return 0;
195} 201}
196 202
197/* 203/*
198 * Check if an item op can be put into a sack. If pl exists then tell 204 * Check if an item op can be put into a sack. If pl exists then tell
268 } 274 }
269 275
270 if (QUERY_FLAG (tmp, FLAG_NO_DROP)) 276 if (QUERY_FLAG (tmp, FLAG_NO_DROP))
271 return; 277 return;
272 278
273 if (QUERY_FLAG (tmp, FLAG_WAS_WIZ) && !QUERY_FLAG (pl, FLAG_WAS_WIZ))
274 {
275 new_draw_info (NDI_UNIQUE, 0, pl, "The object disappears in a puff of smoke!");
276 new_draw_info (NDI_UNIQUE, 0, pl, "It must have been an illusion.");
277
278 if (pl->type == PLAYER)
279 esrv_del_item (pl->contr, tmp->count);
280
281 tmp->destroy ();
282 return;
283 }
284
285 if (nrof > tmp_nrof || nrof == 0) 279 if (nrof > tmp_nrof || nrof == 0)
286 nrof = tmp_nrof; 280 nrof = tmp_nrof;
287 281
288 /* Figure out how much weight this object will add to the player */ 282 /* Figure out how much weight this object will add to the player */
289 weight = tmp->weight * nrof; 283 weight = tmp->weight * nrof;
299 { 293 {
300 new_draw_info (0, 0, pl, "That item is too heavy for you to pick up."); 294 new_draw_info (0, 0, pl, "That item is too heavy for you to pick up.");
301 return; 295 return;
302 } 296 }
303 297
304 if (settings.real_wiz == FALSE && QUERY_FLAG (pl, FLAG_WAS_WIZ))
305 SET_FLAG (tmp, FLAG_WAS_WIZ);
306
307 if (nrof != tmp_nrof) 298 if (nrof != tmp_nrof)
308 { 299 {
309 object *tmp2 = tmp; 300 object *tmp2 = tmp;
310 301
311 tmp = get_split_ob (tmp, nrof); 302 tmp = get_split_ob (tmp, nrof);
313 { 304 {
314 new_draw_info (NDI_UNIQUE, 0, pl, errmsg); 305 new_draw_info (NDI_UNIQUE, 0, pl, errmsg);
315 return; 306 return;
316 } 307 }
317 308
318 /* Tell a client what happened rest of objects */ 309 /* Tell the client what happened to the rest of objects */
319 if (pl->type == PLAYER) 310 if (pl->contr)
320 {
321 if (tmp2->destroyed ()) 311 if (tmp2->destroyed ())
322 esrv_del_item (pl->contr, tmp2->count); 312 esrv_del_item (pl->contr, tmp2->count);
323 else 313 else
324 esrv_send_item (pl, tmp2); 314 esrv_update_item (UPD_NROF, pl, tmp2);
325 }
326 } 315 }
327 else 316 else
328 { 317 {
329 /* If the object is in a container, send a delete to the client. 318 /* If the object is in a container, send a delete to the client.
330 * - we are moving all the items from the container to elsewhere, 319 * - we are moving all the items from the container to elsewhere,
332 */ 321 */
333 if (!QUERY_FLAG (tmp, FLAG_REMOVED)) 322 if (!QUERY_FLAG (tmp, FLAG_REMOVED))
334 { 323 {
335 if (tmp->env && pl->type == PLAYER) 324 if (tmp->env && pl->type == PLAYER)
336 esrv_del_item (pl->contr, tmp->count); 325 esrv_del_item (pl->contr, tmp->count);
326
337 tmp->remove (); /* Unlink it */ 327 tmp->remove (); /* Unlink it */
338 } 328 }
339 } 329 }
330
340 if (QUERY_FLAG (tmp, FLAG_UNPAID)) 331 if (QUERY_FLAG (tmp, FLAG_UNPAID))
341 (void) sprintf (buf, "%s will cost you %s.", query_name (tmp), query_cost_string (tmp, pl, F_BUY | F_SHOP)); 332 sprintf (buf, "%s will cost you %s.", query_name (tmp), query_cost_string (tmp, pl, F_BUY | F_SHOP));
342 else 333 else
343 (void) sprintf (buf, "You pick up the %s.", query_name (tmp)); 334 sprintf (buf, "You pick up the %s.", query_name (tmp));
335
344 new_draw_info (NDI_UNIQUE, 0, pl, buf); 336 new_draw_info (NDI_UNIQUE, 0, pl, buf);
345 337
346 tmp = insert_ob_in_ob (tmp, op); 338 tmp = insert_ob_in_ob (tmp, op);
347 339
348 /* All the stuff below deals with client/server code, and is only 340 /* All the stuff below deals with client/server code, and is only
349 * usable by players 341 * usable by players
350 */ 342 */
351 if (pl->type != PLAYER) 343 if (pl->contr)
352 return; 344 {
353
354 esrv_send_item (pl, tmp); 345 esrv_send_item (pl, tmp);
346
355 /* These are needed to update the weight for the container we 347 /* These are needed to update the weight for the container we
356 * are putting the object in. 348 * are putting the object in.
357 */ 349 */
358 if (op != pl) 350 if (op != pl)
359 { 351 {
360 esrv_update_item (UPD_WEIGHT, pl, op); 352 esrv_update_item (UPD_WEIGHT, pl, op);
361 esrv_send_item (pl, pl); 353 esrv_send_item (pl, pl);
362 } 354 }
363 355
364 /* Update the container the object was in */ 356 /* Update the container the object was in */
365 if (env && env != pl && env != op) 357 if (env && env != pl && env != op)
366 esrv_update_item (UPD_WEIGHT, pl, env); 358 esrv_update_item (UPD_WEIGHT, pl, env);
359 }
367} 360}
368 361
369/* modified slightly to allow monsters use this -b.t. 5-31-95 */ 362/* modified slightly to allow monsters use this -b.t. 5-31-95 */
370void 363void
371pick_up (object *op, object *alt) 364pick_up (object *op, object *alt)
430 423
431 if (!alt) 424 if (!alt)
432 for (alt = op->inv; alt; alt = alt->below) 425 for (alt = op->inv; alt; alt = alt->below)
433 if (alt->type == CONTAINER && QUERY_FLAG (alt, FLAG_APPLIED) && sack_can_hold (NULL, alt, tmp, count)) 426 if (alt->type == CONTAINER && QUERY_FLAG (alt, FLAG_APPLIED) && sack_can_hold (NULL, alt, tmp, count))
434 break; /* General container comes next */ 427 break; /* General container comes next */
428
435 if (!alt) 429 if (!alt)
436 alt = op; /* No free containers */ 430 alt = op; /* No free containers */
437 } 431 }
438 432
439 if (tmp->env == alt) 433 if (tmp->env == alt)
466 460
467leave: 461leave:
468 if (need_fix_tmp) 462 if (need_fix_tmp)
469 fix_stopped_item (tmp, tmp_map, op); 463 fix_stopped_item (tmp, tmp_map, op);
470} 464}
471
472 465
473/* This takes (picks up) and item. op is the player 466/* This takes (picks up) and item. op is the player
474 * who issued the command. params is a string to 467 * who issued the command. params is a string to
475 * match against the item name. Basically, always 468 * match against the item name. Basically, always
476 * returns zero, but that should be improved. 469 * returns zero, but that should be improved.
491 484
492 if (!tmp) 485 if (!tmp)
493 tmp = op->below; 486 tmp = op->below;
494 } 487 }
495 488
496 if (tmp == NULL) 489 if (!tmp)
497 { 490 {
498 new_draw_info (NDI_UNIQUE, 0, op, "Nothing to take!"); 491 new_draw_info (NDI_UNIQUE, 0, op, "Nothing to take!");
499 return 0; 492 return 0;
500 } 493 }
501 494
502 /* Makes processing easier */ 495 /* Makes processing easier */
503 if (params && *params == '\0') 496 if (params && *params == '\0')
504 params = NULL; 497 params = 0;
505 498
506 while (tmp) 499 while (tmp)
507 { 500 {
508 next = tmp->below; 501 next = tmp->below;
509 502
510 if (tmp->invisible) 503 if (tmp->invisible)
511 { 504 {
512 tmp = next; 505 tmp = next;
513 continue; 506 continue;
514 } 507 }
508
515 /* This following two if and else if could be merged into line 509 /* This following two if and else if could be merged into line
516 * but that probably will make it more difficult to read, and 510 * but that probably will make it more difficult to read, and
517 * not make it any more efficient 511 * not make it any more efficient
518 */ 512 */
519 if (params && item_matched_string (op, tmp, params)) 513 if (params && item_matched_string (op, tmp, params))
520 {
521 pick_up (op, tmp); 514 pick_up (op, tmp);
522 }
523 else if (can_pick (op, tmp) && !params) 515 else if (can_pick (op, tmp) && !params)
524 { 516 {
525 pick_up (op, tmp); 517 pick_up (op, tmp);
526 break; 518 break;
527 } 519 }
520
528 tmp = next; 521 tmp = next;
529 /* Might as well just skip over the player immediately -
530 * we know it can't be picked up
531 */
532 if (tmp == op)
533 tmp = tmp->below;
534 } 522 }
523
535 if (!params && !tmp) 524 if (!params && !tmp)
536 { 525 {
537 for (tmp = op->below; tmp != NULL; tmp = tmp->next) 526 for (tmp = op->below; tmp; tmp = tmp->below)
538 if (!tmp->invisible) 527 if (!tmp->invisible)
539 { 528 {
540 char buf[MAX_BUF]; 529 char buf[MAX_BUF];
541 530
542 sprintf (buf, "You can't pick up a %s.", &tmp->name); 531 sprintf (buf, "You can't pick up a %s.", &tmp->name);
543 new_draw_info (NDI_UNIQUE, 0, op, buf); 532 new_draw_info (NDI_UNIQUE, 0, op, buf);
544 break; 533 break;
545 } 534 }
535
546 if (!tmp) 536 if (!tmp)
547 new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up."); 537 new_draw_info (NDI_UNIQUE, 0, op, "There is nothing to pick up.");
548 } 538 }
539
549 return 0; 540 return 0;
550} 541}
551 542
552 543
553/* 544/*
667 658
668 if (QUERY_FLAG (tmp, FLAG_APPLIED)) 659 if (QUERY_FLAG (tmp, FLAG_APPLIED))
669 if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE)) 660 if (apply_special (op, tmp, AP_UNAPPLY | AP_NO_MERGE))
670 return; /* can't unapply it */ 661 return; /* can't unapply it */
671 662
663 //fprintf (stderr, "ui, on space is %ld\n", op->ms ().volume ());//D
664
672 /* We are only dropping some of the items. We split the current object 665 /* We are only dropping some of the items. We split the current object
673 * off 666 * off
674 */ 667 */
675 if (nrof && tmp->nrof != nrof) 668 if (nrof && tmp->nrof != nrof)
676 { 669 {
710 703
711 tmp->destroy (); 704 tmp->destroy ();
712 op->update_stats (); 705 op->update_stats ();
713 return; 706 return;
714 } 707 }
715
716/* If SAVE_INTERVAL is commented out, we never want to save
717 * the player here.
718 */
719#ifdef SAVE_INTERVAL
720 /* I'm not sure why there is a value check - since the save
721 * is done every SAVE_INTERVAL seconds, why care the value
722 * of what he is dropping?
723 */
724 if (op->type == PLAYER && !QUERY_FLAG (tmp, FLAG_UNPAID) &&
725 (tmp->nrof ? tmp->value * tmp->nrof : tmp->value > 2000) && (op->contr->last_save_time + SAVE_INTERVAL) <= time (NULL))
726 {
727 op->contr->save ();
728 op->contr->last_save_time = time (NULL);
729 }
730#endif /* SAVE_INTERVAL */
731 708
732 if (op->type == PLAYER) 709 if (op->type == PLAYER)
733 esrv_del_item (op->contr, tmp->count); 710 esrv_del_item (op->contr, tmp->count);
734 711
735 /* Call this before we update the various windows/players. At least 712 /* Call this before we update the various windows/players. At least
994{ 971{
995 if (!params) 972 if (!params)
996 { 973 {
997 object *tmp = op->below; 974 object *tmp = op->below;
998 975
999 while (tmp && !LOOK_OBJ (tmp)) 976 while (tmp && !tmp->client_visible ())
1000 tmp = tmp->below; 977 tmp = tmp->below;
1001 if (tmp) 978 if (tmp)
1002 examine (op, tmp); 979 examine (op, tmp);
1003 } 980 }
1004 else 981 else
1056 } 1033 }
1057 1034
1058 return 0; 1035 return 0;
1059} 1036}
1060 1037
1061 1038std::string
1062/* op should be a player, params is any params. 1039object::describe_monster (object *who)
1063 * If no params given, we print out the currently marked object.
1064 * otherwise, try to find a matching object - try best match first.
1065 */
1066int
1067command_mark (object *op, char *params)
1068{ 1040{
1069 if (!op->contr) 1041 dynbuf_text buf (512, 512);
1070 return 1;
1071 1042
1072 if (!params) 1043 object *mon = head ? head : this;
1073 {
1074 object *mark = find_marked_object (op);
1075 1044
1076 if (!mark) 1045 if (QUERY_FLAG (mon, FLAG_UNDEAD))
1077 new_draw_info (NDI_UNIQUE, 0, op, "You have no marked object."); 1046 buf << "It is an undead force.\n";
1078 else 1047
1079 new_draw_info_format (NDI_UNIQUE, 0, op, "%s is marked.", query_name (mark)); 1048 if (mon->level > who->level)
1080 } 1049 buf << "It is likely more powerful than you.\n";
1050 else if (mon->level < who->level)
1051 buf << "It is likely less powerful than you.\n";
1081 else 1052 else
1082 { 1053 buf << "It is probably as powerful as you.\n";
1083 object *mark1 = find_best_object_match (op, params);
1084 1054
1085 if (!mark1)
1086 {
1087 new_draw_info_format (NDI_UNIQUE, 0, op, "Could not find an object that matches %s", params);
1088 return 1;
1089 }
1090 else
1091 {
1092 op->contr->mark = mark1;
1093 new_draw_info_format (NDI_UNIQUE, 0, op, "Marked item %s", query_name (mark1));
1094 return 0;
1095 }
1096 }
1097
1098 return 0; /*shouldnt get here */
1099}
1100
1101
1102/* op is the player
1103 * tmp is the monster being examined.
1104 */
1105void
1106examine_monster (object *op, object *tmp)
1107{
1108 object *mon = tmp->head ? tmp->head : tmp;
1109
1110 if (QUERY_FLAG (mon, FLAG_UNDEAD))
1111 new_draw_info (NDI_UNIQUE, 0, op, "It is an undead force.");
1112 if (mon->level > op->level)
1113 new_draw_info (NDI_UNIQUE, 0, op, "It is likely more powerful than you.");
1114 else if (mon->level < op->level)
1115 new_draw_info (NDI_UNIQUE, 0, op, "It is likely less powerful than you.");
1116 else
1117 new_draw_info (NDI_UNIQUE, 0, op, "It is probably as powerful as you.");
1118 if (mon->attacktype & AT_ACID) 1055 if (mon->attacktype & AT_ACID)
1119 new_draw_info (NDI_UNIQUE, 0, op, "You seem to smell an acrid odor."); 1056 buf << "You seem to smell an acrid odor.\n";
1120 1057
1121 /* Anyone know why this used to use the clone value instead of the 1058 /* Anyone know why this used to use the clone value instead of the
1122 * maxhp field? This seems that it should give more accurate results. 1059 * maxhp field? This seems that it should give more accurate results.
1123 */ 1060 */
1124 switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1)) 1061 switch ((mon->stats.hp + 1) * 4 / (mon->stats.maxhp + 1))
1125 { /* From 1-4 */ 1062 { /* From 1-4 */
1126 case 1: 1063 case 1:
1127 new_draw_info (NDI_UNIQUE, 0, op, "It is in a bad shape."); 1064 buf << "It is in a bad shape.\n";
1128 break; 1065 break;
1129 case 2: 1066 case 2:
1130 new_draw_info (NDI_UNIQUE, 0, op, "It is hurt."); 1067 buf << "It is hurt.\n";
1131 break; 1068 break;
1132 case 3: 1069 case 3:
1133 new_draw_info (NDI_UNIQUE, 0, op, "It is somewhat hurt."); 1070 buf << "It is somewhat hurt.\n";
1134 break; 1071 break;
1135 case 4: 1072 case 4:
1136 new_draw_info (NDI_UNIQUE, 0, op, "It is in excellent shape."); 1073 buf << "It is in excellent shape.\n";
1137 break; 1074 break;
1138 } 1075 }
1076
1139 if (present_in_ob (POISONING, mon) != NULL) 1077 if (present_in_ob (POISONING, mon))
1140 new_draw_info (NDI_UNIQUE, 0, op, "It looks very ill."); 1078 buf << "It looks very ill.\n";
1141}
1142 1079
1080 return buf;
1081}
1143 1082
1144/* tmp is the object being described, pl is who is examing it. */ 1083/* tmp is the object being described, pl is who is examing it. */
1145char * 1084const char *
1146long_desc (object *tmp, object *pl) 1085long_desc (object *tmp, object *pl)
1147{ 1086{
1148 static char buf[VERY_BIG_BUF]; 1087 static std::string s;
1149 char *cp;
1150 1088
1151 if (tmp == NULL) 1089 return (s = tmp->long_desc (pl)).c_str ();
1152 return ""; 1090}
1153 1091
1154 buf[0] = '\0'; 1092std::string
1093object::long_desc (object *who)
1094{
1095 std::string buf (query_name (this));
1096
1155 switch (tmp->type) 1097 switch (type)
1156 { 1098 {
1157 case RING: 1099 case RING:
1158 case SKILL: 1100 case SKILL:
1159 case WEAPON: 1101 case WEAPON:
1160 case ARMOUR: 1102 case ARMOUR:
1171 case FOOD: 1113 case FOOD:
1172 case DRINK: 1114 case DRINK:
1173 case FLESH: 1115 case FLESH:
1174 case SKILL_TOOL: 1116 case SKILL_TOOL:
1175 case POWER_CRYSTAL: 1117 case POWER_CRYSTAL:
1176 if (*(cp = describe_item (tmp, pl)) != '\0') 1118 {
1119 const char *cp = ::describe_item (this, who);
1120
1121 if (*cp)
1122 {
1123 buf.append (" ");
1124 buf.append (cp);
1125 }
1126 }
1127 }
1128
1129 return buf;
1130}
1131
1132/* op is the player
1133 * tmp is the monster being examined.
1134 */
1135void
1136examine_monster (object *op, object *tmp)
1137{
1138 new_draw_info (NDI_UNIQUE, 0, op, tmp->describe_monster (op).c_str ());
1139}
1140
1141std::string
1142object::describe (object *who)
1143{
1144 dynbuf_text buf (1024, 1024);
1145
1146 buf.printf ("That is: %s.\n", long_desc (who).c_str ());
1147
1148 if (custom_name)
1149 buf,printf ("You call it %s\n", &custom_name);
1150
1151 switch (type)
1152 {
1153 case SPELLBOOK:
1154 if (flag [FLAG_IDENTIFIED] && inv)
1155 buf.printf ("%s is a %s %s spell\n", &inv->name, get_levelnumber (inv->level), &inv->skill);
1156 break;
1157
1158 case BOOK:
1159 if (msg)
1160 buf << "Something is written in it.\n";
1161 break;
1162
1163 case CONTAINER:
1164 if (race != NULL)
1177 { 1165 {
1166 if (weight_limit && stats.Str < 100)
1167 buf.printf ("It can hold only %s and its weight limit is %.1f kg.\n",
1168 &race, weight_limit / (10.0 * (100 - stats.Str)));
1178 int len; 1169 else
1179 1170 buf.printf ("It can hold only %s.\n", &race);
1180 assign (buf, query_name (tmp));
1181 len = strlen (buf);
1182 if (len < VERY_BIG_BUF - 5)
1183 {
1184 /* Since we know the length, we save a few cpu cycles by using
1185 * it instead of calling strcat */
1186 strcpy (buf + len, " ");
1187 len++;
1188 assign (buf + len, cp, VERY_BIG_BUF - len - 1);
1189 }
1190 } 1171 }
1191 } 1172 else if (weight_limit && stats.Str < 100)
1192 1173 buf.printf ("Its weight limit is %.1f kg.\n", weight_limit / (10.0 * (100 - stats.Str)));
1193 if (buf[0] == '\0')
1194 assign (buf, query_name (tmp));
1195
1196 return buf;
1197}
1198
1199void
1200examine (object *op, object *tmp)
1201{
1202 char buf[VERY_BIG_BUF];
1203 int i;
1204
1205 if (tmp == NULL || tmp->type == CLOSE_CON)
1206 return;
1207
1208 strcpy (buf, "That is ");
1209 strncat (buf, long_desc (tmp, op), VERY_BIG_BUF - strlen (buf) - 1);
1210 buf[VERY_BIG_BUF - 1] = 0;
1211
1212 new_draw_info (NDI_UNIQUE, 0, op, buf);
1213 buf[0] = '\0';
1214
1215 if (tmp->custom_name)
1216 {
1217 strcpy (buf, "You call it ");
1218 strncat (buf, tmp->custom_name, VERY_BIG_BUF - strlen (buf) - 1);
1219 buf[VERY_BIG_BUF - 1] = 0;
1220 new_draw_info (NDI_UNIQUE, 0, op, buf);
1221 buf[0] = '\0';
1222 }
1223
1224 switch (tmp->type)
1225 {
1226 case SPELLBOOK:
1227 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED) && tmp->inv)
1228 {
1229 sprintf (buf, "%s is a %s level %s spell", &tmp->inv->name, get_levelnumber (tmp->inv->level), &tmp->inv->skill);
1230 }
1231 break; 1174 break;
1232 1175
1233 case BOOK: 1176 case WAND:
1234 if (tmp->msg != NULL) 1177 if (flag [FLAG_IDENTIFIED])
1235 strcpy (buf, "Something is written in it."); 1178 buf.printf ("It has %d charges left.\n", stats.food);
1236 break; 1179 break;
1237
1238 case CONTAINER:
1239 if (tmp->race != NULL)
1240 {
1241 if (tmp->weight_limit && tmp->stats.Str < 100)
1242 sprintf (buf, "It can hold only %s and its weight limit is %.1f kg.",
1243 &tmp->race, tmp->weight_limit / (10.0 * (100 - tmp->stats.Str)));
1244 else
1245 sprintf (buf, "It can hold only %s.", &tmp->race);
1246 }
1247 else if (tmp->weight_limit && tmp->stats.Str < 100)
1248 sprintf (buf, "Its weight limit is %.1f kg.", tmp->weight_limit / (10.0 * (100 - tmp->stats.Str)));
1249 break;
1250
1251 case WAND:
1252 if (QUERY_FLAG (tmp, FLAG_IDENTIFIED))
1253 sprintf (buf, "It has %d charges left.", tmp->stats.food);
1254 break;
1255 }
1256
1257 if (buf[0] != '\0')
1258 new_draw_info (NDI_UNIQUE, 0, op, buf);
1259
1260 if (tmp->materialname != NULL && !tmp->msg)
1261 { 1180 }
1181
1182 if (materialname && !msg)
1262 sprintf (buf, "It is made of: %s.", &tmp->materialname); 1183 buf.printf ("It is made of: %s.\n", &materialname);
1263 new_draw_info (NDI_UNIQUE, 0, op, buf); 1184
1264 } 1185 if (who)
1265 /* Where to wear this item */ 1186 /* Where to wear this item */
1266 for (i = 0; i < NUM_BODY_LOCATIONS; i++) 1187 for (int i = 0; i < NUM_BODY_LOCATIONS; i++)
1267 { 1188 if (slot[i].info)
1268 if (tmp->body_info[i] < -1) 1189 {
1190 buf << (who->slot[i].info ? body_locations[i].use_name : body_locations[i].nonuse_name);
1191
1192 if (slot[i].info < -1 && who->slot[i].info)
1193 buf.printf ("(%d)", -slot[i].info);
1194
1195 buf << ".\n";
1269 { 1196 }
1270 if (op->body_info[i]) 1197
1271 new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s (%d)", body_locations[i].use_name, -tmp->body_info[i]); 1198 if (weight)
1199 buf.printf (nrof > 1 ? "They weigh %3.3f kg.\n" : "It weighs %3.3f kg.\n", weight * (nrof ? nrof : 1) / 1000.0);
1200
1201 if (value && !flag [FLAG_STARTEQUIP] && !flag [FLAG_NO_PICK] && who)
1202 {
1203 buf.printf ("You reckon %s worth %s.\n", nrof > 1 ? "they are" : "it is", query_cost_string (this, who, F_TRUE | F_APPROX));
1204
1205 if (is_in_shop (who))
1206 {
1207 if (flag [FLAG_UNPAID])
1208 buf.printf ("%s would cost you %s.\n", nrof > 1 ? "They" : "It", query_cost_string (this, who, F_BUY | F_SHOP));
1272 else 1209 else
1273 new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].nonuse_name);
1274 }
1275 else if (tmp->body_info[i])
1276 {
1277 if (op->body_info[i])
1278 new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].use_name);
1279 else
1280 new_draw_info_format (NDI_UNIQUE, 0, op, "It goes %s", body_locations[i].nonuse_name);
1281 }
1282 }
1283
1284 if (tmp->weight)
1285 {
1286 sprintf (buf, tmp->nrof > 1 ? "They weigh %3.3f kg." : "It weighs %3.3f kg.", tmp->weight * (tmp->nrof ? tmp->nrof : 1) / 1000.0);
1287 new_draw_info (NDI_UNIQUE, 0, op, buf);
1288 }
1289
1290 if (tmp->value && !QUERY_FLAG (tmp, FLAG_STARTEQUIP) && !QUERY_FLAG (tmp, FLAG_NO_PICK))
1291 {
1292 sprintf (buf, "You reckon %s worth %s.", tmp->nrof > 1 ? "they are" : "it is", query_cost_string (tmp, op, F_TRUE | F_APPROX));
1293 new_draw_info (NDI_UNIQUE, 0, op, buf);
1294 if (is_in_shop (op))
1295 {
1296 if (QUERY_FLAG (tmp, FLAG_UNPAID))
1297 sprintf (buf, "%s would cost you %s.", tmp->nrof > 1 ? "They" : "It", query_cost_string (tmp, op, F_BUY | F_SHOP));
1298 else
1299 sprintf (buf, "You are offered %s for %s.", query_cost_string (tmp, op, F_SELL + F_SHOP), tmp->nrof > 1 ? "them" : "it"); 1210 buf.printf ("You are offered %s for %s.\n", query_cost_string (this, who, F_SELL + F_SHOP), nrof > 1 ? "them" : "it");
1300 new_draw_info (NDI_UNIQUE, 0, op, buf);
1301 } 1211 }
1302 } 1212 }
1303 1213
1304 if (QUERY_FLAG (tmp, FLAG_MONSTER)) 1214 if (flag [FLAG_MONSTER])
1305 examine_monster (op, tmp); 1215 buf << describe_monster (who);
1306 1216
1307 /* Is this item buildable? */ 1217 /* Is this item buildable? */
1308 if (QUERY_FLAG (tmp, FLAG_IS_BUILDABLE)) 1218 if (flag [FLAG_IS_BUILDABLE])
1309 new_draw_info (NDI_UNIQUE, 0, op, "This is a buildable item."); 1219 buf << "This is a buildable item.\n";
1310 1220
1311 /* Does the object have a message? Don't show message for all object 1221 /* Does the object have a message? Don't show message for all object
1312 * types - especially if the first entry is a match 1222 * types - especially if the first entry is a match
1313 */ 1223 */
1314 if (tmp->msg && tmp->type != EXIT && tmp->type != BOOK && tmp->type != CORPSE && !tmp->move_on && strncasecmp (tmp->msg, "@match", 7)) 1224 if (msg && type != EXIT && type != BOOK && type != CORPSE && !move_on && strncasecmp (msg, "@match", 7))
1315 { 1225 {
1316
1317 /* This is just a hack so when identifying the items, we print 1226 /* This is just a hack so when identifying the items, we print
1318 * out the extra message 1227 * out the extra message
1319 */ 1228 */
1320 if (need_identify (tmp) && QUERY_FLAG (tmp, FLAG_IDENTIFIED)) 1229 if (need_identify (this) && flag [FLAG_IDENTIFIED])
1321 new_draw_info (NDI_UNIQUE, 0, op, "The object has a story:"); 1230 buf << "The object has a story:\n";
1322 1231
1232 buf << msg << '\n';
1233 }
1234
1235 buf << '\n';
1236
1237 return std::string (buf.linearise (), buf.size ());
1238}
1239
1240void
1241examine (object *op, object *tmp)
1242{
1243 std::string s = tmp->describe (op);
1244
1323 new_draw_info (NDI_UNIQUE, 0, op, tmp->msg); 1245 new_draw_info (NDI_UNIQUE, 0, op, s.c_str ());
1324 }
1325 new_draw_info (NDI_UNIQUE, 0, op, " "); /* Blank line */
1326} 1246}
1327 1247
1328/* 1248/*
1329 * inventory prints object's inventory. If inv==NULL then print player's 1249 * inventory prints object's inventory. If inv==NULL then print player's
1330 * inventory. 1250 * inventory.
1332 */ 1252 */
1333void 1253void
1334inventory (object *op, object *inv) 1254inventory (object *op, object *inv)
1335{ 1255{
1336 object *tmp; 1256 object *tmp;
1337 char *in; 1257 const char *in;
1338 int items = 0, length; 1258 int items = 0, length;
1339 1259
1340 if (inv == NULL && op == NULL) 1260 if (inv == NULL && op == NULL)
1341 { 1261 {
1342 new_draw_info (NDI_UNIQUE, 0, op, "Inventory of what object?"); 1262 new_draw_info (NDI_UNIQUE, 0, op, "Inventory of what object?");
1343 return; 1263 return;
1344 } 1264 }
1265
1345 tmp = inv ? inv->inv : op->inv; 1266 tmp = inv ? inv->inv : op->inv;
1346 1267
1347 while (tmp) 1268 while (tmp)
1348 { 1269 {
1349 if ((!tmp->invisible && 1270 if ((!tmp->invisible &&
1350 (inv == NULL || inv->type == CONTAINER || QUERY_FLAG (tmp, FLAG_APPLIED))) || (!op || QUERY_FLAG (op, FLAG_WIZ))) 1271 (inv == NULL || inv->type == CONTAINER || QUERY_FLAG (tmp, FLAG_APPLIED))) || (!op || QUERY_FLAG (op, FLAG_WIZ)))
1351 items++; 1272 items++;
1352 tmp = tmp->below; 1273 tmp = tmp->below;
1353 } 1274 }
1275
1354 if (inv == NULL) 1276 if (inv == NULL)
1355 { /* player's inventory */ 1277 { /* player's inventory */
1356 if (items == 0) 1278 if (items == 0)
1357 { 1279 {
1358 new_draw_info (NDI_UNIQUE, 0, op, "You carry nothing."); 1280 new_draw_info (NDI_UNIQUE, 0, op, "You carry nothing.");
1375 { 1297 {
1376 length = 28; 1298 length = 28;
1377 in = " "; 1299 in = " ";
1378 } 1300 }
1379 } 1301 }
1302
1380 for (tmp = inv ? inv->inv : op->inv; tmp; tmp = tmp->below) 1303 for (tmp = inv ? inv->inv : op->inv; tmp; tmp = tmp->below)
1381 { 1304 {
1382 if ((!op || !QUERY_FLAG (op, FLAG_WIZ)) && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG (tmp, FLAG_APPLIED)))) 1305 if ((!op || !QUERY_FLAG (op, FLAG_WIZ)) && (tmp->invisible || (inv && inv->type != CONTAINER && !QUERY_FLAG (tmp, FLAG_APPLIED))))
1383 continue; 1306 continue;
1384 if ((!op || QUERY_FLAG (op, FLAG_WIZ))) 1307 if ((!op || QUERY_FLAG (op, FLAG_WIZ)))
1385 new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s (%5d) %-8s", in, length, length, 1308 new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s (%5d) %-8s", in, length, length,
1386 query_name (tmp), tmp->count, query_weight (tmp)); 1309 query_name (tmp), tmp->count, query_weight (tmp));
1387 else 1310 else
1388 new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s %-8s", in, length + 8, length + 8, query_name (tmp), query_weight (tmp)); 1311 new_draw_info_format (NDI_UNIQUE, 0, op, "%s- %-*.*s %-8s", in, length + 8, length + 8, query_name (tmp), query_weight (tmp));
1389 } 1312 }
1313
1390 if (!inv && op) 1314 if (!inv && op)
1391 {
1392 new_draw_info_format (NDI_UNIQUE, 0, op, "%-*s %-8s", 41, "Total weight :", query_weight (op)); 1315 new_draw_info_format (NDI_UNIQUE, 0, op, "%-*s %-8s", 41, "Total weight :", query_weight (op));
1393 }
1394} 1316}
1395 1317
1396static void 1318static void
1397display_new_pickup (object *op) 1319display_new_pickup (object *op)
1398{ 1320{
1559 new_draw_info (NDI_UNIQUE, 0, op, "Example: search magic+1"); 1481 new_draw_info (NDI_UNIQUE, 0, op, "Example: search magic+1");
1560 new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all"); 1482 new_draw_info (NDI_UNIQUE, 0, op, "Would automatically pick up all");
1561 new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'."); 1483 new_draw_info (NDI_UNIQUE, 0, op, "items containing the word 'magic+1'.");
1562 return 1; 1484 return 1;
1563 } 1485 }
1486
1564 op->contr->search_str[0] = '\0'; 1487 op->contr->search_str[0] = '\0';
1565 new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off."); 1488 new_draw_info (NDI_UNIQUE, 0, op, "Search mode turned off.");
1566 op->update_stats (); 1489 op->update_stats ();
1567 return 1; 1490 return 1;
1568 } 1491 }
1492
1569 if ((int) strlen (params) >= MAX_BUF) 1493 if ((int) strlen (params) >= MAX_BUF)
1570 { 1494 {
1571 new_draw_info (NDI_UNIQUE, 0, op, "Search string too long."); 1495 new_draw_info (NDI_UNIQUE, 0, op, "Search string too long.");
1572 return 1; 1496 return 1;
1573 } 1497 }
1498
1574 strcpy (op->contr->search_str, params); 1499 strcpy (op->contr->search_str, params);
1575 sprintf (buf, "Searching for '%s'.", op->contr->search_str); 1500 sprintf (buf, "Searching for '%s'.", op->contr->search_str);
1576 new_draw_info (NDI_UNIQUE, 0, op, buf); 1501 new_draw_info (NDI_UNIQUE, 0, op, buf);
1577 op->update_stats (); 1502 op->update_stats ();
1578 return 1; 1503 return 1;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines