OSDN Git Service

patch src/
[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 /*JP
200         pline("%s level %d.", Goodbye(), u.ulevel--);
201 */
202         pline("\82³\82æ\82¤\82È\82ç\83\8c\83x\83\8b%d\81D", u.ulevel--);
203         /* remove intrinsic abilities */
204         adjabil(u.ulevel + 1, u.ulevel);
205         reset_rndmonst(NON_PM); /* new monster selection */
206     } else {
207         if (drainer) {
208             killer.format = KILLED_BY;
209             if (killer.name != drainer)
210                 Strcpy(killer.name, drainer);
211             done(DIED);
212         }
213         /* no drainer or lifesaved */
214         u.uexp = 0;
215     }
216     num = (int) u.uhpinc[u.ulevel];
217     u.uhpmax -= num;
218     if (u.uhpmax < 1)
219         u.uhpmax = 1;
220     u.uhp -= num;
221     if (u.uhp < 1)
222         u.uhp = 1;
223     else if (u.uhp > u.uhpmax)
224         u.uhp = u.uhpmax;
225
226     num = (int) u.ueninc[u.ulevel];
227     u.uenmax -= num;
228     if (u.uenmax < 0)
229         u.uenmax = 0;
230     u.uen -= num;
231     if (u.uen < 0)
232         u.uen = 0;
233     else if (u.uen > u.uenmax)
234         u.uen = u.uenmax;
235
236     if (u.uexp > 0)
237         u.uexp = newuexp(u.ulevel) - 1;
238
239     if (Upolyd) {
240         num = monhp_per_lvl(&youmonst);
241         u.mhmax -= num;
242         u.mh -= num;
243         if (u.mh <= 0)
244             rehumanize();
245     }
246
247     context.botl = 1;
248 }
249
250 /*
251  * Make experience gaining similar to AD&D(tm), whereby you can at most go
252  * up by one level at a time, extra expr possibly helping you along.
253  * After all, how much real experience does one get shooting a wand of death
254  * at a dragon created with a wand of polymorph??
255  */
256 void
257 newexplevel()
258 {
259     if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
260         pluslvl(TRUE);
261 }
262
263 void
264 pluslvl(incr)
265 boolean incr; /* true iff via incremental experience growth */
266 {             /*        (false for potion of gain level)    */
267     int hpinc, eninc;
268
269     if (!incr)
270 /*JP
271         You_feel("more experienced.");
272 */
273         You("\82æ\82è\8co\8c±\82ð\82Â\82ñ\82¾\82æ\82¤\82È\8bC\82ª\82µ\82½\81D");
274
275     /* increase hit points (when polymorphed, do monster form first
276        in order to retain normal human/whatever increase for later) */
277     if (Upolyd) {
278         hpinc = monhp_per_lvl(&youmonst);
279         u.mhmax += hpinc;
280         u.mh += hpinc;
281     }
282     hpinc = newhp();
283     u.uhpmax += hpinc;
284     u.uhp += hpinc;
285
286     /* increase spell power/energy points */
287     eninc = newpw();
288     u.uenmax += eninc;
289     u.uen += eninc;
290
291     /* increase level (unless already maxxed) */
292     if (u.ulevel < MAXULEV) {
293         /* increase experience points to reflect new level */
294         if (incr) {
295             long tmp = newuexp(u.ulevel + 1);
296             if (u.uexp >= tmp)
297                 u.uexp = tmp - 1;
298         } else {
299             u.uexp = newuexp(u.ulevel);
300         }
301         ++u.ulevel;
302         if (u.ulevelmax < u.ulevel)
303             u.ulevelmax = u.ulevel;
304 /*JP
305         pline("Welcome to experience level %d.", u.ulevel);
306 */
307         pline("\83\8c\83x\83\8b%d\82É\82æ\82¤\82±\82»\81D", u.ulevel);
308         adjabil(u.ulevel - 1, u.ulevel); /* give new intrinsics */
309         reset_rndmonst(NON_PM);          /* new monster selection */
310     }
311     context.botl = 1;
312 }
313
314 /* compute a random amount of experience points suitable for the hero's
315    experience level:  base number of points needed to reach the current
316    level plus a random portion of what it takes to get to the next level */
317 long
318 rndexp(gaining)
319 boolean gaining; /* gaining XP via potion vs setting XP for polyself */
320 {
321     long minexp, maxexp, diff, factor, result;
322
323     minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
324     maxexp = newuexp(u.ulevel);
325     diff = maxexp - minexp, factor = 1L;
326     /* make sure that `diff' is an argument which rn2() can handle */
327     while (diff >= (long) LARGEST_INT)
328         diff /= 2L, factor *= 2L;
329     result = minexp + factor * (long) rn2((int) diff);
330     /* 3.4.1:  if already at level 30, add to current experience
331        points rather than to threshold needed to reach the current
332        level; otherwise blessed potions of gain level can result
333        in lowering the experience points instead of raising them */
334     if (u.ulevel == MAXULEV && gaining) {
335         result += (u.uexp - minexp);
336         /* avoid wrapping (over 400 blessed potions needed for that...) */
337         if (result < u.uexp)
338             result = u.uexp;
339     }
340     return result;
341 }
342
343 /*exper.c*/