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