introduce bank account system

This commit is contained in:
ErikasKontenis 2020-01-22 21:08:22 +02:00
parent 00efade0a1
commit ad7a761167
7 changed files with 200 additions and 14 deletions

View File

@ -82,3 +82,57 @@ Topic=99 -> "Well, can I help you with something else
#Topic=99,"yes",Count(3035)>=Price -> "Here you are.", Create(3043), Amount=Price, Delete(3035)
#Topic=99,"yes" -> "Sorry, you don't have so many platinum coins."
#Topic=99 -> "Well, can I help you with something else?"
# Bank System
"balance" -> Amount=Balance, "Your account balance is %A gold."
"balance",balance>99999 -> Amount=Balance, "You certainly have made a pretty penny. Your account balance is %A gold."
"balance",balance>999999 -> Amount=Balance, "You certainly have made a pretty penny. Your account balance is %A gold."
"balance",balance>9999999 -> Amount=Balance, "You have made ten millions and it still grows! Your account balance is %A gold."
"balance",balance>99999999 -> Amount=Balance, "I think you must be one of the richest inhabitants in the world! Your account balance is %A gold."
"deposit" -> "You don't have any gold with you."
"deposit",CountMoney>0 -> "Please tell me how much gold it is you would like to deposit.", Topic=81
"deposit","all",CountMoney>0 -> Price=CountMoney, "Would you really like to deposit %P gold?", Topic=82
"deposit",$1,0<$1,CountMoney>=$1 -> Price=$1, "Would you really like to deposit %P gold?", Topic=82
"deposit","0" -> "You are joking, aren't you??"
"deposit",$1,0<$1,CountMoney<$1 -> "You do not have enough gold."
Topic=81,$1,0<$1,CountMoney>=$1 -> Price=$1, "Would you really like to deposit %P gold?", Topic=82
Topic=81,"0" -> "You are joking, aren't you?"
Topic=81,$1,0<$1,CountMoney<$1 -> "You do not have enough gold."
Topic=81 -> "Please tell me how much gold it is you would like to deposit.", Topic=81
Topic=82,"yes",CountMoney>=Price -> "Alright, we have added the amount of %P gold to your balance. You can withdraw your money anytime you want to.", DeleteMoney, Deposit(Price)
Topic=82,"yes" -> "I am inconsolable, but it seems you have lost your gold. I hope you get it back."
Topic=82 -> "As you wish. Is there something else I can do for you?"
"withdraw" -> "Please tell me how much gold you would like to withdraw.", Topic=83
"withdraw",$1,0<$1,Balance>=$1 -> Price=$1, "Are you sure you wish to withdraw %P gold from your bank account?", Topic=84
"withdraw","0" -> "Sure, you want nothing you get nothing!"
"withdraw",$1,0<$1,Balance<$1 -> "There is not enough gold on your account."
Topic=83,$1,0<$1,Balance>=$1 -> Price=$1, "Are you sure you wish to withdraw %P gold from your bank account?", Topic=84
Topic=83,"0" -> "Sure, you want nothing you get nothing!"
Topic=83,$1,0<$1,Balance<$1 -> "There is not enough gold on your account."
Topic=83 -> "Please tell me how much gold you would like to withdraw.", Topic=83
Topic=84,"yes",Balance>=Price -> "Here you are, %P gold. Please let me know if there is something else I can do for you.", CreateMoney, Withdraw(Price)
Topic=84,"yes" -> "I am inconsolable, but it seems you don't have that many gold in your bank account."
Topic=84 -> "The customer is king! Come back anytime you want to if you wish to withdraw your money."
"transfer" -> "Please tell me the amount of gold you would like to transfer.", Topic=85
"transfer","0","to" -> "Please think about it. Okay?"
"transfer",$1,0<$1,"to",Balance<$1 -> "There is not enough gold on your account."
"transfer",$1,0<$1,"to",Balance>=$1,TransferToPlayerNameState=2 -> Price=$1, "Would you really like to transfer %P gold to %S?", Topic=88
"transfer",$1,0<$1,"to",Balance>=$1,TransferToPlayerNameState=1 -> "I'm afraid this character only holds a junior account at our bank. Do not worry, though. Once he has chosen his vocation or is no longer on Rookgaard, his account will be upgraded."
"transfer",$1,0<$1,"to",Balance>=$1,TransferToPlayerNameState=0 -> "This player does not exist."
Topic=85,$1,0<$1,Balance>=$1 -> Price=$1, "Who would you like transfer %P gold to?", Topic=86
Topic=85,"0" -> "Please think about it. Okay?"
Topic=85,$1,0<$1,Balance<$1 -> "There is not enough gold on your account."
Topic=86,Balance>=Price,TransferToPlayerNameState=2 -> "Would you really like to transfer %P gold to %S?", Topic=87
Topic=86,Balance>=Price,TransferToPlayerNameState=1 -> "I'm afraid this character only holds a junior account at our bank. Do not worry, though. Once he has chosen his vocation or is no longer on Rookgaard, his account will be upgraded."
Topic=86,Balance>=Price,TransferToPlayerNameState=0 -> "This player does not exist."
Topic=87,"yes",Balance>=Price -> "You have transferred %P gold to %S.", Transfer(Price)
Topic=87,"yes" -> "I am inconsolable, but it seems you don't have that many gold in your bank account."
Topic=87 -> "Ok. What is next?"
Topic=88,"yes",Balance>=Price -> "Very well. You have transferred %P gold to %S.", Transfer(Price)
Topic=88,"yes" -> "I am inconsolable, but it seems you don't have that many gold in your bank account."
Topic=88 -> "Alright, is there something else I can do for you?"

View File

@ -19,6 +19,7 @@
#include "otpch.h"
#include "iologindata.h"
#include "behaviourdatabase.h"
#include "npc.h"
#include "player.h"
@ -174,6 +175,9 @@ bool BehaviourDatabase::loadConditions(ScriptReader& script, NpcBehaviour* behav
} else if (script.getSpecial() == '%') {
condition->setCondition(BEHAVIOUR_TYPE_MESSAGE_COUNT, script.readNumber(), "");
searchTerm = true;
} else if (script.getSpecial() == '$') {
condition->setCondition(BEHAVIOUR_TYPE_MESSAGE_COUNT_NO_LIMIT, script.readNumber(), "");
searchTerm = true;
} else if (script.getSpecial() == ',') {
script.nextToken();
continue;
@ -291,6 +295,9 @@ bool BehaviourDatabase::loadActions(ScriptReader& script, NpcBehaviour* behaviou
} else if (identifier == "deposit") {
action->type = BEHAVIOUR_TYPE_DEPOSIT;
searchType = BEHAVIOUR_PARAMETER_ONE;
} else if (identifier == "transfer") {
action->type = BEHAVIOUR_TYPE_TRANSFER;
searchType = BEHAVIOUR_PARAMETER_ONE;
} else if (identifier == "bless") {
action->type = BEHAVIOUR_TYPE_BLESS;
searchType = BEHAVIOUR_PARAMETER_ONE;
@ -471,16 +478,24 @@ NpcBehaviourNode* BehaviourDatabase::readValue(ScriptReader& script)
}
if (script.Token == SPECIAL) {
if (script.getSpecial() != '%') {
script.error("illegal character");
return nullptr;
if (script.getSpecial() == '%') {
NpcBehaviourNode* node = new NpcBehaviourNode();
node->type = BEHAVIOUR_TYPE_MESSAGE_COUNT;
node->number = script.readNumber();
script.nextToken();
return node;
}
NpcBehaviourNode* node = new NpcBehaviourNode();
node->type = BEHAVIOUR_TYPE_MESSAGE_COUNT;
node->number = script.readNumber();
script.nextToken();
return node;
if (script.getSpecial() == '$') {
NpcBehaviourNode* node = new NpcBehaviourNode();
node->type = BEHAVIOUR_TYPE_MESSAGE_COUNT_NO_LIMIT;
node->number = script.readNumber();
script.nextToken();
return node;
}
script.error("illegal character");
return nullptr;
}
NpcBehaviourNode* node = nullptr;
@ -526,6 +541,9 @@ NpcBehaviourNode* BehaviourDatabase::readValue(ScriptReader& script)
} else if (identifier == "balance") {
node = new NpcBehaviourNode();
node->type = BEHAVIOUR_TYPE_BALANCE;
} else if (identifier == "transfertoplayernamestate") {
node = new NpcBehaviourNode();
node->type = BEHAVIOUR_TYPE_MESSAGE_TRANSFERTOPLAYERNAME_STATE;
} else if (identifier == "spellknown") {
node = new NpcBehaviourNode();
node->type = BEHAVIOUR_TYPE_SPELLKNOWN;
@ -709,6 +727,13 @@ bool BehaviourDatabase::checkCondition(const NpcBehaviourCondition* condition, P
}
break;
}
case BEHAVIOUR_TYPE_MESSAGE_COUNT_NO_LIMIT: {
int32_t value = searchDigitNoLimit(message);
if (value < condition->number) {
return false;
}
break;
}
case BEHAVIOUR_TYPE_STRING:
if (!searchWord(condition->string, message)) {
return false;
@ -1011,6 +1036,32 @@ void BehaviourDatabase::checkAction(const NpcBehaviourAction* action, Player* pl
player->setBankBalance(player->getBankBalance() + money);
break;
}
case BEHAVIOUR_TYPE_TRANSFER: {
int32_t money = evaluate(action->expression, player, message);
uint16_t state = 0;
Player* transferToPlayer = g_game.getPlayerByName(string);
if (!transferToPlayer) {
state = IOLoginData::canTransferMoneyToByName(string);
}
else {
state = transferToPlayer->getVocationId() == 0 ? 1 : 2;
}
if (state != 2) {
break;
}
player->setBankBalance(player->getBankBalance() - money);
if (!transferToPlayer) {
IOLoginData::increaseBankBalance(string, money);
}
else {
transferToPlayer->setBankBalance(transferToPlayer->getBankBalance() + money);
}
break;
}
case BEHAVIOUR_TYPE_BLESS: {
uint8_t number = static_cast<uint8_t>(evaluate(action->expression, player, message)) - 1;
@ -1159,10 +1210,33 @@ int32_t BehaviourDatabase::evaluate(NpcBehaviourNode* node, Player* player, cons
}
return value;
}
case BEHAVIOUR_TYPE_MESSAGE_COUNT_NO_LIMIT: {
int32_t value = searchDigitNoLimit(message);
if (value < node->number) {
return false;
}
return value;
}
case BEHAVIOUR_TYPE_OPERATION:
return checkOperation(player, node, message);
case BEHAVIOUR_TYPE_BALANCE:
return player->getBankBalance();
case BEHAVIOUR_TYPE_MESSAGE_TRANSFERTOPLAYERNAME_STATE: {
std::string lowerMessage = asLowerCaseString(message);
if (lowerMessage.find("to ") != std::string::npos) {
string = asCamelCaseString(message.substr(lowerMessage.find("to ") + 3, message.size()));
}
else {
string = asCamelCaseString(message);
}
Player* transferToPlayer = g_game.getPlayerByName(string);
if (!transferToPlayer) {
return IOLoginData::canTransferMoneyToByName(string);
}
return transferToPlayer->getVocationId() == 0 ? 1 : 2;
}
case BEHAVIOUR_TYPE_SPELLKNOWN: {
if (player->hasLearnedInstantSpell(string)) {
return true;
@ -1217,6 +1291,17 @@ int32_t BehaviourDatabase::checkOperation(Player* player, NpcBehaviourNode* node
}
int32_t BehaviourDatabase::searchDigit(const std::string& message)
{
int32_t value = searchDigitNoLimit(message);
if (value > 500) {
value = 500;
}
return value;
}
int32_t BehaviourDatabase::searchDigitNoLimit(const std::string& message)
{
int32_t start = -1;
int32_t end = -1;
@ -1244,10 +1329,6 @@ int32_t BehaviourDatabase::searchDigit(const std::string& message)
return 0;
}
if (value > 500) {
value = 500;
}
return value;
}
@ -1299,7 +1380,8 @@ std::string BehaviourDatabase::parseResponse(Player* player, const std::string&
replaceString(response, "%D", std::to_string(data));
replaceString(response, "%N", player->getName());
replaceString(response, "%P", std::to_string(price));
replaceString(response, "%S", string);
int32_t worldTime = g_game.getLightHour();
int32_t hours = std::floor<int32_t>(worldTime / 60);
int32_t minutes = worldTime % 60;

View File

@ -38,6 +38,8 @@ enum NpcBehaviourType_t
BEHAVIOUR_TYPE_NUMBER, // return a number
BEHAVIOUR_TYPE_OPERATION, // <, =, >, >=, <=, <>
BEHAVIOUR_TYPE_MESSAGE_COUNT, // get quantity in player message
BEHAVIOUR_TYPE_MESSAGE_COUNT_NO_LIMIT, // get quantity in player message without any max value restriction
BEHAVIOUR_TYPE_MESSAGE_TRANSFERTOPLAYERNAME_STATE, // set player name parsed fro message to string object and return state if it is possible to transfer
BEHAVIOUR_TYPE_IDLE, // idle npc
BEHAVIOUR_TYPE_QUEUE, // queue talking creature
BEHAVIOUR_TYPE_TOPIC, // get/set topic
@ -269,6 +271,7 @@ class BehaviourDatabase
int32_t checkOperation(Player* player, NpcBehaviourNode* node, const std::string& message);
int32_t searchDigit(const std::string& message);
int32_t searchDigitNoLimit(const std::string& message);
bool searchWord(const std::string& pattern, const std::string& message);
std::string parseResponse(Player* player, const std::string& message);

View File

@ -824,6 +824,20 @@ uint32_t IOLoginData::getGuidByName(const std::string& name)
return result->getNumber<uint32_t>("id");
}
// Return 0 means player not found, 1 player is without vocation, 2 player with vocation
uint16_t IOLoginData::canTransferMoneyToByName(const std::string& name)
{
Database* db = Database::getInstance();
std::ostringstream query;
query << "SELECT `vocation` FROM `players` WHERE `name` = " << db->escapeString(name);
DBResult_ptr result = db->storeQuery(query.str());
if (!result) {
return 0;
}
return result->getNumber<uint16_t>("vocation") == 0 ? 1 : 2;
}
bool IOLoginData::getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string& name)
{
Database* db = Database::getInstance();
@ -899,6 +913,15 @@ void IOLoginData::increaseBankBalance(uint32_t guid, uint64_t bankBalance)
Database::getInstance()->executeQuery(query.str());
}
void IOLoginData::increaseBankBalance(std::string name, uint64_t bankBalance)
{
Database* db = Database::getInstance();
std::ostringstream query;
query << "UPDATE `players` SET `balance` = `balance` + " << bankBalance << " WHERE `name` = " << db->escapeString(name);
db->executeQuery(query.str());
}
bool IOLoginData::hasBiddedOnHouse(uint32_t guid)
{
Database* db = Database::getInstance();

View File

@ -44,11 +44,13 @@ class IOLoginData
static bool loadPlayerByName(Player* player, const std::string& name);
static bool loadPlayer(Player* player, DBResult_ptr result);
static bool savePlayer(Player* player);
static uint32_t getGuidByName(const std::string& name);
static uint32_t getGuidByName(const std::string& name);
static uint16_t canTransferMoneyToByName(const std::string& name);
static bool getGuidByNameEx(uint32_t& guid, bool& specialVip, std::string& name);
static std::string getNameByGuid(uint32_t guid);
static bool formatPlayerName(std::string& name);
static void increaseBankBalance(uint32_t guid, uint64_t bankBalance);
static void increaseBankBalance(const std::string name, uint64_t bankBalance);
static bool hasBiddedOnHouse(uint32_t guid);
static std::forward_list<VIPEntry> getVIPEntries(uint32_t accountId);

View File

@ -360,6 +360,27 @@ std::string asUpperCaseString(std::string source)
return source;
}
std::string asCamelCaseString(std::string source) {
bool active = true;
for (int i = 0; source[i] != '\0'; i++) {
if (std::isalpha(source[i])) {
if (active) {
source[i] = std::toupper(source[i]);
active = false;
}
else {
source[i] = std::tolower(source[i]);
}
}
else if (source[i] == ' ') {
active = true;
}
}
return source;
}
StringVec explodeString(const std::string& inString, const std::string& separator, int32_t limit/* = -1*/)
{
StringVec returnVector;

View File

@ -41,6 +41,7 @@ void trim_left(std::string& source, char t);
void toLowerCaseString(std::string& source);
std::string asLowerCaseString(std::string source);
std::string asUpperCaseString(std::string source);
std::string asCamelCaseString(std::string source);
typedef std::vector<std::string> StringVec;
typedef std::vector<int32_t> IntegerVec;