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.19 by root, Sat Sep 16 22:24:13 2006 UTC vs.
Revision 1.89 by elmex, Mon Jan 12 00:17:23 2009 UTC

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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines