rogue

Ken Arnold's Rogue
git clone https://git.woozle.org/neale/rogue.git

Neale Pickett  ·  2011-10-13

rcopy.c

  1/*
  2 * Contains functions for dealing with things like potions, scrolls,
  3 * and other items.
  4 *
  5 * @(#)rcopy.c	4.53 (Berkeley) 02/05/99
  6 */
  7
  8#include <curses.h>
  9#ifdef	attron
 10#include <term.h>
 11#endif	attron
 12#include <ctype.h>
 13#include "netprot.h"
 14
 15/*
 16 * inv_name:
 17 *	Return the name of something as it would appear in an
 18 *	inventory.
 19 */
 20char *
 21inv_name(THING *obj, bool drop)
 22{
 23    char *pb;
 24    struct obj_info *op;
 25    char *sp;
 26    int which;
 27
 28    pb = Prbuf;
 29    which = obj->o_which;
 30    switch (obj->o_type)
 31    {
 32        when POTION:
 33	    nameit(obj, "potion", P_colors[which], &Pot_info[which], nullstr);
 34	when RING:
 35	    nameit(obj, "ring", R_stones[which], &Ring_info[which], ring_num);
 36	when STICK:
 37	    nameit(obj, Ws_type[which], Ws_made[which], &Ws_info[which], charge_str);
 38	when SCROLL:
 39	    if (obj->o_count == 1)
 40	    {
 41		strcpy(pb, "A scroll ");
 42		pb = &Prbuf[9];
 43	    }
 44	    else
 45	    {
 46		sprintf(pb, "%d scrolls ", obj->o_count);
 47		pb = &Prbuf[strlen(Prbuf)];
 48	    }
 49	    op = &Scr_info[which];
 50	    if (op->oi_know)
 51		sprintf(pb, "of %s", op->oi_name);
 52	    else if (op->oi_guess)
 53		sprintf(pb, "called %s", op->oi_guess);
 54	    else
 55		sprintf(pb, "titled '%s'", S_names[which]);
 56	when FOOD:
 57	    if (which == 1)
 58		if (obj->o_count == 1)
 59		    sprintf(pb, "A%s %s", vowelstr(Fruit), Fruit);
 60		else
 61		    sprintf(pb, "%d %ss", obj->o_count, Fruit);
 62	    else
 63		if (obj->o_count == 1)
 64		    strcpy(pb, "Some food");
 65		else
 66		    sprintf(pb, "%d rations of food", obj->o_count);
 67	when WEAPON:
 68	    sp = Weap_info[which].oi_name;
 69	    if (obj->o_count > 1)
 70		sprintf(pb, "%d ", obj->o_count);
 71	    else
 72		sprintf(pb, "A%s ", vowelstr(sp));
 73	    pb = &Prbuf[strlen(Prbuf)];
 74	    if (obj->o_flags & ISKNOW)
 75		sprintf(pb, "%s %s", num(obj->o_hplus,obj->o_dplus,WEAPON), sp);
 76	    else
 77		sprintf(pb, "%s", sp);
 78	    if (obj->o_count > 1)
 79		strcat(pb, "s");
 80	    if (obj->o_label != NULL)
 81	    {
 82		pb = &Prbuf[strlen(Prbuf)];
 83		sprintf(pb, " called %s", obj->o_label);
 84	    }
 85	when ARMOR:
 86	    sp = Arm_info[which].oi_name;
 87	    if (obj->o_flags & ISKNOW)
 88	    {
 89		sprintf(pb, "%s %s [",
 90		    num(A_class[which] - obj->o_arm, 0, ARMOR), sp);
 91		if (!Terse)
 92		    strcat(pb, "protection ");
 93		pb = &Prbuf[strlen(Prbuf)];
 94		sprintf(pb, "%d]", 10 - obj->o_arm);
 95	    }
 96	    else
 97		sprintf(pb, "%s", sp);
 98	    if (obj->o_label != NULL)
 99	    {
100		pb = &Prbuf[strlen(Prbuf)];
101		sprintf(pb, " called %s", obj->o_label);
102	    }
103	when AMULET:
104	    strcpy(pb, "The Amulet of Yendor");
105	when GOLD:
106	    sprintf(Prbuf, "%d Gold pieces", obj->o_goldval);
107#ifdef MASTER
108	otherwise:
109	    debug("Picked up something funny %s", unctrl(obj->o_type));
110	    sprintf(pb, "Something bizarre %s", unctrl(obj->o_type));
111#endif
112    }
113    if (Inv_describe)
114    {
115	if (obj == Cur_armor)
116	    strcat(pb, " (being worn)");
117	if (obj == Cur_weapon)
118	    strcat(pb, " (weapon in hand)");
119	if (obj == Cur_ring[LEFT])
120	    strcat(pb, " (on left hand)");
121	else if (obj == Cur_ring[RIGHT])
122	    strcat(pb, " (on right hand)");
123    }
124    if (drop && isupper(Prbuf[0]))
125	Prbuf[0] = tolower(Prbuf[0]);
126    else if (!drop && islower(*Prbuf))
127	*Prbuf = toupper(*Prbuf);
128    Prbuf[MAXSTR-1] = '\0';
129    return Prbuf;
130}
131
132/*
133 * drop:
134 *	Put something down
135 */
136void
137drop(void)
138{
139    char ch;
140    THING *obj;
141
142    ch = chat(Hero.y, Hero.x);
143    if (ch != FLOOR && ch != PASSAGE)
144    {
145	After = FALSE;
146	msg("there is something there already");
147	return;
148    }
149    if ((obj = get_item("drop", 0)) == NULL)
150	return;
151    if (!dropcheck(obj))
152	return;
153    obj = leave_pack(obj, TRUE, !ISMULT(obj->o_type));
154    /*
155     * Link it into the level object list
156     */
157    attach(Lvl_obj, obj);
158    chat(Hero.y, Hero.x) = obj->o_type;
159    flat(Hero.y, Hero.x) |= F_DROPPED;
160    obj->o_pos = Hero;
161    if (obj->o_type == AMULET)
162	Amulet = FALSE;
163    msg("dropped %s", inv_name(obj, TRUE));
164}
165
166/*
167 * dropcheck:
168 *	Do special checks for dropping or unweilding|unwearing|unringing
169 */
170bool
171dropcheck(THING *obj)
172{
173    if (obj == NULL)
174	return TRUE;
175    if (obj != Cur_armor && obj != Cur_weapon
176	&& obj != Cur_ring[LEFT] && obj != Cur_ring[RIGHT])
177	    return TRUE;
178    if (obj->o_flags & ISCURSED)
179    {
180	msg("you can't.  It appears to be cursed");
181	return FALSE;
182    }
183    if (obj == Cur_weapon)
184	Cur_weapon = NULL;
185    else if (obj == Cur_armor)
186    {
187	waste_time();
188	Cur_armor = NULL;
189    }
190    else
191    {
192	Cur_ring[obj == Cur_ring[LEFT] ? LEFT : RIGHT] = NULL;
193	switch (obj->o_which)
194	{
195	    case R_ADDSTR:
196		chg_str(-obj->o_arm);
197		break;
198	    case R_SEEINVIS:
199		unsee();
200		extinguish(unsee);
201		break;
202	}
203    }
204    return TRUE;
205}
206
207/*
208 * new_thing:
209 *	Return a new thing
210 */
211THING *
212new_thing(void)
213{
214    THING *cur;
215    int r;
216
217    cur = new_item();
218    cur->o_hplus = 0;
219    cur->o_dplus = 0;
220    cur->o_damage = cur->o_hurldmg = "0x0";
221    cur->o_arm = 11;
222    cur->o_count = 1;
223    cur->o_group = 0;
224    cur->o_flags = 0;
225    /*
226     * Decide what kind of object it will be
227     * If we haven't had food for a while, let it be food.
228     */
229    switch (No_food > 3 ? 2 : pick_one(Things, NUMTHINGS))
230    {
231	when 0:
232	    cur->o_type = POTION;
233	    cur->o_which = pick_one(Pot_info, MAXPOTIONS);
234	when 1:
235	    cur->o_type = SCROLL;
236	    cur->o_which = pick_one(Scr_info, MAXSCROLLS);
237	when 2:
238	    cur->o_type = FOOD;
239	    No_food = 0;
240	    if (rnd(10) != 0)
241		cur->o_which = 0;
242	    else
243		cur->o_which = 1;
244	when 3:
245	    init_weapon(cur, pick_one(Weap_info, MAXWEAPONS));
246	    if ((r = rnd(100)) < 10)
247	    {
248		cur->o_flags |= ISCURSED;
249		cur->o_hplus -= rnd(3) + 1;
250	    }
251	    else if (r < 15)
252		cur->o_hplus += rnd(3) + 1;
253	when 4:
254	    cur->o_type = ARMOR;
255	    cur->o_which = pick_one(Arm_info, MAXARMORS);
256	    cur->o_arm = A_class[cur->o_which];
257	    if ((r = rnd(100)) < 20)
258	    {
259		cur->o_flags |= ISCURSED;
260		cur->o_arm += rnd(3) + 1;
261	    }
262	    else if (r < 28)
263		cur->o_arm -= rnd(3) + 1;
264	when 5:
265	    cur->o_type = RING;
266	    cur->o_which = pick_one(Ring_info, MAXRINGS);
267	    switch (cur->o_which)
268	    {
269		when R_ADDSTR:
270		case R_PROTECT:
271		case R_ADDHIT:
272		case R_ADDDAM:
273		    if ((cur->o_arm = rnd(3)) == 0)
274		    {
275			cur->o_arm = -1;
276			cur->o_flags |= ISCURSED;
277		    }
278		when R_AGGR:
279		case R_TELEPORT:
280		    cur->o_flags |= ISCURSED;
281	    }
282	when 6:
283	    cur->o_type = STICK;
284	    cur->o_which = pick_one(Ws_info, MAXSTICKS);
285	    fix_stick(cur);
286#ifdef MASTER
287	otherwise:
288	    debug("Picked a bad kind of object");
289	    wait_for(' ');
290#endif
291    }
292    return cur;
293}
294
295/*
296 * pick_one:
297 *	Pick an item out of a list of nitems possible objects
298 */
299int
300pick_one(struct obj_info *info, int nitems)
301{
302    struct obj_info *end;
303    struct obj_info *start;
304    int i;
305
306    start = info;
307    for (end = &info[nitems], i = rnd(100); info < end; info++)
308	if (i < info->oi_prob)
309	    break;
310    if (info == end)
311    {
312#ifdef MASTER
313	if (Wizard)
314	{
315	    msg("bad pick_one: %d from %d items", i, nitems);
316	    for (info = start; info < end; info++)
317		msg("%s: %d%%", info->oi_name, info->oi_prob);
318	}
319#endif
320	info = start;
321    }
322    return info - start;
323}
324
325/*
326 * discovered:
327 *	list what the player has discovered in this game of a certain type
328 */
329static int Line_cnt = 0;
330
331static bool Newpage = FALSE;
332
333static char *Lastfmt, *Lastarg;
334
335void
336discovered(void)
337{
338    char ch;
339    bool disc_list;
340
341    do {
342	disc_list = FALSE;
343	if (!Terse)
344	    addmsg("for ");
345	addmsg("what type");
346	if (!Terse)
347	    addmsg(" of object do you want a list");
348	msg("? (* for all)");
349	ch = readchar();
350	switch (ch)
351	{
352	    case ESCAPE:
353		msg("");
354		return;
355	    case POTION:
356	    case SCROLL:
357	    case RING:
358	    case STICK:
359	    case '*':
360		disc_list = TRUE;
361		break;
362	    default:
363		if (Terse)
364		    msg("Not a type");
365		else
366		    msg("Please type one of %c%c%c%c (ESCAPE to quit)", POTION, SCROLL, RING, STICK);
367	}
368    } while (!disc_list);
369    if (ch == '*')
370    {
371	print_disc(POTION);
372	add_line("", NULL);
373	print_disc(SCROLL);
374	add_line("", NULL);
375	print_disc(RING);
376	add_line("", NULL);
377	print_disc(STICK);
378	end_line();
379    }
380    else
381    {
382	print_disc(ch);
383	end_line();
384    }
385}
386
387/*
388 * print_disc:
389 *	Print what we've discovered of type 'type'
390 */
391
392#define MAX4(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)))
393
394void
395print_disc(char type)
396{
397    struct obj_info *info;
398    int i, maxnum, num_found;
399    static THING obj;
400    static short order[MAX4(MAXSCROLLS, MAXPOTIONS, MAXRINGS, MAXSTICKS)];
401
402    switch (type)
403    {
404	case SCROLL:
405	    maxnum = MAXSCROLLS;
406	    info = Scr_info;
407	    break;
408	case POTION:
409	    maxnum = MAXPOTIONS;
410	    info = Pot_info;
411	    break;
412	case RING:
413	    maxnum = MAXRINGS;
414	    info = Ring_info;
415	    break;
416	case STICK:
417	    maxnum = MAXSTICKS;
418	    info = Ws_info;
419	    break;
420    }
421    set_order(order, maxnum);
422    obj.o_count = 1;
423    obj.o_flags = 0;
424    num_found = 0;
425    for (i = 0; i < maxnum; i++)
426	if (info[order[i]].oi_know || info[order[i]].oi_guess)
427	{
428	    obj.o_type = type;
429	    obj.o_which = order[i];
430	    add_line("%s", inv_name(&obj, FALSE));
431	    num_found++;
432	}
433    if (num_found == 0)
434	add_line(nothing(type), NULL);
435}
436
437/*
438 * set_order:
439 *	Set up order for list
440 */
441void
442set_order(short *order, int numthings)
443{
444    int i, r, t;
445
446    for (i = 0; i< numthings; i++)
447	order[i] = i;
448
449    for (i = numthings; i > 0; i--)
450    {
451	r = rnd(i);
452	t = order[i - 1];
453	order[i - 1] = order[r];
454	order[r] = t;
455    }
456}
457
458/*
459 * add_line:
460 *	Add a line to the list of discoveries
461 */
462/* VARARGS1 */
463char
464add_line(char *fmt, char *arg)
465{
466    WINDOW *tw, *sw;
467    int x, y;
468    char *prompt = "--Press space to continue--";
469    static int maxlen = -1;
470
471    if (Line_cnt == 0)
472    {
473	    wclear(Hw);
474	    if (Inv_type == INV_SLOW)
475		Mpos = 0;
476    }
477    if (Inv_type == INV_SLOW)
478    {
479	if (*fmt != '\0')
480	    if (msg(fmt, arg) == ESCAPE)
481		return ESCAPE;
482	Line_cnt++;
483    }
484    else
485    {
486	if (maxlen < 0)
487	    maxlen = strlen(prompt);
488	if (Line_cnt >= LINES - 1 || fmt == NULL)
489	{
490	    if (Inv_type == INV_OVER && fmt == NULL && !Newpage)
491	    {
492		msg("");
493		refresh();
494		tw = newwin(Line_cnt + 1, maxlen + 2, 0, COLS - maxlen - 3);
495		sw = subwin(tw, Line_cnt + 1, maxlen + 1, 0, COLS - maxlen - 2);
496		for (y = 0; y <= Line_cnt; y++)
497		{
498		    wmove(sw, y, 0);
499		    for (x = 0; x <= maxlen; x++)
500			waddch(sw, mvwinch(Hw, y, x));
501		}
502		wmove(tw, Line_cnt, 1);
503		waddstr(tw, prompt);
504		/*
505		 * if there are lines below, use 'em
506		 */
507		if (LINES > NUMLINES)
508		    if (NUMLINES + Line_cnt > LINES)
509			mvwin(tw, LINES - (Line_cnt + 1), COLS - maxlen - 3);
510		    else
511			mvwin(tw, NUMLINES, 0);
512		touchwin(tw);
513		wrefresh(tw);
514		wait_for(' ');
515#ifndef	attron
516		if (CE)
517#else	attron
518		if (clr_eol)
519#endif	attron
520		{
521		    werase(tw);
522		    leaveok(tw, TRUE);
523		    wrefresh(tw);
524		}
525		delwin(tw);
526		touchwin(stdscr);
527	    }
528	    else
529	    {
530		wmove(Hw, LINES - 1, 0);
531		waddstr(Hw, prompt);
532		wrefresh(Hw);
533		wait_for(' ');
534		clearok(curscr, TRUE);
535		wclear(Hw);
536#ifdef	attron
537		touchwin(stdscr);
538#endif	attron
539	    }
540	    Newpage = TRUE;
541	    Line_cnt = 0;
542	    maxlen = strlen(prompt);
543	}
544	if (fmt != NULL && !(Line_cnt == 0 && *fmt == '\0'))
545	{
546	    mvwprintw(Hw, Line_cnt++, 0, fmt, arg);
547	    getyx(Hw, y, x);
548	    if (maxlen < x)
549		maxlen = x;
550	    Lastfmt = fmt;
551	    Lastarg = arg;
552	}
553    }
554    return ~ESCAPE;
555}
556
557/*
558 * end_line:
559 *	End the list of lines
560 */
561void
562end_line(void)
563{
564    if (Inv_type != INV_SLOW)
565	if (Line_cnt == 1 && !Newpage)
566	{
567	    Mpos = 0;
568	    msg(Lastfmt, Lastarg);
569	}
570	else
571	    add_line((char *) NULL, NULL);
572    Line_cnt = 0;
573    Newpage = FALSE;
574}
575
576/*
577 * nothing:
578 *	Set up Prbuf so that message for "nothing found" is there
579 */
580char *
581nothing(char type)
582{
583    char *sp, *tystr;
584
585    if (Terse)
586	sprintf(Prbuf, "Nothing");
587    else
588	sprintf(Prbuf, "Haven't discovered anything");
589    if (type != '*')
590    {
591	sp = &Prbuf[strlen(Prbuf)];
592	switch (type)
593	{
594	    when POTION: tystr = "potion";
595	    when SCROLL: tystr = "scroll";
596	    when RING: tystr = "ring";
597	    when STICK: tystr = "stick";
598	}
599	sprintf(sp, " about any %ss", tystr);
600    }
601    return Prbuf;
602}
603
604/*
605 * nameit:
606 *	Give the proper name to a potion, stick, or ring
607 */
608void
609nameit(THING *obj, char *type, char *which, struct obj_info *op,
610    char *(*prfunc)(THING *))
611{
612    char *pb;
613
614    if (op->oi_know || op->oi_guess)
615    {
616	if (obj->o_count == 1)
617	    sprintf(Prbuf, "A %s ", type);
618	else
619	    sprintf(Prbuf, "%d %ss ", obj->o_count, type);
620	pb = &Prbuf[strlen(Prbuf)];
621	if (op->oi_know)
622	    sprintf(pb, "of %s%s(%s)", op->oi_name, (*prfunc)(obj), which);
623	else if (op->oi_guess)
624	    sprintf(pb, "called %s%s(%s)", op->oi_guess, (*prfunc)(obj), which);
625    }
626    else if (obj->o_count == 1)
627	sprintf(Prbuf, "A%s %s %s", vowelstr(which), which, type);
628    else
629	sprintf(Prbuf, "%d %s %ss", obj->o_count, which, type);
630}
631
632/*
633 * nullstr:
634 *	Return a pointer to a null-length string
635 */
636char *
637nullstr(THING *ignored)
638{
639    return "";
640}
641
642# ifdef	MASTER
643/*
644 * pr_list:
645 *	List possible potions, scrolls, etc. for wizard.
646 */
647void
648pr_list(void)
649{
650    int ch;
651
652    if (!Terse)
653	addmsg("for ");
654    addmsg("what type");
655    if (!Terse)
656	addmsg(" of object do you want a list");
657    msg("? ");
658    ch = readchar();
659    switch (ch)
660    {
661	when POTION:
662	    pr_spec(Pot_info, MAXPOTIONS);
663	when SCROLL:
664	    pr_spec(Scr_info, MAXSCROLLS);
665	when RING:
666	    pr_spec(Ring_info, MAXRINGS);
667	when STICK:
668	    pr_spec(Ws_info, MAXSTICKS);
669	when ARMOR:
670	    pr_spec(Arm_info, MAXARMORS);
671	when WEAPON:
672	    pr_spec(Weap_info, MAXWEAPONS);
673	otherwise:
674	    return;
675    }
676}
677
678/*
679 * pr_spec:
680 *	Print specific list of possible items to choose from
681 */
682void
683pr_spec(struct obj_info *info, int nitems)
684{
685    struct obj_info *endp;
686    int i, lastprob;
687
688    endp = &info[nitems];
689    lastprob = 0;
690    for (i = '0'; info < endp; i++)
691    {
692	if (i == '9' + 1)
693	    i = 'a';
694	sprintf(Prbuf, "%c: %%s (%d%%%%)", i, info->oi_prob - lastprob);
695	lastprob = info->oi_prob;
696	add_line(Prbuf, info->oi_name);
697	info++;
698    }
699    end_line();
700}
701# endif	MASTER