/*
* 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);
}
}