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