OSDN Git Service

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