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