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 
7 STATIC_DCL long FDECL(newuexp, (int));
8 STATIC_DCL int FDECL(enermod, (int));
9 
10 STATIC_OVL long
newuexp(lev)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
enermod(en)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
experience(mtmp,nk)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(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 /*	Dungeon fern spores give no experience */
91 	if(is_fern_spore(mtmp->data)) tmp = 0;
92 
93 #ifdef MAIL
94 	/* Mail daemons put up no fight. */
95 	if(mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1;
96 #endif
97 
98 	return(tmp);
99 }
100 
101 /**
102  * Adds to Experience and Scoring counter
103  */
104 void
more_experienced(exp,score,rexp)105 more_experienced(exp, score, rexp)
106 	register int exp, score, rexp;
107 {
108 	u.uexp += exp;
109 	u.urexp += 4*exp + rexp;
110 	u.urscore += 4*score + rexp;
111 	if(exp
112 #ifdef SCORE_ON_BOTL
113 	   || flags.showscore
114 #endif
115 	   ) flags.botl = 1;
116 	if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000))
117 		flags.beginner = 0;
118 }
119 
120 void
losexp(drainer)121 losexp(drainer)		/* e.g., hit by drain life attack */
122 const char *drainer;	/* cause of death, if drain should be fatal */
123 {
124 	register int num;
125 
126 #ifdef WIZARD
127 	/* override life-drain resistance when handling an explicit
128 	   wizard mode request to reduce level; never fatal though */
129 	if (drainer && !strcmp(drainer, "#levelchange"))
130 	    drainer = 0;
131 	else
132 #endif
133 	    if (resists_drli(&youmonst)) return;
134 
135 	if (u.ulevel > 1) {
136 		pline("%s level %d.", Goodbye(), u.ulevel--);
137 		/* remove intrinsic abilities */
138 		adjabil(u.ulevel + 1, u.ulevel);
139 		reset_rndmonst(NON_PM);	/* new monster selection */
140 	} else {
141 		if (drainer) {
142 			killer_format = KILLED_BY;
143 			killer = drainer;
144 			done(DIED);
145 		}
146 		/* no drainer or lifesaved */
147 		u.uexp = 0;
148 	}
149 	num = newhp();
150 	u.uhpmax -= num;
151 	check_uhpmax();
152 	if (u.uhpmax < 1) u.uhpmax = 1;
153 	u.uhp -= num;
154 	if (u.uhp < 1) u.uhp = 1;
155 	else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
156 
157 	if (u.ulevel < urole.xlev)
158 	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
159 			urole.enadv.lofix + urace.enadv.lofix);
160 	else
161 	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
162 			urole.enadv.hifix + urace.enadv.hifix);
163 	num = enermod(num);		/* M. Stephenson */
164 	u.uenmax -= num;
165 	if (u.uenmax < 0) u.uenmax = 0;
166 	u.uen -= num;
167 	if (u.uen < 0) u.uen = 0;
168 	else if (u.uen > u.uenmax) u.uen = u.uenmax;
169 
170 	if (u.uexp > 0)
171 		u.uexp = newuexp(u.ulevel) - 1;
172 	flags.botl = 1;
173 }
174 
175 /*
176  * Make experience gaining similar to AD&D(tm), whereby you can at most go
177  * up by one level at a time, extra expr possibly helping you along.
178  * After all, how much real experience does one get shooting a wand of death
179  * at a dragon created with a wand of polymorph??
180  */
181 void
newexplevel()182 newexplevel()
183 {
184 	if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
185 	    pluslvl(TRUE);
186 }
187 
188 void
pluslvl(incr)189 pluslvl(incr)
190 boolean incr;	/* true iff via incremental experience growth */
191 {		/*	(false for potion of gain level)      */
192 	register int num;
193 
194 	if (!incr) You_feel("more experienced.");
195 	num = newhp();
196 	u.uhpmax += num;
197 	u.uhp += num;
198 	if (Upolyd) {
199 	    num = rnd(8);
200 	    u.mhmax += num;
201 	    u.mh += num;
202 	}
203 	if (u.ulevel < urole.xlev)
204 	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
205 			urole.enadv.lofix + urace.enadv.lofix);
206 	else
207 	    num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
208 			urole.enadv.hifix + urace.enadv.hifix);
209 	num = enermod(num);	/* M. Stephenson */
210 	if (!Role_if(PM_TOURIST)) { /* Tourists have no innate magic abilities */
211 	    u.uenmax += num;
212 	    u.uen += num;
213 	}
214 	if (u.ulevel < MAXULEV) {
215 	    if (incr) {
216 		long tmp = newuexp(u.ulevel + 1);
217 		if (u.uexp >= tmp) u.uexp = tmp - 1;
218 	    } else {
219 		u.uexp = newuexp(u.ulevel);
220 	    }
221 	    ++u.ulevel;
222 	    if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
223 	    pline("Welcome to experience level %d.", u.ulevel);
224 	    adjabil(u.ulevel - 1, u.ulevel);	/* give new intrinsics */
225 	    reset_rndmonst(NON_PM);		/* new monster selection */
226 	}
227 	flags.botl = 1;
228 }
229 
230 /* compute a random amount of experience points suitable for the hero's
231    experience level:  base number of points needed to reach the current
232    level plus a random portion of what it takes to get to the next level */
233 long
rndexp(gaining)234 rndexp(gaining)
235 boolean gaining;	/* gaining XP via potion vs setting XP for polyself */
236 {
237 	long minexp, maxexp, diff, factor, result;
238 
239 	minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
240 	maxexp = newuexp(u.ulevel);
241 	diff = maxexp - minexp,  factor = 1L;
242 	/* make sure that `diff' is an argument which rn2() can handle */
243 	while (diff >= (long)LARGEST_INT)
244 	    diff /= 2L,  factor *= 2L;
245 	result = minexp + factor * (long)rn2((int)diff);
246 	/* 3.4.1:  if already at level 30, add to current experience
247 	   points rather than to threshold needed to reach the current
248 	   level; otherwise blessed potions of gain level can result
249 	   in lowering the experience points instead of raising them */
250 	if (u.ulevel == MAXULEV && gaining) {
251 	    result += (u.uexp - minexp);
252 	    /* avoid wrapping (over 400 blessed potions needed for that...) */
253 	    if (result < u.uexp) result = u.uexp;
254 	}
255 	return result;
256 }
257 
258 /*exper.c*/
259