1 | /* SCCS Id: @(#)exper.c 3.3 2000/07/23 */
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(applec)
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 >= 12) tmp += (ptr->mmove >= 18) ? 5 : 3;
56 |
57 | /* For each "special" attack type give extra experience */
58 | for(i = 0; i < NATTK; i++) {
59 |
60 | tmp2 = ptr->mattk[i].aatyp;
61 | if(tmp2 > AT_BUTT) {
62 |
63 | if(tmp2 == AT_WEAP) tmp += 5;
64 | else if(tmp2 == AT_MAGC) tmp += 10;
65 | else tmp += 3;
66 | }
67 | }
68 |
69 | /* For each "special" damage type give extra experience */
70 | for(i = 0; i < NATTK; i++) {
71 | tmp2 = ptr->mattk[i].adtyp;
72 | if(tmp2 > AD_PHYS && tmp2 < AD_BLND) tmp += 2*mtmp->m_lev;
73 | else if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) ||
74 | (tmp2 == AD_SLIM)) tmp += 50;
75 | else if(tmp != AD_PHYS) tmp += mtmp->m_lev;
76 | /* extra heavy damage bonus */
77 | if((int)(ptr->mattk[i].damd * ptr->mattk[i].damn) > 23)
78 | tmp += mtmp->m_lev;
79 | if (tmp2 == AD_WRAP && ptr->mlet == S_EEL && !Amphibious)
80 | tmp += 1000;
81 | }
82 |
83 | /* For certain "extra nasty" monsters, give even more */
84 | if (extra_nasty(ptr)) tmp += (7 * mtmp->m_lev);
85 |
86 | /* For higher level monsters, an additional bonus is given */
87 | if(mtmp->m_lev > 8) tmp += 50;
88 |
89 | #ifdef MAIL
90 | /* Mail daemons put up no fight. */
91 | if(mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1;
92 | #endif
93 |
94 | return(tmp);
95 | }
96 |
97 | void
98 | more_experienced(exp, rexp)
99 | register int exp, rexp;
100 | {
101 | u.uexp += exp;
102 | u.urexp += 4*exp + rexp;
103 | if(exp
104 | #ifdef SCORE_ON_BOTL
105 | || flags.showscore
106 | #endif
107 | ) flags.botl = 1;
108 | if (u.urexp >= (Role_if(PM_WIZARD) ? 1000 : 2000))
109 | flags.beginner = 0;
110 | }
111 |
112 | void
113 | losexp(drainer) /* e.g., hit by drain life attack */
114 | const char *drainer; /* cause of death, if drain should be fatal */
115 | {
116 | register int num;
117 |
118 | if (resists_drli(&youmonst)) return;
119 |
120 | if (u.ulevel > 1) {
121 | pline("%s level %d.", Goodbye(), u.ulevel--);
122 | /* remove intrinsic abilities */
123 | adjabil(u.ulevel + 1, u.ulevel);
124 | reset_rndmonst(NON_PM); /* new monster selection */
125 | } else {
126 | if (drainer) {
127 | killer_format = KILLED_BY;
128 | killer = drainer;
129 | done(DIED);
130 | }
131 | /* no drainer or lifesaved */
132 | u.uexp = 0;
133 | }
134 | num = newhp();
135 | u.uhpmax -= num;
136 | if (u.uhpmax < 1) u.uhpmax = 1;
137 | u.uhp -= num;
138 | if (u.uhp < 1) u.uhp = 1;
139 | else if (u.uhp > u.uhpmax) u.uhp = u.uhpmax;
140 |
141 | if (u.ulevel < urole.xlev)
142 | num = rn1(u.ulevel/2 + urole.enadv.lornd + urace.enadv.lornd,
143 | urole.enadv.lofix + urace.enadv.lofix);
144 | else
145 | num = rn1(u.ulevel/2 + urole.enadv.hirnd + urace.enadv.hirnd,
146 | urole.enadv.hifix + urace.enadv.hifix);
147 | num = enermod(num); /* M. Stephenson */
148 | u.uenmax -= num;
149 | if (u.uenmax < 0) u.uenmax = 0;
150 | u.uen -= num;
151 | if (u.uen < 0) u.uen = 0;
152 | else if (u.uen > u.uenmax) u.uen = u.uenmax;
153 |
154 | if (u.uexp > 0)
155 | u.uexp = newuexp(u.ulevel) - 1;
156 | flags.botl = 1;
157 | }
158 |
159 | /*
160 | * Make experience gaining similar to AD&D(tm), whereby you can at most go
161 | * up by one level at a time, extra expr possibly helping you along.
162 | * After all, how much real experience does one get shooting a wand of death
163 | * at a dragon created with a wand of polymorph??
164 | */
165 | void
166 | newexplevel()
167 | {
168 | if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel))
169 | pluslvl(TRUE);
170 | }
171 |
172 | void
173 | pluslvl(incr)
174 | boolean incr; /* true iff via incremental experience growth */
175 | { /* (false for potion of gain level) */
176 | register int num;
177 |
178 | if (!incr) You_feel("more experienced.");
179 | num = newhp();
180 | u.uhpmax += num;
181 | u.uhp += num;
182 | if (u.ulevel < urole.xlev)
183 | num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.lornd + urace.enadv.lornd,
184 | urole.enadv.lofix + urace.enadv.lofix);
185 | else
186 | num = rn1((int)ACURR(A_WIS)/2 + urole.enadv.hirnd + urace.enadv.hirnd,
187 | urole.enadv.hifix + urace.enadv.hifix);
188 | num = enermod(num); /* M. Stephenson */
189 | u.uenmax += num;
190 | u.uen += num;
191 | if (u.ulevel < MAXULEV) {
192 | if (incr) {
193 | long tmp = newuexp(u.ulevel + 1);
194 | if (u.uexp >= tmp) u.uexp = tmp - 1;
195 | } else {
196 | u.uexp = newuexp(u.ulevel);
197 | }
198 | ++u.ulevel;
199 | if (u.ulevelmax < u.ulevel) u.ulevelmax = u.ulevel;
200 | pline("Welcome to experience level %d.", u.ulevel);
201 | adjabil(u.ulevel - 1, u.ulevel); /* give new intrinsics */
202 | reset_rndmonst(NON_PM); /* new monster selection */
203 | }
204 | flags.botl = 1;
205 | }
206 |
207 | long
208 | rndexp()
209 | {
210 | long minexp, maxexp, diff, factor;
211 |
212 | minexp = (u.ulevel == 1) ? 0L : newuexp(u.ulevel - 1);
213 | maxexp = newuexp(u.ulevel);
214 | diff = maxexp - minexp, factor = 1L;
215 | while (diff >= (long)LARGEST_INT)
216 | diff /= 2L, factor *= 2L;
217 | return minexp + factor * (long)rn2((int)diff);
218 | }
219 |
220 | /*exper.c*/