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 */
14 static
15 const char	* const plusattr[] = {
16 	"strong", "smart", "wise", "agile", "tough", "charismatic"
17 },
18 		* const minusattr[] = {
19 	"weak", "stupid", "foolish", "clumsy", "fragile", "repulsive"
20 };
21 
22 
23 static
24 const 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 
99 static long next_check = 600L;	/* arbitrary first setting */
100 STATIC_DCL void NDECL(exerper);
101 STATIC_DCL void FDECL(postadjabil, (long *));
102 
103 /* adjust an attribute; return TRUE if change is made, FALSE otherwise */
104 boolean
adjattrib(ndx,incr,msgflg)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 > 1 && (ndx == A_STR || ndx == A_CON))
159 		(void)encumber_msg();
160 	return TRUE;
161 }
162 
163 void
gainstr(otmp,incr)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
losestr(num)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
change_luck(n)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
stone_luck(parameter)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 (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 */
225 void
set_moreluck()226 set_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 
238 void
restore_attrib()239 restore_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 
262 void
exercise(i,inc_or_dec)263 exercise(i, inc_or_dec)
264 int	i;
265 boolean	inc_or_dec;
266 {
267 #ifdef 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 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 
305 STATIC_OVL void
exerper()306 exerper()
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 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 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 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 
366 void
exerchk()367 exerchk()
368 {
369 	int	i, mod_val;
370 
371 	/*	Check out the periodic accumulations */
372 	exerper();
373 
374 #ifdef 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 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 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 DEBUG
412 		pline("exerchk: changing %d.", i);
413 #endif
414 		if(adjattrib(i, mod_val, -1)) {
415 #ifdef 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 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 */
449 void
reset_attribute_clock()450 reset_attribute_clock()
451 {
452 	if (moves > 600L) next_check = moves + rn1(50,800);
453 }
454 
455 
456 void
init_attr(np)457 init_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 
506 void
redist_attr()507 redist_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 
525 STATIC_OVL
526 void
postadjabil(ability)527 postadjabil(ability)
528 long *ability;
529 {
530 	if (!ability) return;
531 	if (ability == &(HWarning) || ability == &(HSee_invisible))
532 		see_monsters();
533 }
534 
535 void
adjabil(oldlevel,newlevel)536 adjabil(oldlevel,newlevel)
537 int 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 
620 int
newhp()621 newhp()
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 
664 schar
acurr(x)665 acurr(x)
666 int 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  */
696 schar
acurrstr()697 acurrstr()
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  */
712 void
adjalign(n)713 adjalign(n)
714 register 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