OSDN Git Service

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