ftp.nice.ch/pub/next/games/strategic/NetHack.s.tar.gz#/NetHackSource/src/attrib.c

This is attrib.c in view mode; [Download] [Up]

/*	SCCS Id: @(#)attrib.c	3.0	90/2/15
/*	Copyright 1988, 1989, 1990, M. Stephenson		  */
/* NetHack may be freely redistributed.  See license for details. */

/*  attribute modification routines. */

#include "hack.h"

#ifdef OVLB

const char	*plusattr[] = {	/* part of the output on gain of attribute */

	"strong", "smart", "wise", "agile", "tough", "charismatic"
};

const char	*minusattr[] = { /* part of the output on loss of attribute */

	"weak", "stupid", "foolish", "clumsy", "vulnerable", "ugly"
};

struct attribs	attrmax = {	/* max values for the attributes */

	118, 18, 18, 18, 18, 18
},
		attrmin = {	/* min values for the attributes */

	3, 3, 3, 3, 3, 3
};

const struct innate {

	schar	ulevel;
	long	*ability;
	const char *gainstr, *losestr;
}	a_abil[] = { {	 1, &(Stealth), "", "" },
		     {   1, &(Fast), "", "" },
		     {  10, &(Searching), "perceptive", "" },
		     {	 0, 0, 0, 0 } },

	b_abil[] = { {	 1, &(HPoison_resistance), "", "" },
		     {   7, &(Fast), "quick", "slow" },
		     {  15, &(Stealth), "stealthy", "" },
		     {	 0, 0, 0, 0 } },

	c_abil[] = { {	 7, &(Fast), "quick", "slow" },
		     {	15, &(Warning), "sensitive", "" },
		     {	 0, 0, 0, 0 } },

	e_abil[] = { {   1, &(Fast), "", "" },
		     {	 1, &(HSee_invisible), "", "" },
		     {	 1, &(Searching), "", "" },
		     {	 1, &(HSleep_resistance), "", "" },
		     {	 0, 0, 0, 0 } },

	h_abil[] = { {	 1, &(HPoison_resistance), "", "" },
		     {	15, &(Warning), "sensitive", "" },
		     {	 0, 0, 0, 0 } },

	k_abil[] = { {	 7, &(Fast), "quick", "slow" },
		     {	 0, 0, 0, 0 } },

	p_abil[] = { {	15, &(Warning), "sensitive", "" },
		     {  20, &(HFire_resistance), "cool", "warmer" },
		     {	 0, 0, 0, 0 } },

	r_abil[] = { {	 1, &(Stealth), "", ""  },
		     {  10, &(Searching), "perceptive", "" },
		     {	 0, 0, 0, 0 } },

	s_abil[] = { {	 1, &(Fast), "", "" },
		     {  15, &(Stealth), "stealthy", "" },
		     {	 0, 0, 0, 0 } },

	t_abil[] = { {	10, &(Searching), "perceptive", "" },
		     {	20, &(HPoison_resistance), "hardy", "" },
		     {	 0, 0, 0, 0 } },

	v_abil[] = { {	 1, &(HCold_resistance), "", "" },
		     {	 1, &(Stealth), "", "" },
		     {   7, &(Fast), "quick", "slow" },
		     {	 0, 0, 0, 0 } },

	w_abil[] = { {	15, &(Warning), "sensitive", "" },
		     {  17, &(HTeleport_control), "controlled","uncontrolled" },
		     {	 0, 0, 0, 0 } };

const struct clattr {

	struct	attribs	base, dist;
 	schar	align, aligntyp;
	schar	shp, hd, xlev, ndx;
/* According to AD&D, HD for some classes (ex. Wizard) should be smaller
 * (4-sided for wizards).  But this is not AD&D, and using the AD&D
 * rule here produces an unplayable character.  This I have used a minimum
 * of an 10-sided hit die for everything.  Another AD&D change: wizards get
 * a minimum strength of 6 since without one you can't teleport or cast
 * spells. --KAA
 */
	const struct	innate *abil;
}	a_attr = { {	 7, 10, 10,  7,  7,  7 },  /* Archeologist */
		   {	20, 20, 20, 10, 20, 10 },
		    10,  1, 13, 10, 14,  2, a_abil },

	b_attr = { {	16,  7,  7, 15, 16,  6 },  /* Barbarian */
		   {	30,  6,  7, 20, 30,  7 },
		    10, -1, 16, 12, 10,  3, b_abil },

	c_attr = { {	10,  7,  7,  7,  8,  6 },  /* Caveman (fighter) */
		   {	30,  6,  7, 20, 30,  7 },
		     0,  1, 16, 10, 10,  3, c_abil },

/*
	e_attr = { {	13, 13, 14,  6, 14,  6 },
 */
	e_attr = { {	13, 13, 13,  9, 13,  7 },  /* Elf (ranger) */
		   {	30, 10, 10, 20, 20, 10 },
		    10,  1, 15, 10, 11,  2, e_abil },

	h_attr = { {	 7,  7, 13,  7, 11, 16 },  /* Healer (druid) */
		   {	15, 20, 20, 15, 25, 10 },
		    10,  1, 13, 10, 20,  2, h_abil },

	k_attr = { {	13,  7, 14,  8, 10, 17 },  /* Knight (paladin) */
		   {	20, 15, 15, 10, 20, 10 },
		    10,  1, 16, 10, 10,  3, k_abil },

	p_attr = { {	 7,  7, 10,  7,  7,  7 },  /* Priest (cleric) */
		   {	15, 10, 30, 15, 20, 10 },
		     0,  0, 14, 10, 10,  2, p_abil },

	r_attr = { {	 7,  7,  7, 10,  7,  6 },  /* Rogue (thief) */
		   {	20, 10, 10, 30, 20, 10 },
		    10, -1, 12, 10, 11,  2, r_abil },

	s_attr = { {	10,  8,  7, 10, 17,  6 },  /* Samurai (fighter/thief) */
		   {	30, 10, 10, 30, 14, 10 },
		    10,  1, 15, 10, 11,  2, s_abil },

	t_attr = { {	 7, 10,  6,  7,  7, 10 },  /* Tourist */
		   {	15, 10, 10, 15, 30, 20 },
		     0,  0, 10, 10, 14,  1, t_abil },

	v_attr = { {	10,  7,  7,  7, 10,  7 },  /* Valkyrie (fighter) */
		   {	30,  6,  7, 20, 30,  7 },
		     0, -1, 16, 10, 10,  3, v_abil },

	w_attr = { {	 7, 10,  7,  7,  7,  7 },  /* Wizard (magic-user) */
		   {	10, 30, 10, 20, 20, 10 },
		     0,  0, 12, 10, 12,  1, w_abil },

	X_attr = { {	 3,  3,  3,  3,  3,  3 },
		   {	20, 15, 15, 15, 20, 15 },
		     0,  0, 12, 10, 14,  1,  0 };

static const struct clattr *NDECL(clx);
static void NDECL(init_align);

void
adjattrib(ndx, incr, silent)

	int	ndx, incr;
	boolean	silent;
{
	if(!incr) return;

	if(incr > 0) {
	    if((AMAX(ndx) >= attrmax.a[ndx]) && (ACURR(ndx) == AMAX(ndx))) {

		if(!silent && flags.verbose)
		    pline("You're already as %s as you can get.",
			  plusattr[ndx]);
		ABASE(ndx) = AMAX(ndx) = attrmax.a[ndx]; /* just in case */
		return;
	    }

	    ABASE(ndx) += incr;
	    if(ABASE(ndx) > AMAX(ndx)) {
		incr = ABASE(ndx) - AMAX(ndx);
		AMAX(ndx) += incr;
		if(AMAX(ndx) > attrmax.a[ndx])
		    AMAX(ndx) = attrmax.a[ndx];
		ABASE(ndx) = AMAX(ndx);
	    }
	} else {
	    if((AMAX(ndx) <= attrmin.a[ndx]) && (ABASE(ndx) == AMAX(ndx))) {
		if(!silent && flags.verbose)
		    pline("You're already as %s as you can get.",
			  minusattr[ndx]);
		ABASE(ndx) = AMAX(ndx) = attrmin.a[ndx]; /* just in case */
		return;
	    }

	    ABASE(ndx) += incr;
	    if(ABASE(ndx) < attrmin.a[ndx]) {
		incr = ABASE(ndx) - attrmin.a[ndx];
		ABASE(ndx) = attrmin.a[ndx];
		AMAX(ndx) += incr;
		if(AMAX(ndx) < attrmin.a[ndx])
		    AMAX(ndx) = attrmin.a[ndx];
	    }
	}
	if(!silent)
	    You("feel %s%s!",
		  (incr > 1) ? "very ": "",
		  (incr > 0) ? plusattr[ndx] : minusattr[ndx]);
	flags.botl = 1;
	return;
}

void
gainstr(otmp, incr)
	register struct obj *otmp;
	register int incr;
{
	int num = 1;

	if(incr) num = incr;
	else {
	    if(ABASE(A_STR) < 18) num = (rn2(4) ? 1 : rnd(6) );
	    else if (ABASE(A_STR) < 103) num = rnd(10);
	}
	adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num, TRUE);
}

void
losestr(num)	/* may kill you; cause may be poison or monster like 'a' */
	register int num;
{
	int ustr = ABASE(A_STR) - num;

	while(ustr < 3) {
		ustr++;
		num--;
		u.uhp -= 6;
		u.uhpmax -= 6;
	}
	adjattrib(A_STR, -num, TRUE);
}

void
change_luck(n)
	register schar n;
{
	u.uluck += n;
	if (u.uluck < 0 && u.uluck < LUCKMIN)	u.uluck = LUCKMIN;
	if (u.uluck > 0 && u.uluck > LUCKMAX)	u.uluck = LUCKMAX;
}

int
stone_luck(parameter)
boolean parameter; /* So I can't think up of a good name.  So sue me. --KAA */
{
	register struct obj *otmp;
	register int bonchance = 0;

	for(otmp = invent; otmp; otmp=otmp->nobj)
	    if(otmp->otyp == LUCKSTONE) {
		if (otmp->cursed) bonchance -= otmp->quan;
		else if (otmp->blessed) bonchance += otmp->quan;
		else if (parameter) bonchance += otmp->quan;
	    }

	return sgn(bonchance);
}

#endif /* OVLB */
#ifdef OVL1

void
restore_attrib() {

	int	i;

	for(i = 0; i < A_MAX; i++) {	/* all temporary losses/gains */

	   if(ATEMP(i) && ATIME(i)) {
		if(!(--(ATIME(i)))) { /* countdown for change */
		    ATEMP(i) += ATEMP(i) > 0 ? -1 : 1;

		    if(ATEMP(i)) /* reset timer */
			ATIME(i) = 100 / ACURR(A_CON);
		}
	    }
	}
}

#endif /* OVL1 */
#ifdef OVLB

static const struct	clattr *
clx()  {

	register const struct	clattr	*attr;

	switch	(pl_character[0]) {

	    case 'A':	attr = &a_attr;
			break;
	    case 'B':	attr = &b_attr;
			break;
	    case 'C':	attr = &c_attr;
			break;
	    case 'E':	attr = &e_attr;
			break;
	    case 'H':	attr = &h_attr;
			break;
	    case 'K':	attr = &k_attr;
			break;
	    case 'P':	attr = &p_attr;
			break;
	    case 'R':	attr = &r_attr;
			break;
	    case 'S':	attr = &s_attr;
			break;
	    case 'T':	attr = &t_attr;
			break;
	    case 'V':	attr = &v_attr;
			break;
	    case 'W':	attr = &w_attr;
			break;
	    default:	/* unknown type */
			attr = &X_attr;
			break;
	}
	return(attr);
}

static void
init_align() {	/* called from newhp if u.ulevel is 0 */

	register const struct	clattr	*attr = clx();

	u.ualign = (int)attr->align;
	u.ualigntyp = attr->aligntyp;
}

void
init_attr(np)
	register int	np;
{
	register int	i, x, tryct;
	register const struct	clattr	*attr = clx();

	for(i = 0; i < A_MAX; i++) {

	    ABASE(i) = AMAX(i) = attr->base.a[i];
	    ATEMP(i) = ATIME(i) = 0;
	    np -= attr->base.a[i];
	}

	tryct = 0;
	while(np > 0 && tryct < 100) {

	    x = rn2(100);
	    for(i = 0; (i < A_MAX) && ((x -= attr->dist.a[i]) > 0); i++);
	    if(i >= A_MAX) continue; /* impossible */

	    if(ABASE(i) >= attrmax.a[i]) {

		tryct++;
		continue;
	    }
	    tryct = 0;
	    ABASE(i)++;
	    AMAX(i)++;
	    np--;
	}

	tryct = 0;
	while(np < 0 && tryct < 100) {		/* for redistribution */

	    x = rn2(100);
	    for(i = 0; (i < A_MAX) && ((x -= attr->dist.a[i]) > 0); i++);
	    if(i >= A_MAX) continue; /* impossible */

	    if(ABASE(i) <= attrmin.a[i]) {

		tryct++;
		continue;
	    }
	    tryct = 0;
	    ABASE(i)--;
	    AMAX(i)--;
	    np++;
	}
}

void
redist_attr() {

	register int i, tmp;

	for(i = 0; i < A_MAX; i++) {
	    if (i==A_INT || i==A_WIS) continue;
		/* Polymorphing doesn't change your mind */
	    tmp = AMAX(i);
	    AMAX(i) += (rn2(5)-2);
	    if (AMAX(i) > attrmax.a[i]) AMAX(i) = attrmax.a[i];
	    if (AMAX(i) < attrmin.a[i]) AMAX(i) = attrmin.a[i];
	    ABASE(i) = ABASE(i) * AMAX(i) / tmp;
	    /* ABASE(i) > attrmax.a[i] is impossible */
	    if (ABASE(i) < attrmin.a[i]) ABASE(i) = attrmin.a[i];
	}
}

void
adjabil(oldlevel,newlevel)
int oldlevel, newlevel;
{
	register const struct clattr	*attr = clx();
#ifdef __GNULINT__
	/* this is the "right" definition */
	register const struct innate	*abil = attr->abil;
#else
	/* this one satisfies more compilers */
	register struct innate	*abil = (struct innate *)attr->abil;
#endif

	if(abil) {
	    for(; abil->ability; abil++) {
		if(oldlevel < abil->ulevel && newlevel >= abil->ulevel) {
			if(!(*(abil->ability) & INTRINSIC)) {
			    *(abil->ability) |= INTRINSIC;
			    if(strlen(abil->gainstr))
				You("feel %s!", abil->gainstr);
			}
		} else if (oldlevel >= abil->ulevel && newlevel < abil->ulevel) {
			if((*(abil->ability) & INTRINSIC)) {
			    *(abil->ability) &= ~INTRINSIC;
			    if(strlen(abil->losestr))
				You("feel %s!", abil->losestr);
			    else if(strlen(abil->gainstr))
				You("feel less %s!", abil->gainstr);
			}
		}
	    }
	}
}

int
newhp() {
	register const struct clattr	*attr = clx();
	int	hp, conplus;

	if(u.ulevel == 0) {

		hp = attr->shp;
		init_align();	/* initialize alignment stuff */
		return hp;
	} else {

	    if(u.ulevel < attr->xlev)
		hp = rnd(attr->hd);
	    else
		hp = attr->ndx;
	}

	switch(ACURR(A_CON)) {
		case	3:	conplus = -2; break;
		case	4:
		case	5:
		case	6:	conplus = -1; break;
		case	15:
		case	16:	conplus = 1; break;
		case	17:	conplus = 2; break;
		case	18:	conplus = 3; break;
		default:	conplus = 0;
	}
	hp += conplus;
	return((hp <= 0) ? 1 : hp);
}

#endif /* OVLB */
#ifdef OVL0

schar
acurr(x)
int x;
{ 
	register int tmp = (u.abon.a[x] + u.atemp.a[x] + u.acurr.a[x]);

	if (x == A_STR) {
		if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER) return(125);
		else return((tmp >= 125) ? 125 : (tmp <= 3) ? 3 : tmp);
	} 
	else return((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp);
}

#endif /* OVL0 */
#ifdef OVL2

/* avoid possible problems with alignment overflow, and provide a centralized
 * location for any future alignment limits
 */
void
adjalign(n)
register int n;
{
	register int newalign = u.ualign + n;

	if(n < 0) {
		if(newalign < u.ualign)
			u.ualign = newalign;
	} else
		if(newalign > u.ualign)
			u.ualign = newalign;
}

#endif /* OVL2 */

These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.