1    | /*	SCCS Id: @(#)exper.c	3.3	2000/07/23	*/
2    | /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3    | /* NetHack may be freely redistributed.  See license for details. */
4    | 
5    | #include "hack.h"
6    | 
7    | STATIC_DCL long FDECL(newuexp, (int));
8    | STATIC_DCL int FDECL(enermod, (int));
9    | 
10   | STATIC_OVL long
11   | newuexp(lev)
12   | int lev;
13   | {
14   | 	if (lev < 10) return (10L * (1L << lev));
15   | 	if (lev < 20) return (10000L * (1L << (lev - 10)));
16   | 	return (10000000L * ((long)(lev - 19)));
17   | }
18   | 
19   | STATIC_OVL int
20   | enermod(en)
21   | int en;
22   | {
23   | 	switch (Role_switch) {
24   | 	case PM_PRIEST:
25   | 	case PM_WIZARD:
26   | 	    return(2 * en);
27   | 	case PM_HEALER:
28   | 	case PM_KNIGHT:
29   | 	    return((3 * en) / 2);
30   | 	case PM_BARBARIAN:
31   | 	case PM_VALKYRIE:
32   | 	    return((3 * en) / 4);
33   | 	default:
34   | 	    return (en);
35   | 	}
36   | }
37   | 
38   | int
39   | experience(mtmp, nk)	/* return # of exp points for mtmp after nk killed */
40   | 	register struct	monst *mtmp;
41   | 	register int	nk;
42   | #if defined(applec)
43   | # pragma unused(nk)
44   | #endif
45   | {
46   | 	register struct permonst *ptr = mtmp->data;
47   | 	int	i, tmp, tmp2;
48   | 
49   | 	tmp = 1 + mtmp->m_lev * mtmp->m_lev;
50   | 
51   | /*	For higher ac values, give extra experience */
52   | 	if((i = find_mac(mtmp)) < 3) tmp += (7 - i) * (i < 0) ? 2 : 1;
53   | 
54   | /*	For very fast monsters, give extra experience */
55   | 	if(ptr->mmove >= 12) tmp += (ptr->mmove >= 18) ? 5 : 3;
56   | 
57   | /*	For each "special" attack type give extra experience */
58   | 	for(i = 0; i < NATTK; i++) {
59   | 
60   | 	    tmp2 = ptr->mattk[i].aatyp;
61   | 	    if(tmp2 > AT_BUTT) {
62   | 
63   | 		if(tmp2 == AT_WEAP) tmp += 5;
64   | 		else if(tmp2 == AT_MAGC) tmp += 10;
65   | 		else tmp += 3;
66   | 	    }
67   | 	}
68   | 
69   | /*	For each "special" damage type give extra experience */
70   | 	for(i = 0; i < NATTK; i++) {
71   | 	    tmp2 = ptr->mattk[i].adtyp;
72   | 	    if(tmp2 > AD_PHYS && tmp2 < AD_BLND) tmp += 2*mtmp->m_lev;
73   | 	    else if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) ||
74   | 	    		(tmp2 == AD_SLIM)) tmp += 50;
75   | 	    else if(tmp != AD_PHYS) tmp += mtmp->m_lev;
76   | 		/* extra heavy damage bonus */
77   | 	    if((int)(ptr->mattk[i].damd * ptr->mattk[i].damn) > 23)
78   | 		tmp += mtmp->m_lev;
79   | 	    if (tmp2 == AD_WRAP && ptr->mlet == S_EEL && !Amphibious)
80   | 		tmp += 1000;
81   | 	}
82   | 
83   | /*	For certain "extra nasty" monsters, give even more */
84   | 	if (extra_nasty(ptr)) tmp += (7 * mtmp->m_lev);
85   | 
86   | /*	For higher level monsters, an additional bonus is given */
87   | 	if(mtmp->m_lev > 8) tmp += 50;
88   | 
89   | #ifdef MAIL
90   | 	/* Mail daemons put up no fight. */
91   | 	if(mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1;
92   | #endif
93   | 
94   | 	return(tmp);
95   | }
96   | 
97   | void
98   | more_experienced(exp, rexp)
99   | 	register int exp, rexp;
100  | {
101  | 	u.uexp += exp;
102  | 	u.urexp += 4*exp + rexp;
103  | 	if(exp
104  | #ifdef SCORE_ON_BOTL
105  | 	   || flags.showscore
106  | #endif
107  | 	   ) flags.botl = 1;
108  | 	if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000))
109  | 		flags.beginner = 0;
110  | }
111  | 
112  | void
113  | losexp(drainer)		/* e.g., hit by drain life attack */
114  | const char *drainer;	/* cause of death, if drain should be fatal */
115  | {
116  | 	register int num;
117  | 
118  | 	if (resists_drli(&youmonst)) return;
119  | 
120  | 	if (u.ulevel > 1) {
121  | 		pline("%s level %d.", Goodbye(), u.ulevel--);
122  | 		/* remove intrinsic abilities */
123  | 		adjabil(u.ulevel + 1, u.ulevel);
124  | 		reset_rndmonst(NON_PM);	/* new monster selection */
125  | 	} else {
126  | 		if (drainer) {
127  | 			killer_format = KILLED_BY;
128  | 			killer = drainer;
129  | 			done(DIED);
130  | 		}
131  | 		/* no drainer or lifesaved */
132  | 		u.uexp = 0;
133  | 	}
134  | 	num = newhp();
135  | 	u.uhpmax -= num;
136  | 	if (u.uhpmax < 1) u.uhpmax = 1;
137  | 	u.uhp -= num;
138  | 	if (u.uhp < 1) u.uhp = 1;
139  | 	else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
140  | 
141  | 	if (u.ulevel < urole.xlev)
142  | 	    num = rn1(u.ulevel/2 + urole.enadv.lornd + urace.enadv.lornd,
143  | 			urole.enadv.lofix + urace.enadv.lofix);
144  | 	else
145  | 	    num = rn1(u.ulevel/2 + urole.enadv.hirnd + urace.enadv.hirnd,
146  | 			urole.enadv.hifix + urace.enadv.hifix);
147  | 	num = enermod(num);		/* M. Stephenson */
148  | 	u.uenmax -= num;
149  | 	if (u.uenmax < 0) u.uenmax = 0;
150  | 	u.uen -= num;
151  | 	if (u.uen < 0) u.uen = 0;
152  | 	else if (u.uen > u.uenmax) u.uen = u.uenmax;
153  | 
154  | 	if (u.uexp > 0)
155  | 		u.uexp = newuexp(u.ulevel) - 1;
156  | 	flags.botl = 1;
157  | }
158  | 
159  | /*
160  |  * Make experience gaining similar to AD&D(tm), whereby you can at most go
161  |  * up by one level at a time, extra expr possibly helping you along.
162  |  * After all, how much real experience does one get shooting a wand of death
163  |  * at a dragon created with a wand of polymorph??
164  |  */
165  | void
166  | newexplevel()
167  | {
168  | 	if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
169  | 	    pluslvl(TRUE);
170  | }
171  | 
172  | void
173  | pluslvl(incr)
174  | boolean incr;	/* true iff via incremental experience growth */
175  | {		/*	(false for potion of gain level)      */
176  | 	register int num;
177  | 
178  | 	if (!incr) You_feel("more experienced.");
179  | 	num = newhp();
180  | 	u.uhpmax += num;
181  | 	u.uhp += num;
182  | 	if (u.ulevel < urole.xlev)
183  | 	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
184  | 	    		urole.enadv.lofix + urace.enadv.lofix);
185  | 	else
186  | 	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
187  | 	    		urole.enadv.hifix + urace.enadv.hifix);
188  | 	num = enermod(num);	/* M. Stephenson */
189  | 	u.uenmax += num;
190  | 	u.uen += num;
191  | 	if (u.ulevel < MAXULEV) {
192  | 	    if (incr) {
193  | 		long tmp = newuexp(u.ulevel + 1);
194  | 		if (u.uexp >= tmp) u.uexp = tmp - 1;
195  | 	    } else {
196  | 		u.uexp = newuexp(u.ulevel);
197  | 	    }
198  | 	    ++u.ulevel;
199  | 	    if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
200  | 	    pline("Welcome to experience level %d.", u.ulevel);
201  | 	    adjabil(u.ulevel - 1, u.ulevel);	/* give new intrinsics */
202  | 	    reset_rndmonst(NON_PM);		/* new monster selection */
203  | 	}
204  | 	flags.botl = 1;
205  | }
206  | 
207  | long
208  | rndexp()
209  | {
210  | 	long minexp, maxexp, diff, factor;
211  | 
212  | 	minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
213  | 	maxexp = newuexp(u.ulevel);
214  | 	diff = maxexp - minexp,  factor = 1L;
215  | 	while (diff >= (long)LARGEST_INT)
216  | 	    diff /= 2L,  factor *= 2L;
217  | 	return minexp + factor * (long)rn2((int)diff);
218  | }
219  | 
220  | /*exper.c*/