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