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