/*      SCCS Id: @(#)exper.c    3.1     90/22/02
/* Copyright (c) Stichting Mathematisch Centrum, Amsterdam, 1985. */
/* NetHack may be freely redistributed.  See license for details. */

#include "hack.h"

#ifdef LINT
#define NEW_SCORING
#endif
long
newuexp(lev)
register unsigned lev;
{
#ifdef LINT     /* long conversion */
	return(0L * lev);
#else
	/*              Old XP routine */
	/* if(lev < 10) return (50L*(1L << lev));  */
	/* if(lev < 15) return (25000L*(lev-9));   */
	/* if(lev < 20) return (75000L*(lev-14));  */
	/* if(lev < 25) return (200000L*(lev-19)); */
	/* return (500000L*(lev-24));              */

/*	if (lev == 1)  return (75L);
	if (lev == 2)  return (150L);
	if (lev == 3)  return (300L);
	if (lev == 4)  return (600L);
	if (lev == 5)  return (1200L); */
	if (lev == 1)  return (50L);     /* need 50           */
	if (lev == 2)  return (100L);    /* need 50           */
	if (lev == 3)  return (200L);    /* need 100          */
	if (lev == 4)  return (500L);    /* need 300          */
	if (lev == 5)  return (1000L);   /* need 500          */
	if (lev == 6)  return (1750L);   /* need 750          */
	if (lev == 7)  return (2750L);   /* need 1000         */
	if (lev == 8)  return (4250L);   /* need 1500         */
	if (lev == 9)  return (6250L);   /* need 2000         */
	if (lev == 10) return (8750L);   /* need 2500         */
	if (lev == 11) return (11750L);  /* need 3000         */
	if (lev == 12) return (15500L);  /* need 3750         */
	if (lev == 13) return (20000L);  /* need 4500         */
	if (lev == 14) return (25000L);  /* need 5000         */
	if (lev == 15) return (31000L);  /* need 6000         */
	if (lev == 16) return (38500L);  /* need 7500         */
	if (lev == 17) return (48000L);  /* need 9500         */
	if (lev == 18) return (60000L);  /* need 12000        */
	if (lev == 19) return (76000L);  /* need 16000        */
	if (lev == 20) return (97000L);  /* need 21000        */
	if (lev == 21) return (125000L); /* need 28000   +7   */
	if (lev == 22) return (163000L); /* need 38000   +10  */
	if (lev == 23) return (213000L); /* need 50000   +12  */
	if (lev == 24) return (279000L); /* need 66000  +16   */
	if (lev == 25) return (365000L); /* need 86000 + 20   */
	if (lev == 26) return (476000L); /* need 111000 + 25  */
	if (lev == 27) return (617000L); /* need 141000+ 30   */
	if (lev == 28) return (798000L); /* need 181000 + 40  */
	if (lev == 29) return (1034000L); /* need 236000 + 55 */
	return (1750000L);
#endif
}

int
experience(mtmp, nk)    /* return # of exp points for mtmp after nk killed */
	register struct monst *mtmp;
	register int    nk;
#if defined(applec)
# pragma unused(nk)
#endif
{
	register struct permonst *ptr = mtmp->data;
	int     i, tmp, tmp2;

	tmp = 1 + mtmp->m_lev * mtmp->m_lev;

/*      For higher ac values, give extra experience */
	if((i = find_mac(mtmp)) < 3) tmp += (7 - i) * (i < 0) ? 2 : 1;

/*      For very fast monsters, give extra experience */
	if(ptr->mmove >= 12) tmp += (ptr->mmove >= 18) ? 5 : 3;

/*      For each "special" attack type give extra experience */
	for(i = 0; i < NATTK; i++) {

	    tmp2 = ptr->mattk[i].aatyp;
	    if(tmp2 > AT_BUTT) {

		if(tmp2 == AT_WEAP) tmp += 5;
		else if(tmp2 == AT_MAGC) tmp += 10;
		else tmp += 3;
	    }
	}

/*      For each "special" damage type give extra experience */
	for(i = 0; i < NATTK; i++) {

	    tmp2 = ptr->mattk[i].adtyp;
	    if(tmp2 > AD_PHYS && tmp2 < AD_BLND) tmp += 2*mtmp->m_lev;
	    else if((tmp2 == AD_DRLI) || (tmp2 == AD_STON) || (tmp2 == AD_SLIM)) tmp += 50;
	    else if(tmp != AD_PHYS) tmp += mtmp->m_lev;
		/* extra heavy damage bonus */
	    if((int)(ptr->mattk[i].damd * ptr->mattk[i].damn) > 23)
		tmp += mtmp->m_lev;
	}

/*      For certain "extra nasty" monsters, give even more */
	if(extra_nasty(ptr)) tmp += (7*mtmp->m_lev);

	if(ptr->mlet == S_EEL) tmp *= 2;

/*      For higher level monsters, an additional bonus is given */
	if(mtmp->m_lev > 8) tmp += 50;

#ifdef NEW_SCORING
	/* ------- recent addition: make nr of points decrease
		   when this is not the first of this kind */
	{ unsigned ul = u.ulevel;
	  int ml = mtmp->m_lev;
	/* points are given based on present and future level */
	  if(ul < MAXULEV)
	    for(tmp2 = 0; !tmp2 || ul + tmp2 <= ml; tmp2++)
		if(u.uexp + 1 + (tmp + ((tmp2 <= 0) ? 0 : 4<<(tmp2-1)))/nk
		    >= newuexp(ul) )
			if(++ul == MAXULEV) break;

	  tmp2 = ml - ul -1;
	  tmp = (tmp + ((tmp2 < 0) ? 0 : 4<<tmp2))/nk;
	  if(tmp <= 0) tmp = 1;
	}
	/* note: ul is not necessarily the future value of u.ulevel */
	/* ------- end of recent valuation change ------- */
#endif /* NEW_SCORING /**/

#ifdef MAIL
	/* Mail daemons put up no fight. */
	if(mtmp->data == &mons[PM_MAIL_DAEMON]) tmp = 1;
#endif

	return(tmp);
}

void
more_experienced(exp, rexp)
	register int exp, rexp;
{
	u.uexp += exp;
	u.urexp += 4*exp + rexp;
	if(exp
#ifdef SCORE_ON_BOTL
	   || flags.showscore
#endif
	   ) flags.botl = 1;
	if(u.urexp >= ((pl_character[0] == 'W') ? 1000 : 2000))
		flags.beginner = 0;
}

void
losexp() {      /* hit by drain life attack */

	register int num;

#ifdef POLYSELF
	if(resists_drli(uasmon)) return;
#endif

	if (Antimagic && rn2(2)) {
	    pline("You feel weaker for a moment, but it passes.");
	    return;
	}
	if (rn2(2)) {
	    pline("You feel weaker for a moment, but it passes.");
	    return;
	}
	if(u.ulevel > 1) {
		pline("Goodbye level %u.", u.ulevel--);
		/* remove intrinsic abilities */
		adjabil((int)u.ulevel+1, (int)u.ulevel);
	} else
/* STEPHEN WHITE'S NEW CODE */                                
		u.uhp = -1;
	num = newhp();
	u.uhp -= num;
	u.uhpmax -= num;
	u.uhpbase -= num;
	
	if (pl_character[0] == 'A') num = rnd(4) + 1;
	else if (pl_character[0] == 'B') num = rnd(2);
	else if (pl_character[0] == 'C') num = rnd(2);
	else if (pl_character[0] == 'D') num = rnd(5) + 1;
	else if (pl_character[0] == 'E') num = rnd(5) + 1;
	else if (pl_character[0] == 'F') num = rnd(6) + 2;
	else if (pl_character[0] == 'G') num = rnd(3);
	else if (pl_character[0] == 'H') num = rnd(6) + 2;
	else if (pl_character[0] == 'I') num = rnd(6) + 2;
	else if (pl_character[0] == 'K') num = rnd(3);
	else if (pl_character[0] == 'L') num = rnd(5) + 1;
	else if (pl_character[0] == 'M') num = rnd(5) + 1;
	else if (pl_character[0] == 'N') num = rnd(6) + 2;
	else if (pl_character[0] == 'P') num = rnd(6) + 2;
	else if (pl_character[0] == 'R') num = rnd(4) + 1;
	else if (pl_character[0] == 'S') num = rnd(2);
#ifdef TOURIST        
	else if (pl_character[0] == 'T') num = rnd(4) + 1;
#endif        
	else if (pl_character[0] == 'U') num = rnd(3);
	else if (pl_character[0] == 'V') num = rnd(2);
	else if (pl_character[0] == 'W') num = rnd(6) + 2;
	else num = rnd(2) + 1;

	u.uen -= num;
	if (u.uen < 0)          u.uen = 0;
	u.uenbase -= num;
	if (u.uenbase < 0)       u.uenbase = 0;
	u.uexp = newuexp(u.ulevel) - 1;
	flags.botl = 1;
}
       

/*
 * Make experience gaining similar to AD&D(tm), whereby you can at most go
 * up by one level at a time, extra expr possibly helping you along.
 * After all, how much real experience does one get shooting a wand of death
 * at a dragon created with a wand of polymorph??
 */
void
newexplevel() {

	register int tmp;

	if(u.ulevel < MAXULEV && u.uexp >= newuexp(u.ulevel)) {

		u.ulevel++;
		if (u.uexp >= newuexp(u.ulevel)) u.uexp = newuexp(u.ulevel) - 1;
		pline("Welcome to experience level %u.", u.ulevel);
		set_uasmon();   /* set up for the new level. */
		/* give new intrinsics */
		adjabil((int)u.ulevel-1, (int)u.ulevel);
/* STEPHEN WHITE'S NEW CODE */                
		tmp = newhp();
		u.uhpbase += tmp;
		u.uhpmax += tmp;
		u.uhp += tmp;
		
		if (pl_character[0] == 'A') u.uenbase += rnd(4) + 1;
		else if (pl_character[0] == 'B') u.uenbase += rnd(2);
		else if (pl_character[0] == 'C') u.uenbase += rnd(2);
		else if (pl_character[0] == 'D') u.uenbase += rnd(5) + 1;
		else if (pl_character[0] == 'E') u.uenbase += rnd(5) + 1;
		else if (pl_character[0] == 'F') u.uenbase += rnd(6) + 2;
		else if (pl_character[0] == 'G') u.uenbase += rnd(3);
		else if (pl_character[0] == 'H') u.uenbase += rnd(6) + 2;
		else if (pl_character[0] == 'I') u.uenbase += rnd(6) + 2;
		else if (pl_character[0] == 'K') u.uenbase += rnd(3);
		else if (pl_character[0] == 'L') u.uenbase += rnd(5) + 1;
		else if (pl_character[0] == 'M') u.uenbase += rnd(5) + 1;
		else if (pl_character[0] == 'N') u.uenbase += rnd(6) + 2;
		else if (pl_character[0] == 'P') u.uenbase += rnd(6) + 2;
		else if (pl_character[0] == 'R') u.uenbase += rnd(4) + 1;
		else if (pl_character[0] == 'S') u.uenbase += rnd(2);
#ifdef TOURIST
		else if (pl_character[0] == 'T') u.uenbase += rnd(4) + 1;
#endif
		else if (pl_character[0] == 'U') u.uenbase += rnd(3);
		else if (pl_character[0] == 'V') u.uenbase += rnd(2);
		else if (pl_character[0] == 'W') u.uenbase += rnd(6) + 2;
		else u.uenbase += rnd(2) + 1;
		flags.botl = 1;
	}
}

void
pluslvl() {
	register int num;

	You("feel more experienced.");
	num = newhp();
	u.uhpbase += num;
	u.uhpmax += num;
	u.uhp += num;
	num = rn1((int)ACURR(A_WIS)/2+1, 2);    /* M. Stephenson */
	u.uenbase += num;
	u.uenmax += num;
	u.uen += num;
	if(u.ulevel < MAXULEV) {
		u.uexp = newuexp(u.ulevel);
		pline("Welcome to experience level %u.", ++u.ulevel);
		adjabil((int)u.ulevel-1, (int)u.ulevel);
	}
	flags.botl = 1;
}

long
rndexp()
{
	register long minexp,maxexp;

	if(u.ulevel == 1)
		return rn2((int)newuexp(1));
	else {
		minexp = newuexp(u.ulevel - 1);
		maxexp = newuexp(u.ulevel);
		return(minexp + rn2((int)(maxexp - minexp)));
	}
}

/*exper.c*/
