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