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