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