OSDN Git Service

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