Iron bars, water and lava are not interesting for travel
[aNetHack.git] / src / exper.c
blob06456e0c0e436df75133e43a6f1855b8d34a9357
1 /* NetHack 3.6 exper.c $NHDT-Date: 1446975467 2015/11/08 09:37:47 $ $NHDT-Branch: master $:$NHDT-Revision: 1.26 $ */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed. See license for details. */
5 #include "hack.h"
6 #include <limits.h>
8 STATIC_DCL long FDECL(newuexp, (int));
9 STATIC_DCL int FDECL(enermod, (int));
11 STATIC_OVL long
12 newuexp(lev)
13 int lev;
15 if (lev < 10)
16 return (10L * (1L << lev));
17 if (lev < 20)
18 return (10000L * (1L << (lev - 10)));
19 return (10000000L * ((long) (lev - 19)));
22 STATIC_OVL int
23 enermod(en)
24 int en;
26 switch (Role_switch) {
27 case PM_PRIEST:
28 case PM_WIZARD:
29 return (2 * en);
30 case PM_HEALER:
31 case PM_KNIGHT:
32 return ((3 * en) / 2);
33 case PM_BARBARIAN:
34 case PM_VALKYRIE:
35 return ((3 * en) / 4);
36 default:
37 return en;
41 /* calculate spell power/energy points for new level */
42 int
43 newpw()
45 int en = 0, enrnd, enfix;
47 if (u.ulevel == 0) {
48 en = urole.enadv.infix + urace.enadv.infix;
49 if (urole.enadv.inrnd > 0)
50 en += rnd(urole.enadv.inrnd);
51 if (urace.enadv.inrnd > 0)
52 en += rnd(urace.enadv.inrnd);
53 } else {
54 enrnd = (int) ACURR(A_WIS) / 2;
55 if (u.ulevel < urole.xlev) {
56 enrnd += urole.enadv.lornd + urace.enadv.lornd;
57 enfix = urole.enadv.lofix + urace.enadv.lofix;
58 } else {
59 enrnd += urole.enadv.hirnd + urace.enadv.hirnd;
60 enfix = urole.enadv.hifix + urace.enadv.hifix;
62 en = enermod(rn1(enrnd, enfix));
64 if (en <= 0)
65 en = 1;
66 if (u.ulevel < MAXULEV)
67 u.ueninc[u.ulevel] = (xchar) en;
68 return en;
71 /* return # of exp points for mtmp after nk killed */
72 int
73 experience(mtmp, nk)
74 register struct monst *mtmp;
75 register int nk;
77 register struct permonst *ptr = mtmp->data;
78 int i, tmp, tmp2;
80 tmp = 1 + mtmp->m_lev * mtmp->m_lev;
82 /* For higher ac values, give extra experience */
83 if ((i = find_mac(mtmp)) < 3)
84 tmp += (7 - i) * ((i < 0) ? 2 : 1);
86 /* For very fast monsters, give extra experience */
87 if (ptr->mmove > NORMAL_SPEED)
88 tmp += (ptr->mmove > (3 * NORMAL_SPEED / 2)) ? 5 : 3;
90 /* For each "special" attack type give extra experience */
91 for (i = 0; i < NATTK; i++) {
92 tmp2 = ptr->mattk[i].aatyp;
93 if (tmp2 > AT_BUTT) {
94 if (tmp2 == AT_WEAP)
95 tmp += 5;
96 else if (tmp2 == AT_MAGC)
97 tmp += 10;
98 else
99 tmp += 3;
103 /* For each "special" damage type give extra experience */
104 for (i = 0; i < NATTK; i++) {
105 tmp2 = ptr->mattk[i].adtyp;
106 if (tmp2 > AD_PHYS && tmp2 < AD_BLND)
107 tmp += 2 * mtmp->m_lev;
108 else if ((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_SLIM))
109 tmp += 50;
110 else if (tmp2 != AD_PHYS)
111 tmp += mtmp->m_lev;
112 /* extra heavy damage bonus */
113 if ((int) (ptr->mattk[i].damd * ptr->mattk[i].damn) > 23)
114 tmp += mtmp->m_lev;
115 if (tmp2 == AD_WRAP && ptr->mlet == S_EEL && !Amphibious)
116 tmp += 1000;
119 /* For certain "extra nasty" monsters, give even more */
120 if (extra_nasty(ptr))
121 tmp += (7 * mtmp->m_lev);
123 /* For higher level monsters, an additional bonus is given */
124 if (mtmp->m_lev > 8)
125 tmp += 50;
127 #ifdef MAIL
128 /* Mail daemons put up no fight. */
129 if (mtmp->data == &mons[PM_MAIL_DAEMON])
130 tmp = 1;
131 #endif
133 if (mtmp->mrevived || mtmp->mcloned) {
135 * Reduce experience awarded for repeated killings of
136 * "the same monster". Kill count includes all of this
137 * monster's type which have been killed--including the
138 * current monster--regardless of how they were created.
139 * 1.. 20 full experience
140 * 21.. 40 xp / 2
141 * 41.. 80 xp / 4
142 * 81..120 xp / 8
143 * 121..180 xp / 16
144 * 181..240 xp / 32
145 * 241..255+ xp / 64
147 for (i = 0, tmp2 = 20; nk > tmp2 && tmp > 1; ++i) {
148 tmp = (tmp + 1) / 2;
149 nk -= tmp2;
150 if (i & 1)
151 tmp2 += 20;
155 return (tmp);
158 void
159 more_experienced(exper, rexp)
160 register int exper, rexp;
162 long newexp = u.uexp + exper;
163 long rexpincr = 4 * exper + rexp;
164 long newrexp = u.urexp + rexpincr;
166 /* cap experience and score on wraparound */
167 if (newexp < 0 && exper > 0)
168 newexp = LONG_MAX;
169 if (newrexp < 0 && rexpincr > 0)
170 newrexp = LONG_MAX;
171 u.uexp = newexp;
172 u.urexp = newrexp;
174 if (exper
175 #ifdef SCORE_ON_BOTL
176 || flags.showscore
177 #endif
179 context.botl = 1;
180 if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000))
181 flags.beginner = 0;
184 /* e.g., hit by drain life attack */
185 void
186 losexp(drainer)
187 const char *drainer; /* cause of death, if drain should be fatal */
189 register int num;
191 /* override life-drain resistance when handling an explicit
192 wizard mode request to reduce level; never fatal though */
193 if (drainer && !strcmp(drainer, "#levelchange"))
194 drainer = 0;
195 else if (resists_drli(&youmonst))
196 return;
198 if (u.ulevel > 1) {
199 pline("%s level %d.", Goodbye(), u.ulevel--);
200 /* remove intrinsic abilities */
201 adjabil(u.ulevel + 1, u.ulevel);
202 reset_rndmonst(NON_PM); /* new monster selection */
203 } else {
204 if (drainer) {
205 killer.format = KILLED_BY;
206 if (killer.name != drainer)
207 Strcpy(killer.name, drainer);
208 done(DIED);
210 /* no drainer or lifesaved */
211 u.uexp = 0;
213 num = (int) u.uhpinc[u.ulevel];
214 u.uhpmax -= num;
215 if (u.uhpmax < 1)
216 u.uhpmax = 1;
217 u.uhp -= num;
218 if (u.uhp < 1)
219 u.uhp = 1;
220 else if (u.uhp > u.uhpmax)
221 u.uhp = u.uhpmax;
223 num = (int) u.ueninc[u.ulevel];
224 u.uenmax -= num;
225 if (u.uenmax < 0)
226 u.uenmax = 0;
227 u.uen -= num;
228 if (u.uen < 0)
229 u.uen = 0;
230 else if (u.uen > u.uenmax)
231 u.uen = u.uenmax;
233 if (u.uexp > 0)
234 u.uexp = newuexp(u.ulevel) - 1;
236 if (Upolyd) {
237 num = monhp_per_lvl(&youmonst);
238 u.mhmax -= num;
239 u.mh -= num;
240 if (u.mh <= 0)
241 rehumanize();
244 context.botl = 1;
248 * Make experience gaining similar to AD&D(tm), whereby you can at most go
249 * up by one level at a time, extra expr possibly helping you along.
250 * After all, how much real experience does one get shooting a wand of death
251 * at a dragon created with a wand of polymorph??
253 void
254 newexplevel()
256 if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
257 pluslvl(TRUE);
260 void
261 pluslvl(incr)
262 boolean incr; /* true iff via incremental experience growth */
263 { /* (false for potion of gain level) */
264 int hpinc, eninc;
266 if (!incr)
267 You_feel("more experienced.");
269 /* increase hit points (when polymorphed, do monster form first
270 in order to retain normal human/whatever increase for later) */
271 if (Upolyd) {
272 hpinc = monhp_per_lvl(&youmonst);
273 u.mhmax += hpinc;
274 u.mh += hpinc;
276 hpinc = newhp();
277 u.uhpmax += hpinc;
278 u.uhp += hpinc;
280 /* increase spell power/energy points */
281 eninc = newpw();
282 u.uenmax += eninc;
283 u.uen += eninc;
285 /* increase level (unless already maxxed) */
286 if (u.ulevel < MAXULEV) {
287 /* increase experience points to reflect new level */
288 if (incr) {
289 long tmp = newuexp(u.ulevel + 1);
290 if (u.uexp >= tmp)
291 u.uexp = tmp - 1;
292 } else {
293 u.uexp = newuexp(u.ulevel);
295 ++u.ulevel;
296 if (u.ulevelmax < u.ulevel)
297 u.ulevelmax = u.ulevel;
298 pline("Welcome to experience level %d.", u.ulevel);
299 adjabil(u.ulevel - 1, u.ulevel); /* give new intrinsics */
300 reset_rndmonst(NON_PM); /* new monster selection */
302 context.botl = 1;
305 /* compute a random amount of experience points suitable for the hero's
306 experience level: base number of points needed to reach the current
307 level plus a random portion of what it takes to get to the next level */
308 long
309 rndexp(gaining)
310 boolean gaining; /* gaining XP via potion vs setting XP for polyself */
312 long minexp, maxexp, diff, factor, result;
314 minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
315 maxexp = newuexp(u.ulevel);
316 diff = maxexp - minexp, factor = 1L;
317 /* make sure that `diff' is an argument which rn2() can handle */
318 while (diff >= (long) LARGEST_INT)
319 diff /= 2L, factor *= 2L;
320 result = minexp + factor * (long) rn2((int) diff);
321 /* 3.4.1: if already at level 30, add to current experience
322 points rather than to threshold needed to reach the current
323 level; otherwise blessed potions of gain level can result
324 in lowering the experience points instead of raising them */
325 if (u.ulevel == MAXULEV && gaining) {
326 result += (u.uexp - minexp);
327 /* avoid wrapping (over 400 blessed potions needed for that...) */
328 if (result < u.uexp)
329 result = u.uexp;
331 return result;
334 /*exper.c*/