xref: /original-bsd/games/rogue/pack.c (revision ca3b5b26)
1 /*
2  * Copyright (c) 1988 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Timothy C. Stoehr.
7  *
8  * Redistribution and use in source and binary forms are permitted
9  * provided that the above copyright notice and this paragraph are
10  * duplicated in all such forms and that any documentation,
11  * advertising materials, and other materials related to such
12  * distribution and use acknowledge that the software was developed
13  * by the University of California, Berkeley.  The name of the
14  * University may not be used to endorse or promote products derived
15  * from this software without specific prior written permission.
16  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  */
20 
21 #ifndef lint
22 static char sccsid[] = "@(#)pack.c	5.2 (Berkeley) 02/07/89";
23 #endif /* not lint */
24 
25 /*
26  * pack.c
27  *
28  * This source herein may be modified and/or distributed by anybody who
29  * so desires, with the following restrictions:
30  *    1.)  No portion of this notice shall be removed.
31  *    2.)  Credit shall not be taken for the creation of this source.
32  *    3.)  This code is not to be traded, sold, or used for personal
33  *         gain or profit.
34  *
35  */
36 
37 #include "rogue.h"
38 
39 char *curse_message = "you can't, it appears to be cursed";
40 
41 extern short levitate;
42 
43 object *
44 add_to_pack(obj, pack, condense)
45 object *obj, *pack;
46 {
47 	object *op;
48 
49 	if (condense) {
50 		if (op = check_duplicate(obj, pack)) {
51 			free_object(obj);
52 			return(op);
53 		} else {
54 			obj->ichar = next_avail_ichar();
55 		}
56 	}
57 	if (pack->next_object == 0) {
58 		pack->next_object = obj;
59 	} else {
60 		op = pack->next_object;
61 
62 		while (op->next_object) {
63 			op = op->next_object;
64 		}
65 		op->next_object = obj;
66 	}
67 	obj->next_object = 0;
68 	return(obj);
69 }
70 
71 take_from_pack(obj, pack)
72 object *obj, *pack;
73 {
74 	while (pack->next_object != obj) {
75 		pack = pack->next_object;
76 	}
77 	pack->next_object = pack->next_object->next_object;
78 }
79 
80 /* Note: *status is set to 0 if the rogue attempts to pick up a scroll
81  * of scare-monster and it turns to dust.  *status is otherwise set to 1.
82  */
83 
84 object *
85 pick_up(row, col, status)
86 short *status;
87 {
88 	object *obj;
89 
90 	*status = 1;
91 
92 	if (levitate) {
93 		message("you're floating in the air!", 0);
94 		return((object *) 0);
95 	}
96 	obj = object_at(&level_objects, row, col);
97 	if (!obj) {
98 		message("pick_up(): inconsistent", 1);
99 		return(obj);
100 	}
101 	if (	(obj->what_is == SCROL) &&
102 			(obj->which_kind == SCARE_MONSTER) &&
103 			obj->picked_up) {
104 		message("the scroll turns to dust as you pick it up", 0);
105 		dungeon[row][col] &= (~OBJECT);
106 		vanish(obj, 0, &level_objects);
107 		*status = 0;
108 		if (id_scrolls[SCARE_MONSTER].id_status == UNIDENTIFIED) {
109 			id_scrolls[SCARE_MONSTER].id_status = IDENTIFIED;
110 		}
111 		return((object *) 0);
112 	}
113 	if (obj->what_is == GOLD) {
114 		rogue.gold += obj->quantity;
115 		dungeon[row][col] &= ~(OBJECT);
116 		take_from_pack(obj, &level_objects);
117 		print_stats(STAT_GOLD);
118 		return(obj);	/* obj will be free_object()ed in caller */
119 	}
120 	if (pack_count(obj) >= MAX_PACK_COUNT) {
121 		message("pack too full", 1);
122 		return((object *) 0);
123 	}
124 	dungeon[row][col] &= ~(OBJECT);
125 	take_from_pack(obj, &level_objects);
126 	obj = add_to_pack(obj, &rogue.pack, 1);
127 	obj->picked_up = 1;
128 	return(obj);
129 }
130 
131 drop()
132 {
133 	object *obj, *new;
134 	short ch;
135 	char desc[DCOLS];
136 
137 	if (dungeon[rogue.row][rogue.col] & (OBJECT | STAIRS | TRAP)) {
138 		message("there's already something there", 0);
139 		return;
140 	}
141 	if (!rogue.pack.next_object) {
142 		message("you have nothing to drop", 0);
143 		return;
144 	}
145 	if ((ch = pack_letter("drop what?", ALL_OBJECTS)) == CANCEL) {
146 		return;
147 	}
148 	if (!(obj = get_letter_object(ch))) {
149 		message("no such item.", 0);
150 		return;
151 	}
152 	if (obj->in_use_flags & BEING_WIELDED) {
153 		if (obj->is_cursed) {
154 			message(curse_message, 0);
155 			return;
156 		}
157 		unwield(rogue.weapon);
158 	} else if (obj->in_use_flags & BEING_WORN) {
159 		if (obj->is_cursed) {
160 			message(curse_message, 0);
161 			return;
162 		}
163 		mv_aquatars();
164 		unwear(rogue.armor);
165 		print_stats(STAT_ARMOR);
166 	} else if (obj->in_use_flags & ON_EITHER_HAND) {
167 		if (obj->is_cursed) {
168 			message(curse_message, 0);
169 			return;
170 		}
171 		un_put_on(obj);
172 	}
173 	obj->row = rogue.row;
174 	obj->col = rogue.col;
175 
176 	if ((obj->quantity > 1) && (obj->what_is != WEAPON)) {
177 		obj->quantity--;
178 		new = alloc_object();
179 		*new = *obj;
180 		new->quantity = 1;
181 		obj = new;
182 	} else {
183 		obj->ichar = 'L';
184 		take_from_pack(obj, &rogue.pack);
185 	}
186 	place_at(obj, rogue.row, rogue.col);
187 	(void) strcpy(desc, "dropped ");
188 	get_desc(obj, desc+8);
189 	message(desc, 0);
190 	(void) reg_move();
191 }
192 
193 object *
194 check_duplicate(obj, pack)
195 object *obj, *pack;
196 {
197 	object *op;
198 
199 	if (!(obj->what_is & (WEAPON | FOOD | SCROL | POTION))) {
200 		return(0);
201 	}
202 	if ((obj->what_is == FOOD) && (obj->which_kind == FRUIT)) {
203 		return(0);
204 	}
205 	op = pack->next_object;
206 
207 	while (op) {
208 		if ((op->what_is == obj->what_is) &&
209 			(op->which_kind == obj->which_kind)) {
210 
211 			if ((obj->what_is != WEAPON) ||
212 			((obj->what_is == WEAPON) &&
213 			((obj->which_kind == ARROW) ||
214 			(obj->which_kind == DAGGER) ||
215 			(obj->which_kind == DART) ||
216 			(obj->which_kind == SHURIKEN)) &&
217 			(obj->quiver == op->quiver))) {
218 				op->quantity += obj->quantity;
219 				return(op);
220 			}
221 		}
222 		op = op->next_object;
223 	}
224 	return(0);
225 }
226 
227 next_avail_ichar()
228 {
229 	register object *obj;
230 	register i;
231 	boolean ichars[26];
232 
233 	for (i = 0; i < 26; i++) {
234 		ichars[i] = 0;
235 	}
236 	obj = rogue.pack.next_object;
237 	while (obj) {
238 		ichars[(obj->ichar - 'a')] = 1;
239 		obj = obj->next_object;
240 	}
241 	for (i = 0; i < 26; i++) {
242 		if (!ichars[i]) {
243 			return(i + 'a');
244 		}
245 	}
246 	return('?');
247 }
248 
249 wait_for_ack()
250 {
251 	while (rgetchar() != ' ') ;
252 }
253 
254 pack_letter(prompt, mask)
255 char *prompt;
256 unsigned short mask;
257 {
258 	short ch;
259 	unsigned short tmask = mask;
260 
261 	if (!mask_pack(&rogue.pack, mask)) {
262 		message("nothing appropriate", 0);
263 		return(CANCEL);
264 	}
265 	for (;;) {
266 
267 		message(prompt, 0);
268 
269 		for (;;) {
270 			ch = rgetchar();
271 			if (!is_pack_letter(&ch, &mask)) {
272 				sound_bell();
273 			} else {
274 				break;
275 			}
276 		}
277 
278 		if (ch == LIST) {
279 			check_message();
280 			inventory(&rogue.pack, mask);
281 		} else {
282 			break;
283 		}
284 		mask = tmask;
285 	}
286 	check_message();
287 	return(ch);
288 }
289 
290 take_off()
291 {
292 	char desc[DCOLS];
293 	object *obj;
294 
295 	if (rogue.armor) {
296 		if (rogue.armor->is_cursed) {
297 			message(curse_message, 0);
298 		} else {
299 			mv_aquatars();
300 			obj = rogue.armor;
301 			unwear(rogue.armor);
302 			(void) strcpy(desc, "was wearing ");
303 			get_desc(obj, desc+12);
304 			message(desc, 0);
305 			print_stats(STAT_ARMOR);
306 			(void) reg_move();
307 		}
308 	} else {
309 		message("not wearing any", 0);
310 	}
311 }
312 
313 wear()
314 {
315 	short ch;
316 	register object *obj;
317 	char desc[DCOLS];
318 
319 	if (rogue.armor) {
320 		message("your already wearing some", 0);
321 		return;
322 	}
323 	ch = pack_letter("wear what?", ARMOR);
324 
325 	if (ch == CANCEL) {
326 		return;
327 	}
328 	if (!(obj = get_letter_object(ch))) {
329 		message("no such item.", 0);
330 		return;
331 	}
332 	if (obj->what_is != ARMOR) {
333 		message("you can't wear that", 0);
334 		return;
335 	}
336 	obj->identified = 1;
337 	(void) strcpy(desc, "wearing ");
338 	get_desc(obj, desc + 8);
339 	message(desc, 0);
340 	do_wear(obj);
341 	print_stats(STAT_ARMOR);
342 	(void) reg_move();
343 }
344 
345 unwear(obj)
346 object *obj;
347 {
348 	if (obj) {
349 		obj->in_use_flags &= (~BEING_WORN);
350 	}
351 	rogue.armor = (object *) 0;
352 }
353 
354 do_wear(obj)
355 object *obj;
356 {
357 	rogue.armor = obj;
358 	obj->in_use_flags |= BEING_WORN;
359 	obj->identified = 1;
360 }
361 
362 wield()
363 {
364 	short ch;
365 	register object *obj;
366 	char desc[DCOLS];
367 
368 	if (rogue.weapon && rogue.weapon->is_cursed) {
369 		message(curse_message, 0);
370 		return;
371 	}
372 	ch = pack_letter("wield what?", WEAPON);
373 
374 	if (ch == CANCEL) {
375 		return;
376 	}
377 	if (!(obj = get_letter_object(ch))) {
378 		message("No such item.", 0);
379 		return;
380 	}
381 	if (obj->what_is & (ARMOR | RING)) {
382 		sprintf(desc, "you can't wield %s",
383 			((obj->what_is == ARMOR) ? "armor" : "rings"));
384 		message(desc, 0);
385 		return;
386 	}
387 	if (obj->in_use_flags & BEING_WIELDED) {
388 		message("in use", 0);
389 	} else {
390 		unwield(rogue.weapon);
391 		(void) strcpy(desc, "wielding ");
392 		get_desc(obj, desc + 9);
393 		message(desc, 0);
394 		do_wield(obj);
395 		(void) reg_move();
396 	}
397 }
398 
399 do_wield(obj)
400 object *obj;
401 {
402 	rogue.weapon = obj;
403 	obj->in_use_flags |= BEING_WIELDED;
404 }
405 
406 unwield(obj)
407 object *obj;
408 {
409 	if (obj) {
410 		obj->in_use_flags &= (~BEING_WIELDED);
411 	}
412 	rogue.weapon = (object *) 0;
413 }
414 
415 call_it()
416 {
417 	short ch;
418 	register object *obj;
419 	struct id *id_table;
420 	char buf[MAX_TITLE_LENGTH+2];
421 
422 	ch = pack_letter("call what?", (SCROL | POTION | WAND | RING));
423 
424 	if (ch == CANCEL) {
425 		return;
426 	}
427 	if (!(obj = get_letter_object(ch))) {
428 		message("no such item.", 0);
429 		return;
430 	}
431 	if (!(obj->what_is & (SCROL | POTION | WAND | RING))) {
432 		message("surely you already know what that's called", 0);
433 		return;
434 	}
435 	id_table = get_id_table(obj);
436 
437 	if (get_input_line("call it:","",buf,id_table[obj->which_kind].title,1,1)) {
438 		id_table[obj->which_kind].id_status = CALLED;
439 		(void) strcpy(id_table[obj->which_kind].title, buf);
440 	}
441 }
442 
443 pack_count(new_obj)
444 object *new_obj;
445 {
446 	object *obj;
447 	short count = 0;
448 
449 	obj = rogue.pack.next_object;
450 
451 	while (obj) {
452 		if (obj->what_is != WEAPON) {
453 			count += obj->quantity;
454 		} else if (!new_obj) {
455 			count++;
456 		} else if ((new_obj->what_is != WEAPON) ||
457 			((obj->which_kind != ARROW) &&
458 			(obj->which_kind != DAGGER) &&
459 			(obj->which_kind != DART) &&
460 			(obj->which_kind != SHURIKEN)) ||
461 			(new_obj->which_kind != obj->which_kind) ||
462 			(obj->quiver != new_obj->quiver)) {
463 			count++;
464 		}
465 		obj = obj->next_object;
466 	}
467 	return(count);
468 }
469 
470 boolean
471 mask_pack(pack, mask)
472 object *pack;
473 unsigned short mask;
474 {
475 	while (pack->next_object) {
476 		pack = pack->next_object;
477 		if (pack->what_is & mask) {
478 			return(1);
479 		}
480 	}
481 	return(0);
482 }
483 
484 is_pack_letter(c, mask)
485 short *c;
486 unsigned short *mask;
487 {
488 	if (((*c == '?') || (*c == '!') || (*c == ':') || (*c == '=') ||
489 		(*c == ')') || (*c == ']') || (*c == '/') || (*c == ','))) {
490 		switch(*c) {
491 		case '?':
492 			*mask = SCROL;
493 			break;
494 		case '!':
495 			*mask = POTION;
496 			break;
497 		case ':':
498 			*mask = FOOD;
499 			break;
500 		case ')':
501 			*mask = WEAPON;
502 			break;
503 		case ']':
504 			*mask = ARMOR;
505 			break;
506 		case '/':
507 			*mask = WAND;
508 			break;
509 		case '=':
510 			*mask = RING;
511 			break;
512 		case ',':
513 			*mask = AMULET;
514 			break;
515 		}
516 		*c = LIST;
517 		return(1);
518 	}
519 	return(((*c >= 'a') && (*c <= 'z')) || (*c == CANCEL) || (*c == LIST));
520 }
521 
522 has_amulet()
523 {
524 	return(mask_pack(&rogue.pack, AMULET));
525 }
526 
527 kick_into_pack()
528 {
529 	object *obj;
530 	char desc[DCOLS];
531 	short n, stat;
532 
533 	if (!(dungeon[rogue.row][rogue.col] & OBJECT)) {
534 		message("nothing here", 0);
535 	} else {
536 		if (obj = pick_up(rogue.row, rogue.col, &stat)) {
537 			get_desc(obj, desc);
538 			if (obj->what_is == GOLD) {
539 				message(desc, 0);
540 				free_object(obj);
541 			} else {
542 				n = strlen(desc);
543 				desc[n] = '(';
544 				desc[n+1] = obj->ichar;
545 				desc[n+2] = ')';
546 				desc[n+3] = 0;
547 				message(desc, 0);
548 			}
549 		}
550 		if (obj || (!stat)) {
551 			(void) reg_move();
552 		}
553 	}
554 }
555