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