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