1 /*
2  * Contains functions for dealing with things like potions, scrolls,
3  * and other items.
4  *
5  * things.c	1.4 (AI Design)	12/14/84
6  */
7 
8 #include "rogue.h"
9 #include "curses.h"
10 
11 /*
12  * inv_name:
13  *	Return the name of something as it would appear in an
14  *	inventory.
15  */
16 char *
17 inv_name(obj, drop)
18 register THING *obj;
19 bool drop;
20 {
21 	register int which = obj->o_which;
22     register char *pb;
23 
24     pb = prbuf;
25     switch (obj->o_type)
26     {
27 	when SCROLL:
28 	    if (obj->o_count == 1) {
29 			strcpy(pb, "A scroll ");
30 			pb = &prbuf[9];
31 	    } else {
32 			sprintf(pb, "%d scrolls ", obj->o_count);
33 			pb = &prbuf[strlen(prbuf)];
34 	    }
35 	    if (s_know[which])
36 			sprintf(pb, "of %s", s_magic[which].mi_name);
37 	    else if (*s_guess[which])
38 			sprintf(pb, "called %s", s_guess[which]);
39 	    else 
40 			chopmsg(pb, "titled '%.17s'","titled '%s'", &s_names[which]);
41 	when POTION:
42 	    if (obj->o_count == 1)
43 	    {
44 		strcpy(pb, "A potion ");
45 		pb = &prbuf[9];
46 	    }
47 	    else
48 	    {
49 		sprintf(pb, "%d potions ", obj->o_count);
50 		pb = &pb[strlen(prbuf)];
51 	    }
52 	    if (p_know[which]) {
53 		chopmsg(pb, "of %s", "of %s(%s)", 
54 		   p_magic[which].mi_name, p_colors[which]);
55             }
56 	    else if (*p_guess[which]) {
57 		chopmsg(pb, "called %s","called %s(%s)", p_guess[which],
58 		    p_colors[which]);
59             }
60 	    else if (obj->o_count == 1)
61 		sprintf(prbuf, "A%s %s potion", vowelstr(p_colors[which]),
62 		    p_colors[which]);
63 	    else
64 		sprintf(prbuf, "%d %s potions", obj->o_count,
65 		    p_colors[which]);
66 	when FOOD:
67 	    if (which == 1)
68 		if (obj->o_count == 1)
69 		    sprintf(pb, "A%s %s", vowelstr(fruit), fruit);
70 		else
71 		    sprintf(pb, "%d %ss", obj->o_count, fruit);
72 	    else
73 		if (obj->o_count == 1)
74 		    strcpy(pb, "Some food");
75 		else
76 		    sprintf(pb, "%d rations of food", obj->o_count);
77 	when WEAPON:
78 	    if (obj->o_count > 1)
79 		sprintf(pb, "%d ", obj->o_count);
80         else
81 		sprintf(pb, "A%s ", vowelstr(w_names[which]));
82 	    pb = &prbuf[strlen(prbuf)];
83 	    if (obj->o_flags & ISKNOW)
84 		sprintf(pb, "%s %s", num(obj->o_hplus, obj->o_dplus, WEAPON),
85 		    w_names[which]);
86 	    else
87 		sprintf(pb, "%s", w_names[which]);
88 	    if (obj->o_count > 1)
89 		strcat(pb, "s");
90 	    if (obj->o_enemy && obj->o_flags & ISREVEAL)
91 	    {
92 		strcat(pb, " of ");
93 		strcat(pb, monsters[obj->o_enemy-'A'].m_name);
94 		strcat(pb, " slaying");
95 	    }
96 	when ARMOR:
97 	    if (obj->o_flags & ISKNOW)
98 		    chopmsg(pb, "%s %s","%s %s [armor class %d]",
99 		        num(a_class[which] - obj->o_ac, 0, ARMOR),
100 		        a_names[which], -(obj->o_ac-11));
101 	    else
102 			sprintf(pb, "%s", a_names[which]);
103 	when AMULET:
104 	    strcpy(pb, "The Amulet of Yendor");
105 	when STICK:
106 	    sprintf(pb, "A%s %s ", vowelstr(ws_type[which]),
107 		ws_type[which]);
108 	    pb = &prbuf[strlen(prbuf)];
109 	    if (ws_know[which]) 
110 			chopmsg(pb, "of %s%s", "of %s%s(%s)", 
111 			    ws_magic[which].mi_name,
112 		        charge_str(obj), ws_made[which]);
113         else if (*ws_guess[which]) 
114 	        chopmsg(pb, "called %s", "called %s(%s)", ws_guess[which],
115 			    ws_made[which]);
116 	    else
117 		sprintf(pb = &prbuf[2], "%s %s", ws_made[which],
118 		    ws_type[which]);
119         when RING:
120 	    if (r_know[which]) 
121 	   	    chopmsg(pb, "A%s ring of %s", "A%s ring of %s(%s)", ring_num(obj),
122 		        r_magic[which].mi_name, r_stones[which]);
123 	    else if (*r_guess[which])
124 	        chopmsg(pb, "A ring called %s", "A ring called %s(%s)",
125 		        r_guess[which], r_stones[which]);
126 	    else
127 		sprintf(pb, "A%s %s ring", vowelstr(r_stones[which]),
128 		    r_stones[which]);
129 #ifdef DEBUG
130 	when GOLD:
131 		sprintf(pb, "Gold at %d,%d", obj->o_pos.y, obj->o_pos.x);
132 	otherwise:
133 		debug("Picked up someting bizzare %s", unctrl(obj->o_type));
134 	    sprintf(pb, "Something bizarre %c(%d)", obj->o_type, obj->o_type);
135 #endif
136     }
137     if (obj == cur_armor)
138 		strcat(pb, " (being worn)");
139     if (obj == cur_weapon)
140 		strcat(pb, " (weapon in hand)");
141     if (obj == cur_ring[LEFT])
142 		strcat(pb, " (on left hand)");
143     else if (obj == cur_ring[RIGHT])
144 		strcat(pb, " (on right hand)");
145     if (drop && isupper(prbuf[0]))
146 		prbuf[0] = tolower(prbuf[0]);
147     else if (!drop && islower(*prbuf))
148 		*prbuf = toupper(*prbuf);
149     return prbuf;
150 }
151 
152 chopmsg(s,shmsg,lnmsg,arg1,arg2,arg3)
153     char *s, *shmsg, *lnmsg;
154     int arg1, arg2, arg3;
155 {
156    	sprintf(s,lnmsg,arg1,arg2,arg3);
157     if (terse || expert)
158     	sprintf(s,shmsg,arg1,arg2,arg3);
159 }
160 
161 /*
162  * drop:
163  *	Put something down
164  */
165 drop()
166 {
167     register byte ch;
168     register THING *nobj, *op;
169 
170     ch = chat(hero.y, hero.x);
171     if (ch != FLOOR && ch != PASSAGE)
172     {
173 	msg("there is something there already");
174 	return;
175     }
176     if ((op = get_item("drop", 0)) == NULL)
177 	return;
178     if (!can_drop(op))
179 	return;
180     /*
181      * Take it out of the pack
182      */
183     if (op->o_count >= 2 && op->o_type != WEAPON)
184     {
185 	if ((nobj = new_item()) == NULL)
186 	{
187 	    msg("%sit appears to be stuck in your pack!",noterse("can't drop it, "));
188 	    return;
189 	}
190 	op->o_count--;
191 	bcopy(*nobj,*op);
192 	nobj->o_count = 1;
193 	op = nobj;
194 	if (op->o_group != 0)
195 		inpack++;
196     }
197     else
198 	detach(pack, op);
199     inpack--;
200     /*
201      * Link it into the level object list
202      */
203     attach(lvl_obj, op);
204     chat(hero.y, hero.x) = op->o_type;
205     bcopy(op->o_pos,hero);
206     if (op->o_type == AMULET)
207 	amulet = FALSE;
208     msg("dropped %s", inv_name(op, TRUE));
209 }
210 
211 /*
212  * can_drop:
213  *	Do special checks for dropping or unweilding|unwearing|unringing
214  */
215 can_drop(op)
216 register THING *op;
217 {
218     if (op == NULL)
219 		return TRUE;
220     if (op != cur_armor && op != cur_weapon
221 		&& op != cur_ring[LEFT] && op != cur_ring[RIGHT])
222 	    return TRUE;
223     if (op->o_flags & ISCURSED) {
224 		msg("you can't.  It appears to be cursed");
225 		return FALSE;
226     }
227     if (op == cur_weapon)
228 		cur_weapon = NULL;
229     else if (op == cur_armor) {
230 		waste_time();
231 		cur_armor = NULL;
232     } else {
233 		register int hand;
234 
235 		if (op != cur_ring[hand = LEFT])
236 			if (op != cur_ring[hand = RIGHT]) {
237 #ifdef DEBUG
238 				debug("Candrop called with funny thing");
239 #endif
240 				return TRUE;
241 			}
242 		cur_ring[hand] = NULL;
243 		switch (op->o_which) {
244 	    case R_ADDSTR:
245 			chg_str(-op->o_ac);
246 			break;
247 	    case R_SEEINVIS:
248 			unsee();
249 			extinguish(unsee);
250 			break;
251 		}
252     }
253     return TRUE;
254 }
255 
256 /*
257  * new_thing:
258  *	Return a new thing
259  */
260 THING *
261 new_thing()
262 {
263     register THING *cur;
264     register int j, k;
265 
266     if ((cur = new_item()) == NULL)
267     	return NULL;
268     cur->o_hplus = cur->o_dplus = 0;
269     cur->o_damage = cur->o_hurldmg = "0d0";
270     cur->o_ac = 11;
271     cur->o_count = 1;
272     cur->o_group = 0;
273     cur->o_flags = 0;
274     cur->o_enemy = 0;
275     /*
276      * Decide what kind of object it will be
277      * If we haven't had food for a while, let it be food.
278      */
279     switch (no_food > 3 ? 2 : pick_one(things, NUMTHINGS))
280     {
281 	when 0:
282 	    cur->o_type = POTION;
283 	    cur->o_which = pick_one(p_magic, MAXPOTIONS);
284 	when 1:
285 	    cur->o_type = SCROLL;
286 	    cur->o_which = pick_one(s_magic, MAXSCROLLS);
287 	when 2:
288 	    no_food = 0;
289 	    cur->o_type = FOOD;
290 	    if (rnd(10) != 0)
291 		cur->o_which = 0;
292 	    else
293 		cur->o_which = 1;
294 	when 3:
295 	    cur->o_type = WEAPON;
296 	    cur->o_which = rnd(MAXWEAPONS);
297 	    init_weapon(cur, cur->o_which);
298 	    if ((k = rnd(100)) < 10)
299 	    {
300 		cur->o_flags |= ISCURSED;
301 		cur->o_hplus -= rnd(3) + 1;
302 	    }
303 	    else if (k < 15)
304 		cur->o_hplus += rnd(3) + 1;
305 	when 4:
306 	    cur->o_type = ARMOR;
307 	    for (j = 0, k = rnd(100); j < MAXARMORS; j++)
308 		if (k < a_chances[j])
309 		    break;
310 #ifdef DEBUG
311 	    if (j == MAXARMORS)
312 	    {
313 		debug("Picked a bad armor %d", k);
314 		j = 0;
315 	    }
316 #endif
317 	    cur->o_which = j;
318 	    cur->o_ac = a_class[j];
319 	    if ((k = rnd(100)) < 20)
320 	    {
321 		cur->o_flags |= ISCURSED;
322 		cur->o_ac += rnd(3) + 1;
323 	    }
324 	    else if (k < 28)
325 		cur->o_ac -= rnd(3) + 1;
326 	when 5:
327 	    cur->o_type = RING;
328 	    cur->o_which = pick_one(r_magic, MAXRINGS);
329 	    switch (cur->o_which)
330 	    {
331 		when R_ADDSTR:
332 		case R_PROTECT:
333 		case R_ADDHIT:
334 		case R_ADDDAM:
335 		    if ((cur->o_ac = rnd(3)) == 0)
336 		    {
337 			cur->o_ac = -1;
338 			cur->o_flags |= ISCURSED;
339 		    }
340 		when R_AGGR:
341 		case R_TELEPORT:
342 		    cur->o_flags |= ISCURSED;
343 	    }
344 	when 6:
345 	    cur->o_type = STICK;
346 	    cur->o_which = pick_one(ws_magic, MAXSTICKS);
347 	    fix_stick(cur);
348 #ifdef DEBUG
349 	otherwise:
350 	    debug("Picked a bad kind of object");
351 	    wait_for(' ');
352 #endif
353     }
354     return cur;
355 }
356 
357 /*
358  * pick_one:
359  *	Pick an item out of a list of nitems possible magic items
360  */
361 pick_one(magic, nitems)
362 register struct magic_item *magic;
363 int nitems;
364 {
365     register struct magic_item *end;
366     register int i;
367     register struct magic_item *start;
368 
369     start = magic;
370     for (end = &magic[nitems], i = rnd(100); magic < end; magic++)
371 	if (i < magic->mi_prob)
372 	    break;
373     if (magic == end)
374     {
375 #ifdef DEBUG
376 	if (wizard)
377 	{
378 	    msg("bad pick_one: %d from %d items", i, nitems);
379 	    for (magic = start; magic < end; magic++)
380 		msg("%s: %d%%", magic->mi_name, magic->mi_prob);
381 	}
382 #endif
383 	magic = start;
384     }
385     return magic - start;
386 }
387 
388 /*
389  * discovered:
390  *	list what the player has discovered in this game of a certain type
391  */
392 static int line_cnt = 0;
393 
394 static bool newpage = FALSE;
395 
396 static char *lastfmt, *lastarg;
397 
398 discovered()
399 {
400 	print_disc(POTION);
401 	add_line(nullstr, " ");
402 	print_disc(SCROLL);
403 	add_line(nullstr, " ");
404 	print_disc(RING);
405 	add_line(nullstr, " ");
406 	print_disc(STICK);
407 	end_line(nullstr);
408 }
409 
410 /*
411  * print_disc:
412  *	Print what we've discovered of type 'type'
413  */
414 
415 #define MAX(a,b,c,d) (a>b?(a>c?(a>d?a:d):(c>d?c:d)):(b>c?(b>d?b:d):(c>d?c:d)))
416 
417 print_disc(type)
418 byte type;
419 {
420     register bool *know;
421     register char **guess;
422     register int i, maxnum, num_found;
423     static THING obj;
424     static short order[MAX(MAXSCROLLS, MAXPOTIONS, MAXRINGS, MAXSTICKS)];
425 
426     switch (type)
427     {
428 	case SCROLL:
429 	    maxnum = MAXSCROLLS;
430 	    know = s_know;
431 	    guess = s_guess;
432 	    break;
433 	case POTION:
434 	    maxnum = MAXPOTIONS;
435 	    know = p_know;
436 	    guess = p_guess;
437 	    break;
438 	case RING:
439 	    maxnum = MAXRINGS;
440 	    know = r_know;
441 	    guess = r_guess;
442 	    break;
443 	case STICK:
444 	    maxnum = MAXSTICKS;
445 	    know = ws_know;
446 	    guess = ws_guess;
447 	    break;
448     }
449     set_order(order, maxnum);
450     obj.o_count = 1;
451     obj.o_flags = 0;
452     num_found = 0;
453     for (i = 0; i < maxnum; i++)
454 	if (know[order[i]] || *guess[order[i]])
455 	{
456 	    obj.o_type = type;
457 	    obj.o_which = order[i];
458 	    add_line(nullstr, "%s", inv_name(&obj, FALSE));
459 	    num_found++;
460 	}
461     if (num_found == 0)
462 	add_line(nullstr, nothing(type));
463 }
464 
465 /*
466  * set_order:
467  *	Set up order for list
468  */
469 set_order(order, numthings)
470 short *order;
471 int numthings;
472 {
473     register int i, r, t;
474 
475     for (i = 0; i< numthings; i++)
476 	order[i] = i;
477 
478     for (i = numthings; i > 0; i--)
479     {
480 	r = rnd(i);
481 	t = order[i - 1];
482 	order[i - 1] = order[r];
483 	order[r] = t;
484     }
485 }
486 
487 /*
488  * add_line:
489  *	Add a line to the list of discoveries
490  */
491 /* VARARGS1 */
492 add_line(use, fmt, arg)
493 char *use, *fmt, *arg;
494 {
495     int x, y;
496     register int retchar = ' ';
497     if (line_cnt == 0)
498     {
499         wdump(0);
500         clear();
501     }
502     if (line_cnt >= LINES - 1 || fmt == NULL)
503     {
504 	move(LINES-1, 0);
505 	if (*use)
506 	    printw("-Select item to %s. Esc to cancel-", use);
507 	else
508 	    addstr("-Press space to continue-");
509 	do
510 	    retchar = readchar();
511 	while (retchar != ESCAPE && retchar != ' ' && (!islower(retchar))) ;
512 	clear();
513 	newpage = TRUE;
514 	line_cnt = 0;
515     }
516     if (fmt != NULL && !(line_cnt == 0 && *fmt == '\0'))
517     {
518 	move(line_cnt, 0);
519 	printw(fmt, arg);
520 	getxy(&x,&y);
521 	/*
522 	 * if the line wrapped but nothing was printed on this
523 	 * line you might as well use it for the next item
524 	 */
525 	if (y!=0)
526 	    line_cnt = x + 1;
527 	lastfmt = fmt;
528 	lastarg = arg;
529     }
530     return(retchar);
531 }
532 
533 /*
534  * end_line:
535  *	End the list of lines
536  */
537 end_line(use)
538 char *use;
539 {
540     register int retchar;
541 
542     retchar = add_line(use, NULL);
543     wrestor(0);
544     line_cnt = 0;
545     newpage = FALSE;
546     return(retchar);
547 }
548 
549 /*
550  * nothing:
551  *	Set up prbuf so that message for "nothing found" is there
552  */
553 char *
554 nothing(type)
555 register byte type;
556 {
557     register char *sp, *tystr;
558 
559     sprintf(prbuf, "Haven't discovered anything");
560     if (terse)
561     	sprintf(prbuf,"Nothing");
562     sp = &prbuf[strlen(prbuf)];
563     switch (type)
564     {
565         when POTION: tystr = "potion";
566         when SCROLL: tystr = "scroll";
567         when RING: tystr = "ring";
568         when STICK: tystr = "stick";
569     }
570     sprintf(sp, " about any %ss", tystr);
571     return prbuf;
572 }
573 