OSDN Git Service

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