386BSD 0.1 development
[unix-history] / usr / othersrc / games / rogue / pack.c
CommitLineData
8bb0f55f
WJ
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
38static 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
55char *curse_message = "you can't, it appears to be cursed";
56
57extern short levitate;
58
59object *
60add_to_pack(obj, pack, condense)
61object *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
87take_from_pack(obj, pack)
88object *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
100object *
101pick_up(row, col, status)
102short *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
147drop()
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
209object *
210check_duplicate(obj, pack)
211object *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
243next_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
265wait_for_ack()
266{
267 while (rgetchar() != ' ') ;
268}
269
270pack_letter(prompt, mask)
271char *prompt;
272unsigned 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
306take_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
329wear()
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
361unwear(obj)
362object *obj;
363{
364 if (obj) {
365 obj->in_use_flags &= (~BEING_WORN);
366 }
367 rogue.armor = (object *) 0;
368}
369
370do_wear(obj)
371object *obj;
372{
373 rogue.armor = obj;
374 obj->in_use_flags |= BEING_WORN;
375 obj->identified = 1;
376}
377
378wield()
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
415do_wield(obj)
416object *obj;
417{
418 rogue.weapon = obj;
419 obj->in_use_flags |= BEING_WIELDED;
420}
421
422unwield(obj)
423object *obj;
424{
425 if (obj) {
426 obj->in_use_flags &= (~BEING_WIELDED);
427 }
428 rogue.weapon = (object *) 0;
429}
430
431call_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
459pack_count(new_obj)
460object *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
486boolean
487mask_pack(pack, mask)
488object *pack;
489unsigned 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
500is_pack_letter(c, mask)
501short *c;
502unsigned 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
538has_amulet()
539{
540 return(mask_pack(&rogue.pack, AMULET));
541}
542
543kick_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}