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