roh/conf.old/area/
roh/config/code/python/
roh/config/game/area/
roh/config/game/signs/
roh/help/dmhelp/
roh/help/help/
roh/log/
roh/log/staff/
roh/monsters/ocean/
roh/objects/misc/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.47e/
/*
 * player2.cpp
 *	 Player routines.
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * Permission to use, modify and distribute is granted via the
 *  Creative Commons - Attribution - Non Commercial - Share Alike 3.0 License
 *    http://creativecommons.org/licenses/by-nc-sa/3.0/
 *
 * 	Copyright (C) 2007-2012 Jason Mitchell, Randi Mitchell
 * 	   Contributions by Tim Callahan, Jonathan Hseu
 *  Based on Mordor (C) Brooke Paul, Brett J. Vickers, John P. Freeman
 *
 */
#include "mud.h"
#include <math.h>
#include "login.h"
#include "commands.h"

//********************************************************************
//						calcStats
//********************************************************************

void Player::calcStats(vstat sendStat, vstat *toStat) {
	int			i=0, levels = 0, switchNum=0;
	int			cls=0, cls2=0, lvl=0, r=0;
	int			hptemp=0,mptemp=0;

	// stats are 1 based, the array is 0 based, so give us extra room
	int		num[MAX_STAT+1];



	if(sendStat.race)
		r = tstat.race;
	else
		r = race;

	if(sendStat.cls)
		cls = tstat.cls;
	else
		cls = cClass;

	if(sendStat.cls2)
		cls2 = tstat.cls2;
	else
		cls2 = cClass2;

	if(sendStat.level)
		lvl = tstat.level;
	else
		lvl = level;


	for(i=1; i<=MAX_STAT; i++) {
		num[i] = sendStat.num[i-1] * 10;
		num[i] += gConfig->getRace(r)->getStatAdj(i);
		num[i] = MAX(1, num[i]);
	}

    PlayerClass *pClass = gConfig->classes[getClassString()];
    //const RaceData* rData = gConfig->getRace(race);
    LevelGain *lGain = 0;

    // Check for level info
	if(!pClass) {
		print("Error: Can't find your class!\n");
		if(!isStaff()) {
			bstring errorStr = "Error: Can't find class: " + getClassString();
			merror(errorStr.c_str(), NONFATAL);
		}
		return;
	} 


	// Now to adjust hit points accordingly
	hptemp = pClass->getBaseHp();
    if(cClass != BERSERKER && cClass != LICH)
    	mptemp = pClass->getBaseMp();


	for(levels = 1; levels <= lvl; levels ++) {
		lGain = pClass->getLevelGain(levels);
		if(!lGain) {
			print("Error: Can't find any information for level %d!\n", levels);
			if(!isStaff()) {
				bstring errorStr = "Error: Can't find level info for " + getClassString() + level;
				merror(errorStr.c_str(), NONFATAL);
			}
			continue;
		}

		switchNum = lGain->getStat();
		num[switchNum] += 10;

		// Now to adjust hit points accordingly
		hptemp += lGain->getHp();

		if(cClass != BERSERKER && cClass != LICH)
			mptemp += lGain->getMp();

		if(cls != LICH)	{
			if(cls == BERSERKER && num[CON] >= 70)
				hptemp++;
			if(num[CON] >= 130)
				hptemp++;
			if(num[CON] >= 210)
				hptemp++;
			if(num[CON] >= 250)
				hptemp++;
		}

		// liches gain an extra HP at every even level.
		if(levels % 2 == 0 && cls == LICH)
			hptemp++;
	}

	for(i=0; i<MAX_STAT; i++)
		toStat->num[i] = num[i+1];

	toStat->hp = hptemp;
	toStat->mp = mptemp;
}

//********************************************************************
//						checkConfusion
//********************************************************************

bool Player::checkConfusion() {
	int		action=0, dmg=0;
	mType	targetType = PLAYER;
	char	atk[50];
	Creature* target=0;
	Exit	*newExit=0;
	BaseRoom* room = getRoomParent(), *bRoom=0;
	CatRef	cr;


	if(!isEffected("confusion"))
		return(false);

	action = mrand(1,4);
	switch(action) {
	case 1: // Stand confused

		broadcast(getSock(), room, "%M stands with a confused look on %s face.", this, hisHer());
		printColor("^BYou are confused and dizzy. You stand and look around cluelessly.\n");
		stun(mrand(5,10));
		return(true);
		break;
	case 2: // Wander to random exit

		newExit = getFleeableExit();
		if(!newExit)
			return(false);
		bRoom = getFleeableRoom(newExit);
		if(!bRoom)
			return(false);

		printColor("^BWanderlust overtakes you.\n");
		printColor("^BYou wander aimlessly to the %s exit.\n", newExit->getCName());
		broadcast(getSock(), room, "%M wanders aimlessly to the %s exit.", this, newExit->getCName());
		deleteFromRoom();
		addToRoom(bRoom);
		doPetFollow();
		return(true);
		break;
	case 3: // Attack something randomly
		if(!checkAttackTimer(false))
			return(false);

		switch(mrand(1,2)) {
		case 1:
			target = getRandomMonster(room);
			if(!target)
				target = getRandomPlayer(room);
			if(target) {
				targetType = target->getType();
				break;
			}
			break;
		case 2:
			target = getRandomPlayer(room);
			if(!target)
				target = getRandomMonster(room);
			if(target) {
				targetType = target->getType();
				break;
			}
			break;
		default:
			break;
		}

		if(!target || target == this)
			targetType = INVALID;


		switch(targetType) {
		case PLAYER: // Random player in room
			printColor("^BYou are convinced %s is trying to kill you!\n", target->getCName());
			attackCreature(target);
			return(true);
			break;
		case INVALID: // Self

			if(ready[WIELD-1]) {
				dmg = ready[WIELD-1]->damage.roll() +
				      bonus((int)strength.getCur()) + ready[WIELD-1]->getAdjustment();
				printColor("^BYou frantically swing your weapon at imaginary enemies.\n");
			} else {
				printColor("^BYou madly flail around at imaginary enemies.\n");
				if(cClass == MONK) {
					dmg = mrand(1,2) + level/3 + mrand(1,(1+level)/2);
					if(strength.getCur() < 90) {
						dmg -= (90-strength.getCur())/10;
						dmg = MAX(1,dmg);
					}
				} else
					dmg = damage.roll();
			}

			getDamageString(atk, this, ready[WIELD - 1]);

			printColor("^BYou %s yourself for %d damage!\n", atk, dmg);

			broadcast(getSock(), room, "%M %s %sself!", this, atk, himHer());
			hp.decrease(dmg);
			if(hp.getCur() < 1) {

				hp.setCur(1);

				printColor("^BYou accidentally killed yourself!\n");
				broadcast("### Sadly, %s accidentally killed %sself.", getCName(), himHer());

				mp.setCur(1);

				if(!inJail()) {
					bRoom = getLimboRoom().loadRoom(this);
					if(bRoom) {
						deleteFromRoom();
						addToRoom(bRoom);
						doPetFollow();
					}
				}
			}
			return(true);
			break;
		default: // Random monster in room.
			if(target->flagIsSet(M_UNKILLABLE))
				return(false);

			printColor("^BYou think %s is attacking you!\n", target);
			broadcast(getSock(), room, "%M yells, \"DIE %s!!!\"\n", this, target->getCName());
			attackCreature(target);
			return(true);
			break;
		}
		break;
	case 4: // flee
		printColor("^BPhantom dangers in your head beckon you to flee!\n");
		broadcast(getSock(), room, "%M screams in terror, pointing around at everything.", this);
		flee();
		return(true);
		break;
	default:
		break;
	}
	return(false);
}

//********************************************************************
//						getEtherealTravelRoom
//********************************************************************

CatRef getEtherealTravelRoom() {
	const CatRefInfo* eth = gConfig->getCatRefInfo("et");
	CatRef cr;
	cr.setArea("et");
	cr.id = mrand(1, eth->getTeleportWeight());
	return(cr);
}

//********************************************************************
//						etherealTravel
//********************************************************************

void etherealTravel(Player* player) {
	UniqueRoom	*newRoom=0;
	CatRef	cr = getEtherealTravelRoom();

	if(!loadRoom(cr, &newRoom))
		return;

	player->deleteFromRoom();
	player->addToRoom(newRoom);
	player->doPetFollow();
}

//********************************************************************
//						cmdVisible
//********************************************************************

int cmdVisible(Player* player, cmd* cmnd) {
	if(!player->isInvisible()) {
		player->print("You are not invisible.\n");
		return(0);
	} else {
		player->removeEffect("invisibility");
		player->removeEffect("greater-invisibility");
	}
	return(0);
}

//********************************************************************
//						cmdDice
//********************************************************************

int cmdDice(Creature* player, cmd* cmnd) {
	char	*str=0, *tok=0, diceOutput[256], add[256];
	int		strLen=0, i=0;
	int		diceSides=0,diceNum=0,diceAdd=0;
	int		rolls=0, total=0;

	const char *Syntax =	"\nSyntax: dice 1d2\n"
					"        dice 1d2+3\n";

	strcpy(diceOutput, "");
	strcpy(add ,"");

	strLen = cmnd->fullstr.length();

	// This kills all leading whitespace
	while(i<strLen && isspace(cmnd->fullstr[i]))
		i++;
	// This kills the command itself
	while(i<strLen && !isspace(cmnd->fullstr[i]))
		i++;

	str = strstr(&cmnd->fullstr[i], "d");
	if(!str)
		return(cmdAction(player, cmnd));

	str = strdup(&cmnd->fullstr[i]);
	if(!str) {
		player->print(Syntax);
		return(0);
	}

	tok = strtok(str, "d");
	if(!tok) {
		player->print(Syntax);
		return(0);
	}
	diceNum = atoi(tok);

	tok = strtok(NULL, "+");
	if(!tok) {
		player->print(Syntax);
		return(0);
	}
	diceSides = atoi(tok);

	tok = strtok(NULL, "+");

	if(tok)
		diceAdd = atoi(tok);

	if(diceNum < 0) {
		player->print("How can you roll a negative number of dice?\n");
		return(0);
	}

	diceNum = MAX(1, diceNum);

	if(diceSides<2) {
		player->print("A die has a minimum of 2 sides.\n");
		return(0);
	}

	diceNum = MIN(100, diceNum);
	diceSides = MIN(100, diceSides);
	diceAdd = MAX(-100,MIN(100, diceAdd));


	sprintf(diceOutput, "%dd%d", diceNum, diceSides);
	if(diceAdd) {
		if(diceAdd > 0)
			sprintf(add, "+%d", diceAdd);
		else
			sprintf(add, "%d", diceAdd);
		strcat(diceOutput, add);
	}


	for(rolls=0;rolls<diceNum;rolls++)
		total += mrand(1, diceSides);

	total += diceAdd;


	player->print("You roll %s\n: %d\n", diceOutput, total);
	broadcast(player->getSock(), player->getParent(), "(Dice %s): %M got %d.", diceOutput, player, total );

	return(0);
}
//
////********************************************************************
////						plyHasObj
////********************************************************************
//// This will check to see if a player has a specific object type
//// either in their inventory or in a bag, or in their worn equipment.
//
//bool plyHasObj(Creature* player, Object *item) {
//	int		a=0;
//	Object	*obj=0;
//	UniqueRoom* room=0;
//
//
//	//check inventory
//	for(Object* obj : player->objects) {
//		if(obj->info == item->info)
//			return(true);
//
//		// if item is a bag, check in bag
//		if(obj->getType() == CONTAINER) {
//			cop = obj->first_obj;
//			while(cop) {
//				if(*&cop->obj->info == *&item->info)
//					return(true);
//				cop = cop->next_tag;
//			}
//		}
//
//		op = op->next_tag;
//
//	}
//	// check worn equipment
//	for(a=0;a<MAXWEAR;a++) {
//
//		if(!player->ready[a])
//			continue;
//
//		obj = player->ready[a];
//		if(*&obj->info == *&item->info && obj != item)
//			return(true);
//
//		// if worn item is a bag, check in bag
//		if(obj->getType() == CONTAINER) {
//			cop = obj->first_obj;
//			while(cop) {
//				if(*&cop->obj->info == *&item->info && cop->obj != item)
//					return(true);
//				cop = cop->next_tag;
//			}
//		}
//
//
//	}
//
//	// check player's storage room, if it exists
//	if(player->isPlayer()) {
//		CatRef	sr = gConfig->getSingleProperty(player->getAsPlayer(), PROP_STORAGE);
//		if(sr.id < 1 || !loadRoom(sr, &room))
//			return(0);
//
//		op = room->first_obj;
//		while(op) {
//			if(op->obj->getType() == CONTAINER) {
//				cop = op->obj->first_obj;
//				while(cop) {
//					if(*&cop->obj->info == *&item->info && cop->obj != item)
//						return(true);
//					cop = cop->next_tag;
//				}
//			}
//
//			if(*&op->obj->info == *&item->info && op->obj != item)
//				return(true);
//			op = op->next_tag;
//		}
//
//	}
//
//	return(false);
//}
//