1    | /*	SCCS Id: @(#)attrib.c	3.3	2000/05/17	*/
2    | /*	Copyright 1988, 1989, 1990, 1992, M. Stephenson		  */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | /*  attribute modification routines. */
6    | 
7    | #include "hack.h"
8    | #include "artifact.h"
9    | 
10   | /* #define DEBUG */	/* uncomment for debugging info */
11   | 
12   | #ifdef OVLB
13   | 
14   | 	/* part of the output on gain or loss of attribute */
15   | static
16   | const char	*plusattr[] = {
17   | 	"strong", "smart", "wise", "agile", "tough", "charismatic"
18   | },
19   | 		*minusattr[] = {
20   | 	"weak", "stupid", "foolish", "clumsy", "fragile", "repulsive"
21   | };
22   | 
23   | 
24   | static
25   | const struct innate {
26   | 	schar	ulevel;
27   | 	long	*ability;
28   | 	const char *gainstr, *losestr;
29   | }	arc_abil[] = { {	 1, &(HStealth), "", "" },
30   | 		     {   1, &(HFast), "", "" },
31   | 		     {  10, &(HSearching), "perceptive", "" },
32   | 		     {	 0, 0, 0, 0 } },
33   | 
34   | 	bar_abil[] = { {	 1, &(HPoison_resistance), "", "" },
35   | 		     {   7, &(HFast), "quick", "slow" },
36   | 		     {  15, &(HStealth), "stealthy", "" },
37   | 		     {	 0, 0, 0, 0 } },
38   | 
39   | 	cav_abil[] = { {	 7, &(HFast), "quick", "slow" },
40   | 		     {	15, &(HWarning), "sensitive", "" },
41   | 		     {	 0, 0, 0, 0 } },
42   | 
43   | 	hea_abil[] = { {	 1, &(HPoison_resistance), "", "" },
44   | 		     {	15, &(HWarning), "sensitive", "" },
45   | 		     {	 0, 0, 0, 0 } },
46   | 
47   | 	kni_abil[] = { {	 7, &(HFast), "quick", "slow" },
48   | 		     {	 0, 0, 0, 0 } },
49   | 
50   | 	mon_abil[] = { {   1, &(HFast), "", "" },
51   | 		     {   1, &(HSleep_resistance), "", "" },
52   | 		     {   1, &(HSee_invisible), "", "" },
53   | 		     {   3, &(HPoison_resistance), "healthy", "" },
54   | 		     {   5, &(HStealth), "stealthy", "" },
55   | 		     {   7, &(HWarning), "sensitive", "" },
56   | 		     {   9, &(HSearching), "perceptive", "unaware" },
57   | 		     {  11, &(HFire_resistance), "cool", "warmer" },
58   | 		     {  13, &(HCold_resistance), "warm", "cooler" },
59   | 		     {  15, &(HShock_resistance), "insulated", "conductive" },
60   | 		     {  17, &(HTeleport_control), "controlled","uncontrolled" },
61   | 		     {   0, 0, 0, 0 } },
62   | 
63   | 	pri_abil[] = { {	15, &(HWarning), "sensitive", "" },
64   | 		     {  20, &(HFire_resistance), "cool", "warmer" },
65   | 		     {	 0, 0, 0, 0 } },
66   | 
67   | 	ran_abil[] = { {   1, &(HSearching), "", "" },
68   | 		     {	 7, &(HStealth), "stealthy", "" },
69   | 		     {	15, &(HSee_invisible), "", "" },
70   | 		     {	 0, 0, 0, 0 } },
71   | 
72   | 	rog_abil[] = { {	 1, &(HStealth), "", ""  },
73   | 		     {  10, &(HSearching), "perceptive", "" },
74   | 		     {	 0, 0, 0, 0 } },
75   | 
76   | 	sam_abil[] = { {	 1, &(HFast), "", "" },
77   | 		     {  15, &(HStealth), "stealthy", "" },
78   | 		     {	 0, 0, 0, 0 } },
79   | 
80   | 	tou_abil[] = { {	10, &(HSearching), "perceptive", "" },
81   | 		     {	20, &(HPoison_resistance), "hardy", "" },
82   | 		     {	 0, 0, 0, 0 } },
83   | 
84   | 	val_abil[] = { {	 1, &(HCold_resistance), "", "" },
85   | 		     {	 1, &(HStealth), "", "" },
86   | 		     {   7, &(HFast), "quick", "slow" },
87   | 		     {	 0, 0, 0, 0 } },
88   | 
89   | 	wiz_abil[] = { {	15, &(HWarning), "sensitive", "" },
90   | 		     {  17, &(HTeleport_control), "controlled","uncontrolled" },
91   | 		     {	 0, 0, 0, 0 } },
92   | 
93   | 	/* Intrinsics conferred by race */
94   | 	elf_abil[] = { {	4, &(HSleep_resistance), "awake", "tired" },
95   | 		     {	 0, 0, 0, 0 } },
96   | 
97   | 	orc_abil[] = { {	1, &(HPoison_resistance), "", "" },
98   | 		     {	 0, 0, 0, 0 } };
99   | 
100  | static long next_check = 600L;	/* arbitrary first setting */
101  | STATIC_DCL void NDECL(exerper);
102  | 
103  | /* adjust an attribute; return TRUE if change is made, FALSE otherwise */
104  | boolean
105  | adjattrib(ndx, incr, msgflg)
106  | 	int	ndx, incr;
107  | 	int	msgflg;	    /* positive => no message, zero => message, and */
108  | {			    /* negative => conditional (msg if change made) */
109  | 	if (Fixed_abil || !incr) return FALSE;
110  | 
111  | 	if ((ndx == A_INT || ndx == A_WIS)
112  | 				&& uarmh && uarmh->otyp == DUNCE_CAP) {
113  | 		if (msgflg == 0)
114  | 		    Your("cap constricts briefly, then relaxes again.");
115  | 		return FALSE;
116  | 	}
117  | 
118  | 	if (incr > 0) {
119  | 	    if ((AMAX(ndx) >= ATTRMAX(ndx)) && (ACURR(ndx) >= AMAX(ndx))) {
120  | 		if (msgflg == 0 && flags.verbose)
121  | 		    pline("You're already as %s as you can get.",
122  | 			  plusattr[ndx]);
123  | 		ABASE(ndx) = AMAX(ndx) = ATTRMAX(ndx); /* just in case */
124  | 		return FALSE;
125  | 	    }
126  | 
127  | 	    ABASE(ndx) += incr;
128  | 	    if(ABASE(ndx) > AMAX(ndx)) {
129  | 		incr = ABASE(ndx) - AMAX(ndx);
130  | 		AMAX(ndx) += incr;
131  | 		if(AMAX(ndx) > ATTRMAX(ndx))
132  | 		    AMAX(ndx) = ATTRMAX(ndx);
133  | 		ABASE(ndx) = AMAX(ndx);
134  | 	    }
135  | 	} else {
136  | 	    if (ABASE(ndx) <= ATTRMIN(ndx)) {
137  | 		if (msgflg == 0 && flags.verbose)
138  | 		    pline("You're already as %s as you can get.",
139  | 			  minusattr[ndx]);
140  | 		ABASE(ndx) = ATTRMIN(ndx); /* just in case */
141  | 		return FALSE;
142  | 	    }
143  | 
144  | 	    ABASE(ndx) += incr;
145  | 	    if(ABASE(ndx) < ATTRMIN(ndx)) {
146  | 		incr = ABASE(ndx) - ATTRMIN(ndx);
147  | 		ABASE(ndx) = ATTRMIN(ndx);
148  | 		AMAX(ndx) += incr;
149  | 		if(AMAX(ndx) < ATTRMIN(ndx))
150  | 		    AMAX(ndx) = ATTRMIN(ndx);
151  | 	    }
152  | 	}
153  | 	if (msgflg <= 0)
154  | 	    You_feel("%s%s!",
155  | 		  (incr > 1 || incr < -1) ? "very ": "",
156  | 		  (incr > 0) ? plusattr[ndx] : minusattr[ndx]);
157  | 	flags.botl = 1;
158  | 	if (moves > 0 && (ndx == A_STR || ndx == A_CON))
159  | 		(void)encumber_msg();
160  | 	return TRUE;
161  | }
162  | 
163  | void
164  | gainstr(otmp, incr)
165  | 	register struct obj *otmp;
166  | 	register int incr;
167  | {
168  | 	int num = 1;
169  | 
170  | 	if(incr) num = incr;
171  | 	else {
172  | 	    if(ABASE(A_STR) < 18) num = (rn2(4) ? 1 : rnd(6) );
173  | 	    else if (ABASE(A_STR) < STR18(85)) num = rnd(10);
174  | 	}
175  | 	(void) adjattrib(A_STR, (otmp && otmp->cursed) ? -num : num, TRUE);
176  | }
177  | 
178  | void
179  | losestr(num)	/* may kill you; cause may be poison or monster like 'a' */
180  | 	register int num;
181  | {
182  | 	int ustr = ABASE(A_STR) - num;
183  | 
184  | 	while(ustr < 3) {
185  | 	    ++ustr;
186  | 	    --num;
187  | 	    if (Upolyd) {
188  | 		u.mh -= 6;
189  | 		u.mhmax -= 6;
190  | 	    } else {
191  | 		u.uhp -= 6;
192  | 		u.uhpmax -= 6;
193  | 	    }
194  | 	}
195  | 	(void) adjattrib(A_STR, -num, TRUE);
196  | }
197  | 
198  | void
199  | change_luck(n)
200  | 	register schar n;
201  | {
202  | 	u.uluck += n;
203  | 	if (u.uluck < 0 && u.uluck < LUCKMIN)	u.uluck = LUCKMIN;
204  | 	if (u.uluck > 0 && u.uluck > LUCKMAX)	u.uluck = LUCKMAX;
205  | }
206  | 
207  | int
208  | stone_luck(parameter)
209  | boolean parameter; /* So I can't think up of a good name.  So sue me. --KAA */
210  | {
211  | 	register struct obj *otmp;
212  | 	register long bonchance = 0;
213  | 
214  | 	for(otmp = invent; otmp; otmp=otmp->nobj)
215  | 	    if (otmp->otyp == LUCKSTONE
216  | 		|| (otmp->oartifact && spec_ability(otmp, SPFX_LUCK))) {
217  | 		if (otmp->cursed) bonchance -= otmp->quan;
218  | 		else if (otmp->blessed) bonchance += otmp->quan;
219  | 		else if (parameter) bonchance += otmp->quan;
220  | 	    }
221  | 
222  | 	return sgn((int)bonchance);
223  | }
224  | 
225  | /* there has just been an inventory change affecting a luck-granting item */
226  | void
227  | set_moreluck()
228  | {
229  | 	int luckbon = stone_luck(TRUE);
230  | 
231  | 	if (!luckbon && !carrying(LUCKSTONE)) u.moreluck = 0;
232  | 	else if (luckbon >= 0) u.moreluck = LUCKADD;
233  | 	else u.moreluck = -LUCKADD;
234  | }
235  | 
236  | #endif /* OVLB */
237  | #ifdef OVL1
238  | 
239  | void
240  | restore_attrib()
241  | {
242  | 	int	i;
243  | 
244  | 	for(i = 0; i < A_MAX; i++) {	/* all temporary losses/gains */
245  | 
246  | 	   if(ATEMP(i) && ATIME(i)) {
247  | 		if(!(--(ATIME(i)))) { /* countdown for change */
248  | 		    ATEMP(i) += ATEMP(i) > 0 ? -1 : 1;
249  | 
250  | 		    if(ATEMP(i)) /* reset timer */
251  | 			ATIME(i) = 100 / ACURR(A_CON);
252  | 		}
253  | 	    }
254  | 	}
255  | 	(void)encumber_msg();
256  | }
257  | 
258  | #endif /* OVL1 */
259  | #ifdef OVLB
260  | 
261  | #define AVAL	50		/* tune value for exercise gains */
262  | 
263  | void
264  | exercise(i, inc_or_dec)
265  | int	i;
266  | boolean	inc_or_dec;
267  | {
268  | #ifdef DEBUG
269  | 	pline("Exercise:");
270  | #endif
271  | 	if (i == A_INT || i == A_CHA) return;	/* can't exercise these */
272  | 
273  | 	/* no physical exercise while polymorphed; the body's temporary */
274  | 	if (Upolyd && i != A_WIS) return;
275  | 
276  | 	if(abs(AEXE(i)) < AVAL) {
277  | 		/*
278  | 		 *	Law of diminishing returns (Part I):
279  | 		 *
280  | 		 *	Gain is harder at higher attribute values.
281  | 		 *	79% at "3" --> 0% at "18"
282  | 		 *	Loss is even at all levels (50%).
283  | 		 *
284  | 		 *	Note: *YES* ACURR is the right one to use.
285  | 		 */
286  | 		AEXE(i) += (inc_or_dec) ? (rn2(19) > ACURR(i)) : -rn2(2);
287  | #ifdef DEBUG
288  | 		pline("%s, %s AEXE = %d",
289  | 			(i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" :
290  | 			(i == A_DEX) ? "Dex" : "Con",
291  | 			(inc_or_dec) ? "inc" : "dec", AEXE(i));
292  | #endif
293  | 	}
294  | 	if (moves > 0 && (i == A_STR || i == A_CON)) (void)encumber_msg();
295  | }
296  | 
297  | /* hunger values - from eat.c */
298  | #define SATIATED	0
299  | #define NOT_HUNGRY	1
300  | #define HUNGRY		2
301  | #define WEAK		3
302  | #define FAINTING	4
303  | #define FAINTED		5
304  | #define STARVED		6
305  | 
306  | STATIC_OVL void
307  | exerper()
308  | {
309  | 	if(!(moves % 10)) {
310  | 		/* Hunger Checks */
311  | 
312  | 		int hs = (u.uhunger > 1000) ? SATIATED :
313  | 			 (u.uhunger > 150) ? NOT_HUNGRY :
314  | 			 (u.uhunger > 50) ? HUNGRY :
315  | 			 (u.uhunger > 0) ? WEAK : FAINTING;
316  | 
317  | #ifdef DEBUG
318  | 		pline("exerper: Hunger checks");
319  | #endif
320  | 		switch (hs) {
321  | 		    case SATIATED:	exercise(A_DEX, FALSE); break;
322  | 		    case NOT_HUNGRY:	exercise(A_CON, TRUE); break;
323  | 		    case WEAK:		exercise(A_STR, FALSE); break;
324  | 		    case FAINTING:
325  | 		    case FAINTED:	exercise(A_CON, FALSE); break;
326  | 		}
327  | 
328  | 		/* Encumberance Checks */
329  | #ifdef DEBUG
330  | 		pline("exerper: Encumber checks");
331  | #endif
332  | 		switch (near_capacity()) {
333  | 		    case MOD_ENCUMBER:	exercise(A_STR, TRUE); break;
334  | 		    case HVY_ENCUMBER:	exercise(A_STR, TRUE);
335  | 					exercise(A_DEX, FALSE); break;
336  | 		    case EXT_ENCUMBER:	exercise(A_DEX, FALSE);
337  | 					exercise(A_CON, FALSE); break;
338  | 		}
339  | 
340  | 	}
341  | 
342  | 	/* status checks */
343  | 	if(!(moves % 5)) {
344  | #ifdef DEBUG
345  | 		pline("exerper: Status checks");
346  | #endif
347  | 		if ((HClairvoyant & (INTRINSIC|TIMEOUT)) &&
348  | 			!BClairvoyant)                      exercise(A_WIS, TRUE);
349  | 		if (HRegeneration)			exercise(A_STR, TRUE);
350  | 
351  | 		if(Sick || Vomiting)     exercise(A_CON, FALSE);
352  | 		if(Confusion || Hallucination)		exercise(A_WIS, FALSE);
353  | 		if(Wounded_legs || Fumbling || HStun)	exercise(A_DEX, FALSE);
354  | 	}
355  | }
356  | 
357  | void
358  | exerchk()
359  | {
360  | 	int	i, mod_val;
361  | 
362  | 	/*	Check out the periodic accumulations */
363  | 	exerper();
364  | 
365  | #ifdef DEBUG
366  | 	if(moves >= next_check)
367  | 		pline("exerchk: ready to test. multi = %d.", multi);
368  | #endif
369  | 	/*	Are we ready for a test?	*/
370  | 	if(moves >= next_check && !multi) {
371  | #ifdef DEBUG
372  | 	    pline("exerchk: testing.");
373  | #endif
374  | 	    /*
375  | 	     *	Law of diminishing returns (Part II):
376  | 	     *
377  | 	     *	The effects of "exercise" and "abuse" wear
378  | 	     *	off over time.  Even if you *don't* get an
379  | 	     *	increase/decrease, you lose some of the
380  | 	     *	accumulated effects.
381  | 	     */
382  | 	    for(i = 0; i < A_MAX; AEXE(i++) /= 2) {
383  | 
384  | 		if(ABASE(i) >= 18 || !AEXE(i)) continue;
385  | 		if(i == A_INT || i == A_CHA) continue;/* can't exercise these */
386  | 
387  | #ifdef DEBUG
388  | 		pline("exerchk: testing %s (%d).",
389  | 			(i == A_STR) ? "Str" : (i == A_WIS) ? "Wis" :
390  | 			(i == A_DEX) ? "Dex" : "Con", AEXE(i));
391  | #endif
392  | 		/*
393  | 		 *	Law of diminishing returns (Part III):
394  | 		 *
395  | 		 *	You don't *always* gain by exercising.
396  | 		 *	[MRS 92/10/28 - Treat Wisdom specially for balance.]
397  | 		 */
398  | 		if(rn2(AVAL) > ((i != A_WIS) ? abs(AEXE(i)*2/3) : abs(AEXE(i))))
399  | 		    continue;
400  | 		mod_val = sgn(AEXE(i));
401  | 
402  | #ifdef DEBUG
403  | 		pline("exerchk: changing %d.", i);
404  | #endif
405  | 		if(adjattrib(i, mod_val, -1)) {
406  | #ifdef DEBUG
407  | 		    pline("exerchk: changed %d.", i);
408  | #endif
409  | 		    /* if you actually changed an attrib - zero accumulation */
410  | 		    AEXE(i) = 0;
411  | 		    /* then print an explanation */
412  | 		    switch(i) {
413  | 		    case A_STR: You((mod_val >0) ?
414  | 				    "must have been exercising." :
415  | 				    "must have been abusing your body.");
416  | 				break;
417  | 		    case A_WIS: You((mod_val >0) ?
418  | 				    "must have been very observant." :
419  | 				    "haven't been paying attention.");
420  | 				break;
421  | 		    case A_DEX: You((mod_val >0) ?
422  | 				    "must have been working on your reflexes." :
423  | 				    "haven't been working on reflexes lately.");
424  | 				break;
425  | 		    case A_CON: You((mod_val >0) ?
426  | 				    "must be leading a healthy life-style." :
427  | 				    "haven't been watching your health.");
428  | 				break;
429  | 		    }
430  | 		}
431  | 	    }
432  | 	    next_check += rn1(200,800);
433  | #ifdef DEBUG
434  | 	    pline("exerchk: next check at %ld.", next_check);
435  | #endif
436  | 	}
437  | }
438  | 
439  | /* next_check will otherwise have its initial 600L after a game restore */
440  | void
441  | reset_attribute_clock()
442  | {
443  | 	if (moves > 600L) next_check = moves + rn1(50,800);
444  | }
445  | 
446  | 
447  | void
448  | init_attr(np)
449  | 	register int	np;
450  | {
451  | 	register int	i, x, tryct;
452  | 
453  | 
454  | 	for(i = 0; i < A_MAX; i++) {
455  | 	    ABASE(i) = AMAX(i) = urole.attrbase[i];
456  | 	    ATEMP(i) = ATIME(i) = 0;
457  | 	    np -= urole.attrbase[i];
458  | 	}
459  | 
460  | 	tryct = 0;
461  | 	while(np > 0 && tryct < 100) {
462  | 
463  | 	    x = rn2(100);
464  | 	    for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++) ;
465  | 	    if(i >= A_MAX) continue; /* impossible */
466  | 
467  | 	    if(ABASE(i) >= ATTRMAX(i)) {
468  | 
469  | 		tryct++;
470  | 		continue;
471  | 	    }
472  | 	    tryct = 0;
473  | 	    ABASE(i)++;
474  | 	    AMAX(i)++;
475  | 	    np--;
476  | 	}
477  | 
478  | 	tryct = 0;
479  | 	while(np < 0 && tryct < 100) {		/* for redistribution */
480  | 
481  | 	    x = rn2(100);
482  | 	    for (i = 0; (i < A_MAX) && ((x -= urole.attrdist[i]) > 0); i++) ;
483  | 	    if(i >= A_MAX) continue; /* impossible */
484  | 
485  | 	    if(ABASE(i) <= ATTRMIN(i)) {
486  | 
487  | 		tryct++;
488  | 		continue;
489  | 	    }
490  | 	    tryct = 0;
491  | 	    ABASE(i)--;
492  | 	    AMAX(i)--;
493  | 	    np++;
494  | 	}
495  | }
496  | 
497  | void
498  | redist_attr()
499  | {
500  | 	register int i, tmp;
501  | 
502  | 	for(i = 0; i < A_MAX; i++) {
503  | 	    if (i==A_INT || i==A_WIS) continue;
504  | 		/* Polymorphing doesn't change your mind */
505  | 	    tmp = AMAX(i);
506  | 	    AMAX(i) += (rn2(5)-2);
507  | 	    if (AMAX(i) > ATTRMAX(i)) AMAX(i) = ATTRMAX(i);
508  | 	    if (AMAX(i) < ATTRMIN(i)) AMAX(i) = ATTRMIN(i);
509  | 	    ABASE(i) = ABASE(i) * AMAX(i) / tmp;
510  | 	    /* ABASE(i) > ATTRMAX(i) is impossible */
511  | 	    if (ABASE(i) < ATTRMIN(i)) ABASE(i) = ATTRMIN(i);
512  | 	}
513  | 	(void)encumber_msg();
514  | }
515  | 
516  | void
517  | adjabil(oldlevel,newlevel)
518  | int oldlevel, newlevel;
519  | {
520  | 	register const struct innate *abil, *rabil;
521  | 	long mask = FROMEXPER;
522  | 
523  | 
524  | 	switch (Role_switch) {
525  | 	case PM_ARCHEOLOGIST:   abil = arc_abil;	break;
526  | 	case PM_BARBARIAN:      abil = bar_abil;	break;
527  | 	case PM_CAVEMAN:        abil = cav_abil;	break;
528  | 	case PM_HEALER:         abil = hea_abil;	break;
529  | 	case PM_KNIGHT:         abil = kni_abil;	break;
530  | 	case PM_MONK:           abil = mon_abil;	break;
531  | 	case PM_PRIEST:         abil = pri_abil;	break;
532  | 	case PM_RANGER:         abil = ran_abil;	break;
533  | 	case PM_ROGUE:          abil = rog_abil;	break;
534  | 	case PM_SAMURAI:        abil = sam_abil;	break;
535  | #ifdef TOURIST
536  | 	case PM_TOURIST:        abil = tou_abil;	break;
537  | #endif
538  | 	case PM_VALKYRIE:       abil = val_abil;	break;
539  | 	case PM_WIZARD:         abil = wiz_abil;	break;
540  | 	default:                abil = 0;		break;
541  | 	}
542  | 
543  | 	switch (Race_switch) {
544  | 	case PM_ELF:            rabil = elf_abil;	break;
545  | 	case PM_ORC:            rabil = orc_abil;	break;
546  | 	case PM_HUMAN:
547  | 	case PM_DWARF:
548  | 	case PM_GNOME:
549  | 	default:                rabil = 0;		break;
550  | 	}
551  | 
552  | 	while (abil || rabil) {
553  | 	    /* Have we finished with the intrinsics list? */
554  | 	    if (!abil || !abil->ability) {
555  | 	    	/* Try the race intrinsics */
556  | 	    	if (!rabil || !rabil->ability) break;
557  | 	    	abil = rabil;
558  | 	    	rabil = 0;
559  | 	    	mask = FROMRACE;
560  | 	    }
561  | 
562  | 		if(oldlevel < abil->ulevel && newlevel >= abil->ulevel) {
563  | 			/* Abilities gained at level 1 can never be lost
564  | 			 * via level loss, only via means that remove _any_
565  | 			 * sort of ability.  A "gain" of such an ability from
566  | 			 * an outside source is devoid of meaning, so we set
567  | 			 * FROMOUTSIDE to avoid such gains.
568  | 			 */
569  | 			if (abil->ulevel == 1)
570  | 				*(abil->ability) |= (mask|FROMOUTSIDE);
571  | 			else
572  | 				*(abil->ability) |= mask;
573  | 			if(!(*(abil->ability) & INTRINSIC & ~mask)) {
574  | 			    if(*(abil->gainstr))
575  | 				You_feel("%s!", abil->gainstr);
576  | 			}
577  | 		} else if (oldlevel >= abil->ulevel && newlevel < abil->ulevel) {
578  | 			*(abil->ability) &= ~mask;
579  | 			if(!(*(abil->ability) & INTRINSIC)) {
580  | 			    if(*(abil->losestr))
581  | 				You_feel("%s!", abil->losestr);
582  | 			    else if(*(abil->gainstr))
583  | 				You_feel("less %s!", abil->gainstr);
584  | 			}
585  | 		}
586  | 	    abil++;
587  | 	}
588  | 
589  | 	if (oldlevel > 0) {
590  | 	    if (newlevel > oldlevel)
591  | 		add_weapon_skill(newlevel - oldlevel);
592  | 	    else
593  | 		lose_weapon_skill(oldlevel - newlevel);
594  | 	}
595  | }
596  | 
597  | 
598  | int
599  | newhp()
600  | {
601  | 	int	hp, conplus;
602  | 
603  | 
604  | 	if (u.ulevel == 0) {
605  | 	    /* Initialize hit points */
606  | 	    hp = urole.hpadv.infix + urace.hpadv.infix;
607  | 	    if (urole.hpadv.inrnd > 0) hp += rnd(urole.hpadv.inrnd);
608  | 	    if (urace.hpadv.inrnd > 0) hp += rnd(urace.hpadv.inrnd);
609  | 
610  | 	    /* Initialize alignment stuff */
611  | 	    u.ualign.type = aligns[flags.initalign].value;
612  | 	    u.ualign.record = urole.initrecord;
613  | 
614  | 		return hp;
615  | 	} else {
616  | 	    if (u.ulevel < urole.xlev) {
617  | 	    	hp = urole.hpadv.lofix + urace.hpadv.lofix;
618  | 	    	if (urole.hpadv.lornd > 0) hp += rnd(urole.hpadv.lornd);
619  | 	    	if (urace.hpadv.lornd > 0) hp += rnd(urace.hpadv.lornd);
620  | 	    } else {
621  | 	    	hp = urole.hpadv.hifix + urace.hpadv.hifix;
622  | 	    	if (urole.hpadv.hirnd > 0) hp += rnd(urole.hpadv.hirnd);
623  | 	    	if (urace.hpadv.hirnd > 0) hp += rnd(urace.hpadv.hirnd);
624  | 	    }
625  | 	}
626  | 
627  | 	if (ACURR(A_CON) <= 3) conplus = -2;
628  | 	else if (ACURR(A_CON) <= 6) conplus = -1;
629  | 	else if (ACURR(A_CON) <= 14) conplus = 0;
630  | 	else if (ACURR(A_CON) <= 16) conplus = 1;
631  | 	else if (ACURR(A_CON) == 17) conplus = 2;
632  | 	else if (ACURR(A_CON) == 18) conplus = 3;
633  | 	else conplus = 4;
634  | 	
635  | 	hp += conplus;
636  | 	return((hp <= 0) ? 1 : hp);
637  | }
638  | 
639  | #endif /* OVLB */
640  | #ifdef OVL0
641  | 
642  | schar
643  | acurr(x)
644  | int x;
645  | {
646  | 	register int tmp = (u.abon.a[x] + u.atemp.a[x] + u.acurr.a[x]);
647  | 
648  | 	if (x == A_STR) {
649  | 		if (uarmg && uarmg->otyp == GAUNTLETS_OF_POWER) return(125);
650  | #ifdef WIN32_BUG
651  | 		else return(x=((tmp >= 125) ? 125 : (tmp <= 3) ? 3 : tmp));
652  | #else
653  | 		else return((schar)((tmp >= 125) ? 125 : (tmp <= 3) ? 3 : tmp));
654  | #endif
655  | 	} else if (x == A_CHA) {
656  | 		if (tmp < 18 && (youmonst.data->mlet == S_NYMPH ||
657  | 		    u.umonnum==PM_SUCCUBUS || u.umonnum == PM_INCUBUS))
658  | 		    return 18;
659  | 	} else if (x == A_INT || x == A_WIS) {
660  | 		/* yes, this may raise int/wis if player is sufficiently
661  | 		 * stupid.  there are lower levels of cognition than "dunce".
662  | 		 */
663  | 		if (uarmh && uarmh->otyp == DUNCE_CAP) return(6);
664  | 	}
665  | #ifdef WIN32_BUG
666  | 	return(x=((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp));
667  | #else
668  | 	return((schar)((tmp >= 25) ? 25 : (tmp <= 3) ? 3 : tmp));
669  | #endif
670  | }
671  | 
672  | /* condense clumsy ACURR(A_STR) value into value that fits into game formulas
673  |  */
674  | schar
675  | acurrstr()
676  | {
677  | 	register int str = ACURR(A_STR);
678  | 
679  | 	if (str <= 18) return((schar)str);
680  | 	if (str <= 121) return((schar)(19 + str / 50)); /* map to 19-21 */
681  | 	else return((schar)(str - 100));
682  | }
683  | 
684  | #endif /* OVL0 */
685  | #ifdef OVL2
686  | 
687  | /* avoid possible problems with alignment overflow, and provide a centralized
688  |  * location for any future alignment limits
689  |  */
690  | void
691  | adjalign(n)
692  | register int n;
693  | {
694  | 	register int newalign = u.ualign.record + n;
695  | 
696  | 	if(n < 0) {
697  | 		if(newalign < u.ualign.record)
698  | 			u.ualign.record = newalign;
699  | 	} else
700  | 		if(newalign > u.ualign.record) {
701  | 			u.ualign.record = newalign;
702  | 			if(u.ualign.record > ALIGNLIM)
703  | 				u.ualign.record = ALIGNLIM;
704  | 		}
705  | }
706  | 
707  | #endif /* OVL2 */
708  | 
709  | /*attrib.c*/