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