OSDN Git Service

shrink mine
[nethackexpress/trunk.git] / src / exper.c
1 /*      SCCS Id: @(#)exper.c    3.4     2002/11/20      */
2 /* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
3 /* NetHack may be freely redistributed.  See license for details. */
4
5 #include "hack.h"
6
7 STATIC_DCL long FDECL(newuexp, (int));
8 STATIC_DCL int FDECL(enermod, (int));
9
10 STATIC_OVL long
11 newuexp(lev)
12 int lev;
13 {
14         if (lev < 10) return (10L * (1L << lev));
15         if (lev < 20) return (10000L * (1L << (lev - 10)));
16         return (10000000L * ((long)(lev - 19)));
17 }
18
19 STATIC_OVL int
20 enermod(en)
21 int en;
22 {
23         switch (Role_switch) {
24         case PM_PRIEST:
25         case PM_WIZARD:
26             return(2 * en);
27         case PM_HEALER:
28         case PM_KNIGHT:
29             return((3 * en) / 2);
30         case PM_BARBARIAN:
31         case PM_VALKYRIE:
32             return((3 * en) / 4);
33         default:
34             return (en);
35         }
36 }
37
38 int
39 experience(mtmp, nk)    /* return # of exp points for mtmp after nk killed */
40         register struct monst *mtmp;
41         register int    nk;
42 #if defined(macintosh) && (defined(__SC__) || defined(__MRC__))
43 # pragma unused(nk)
44 #endif
45 {
46         register struct permonst *ptr = mtmp->data;
47         int     i, tmp, tmp2;
48
49         tmp = 1 + mtmp->m_lev * mtmp->m_lev;
50
51 /*      For higher ac values, give extra experience */
52         if ((i = find_mac(mtmp)) < 3) tmp += (7 - i) * ((i < 0) ? 2 : 1);
53
54 /*      For very fast monsters, give extra experience */
55         if (ptr->mmove > NORMAL_SPEED)
56             tmp += (ptr->mmove > (3*NORMAL_SPEED/2)) ? 5 : 3;
57
58 /*      For each "special" attack type give extra experience */
59         for(i = 0; i < NATTK; i++) {
60
61             tmp2 = ptr->mattk[i].aatyp;
62             if(tmp2 > AT_BUTT) {
63
64                 if(tmp2 == AT_WEAP) tmp += 5;
65                 else if(tmp2 == AT_MAGC) tmp += 10;
66                 else tmp += 3;
67             }
68         }
69
70 /*      For each "special" damage type give extra experience */
71         for(i = 0; i < NATTK; i++) {
72             tmp2 = ptr->mattk[i].adtyp;
73             if(tmp2 > AD_PHYS && tmp2 < AD_BLND) tmp += 2*mtmp->m_lev;
74             else if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) ||
75                         (tmp2 == AD_SLIM)) tmp += 50;
76             else if(tmp != AD_PHYS) tmp += mtmp->m_lev;
77                 /* extra heavy damage bonus */
78             if((int)(ptr->mattk[i].damd * ptr->mattk[i].damn) > 23)
79                 tmp += mtmp->m_lev;
80             if (tmp2 == AD_WRAP && ptr->mlet == S_EEL && !Amphibious)
81                 tmp += 1000;
82         }
83
84 /*      For certain "extra nasty" monsters, give even more */
85         if (extra_nasty(ptr)) tmp += (7 * mtmp->m_lev);
86
87 /*      For higher level monsters, an additional bonus is given */
88         if(mtmp->m_lev > 8) tmp += 50;
89
90 #ifdef MAIL
91         /* Mail daemons put up no fight. */
92         if(mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1;
93 #endif
94
95         return(tmp);
96 }
97
98 void
99 more_experienced(exp, rexp)
100         register int exp, rexp;
101 {
102         u.uexp += exp;
103         u.urexp += 4*exp + rexp;
104         if(exp
105 #ifdef SCORE_ON_BOTL
106            || flags.showscore
107 #endif
108            ) flags.botl = 1;
109         if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000))
110                 flags.beginner = 0;
111 }
112
113 void
114 losexp(drainer)         /* e.g., hit by drain life attack */
115 const char *drainer;    /* cause of death, if drain should be fatal */
116 {
117         register int num;
118
119 #ifdef WIZARD
120         /* override life-drain resistance when handling an explicit
121            wizard mode request to reduce level; never fatal though */
122         if (drainer && !strcmp(drainer, "#levelchange"))
123             drainer = 0;
124         else
125 #endif
126             if (resists_drli(&youmonst)) return;
127
128         if (u.ulevel > 1) {
129                 pline("%s level %d.", Goodbye(), u.ulevel--);
130                 /* remove intrinsic abilities */
131                 adjabil(u.ulevel + 1, u.ulevel);
132                 reset_rndmonst(NON_PM); /* new monster selection */
133         } else {
134                 if (drainer) {
135                         killer_format = KILLED_BY;
136                         killer = drainer;
137                         done(DIED);
138                 }
139                 /* no drainer or lifesaved */
140                 u.uexp = 0;
141         }
142         num = newhp();
143         u.uhpmax -= num;
144         if (u.uhpmax < 1) u.uhpmax = 1;
145         u.uhp -= num;
146         if (u.uhp < 1) u.uhp = 1;
147         else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
148
149         if (u.ulevel < urole.xlev)
150             num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
151                         urole.enadv.lofix + urace.enadv.lofix);
152         else
153             num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
154                         urole.enadv.hifix + urace.enadv.hifix);
155         num = enermod(num);             /* M. Stephenson */
156         u.uenmax -= num;
157         if (u.uenmax < 0) u.uenmax = 0;
158         u.uen -= num;
159         if (u.uen < 0) u.uen = 0;
160         else if (u.uen > u.uenmax) u.uen = u.uenmax;
161
162         if (u.uexp > 0)
163                 u.uexp = newuexp(u.ulevel) - 1;
164         flags.botl = 1;
165 }
166
167 /*
168  * Make experience gaining similar to AD&D(tm), whereby you can at most go
169  * up by one level at a time, extra expr possibly helping you along.
170  * After all, how much real experience does one get shooting a wand of death
171  * at a dragon created with a wand of polymorph??
172  */
173 void
174 newexplevel()
175 {
176         if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
177             pluslvl(TRUE);
178 }
179
180 void
181 pluslvl(incr)
182 boolean incr;   /* true iff via incremental experience growth */
183 {               /*      (false for potion of gain level)      */
184         register int num;
185
186         if (!incr) You_feel("more experienced.");
187         num = newhp();
188         u.uhpmax += num;
189         u.uhp += num;
190         if (Upolyd) {
191             num = rnd(8);
192             u.mhmax += num;
193             u.mh += num;
194         }
195         if (u.ulevel < urole.xlev)
196             num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
197                         urole.enadv.lofix + urace.enadv.lofix);
198         else
199             num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
200                         urole.enadv.hifix + urace.enadv.hifix);
201         num = enermod(num);     /* M. Stephenson */
202         u.uenmax += num;
203         u.uen += num;
204         if (u.ulevel < MAXULEV) {
205             if (incr) {
206                 long tmp = newuexp(u.ulevel + 1);
207                 if (u.uexp >= tmp) u.uexp = tmp - 1;
208             } else {
209                 u.uexp = newuexp(u.ulevel);
210             }
211             ++u.ulevel;
212             if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
213             pline("Welcome to experience level %d.", u.ulevel);
214             adjabil(u.ulevel - 1, u.ulevel);    /* give new intrinsics */
215             reset_rndmonst(NON_PM);             /* new monster selection */
216         }
217         flags.botl = 1;
218 }
219
220 /* compute a random amount of experience points suitable for the hero's
221    experience level:  base number of points needed to reach the current
222    level plus a random portion of what it takes to get to the next level */
223 long
224 rndexp(gaining)
225 boolean gaining;        /* gaining XP via potion vs setting XP for polyself */
226 {
227         long minexp, maxexp, diff, factor, result;
228
229         minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
230         maxexp = newuexp(u.ulevel);
231         diff = maxexp - minexp,  factor = 1L;
232         /* make sure that `diff' is an argument which rn2() can handle */
233         while (diff >= (long)LARGEST_INT)
234             diff /= 2L,  factor *= 2L;
235         result = minexp + factor * (long)rn2((int)diff);
236         /* 3.4.1:  if already at level 30, add to current experience
237            points rather than to threshold needed to reach the current
238            level; otherwise blessed potions of gain level can result
239            in lowering the experience points instead of raising them */
240         if (u.ulevel == MAXULEV && gaining) {
241             result += (u.uexp - minexp);
242             /* avoid wrapping (over 400 blessed potions needed for that...) */
243             if (result < u.uexp) result = u.uexp;
244         }
245         return result;
246 }
247
248 /*exper.c*/