OSDN Git Service

import nethack-3.6.0
[jnethack/source.git] / src / exper.c
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. */
4
5 #include "hack.h"
6 #include <limits.h>
7
8 STATIC_DCL long FDECL(newuexp, (int));
9 STATIC_DCL int FDECL(enermod, (int));
10
11 STATIC_OVL long
12 newuexp(lev)
13 int lev;
14 {
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)));
20 }
21
22 STATIC_OVL int
23 enermod(en)
24 int en;
25 {
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;
38     }
39 }
40
41 /* calculate spell power/energy points for new level */
42 int
43 newpw()
44 {
45     int en = 0, enrnd, enfix;
46
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;
61         }
62         en = enermod(rn1(enrnd, enfix));
63     }
64     if (en <= 0)
65         en = 1;
66     if (u.ulevel < MAXULEV)
67         u.ueninc[u.ulevel] = (xchar) en;
68     return en;
69 }
70
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;
76 {
77     register struct permonst *ptr = mtmp->data;
78     int i, tmp, tmp2;
79
80     tmp = 1 + mtmp->m_lev * mtmp->m_lev;
81
82     /*  For higher ac values, give extra experience */
83     if ((i = find_mac(mtmp)) < 3)
84         tmp += (7 - i) * ((i < 0) ? 2 : 1);
85
86     /*  For very fast monsters, give extra experience */
87     if (ptr->mmove > NORMAL_SPEED)
88         tmp += (ptr->mmove > (3 * NORMAL_SPEED / 2)) ? 5 : 3;
89
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;
100         }
101     }
102
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;
117     }
118
119     /*  For certain "extra nasty" monsters, give even more */
120     if (extra_nasty(ptr))
121         tmp += (7 * mtmp->m_lev);
122
123     /*  For higher level monsters, an additional bonus is given */
124     if (mtmp->m_lev > 8)
125         tmp += 50;
126
127 #ifdef MAIL
128     /* Mail daemons put up no fight. */
129     if (mtmp->data == &mons[PM_MAIL_DAEMON])
130         tmp = 1;
131 #endif
132
133     if (mtmp->mrevived || mtmp->mcloned) {
134         /*
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
146          */
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;
152         }
153     }
154
155     return (tmp);
156 }
157
158 void
159 more_experienced(exper, rexp)
160 register int exper, rexp;
161 {
162     long newexp = u.uexp + exper;
163     long rexpincr = 4 * exper + rexp;
164     long newrexp = u.urexp + rexpincr;
165
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;
173
174     if (exper
175 #ifdef SCORE_ON_BOTL
176         || flags.showscore
177 #endif
178         )
179         context.botl = 1;
180     if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000))
181         flags.beginner = 0;
182 }
183
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 */
188 {
189     register int num;
190
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;
197
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);
209         }
210         /* no drainer or lifesaved */
211         u.uexp = 0;
212     }
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;
222
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;
232
233     if (u.uexp > 0)
234         u.uexp = newuexp(u.ulevel) - 1;
235
236     if (Upolyd) {
237         num = monhp_per_lvl(&youmonst);
238         u.mhmax -= num;
239         u.mh -= num;
240         if (u.mh <= 0)
241             rehumanize();
242     }
243
244     context.botl = 1;
245 }
246
247 /*
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??
252  */
253 void
254 newexplevel()
255 {
256     if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
257         pluslvl(TRUE);
258 }
259
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;
265
266     if (!incr)
267         You_feel("more experienced.");
268
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;
275     }
276     hpinc = newhp();
277     u.uhpmax += hpinc;
278     u.uhp += hpinc;
279
280     /* increase spell power/energy points */
281     eninc = newpw();
282     u.uenmax += eninc;
283     u.uen += eninc;
284
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);
294         }
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 */
301     }
302     context.botl = 1;
303 }
304
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 */
311 {
312     long minexp, maxexp, diff, factor, result;
313
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;
330     }
331     return result;
332 }
333
334 /*exper.c*/