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