1/*	SCCS Id: @(#)exper.c	3.4	2002/11/20	*/
2/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3/* NetHack may be freely redistributed.  See license for details. */
4
5#include "hack.h"
6
7STATIC_DCL long FDECL(newuexp, (int));
8STATIC_DCL int FDECL(enermod, (int));
9
10STATIC_OVL long
11newuexp(lev)
12int 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
19STATIC_OVL int
20enermod(en)
21int 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
38int
39experience(mtmp, nk)	/* return # of exp points for mtmp after nk killed */
40	register struct	monst *mtmp;
41	register int	nk;
42#if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
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 > NORMAL_SPEED)
56	    tmp += (ptr->mmove > (3*NORMAL_SPEED/2)) ? 5 : 3;
57
58/*	For each "special" attack type give extra experience */
59	for(i = 0; i < NATTK; i++) {
60
61	    tmp2 = ptr->mattk[i].aatyp;
62	    if(tmp2 > AT_BUTT) {
63
64		if(tmp2 == AT_WEAP) tmp += 5;
65		else if(tmp2 == AT_MAGC) tmp += 10;
66		else tmp += 3;
67	    }
68	}
69
70/*	For each "special" damage type give extra experience */
71	for(i = 0; i < NATTK; i++) {
72	    tmp2 = ptr->mattk[i].adtyp;
73	    if(tmp2 > AD_PHYS && tmp2 < AD_BLND) tmp += 2*mtmp->m_lev;
74	    else if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) ||
75	    		(tmp2 == AD_SLIM)) tmp += 50;
76	    else if(tmp != AD_PHYS) tmp += mtmp->m_lev;
77		/* extra heavy damage bonus */
78	    if((int)(ptr->mattk[i].damd * ptr->mattk[i].damn) > 23)
79		tmp += mtmp->m_lev;
80	    if (tmp2 == AD_WRAP && ptr->mlet == S_EEL && !Amphibious)
81		tmp += 1000;
82	}
83
84/*	For certain "extra nasty" monsters, give even more */
85	if (extra_nasty(ptr)) tmp += (7 * mtmp->m_lev);
86
87/*	For higher level monsters, an additional bonus is given */
88	if(mtmp->m_lev > 8) tmp += 50;
89
90#ifdef MAIL
91	/* Mail daemons put up no fight. */
92	if(mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1;
93#endif
94
95	return(tmp);
96}
97
98void
99more_experienced(exp, rexp)
100	register int exp, rexp;
101{
102	u.uexp += exp;
103	u.urexp += 4*exp + rexp;
104	if(exp
105#ifdef SCORE_ON_BOTL
106	   || flags.showscore
107#endif
108	   ) flags.botl = 1;
109	if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000))
110		flags.beginner = 0;
111}
112
113void
114losexp(drainer)		/* e.g., hit by drain life attack */
115const char *drainer;	/* cause of death, if drain should be fatal */
116{
117	register int num;
118
119#ifdef WIZARD
120	/* override life-drain resistance when handling an explicit
121	   wizard mode request to reduce level; never fatal though */
122	if (drainer && !strcmp(drainer, "#levelchange"))
123	    drainer = 0;
124	else
125#endif
126	    if (resists_drli(&youmonst)) return;
127
128	if (u.ulevel > 1) {
129		pline("%s level %d.", Goodbye(), u.ulevel--);
130		/* remove intrinsic abilities */
131		adjabil(u.ulevel + 1, u.ulevel);
132		reset_rndmonst(NON_PM);	/* new monster selection */
133	} else {
134		if (drainer) {
135			killer_format = KILLED_BY;
136			killer = drainer;
137			done(DIED);
138		}
139		/* no drainer or lifesaved */
140		u.uexp = 0;
141	}
142	num = newhp();
143	u.uhpmax -= num;
144	if (u.uhpmax < 1) u.uhpmax = 1;
145	u.uhp -= num;
146	if (u.uhp < 1) u.uhp = 1;
147	else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
148
149	if (u.ulevel < urole.xlev)
150	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
151			urole.enadv.lofix + urace.enadv.lofix);
152	else
153	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
154			urole.enadv.hifix + urace.enadv.hifix);
155	num = enermod(num);		/* M. Stephenson */
156	u.uenmax -= num;
157	if (u.uenmax < 0) u.uenmax = 0;
158	u.uen -= num;
159	if (u.uen < 0) u.uen = 0;
160	else if (u.uen > u.uenmax) u.uen = u.uenmax;
161
162	if (u.uexp > 0)
163		u.uexp = newuexp(u.ulevel) - 1;
164	flags.botl = 1;
165}
166
167/*
168 * Make experience gaining similar to AD&D(tm), whereby you can at most go
169 * up by one level at a time, extra expr possibly helping you along.
170 * After all, how much real experience does one get shooting a wand of death
171 * at a dragon created with a wand of polymorph??
172 */
173void
174newexplevel()
175{
176	if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
177	    pluslvl(TRUE);
178}
179
180void
181pluslvl(incr)
182boolean incr;	/* true iff via incremental experience growth */
183{		/*	(false for potion of gain level)      */
184	register int num;
185
186	if (!incr) You_feel("more experienced.");
187	num = newhp();
188	u.uhpmax += num;
189	u.uhp += num;
190	if (Upolyd) {
191	    num = rnd(8);
192	    u.mhmax += num;
193	    u.mh += num;
194	}
195	if (u.ulevel < urole.xlev)
196	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
197			urole.enadv.lofix + urace.enadv.lofix);
198	else
199	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
200			urole.enadv.hifix + urace.enadv.hifix);
201	num = enermod(num);	/* M. Stephenson */
202	u.uenmax += num;
203	u.uen += num;
204	if (u.ulevel < MAXULEV) {
205	    if (incr) {
206		long tmp = newuexp(u.ulevel + 1);
207		if (u.uexp >= tmp) u.uexp = tmp - 1;
208	    } else {
209		u.uexp = newuexp(u.ulevel);
210	    }
211	    ++u.ulevel;
212	    if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
213	    pline("Welcome to experience level %d.", u.ulevel);
214	    adjabil(u.ulevel - 1, u.ulevel);	/* give new intrinsics */
215	    reset_rndmonst(NON_PM);		/* new monster selection */
216	}
217	flags.botl = 1;
218}
219
220/* compute a random amount of experience points suitable for the hero's
221   experience level:  base number of points needed to reach the current
222   level plus a random portion of what it takes to get to the next level */
223long
224rndexp(gaining)
225boolean gaining;	/* gaining XP via potion vs setting XP for polyself */
226{
227	long minexp, maxexp, diff, factor, result;
228
229	minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
230	maxexp = newuexp(u.ulevel);
231	diff = maxexp - minexp,  factor = 1L;
232	/* make sure that `diff' is an argument which rn2() can handle */
233	while (diff >= (long)LARGEST_INT)
234	    diff /= 2L,  factor *= 2L;
235	result = minexp + factor * (long)rn2((int)diff);
236	/* 3.4.1:  if already at level 30, add to current experience
237	   points rather than to threshold needed to reach the current
238	   level; otherwise blessed potions of gain level can result
239	   in lowering the experience points instead of raising them */
240	if (u.ulevel == MAXULEV && gaining) {
241	    result += (u.uexp - minexp);
242	    /* avoid wrapping (over 400 blessed potions needed for that...) */
243	    if (result < u.uexp) result = u.uexp;
244	}
245	return result;
246}
247
248/*exper.c*/
249