xref: /original-bsd/games/rogue/pack.c (revision 7c3db03c)
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.3 (Berkeley) 06/01/90";
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 			inventory(&rogue.pack, mask);
271 		} else {
272 			break;
273 		}
274 		mask = tmask;
275 	}
276 	check_message();
277 	return(ch);
278 }
279 
280 take_off()
281 {
282 	char desc[DCOLS];
283 	object *obj;
284 
285 	if (rogue.armor) {
286 		if (rogue.armor->is_cursed) {
287 			message(curse_message, 0);
288 		} else {
289 			mv_aquatars();
290 			obj = rogue.armor;
291 			unwear(rogue.armor);
292 			(void) strcpy(desc, "was wearing ");
293 			get_desc(obj, desc+12);
294 			message(desc, 0);
295 			print_stats(STAT_ARMOR);
296 			(void) reg_move();
297 		}
298 	} else {
299 		message("not wearing any", 0);
300 	}
301 }
302 
303 wear()
304 {
305 	short ch;
306 	register object *obj;
307 	char desc[DCOLS];
308 
309 	if (rogue.armor) {
310 		message("your already wearing some", 0);
311 		return;
312 	}
313 	ch = pack_letter("wear what?", ARMOR);
314 
315 	if (ch == CANCEL) {
316 		return;
317 	}
318 	if (!(obj = get_letter_object(ch))) {
319 		message("no such item.", 0);
320 		return;
321 	}
322 	if (obj->what_is != ARMOR) {
323 		message("you can't wear that", 0);
324 		return;
325 	}
326 	obj->identified = 1;
327 	(void) strcpy(desc, "wearing ");
328 	get_desc(obj, desc + 8);
329 	message(desc, 0);
330 	do_wear(obj);
331 	print_stats(STAT_ARMOR);
332 	(void) reg_move();
333 }
334 
335 unwear(obj)
336 object *obj;
337 {
338 	if (obj) {
339 		obj->in_use_flags &= (~BEING_WORN);
340 	}
341 	rogue.armor = (object *) 0;
342 }
343 
344 do_wear(obj)
345 object *obj;
346 {
347 	rogue.armor = obj;
348 	obj->in_use_flags |= BEING_WORN;
349 	obj->identified = 1;
350 }
351 
352 wield()
353 {
354 	short ch;
355 	register object *obj;
356 	char desc[DCOLS];
357 
358 	if (rogue.weapon && rogue.weapon->is_cursed) {
359 		message(curse_message, 0);
360 		return;
361 	}
362 	ch = pack_letter("wield what?", WEAPON);
363 
364 	if (ch == CANCEL) {
365 		return;
366 	}
367 	if (!(obj = get_letter_object(ch))) {
368 		message("No such item.", 0);
369 		return;
370 	}
371 	if (obj->what_is & (ARMOR | RING)) {
372 		sprintf(desc, "you can't wield %s",
373 			((obj->what_is == ARMOR) ? "armor" : "rings"));
374 		message(desc, 0);
375 		return;
376 	}
377 	if (obj->in_use_flags & BEING_WIELDED) {
378 		message("in use", 0);
379 	} else {
380 		unwield(rogue.weapon);
381 		(void) strcpy(desc, "wielding ");
382 		get_desc(obj, desc + 9);
383 		message(desc, 0);
384 		do_wield(obj);
385 		(void) reg_move();
386 	}
387 }
388 
389 do_wield(obj)
390 object *obj;
391 {
392 	rogue.weapon = obj;
393 	obj->in_use_flags |= BEING_WIELDED;
394 }
395 
396 unwield(obj)
397 object *obj;
398 {
399 	if (obj) {
400 		obj->in_use_flags &= (~BEING_WIELDED);
401 	}
402 	rogue.weapon = (object *) 0;
403 }
404 
405 call_it()
406 {
407 	short ch;
408 	register object *obj;
409 	struct id *id_table;
410 	char buf[MAX_TITLE_LENGTH+2];
411 
412 	ch = pack_letter("call what?", (SCROL | POTION | WAND | RING));
413 
414 	if (ch == CANCEL) {
415 		return;
416 	}
417 	if (!(obj = get_letter_object(ch))) {
418 		message("no such item.", 0);
419 		return;
420 	}
421 	if (!(obj->what_is & (SCROL | POTION | WAND | RING))) {
422 		message("surely you already know what that's called", 0);
423 		return;
424 	}
425 	id_table = get_id_table(obj);
426 
427 	if (get_input_line("call it:","",buf,id_table[obj->which_kind].title,1,1)) {
428 		id_table[obj->which_kind].id_status = CALLED;
429 		(void) strcpy(id_table[obj->which_kind].title, buf);
430 	}
431 }
432 
433 pack_count(new_obj)
434 object *new_obj;
435 {
436 	object *obj;
437 	short count = 0;
438 
439 	obj = rogue.pack.next_object;
440 
441 	while (obj) {
442 		if (obj->what_is != WEAPON) {
443 			count += obj->quantity;
444 		} else if (!new_obj) {
445 			count++;
446 		} else if ((new_obj->what_is != WEAPON) ||
447 			((obj->which_kind != ARROW) &&
448 			(obj->which_kind != DAGGER) &&
449 			(obj->which_kind != DART) &&
450 			(obj->which_kind != SHURIKEN)) ||
451 			(new_obj->which_kind != obj->which_kind) ||
452 			(obj->quiver != new_obj->quiver)) {
453 			count++;
454 		}
455 		obj = obj->next_object;
456 	}
457 	return(count);
458 }
459 
460 boolean
461 mask_pack(pack, mask)
462 object *pack;
463 unsigned short mask;
464 {
465 	while (pack->next_object) {
466 		pack = pack->next_object;
467 		if (pack->what_is & mask) {
468 			return(1);
469 		}
470 	}
471 	return(0);
472 }
473 
474 is_pack_letter(c, mask)
475 short *c;
476 unsigned short *mask;
477 {
478 	if (((*c == '?') || (*c == '!') || (*c == ':') || (*c == '=') ||
479 		(*c == ')') || (*c == ']') || (*c == '/') || (*c == ','))) {
480 		switch(*c) {
481 		case '?':
482 			*mask = SCROL;
483 			break;
484 		case '!':
485 			*mask = POTION;
486 			break;
487 		case ':':
488 			*mask = FOOD;
489 			break;
490 		case ')':
491 			*mask = WEAPON;
492 			break;
493 		case ']':
494 			*mask = ARMOR;
495 			break;
496 		case '/':
497 			*mask = WAND;
498 			break;
499 		case '=':
500 			*mask = RING;
501 			break;
502 		case ',':
503 			*mask = AMULET;
504 			break;
505 		}
506 		*c = LIST;
507 		return(1);
508 	}
509 	return(((*c >= 'a') && (*c <= 'z')) || (*c == CANCEL) || (*c == LIST));
510 }
511 
512 has_amulet()
513 {
514 	return(mask_pack(&rogue.pack, AMULET));
515 }
516 
517 kick_into_pack()
518 {
519 	object *obj;
520 	char desc[DCOLS];
521 	short n, stat;
522 
523 	if (!(dungeon[rogue.row][rogue.col] & OBJECT)) {
524 		message("nothing here", 0);
525 	} else {
526 		if (obj = pick_up(rogue.row, rogue.col, &stat)) {
527 			get_desc(obj, desc);
528 			if (obj->what_is == GOLD) {
529 				message(desc, 0);
530 				free_object(obj);
531 			} else {
532 				n = strlen(desc);
533 				desc[n] = '(';
534 				desc[n+1] = obj->ichar;
535 				desc[n+2] = ')';
536 				desc[n+3] = 0;
537 				message(desc, 0);
538 			}
539 		}
540 		if (obj || (!stat)) {
541 			(void) reg_move();
542 		}
543 	}
544 }
545