roh/conf/area/
roh/game/talk/
roh/help/
roh/monsters/ocean/
roh/objects/ocean/
roh/player/
roh/rooms/area/1/
roh/rooms/misc/
roh/rooms/ocean/
roh/src-2.44b/
/*
 * bank.cpp
 *	 Bank code
 *   ____            _
 *  |  _ \ ___  __ _| |_ __ ___  ___
 *  | |_) / _ \/ _` | | '_ ` _ \/ __|
 *  |  _ <  __/ (_| | | | | | | \__ \
 *  |_| \_\___|\__,_|_|_| |_| |_|___/
 *
 * 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-2009 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"

//*********************************************************************
//						bankTeller
//*********************************************************************
// we get the bankteller mob in the room, if there is one

Monster* bankTeller(BaseRoom* room) {
	ctag* cp = room->first_mon;
	while(cp) {
		if(!strcmp(cp->crt->name, "bank teller"))
			return(cp->crt->getMonster());
		cp = cp->next_tag;
	}
	return(0);
}


//*********************************************************************
//						bankTeller
//*********************************************************************
// we get the bankteller mob in the room, if there is one

bool bankerCanSee(Player* player) {
	if(player->isCt())
		return(true);

	if(player->flagIsSet(P_MISTED)) {
		player->print("You are in mist form and cannot handle physical objects.\n");
		return(false);
	}

	if(!player->isInvisible())
		return(true);

	// magic money machines don't need to see people
	if(player->getRoom()->flagIsSet(R_MAGIC_MONEY_MACHINE))
		return(true);

	Monster* teller = bankTeller(player->getRoom());
	if(teller && teller->canSee(player))
		return(true);

	player->print("The bank teller says, \"I don't deal with people I can't see!\"\n");
	return(false);
}


//*********************************************************************
//						noNeedBank
//*********************************************************************
// can this person use the bank without being in a bank room?

bool noNeedBank(Player* player) {
	return(
		(player->getClass() == CLERIC && player->getDeity() == JAKAR) ||
		player->isCt()
	);
}


//*********************************************************************
//						canBank
//*********************************************************************

bool canBank(Player* player) {
	player->clearFlag(P_AFK);

	if(!player->ableToDoCommand())
		return(false);

	if(player->getClass() == BUILDER) {
		player->print("You do not have a bank account.\n");
		return(false);
	}

	if( !player->getRoom()->flagIsSet(R_BANK) &&
		!player->getRoom()->flagIsSet(R_MAGIC_MONEY_MACHINE) &&
		!noNeedBank(player)
	) {
		player->print("You don't see a bank teller anywhere in this room!\n");
		return(false);
	}

	player->unhide();
	return(true);
}


//*********************************************************************
//						cmdBalance
//*********************************************************************
// gives you your current balance

int cmdBalance(Player* player, cmd* cmnd) {

	// can they use the bank?
	if(!canBank(player))
		return(0);

	if(player->bank.isZero()) {
		if(player->getRoom()->flagIsSet(R_BANK))
			player->print("The bank teller says, \"You haven't got a single coin in the bank!\"\n");
		else
			player->print("The magic money machine reports your current balance as 0 coins.\n");
	} else {
		if(player->getRoom()->flagIsSet(R_BANK))
			player->print("The bank teller says, \"Your current balance is: %s.\"\n",
				player->bank.str().c_str());
		else
			player->print("The magic money machine reports your current balance as %s.\n",
				player->bank.str().c_str());

	}

	return(0);
}


//*********************************************************************
//						cmdDeposit
//*********************************************************************
// lets you put money in your account

int cmdDeposit(Player* player, cmd* cmnd) {
	unsigned long amt;

	// can they use the bank?
	if(!canBank(player))
		return(0);

	if(cmnd->num < 2) {
		player->print("The bank teller says, \"Well! How much do you want to deposit!\"\n");
		return(0);
	}
	if(!strcmp(cmnd->str[1], "all")) {
		amt = player->coins[GOLD];
		if(amt < 1) {
			player->print("The bank teller says, \"You ain't got no money I'm afraid!\"\n");
			return(0);
		}
		player->print("You deposit all your gold!\n");
	} else if(cmnd->str[1][0] != '$') {
		player->print("The bank teller says, \"Well! How much do you want to deposit!\"\n");
		return(0);
	} else {
		amt = atol(&cmnd->str[1][1]);
		if(amt < 1) {
			player->print("The bank teller says, \"You've got to be kidding\".\n");
			return(0);
		}
	}
	if(amt > player->coins[GOLD]) {
		player->print("The bank teller says, \"You can't deposit money you don't have!\".\n");
		return(0);
	}


	if(!bankerCanSee(player))
		return(0);

	player->print("You give the bank teller %ld gold coins.\n", amt);
	player->bank.add(amt, GOLD);
	player->coins.sub(amt, GOLD);
	player->print("The bank teller says, \"Your balance is now %s.\"\n",
		player->bank.str().c_str());
	broadcast(player->getSock(), player->getRoom(), "%s deposits some gold.", player->name);

	player->save(true);
	banklog(player->name, "DEPOSIT: %lu [Balance: %s]\n", amt, player->bank.str().c_str());
	return(0);
}


//*********************************************************************
//						cmdWithdraw
//*********************************************************************
// lets you withdraw money from your account

int cmdWithdraw(Player* player, cmd* cmnd) {
	char	name[20];
	unsigned long amt;

	// can they use the bank?
	if(!canBank(player))
		return(0);

	if(player->getRoom()->flagIsSet(R_BANK))
		strcpy(name, "bank teller");
	else
		strcpy(name, "magic money machine");


	if(cmnd->num < 2) {
		player->print("The %s tells you, \"How much do you want to withdraw?\"\n", name);
		return(0);
	}
	if(!strcmp(cmnd->str[1], "all")) {
		amt = player->bank[GOLD];
		if(amt < 1) {
			player->print("You don't have any money saved up!\n");
			return(0);
		}
		player->print("You withdraw your life savings.\n");
	} else if(cmnd->str[1][0] != '$') {
		player->print("The %s tells you, \"How much do you want to withdraw?\"\n", name);
		return(0);
	} else {
		amt = atol(&cmnd->str[1][1]);
		if(amt < 1) {
			player->print("The %s tells you, \"You've got to be kidding\".\n", name);
			return(0);
		}
	}
	if(amt > player->bank[GOLD]) {
		player->print("The %s tells you, \"You can't withdraw money you don't have!\".\n", name);
		return(0);
	}

	player->unhide();

	if(!bankerCanSee(player))
		return(0);

	if(player->getRoom()->flagIsSet(R_BANK))
		player->print("The bank teller gives you %ld gold coins.\n", amt);
	else
		player->print("You get %ld gold coins from the magic money machine.\n", amt);
	player->bank.sub(amt, GOLD);
	player->coins.add(amt, GOLD);
	player->print("The %s tells you, \"Your balance is now %s.\"\n",
		name, player->bank.str().c_str());
	broadcast(player->getSock(), player->getRoom(), "%s withdrew some gold.", player->name);
	//	logn("log.bank", "%s withdrew %ld gold. (Balance=%ld)\n",player->name, amt, player->bank[GOLD]);
	banklog(player->name, "WITHDRAW: %ld [Balance: %s]\n", amt, player->bank.str().c_str());

	player->save(true);
	return(0);
}


//*********************************************************************
//						cmdTransfer
//*********************************************************************
// lets you move funds

int cmdTransfer(Player* player, cmd* cmnd) {
	Player* target=0;
	unsigned long amt=0;
	bool	online=false;

	// can they use the bank?
	if(!canBank(player))
		return(0);

	if(cmnd->num < 2) {
		player->print("The bank teller says, \"Well! How much do you want to transfer!\"\n");
		return(0);
	}
	if(cmnd->str[1][0] != '$') {
		player->print("The bank teller says, \"Well! How much do you want to transfer!\"\n");
		return(0);
	}
	if(cmnd->num < 3) {
		player->print("The bank teller says, \"And just who is this money going to?\"\n");
		return(0);
	}

	amt = atol(&cmnd->str[1][1]);
	if(amt < 1) {
		player->print("The bank teller says, \"You've got to be kidding\".\n");
		return(0);
	}
	if(amt < 500 && !player->isDm()) {
		player->print("The bank teller says, \"It's not worth it to transfer so few coins!\"\n");
		return(0);
	}
	if(amt > player->bank[GOLD]) {
		player->print("The bank teller says, \"You can't transfer money you don't have!\".\n");
		return(0);
	}

	if(!bankerCanSee(player))
		return(0);

	// load up the guy if nessesarry
	cmnd->str[2][0] = up(cmnd->str[2][0]);

	target = 0;
	target = gServer->findPlayer(cmnd->str[2]);

	if(!target) {
		if(!loadPlayer(cmnd->str[2], &target)) {
			player->print("The bank teller says, \"I don't know who that is!\"\n");
			return(0);
		}
	} else
		online = true;

	if(target->getClass() == BUILDER) {
		player->print("The bank teller says, \"I don't know who that is!\"\n");
		if(!online)
			free_crt(target);
		return(0);
	}

	// TODO: Dom: HC: only for tournament
	//if(target->isHardcore()) {
	//	player->print("You cannot transfer money to hardcore characters for the duration of the tournament.\n");
	//	if(!online)
	//		free_crt(target);
	//	return(0);
	//}

	if(!online)
		target->computeInterest(0, false);

	player->bank.sub(amt, GOLD);
	player->print("The bank tellers transfers %lu gold coin%s from your account to %s's.\n",
		amt, amt != 1 ? "s" : "", target->name);
	target->bank.add(amt, GOLD);

	if(player->getClass() == CARETAKER)
		log_immort(true, player, "%s transferred %lu gold to %s. (Balance=%s)(%s)\n",
		player->name, amt, target->name, player->bank.str().c_str(),
		target->bank.str().c_str());
	//	else
	//		logn("log.bank", "%s transferred %ld gold to %s. (Balance=%ld)(%ld)\n",player->name, amt, target->name, player->bank[GOLD], target->bank);

	banklog(player->name, "TRANSFER to %s: %ld [Balance: %s]\n",
		target->name, amt, player->bank.str().c_str());
	banklog(target->name, "TRANSFER from %s: %ld [Balance: %s]\n",
		player->name, amt, target->bank.str().c_str());
	if(online)
		target->print("*** %s just transferred %ld gold to your account.\n",
			player->name, amt);

	player->save(true);
	// update their time only if they are lone
	target->save(online);
	if(!online)
		free_crt(target);

	// save them and unload if nessesarry
	broadcast(player->getSock(), player->getRoom(), "%s transfers some gold.", player->name);
	player->print("The bank teller says, \"Your balance is now %s.\"\n", player->bank.str().c_str());
	return(0);
}


//*********************************************************************
//						cmdStatement
//*********************************************************************
// lets someone view their transaction history

int cmdStatement(Player* player, cmd* cmnd) {
	char file[80];

	// can they use the bank?
	if(!canBank(player))
		return(0);

	player->print("The bank teller shows you your bank statement:\n");

	sprintf(file, "%s/%s.txt", BANKDIR, player->name);

	if(file_exists(file)) {
		strcpy(player->getSock()->tempstr[3], "\0");
		viewFileReverse(player->getSock(), file);
	} else {
		player->print("\n   You have no transaction history.\n");
	}

	return(0);
}

//*********************************************************************
//						cmdDeleteStatement
//*********************************************************************

int cmdDeleteStatement(Player* player, cmd* cmnd) {
	char file[80];

	// can they use the bank?
	if(!canBank(player))
		return(0);

	sprintf(file, "%s/%s.txt", BANKDIR, player->name);
	player->print("Statement deleted.\n");
	unlink(file);

	return(0);
}

//*********************************************************************
//						getInterest
//*********************************************************************

long Player::getInterest(long principal, double annualRate, long seconds) {
	// Effective interest rate, compounded continuously
	double r = log(annualRate + 1);

	double interest = (principal * exp( (r / (60.0*60.0*24.0*365.0) * seconds)) )-principal;

	return((long)interest);
}

//*********************************************************************
//						computeInterest
//*********************************************************************
// Computes interest the player has earned. If online = false, it is the responsibility
// of the calling function to save the player.

void Player::computeInterest(long t, bool online) {
	if(isStaff())
		return;
	// people in jail don't earn interest
	if(inJail()) {
		lastInterest = time(0);
		if(online)
			save(true);
		return;
	}

	if(!t)
		t = time(0);
	if(!lastInterest)
		lastInterest = lastLogin;

	int interestDays = (t - lastInterest) / (60*60*24);
	int rateDays = (t - lastLogin) / (60*60*24);
	double rate = 0.0;

	// check interest once a day
	if(!interestDays)
		return;

	// determine what rate they earn based on how long since they last logged in
	if(rateDays < 2) {
		rate = 0.08;
	} else if(rateDays < 14) {
		rate = 0.06;
	} else if(rateDays < 30) {
		rate = 0.02;
	}

	// calculate interest based on when we last checked
	long amt = getInterest(bank[GOLD], rate, t - lastInterest);

	// if they don't get any money because they don't have enough in the bank,
	// don't record this computation.
	if(!amt)
		return;
	lastInterest = t;

	bank.add(amt, GOLD);

	banklog(name, "INTEREST for %d day%s at %d%%: %ld [Balance: %s]\n",
		interestDays, interestDays != 1 ? "s" : "", (int)(rate*100), amt, bank.str().c_str());

	if(online) {
		print("You earn %d gold coins in interest.\n", amt);
		save(true);
	}
}