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 7STATIC_DCL long FDECL(newuexp, (int)); 8STATIC_DCL int FDECL(enermod, (int)); 9 10STATIC_OVL long 11newuexp(lev) 12int 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 19STATIC_OVL int 20enermod(en) 21int 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 38int 39experience(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 98void 99more_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 113void 114losexp(drainer) /* e.g., hit by drain life attack */ 115const 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 */ 173void 174newexplevel() 175{ 176 if (u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel)) 177 pluslvl(TRUE); 178} 179 180void 181pluslvl(incr) 182boolean 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 */ 223long 224rndexp(gaining) 225boolean 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*/ 249