Parcourir la source

Implemented new YML database for Tax Config
* Credits to @aleos89

Cydh il y a 5 ans
Parent
commit
4d4f0eb1b8

+ 39 - 6
conf/import-tmpl/tax.yml

@@ -1,7 +1,40 @@
-# Taxes for selling something (Vending)
-# Zeny received for the seller will be reduced after taxes from the total selling price but the buyer pays just the total selling price
-Selling:
+# This file is a part of rAthena.
+#   Copyright(C) 2019 rAthena Development Team
+#   https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# Import Tax Database
+###########################################################################
+#
+# Tax Settings
+#
+###########################################################################
+# Type                Tax type. Valid types are TAX_SELLING for vending and TAX_BUYING for buyingstore.
+#   InTotal           Tax applied for total transaction. Supports unlimited entries.
+#     - MinimalValue  Amount of Zeny before Tax is applied. (Default: 0)
+#       Tax           Tax percentage applied to MinimalValue. (Default: 0)
+#   EachEntry         Tax by selling entry. Supports unlimited entries.
+#     - MinimalValue  Amount of Zeny before Tax is applied. (Default: 0)
+#       Tax           Tax percentage applied to MinimalValue. (Default: 0)
+###########################################################################
 
-# Taxes for buying something (Buyingstore)
-# Zeny received for the seller will be the total selling price but the buyer must pay taxes for the total selling price
-Buying:
+Header:
+  Type: TAX_DB
+  Version: 1
+
+#Body:
+#  - Type: TAX_SELLING
+#  - Type: TAX_BUYING

+ 0 - 3
conf/map_athena.conf

@@ -124,9 +124,6 @@ charhelp_txt: conf/charhelp.txt
 // Load channel config from
 channel_conf: conf/channels.conf
 
-// Load Store tax config from
-tax_conf: conf/tax.yml
-
 // Maps:
 import: conf/maps_athena.conf
 

+ 85 - 48
conf/tax.yml

@@ -1,51 +1,88 @@
-# Taxes for selling something (Vending)
-# Zeny received for the seller will be reduced after taxes from the total selling price but the buyer pays just the total selling price
-Selling:
-  # Tax applied for total transaction
-  InTotal:
-  - MinimalValue: 0
-    Tax: 0
+# This file is a part of rAthena.
+#   Copyright(C) 2019 rAthena Development Team
+#   https://rathena.org - https://github.com/rathena
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+###########################################################################
+# Import Tax Database
+###########################################################################
+#
+# Tax Settings
+#
+###########################################################################
+# Type                Tax type. Valid types are TAX_SELLING for vending and TAX_BUYING for buyingstore.
+#   InTotal           Tax applied for total transaction. Supports unlimited entries.
+#     - MinimalValue  Amount of Zeny before Tax is applied. (Default: 0)
+#       Tax           Tax percentage applied to MinimalValue. (Default: 0)
+#   EachEntry         Tax by selling entry. Supports unlimited entries.
+#     - MinimalValue  Amount of Zeny before Tax is applied. (Default: 0)
+#       Tax           Tax percentage applied to MinimalValue. (Default: 0)
+###########################################################################
 
-  # Tax by selling entry
-  EachEntry:
-  # 10% if >= 100,000,001
-  - MinimalValue: 100000001
-    Tax: 1000
-  # 8% if >= 10,000,001
-  - MinimalValue: 10000001
-    Tax: 800
-  # 6% if >= 1,000,001
-  - MinimalValue: 1000001
-    Tax: 600
-  # 4% if >= 100,001
-  - MinimalValue: 100001
-    Tax: 400
-  # 2% if >= 10,001
-  - MinimalValue: 10001
-    Tax: 200
+Header:
+  Type: TAX_DB
+  Version: 1
 
-# Taxes for buying something (Buyingstore)
-# Zeny received for the seller will be the total selling price but the buyer must pay taxes for the total selling price
-Buying:
-  # Tax applied for total transaction
-  InTotal:
-  - MinimalValue: 0
-    Tax: 0
+Body:
+  # Zeny received for the seller will be reduced after taxes from the total selling price but the buyer pays just the total selling price
+  - Type: TAX_SELLING
+    InTotal:
+    - MinimalValue: 0
+      Tax: 0
 
-  # Tax by buying entry
-  EachEntry:
-  # 10% if >= 100,000,001
-  - MinimalValue: 100000001
-    Tax: 1000
-  # 8% if >= 10,000,001
-  - MinimalValue: 10000001
-    Tax: 800
-  # 6% if >= 1,000,001
-  - MinimalValue: 1000001
-    Tax: 600
-  # 4% if >= 100,001
-  - MinimalValue: 100001
-    Tax: 400
-  # 2% if >= 10,001
-  - MinimalValue: 10001
-    Tax: 200
+    EachEntry:
+    # 10% if >= 100,000,001
+    - MinimalValue: 100000001
+      Tax: 1000
+    # 8% if >= 10,000,001
+    - MinimalValue: 10000001
+      Tax: 800
+    # 6% if >= 1,000,001
+    - MinimalValue: 1000001
+      Tax: 600
+    # 4% if >= 100,001
+    - MinimalValue: 100001
+      Tax: 400
+    # 2% if >= 10,001
+    - MinimalValue: 10001
+      Tax: 200
+
+  # Zeny received for the seller will be the total selling price but the buyer must pay taxes for the total selling price
+  - Type: TAX_BUYING
+    InTotal:
+    - MinimalValue: 0
+      Tax: 0
+
+    # Tax by buying entry
+    EachEntry:
+    # 10% if >= 100,000,001
+    - MinimalValue: 100000001
+      Tax: 1000
+    # 8% if >= 10,000,001
+    - MinimalValue: 10000001
+      Tax: 800
+    # 6% if >= 1,000,001
+    - MinimalValue: 1000001
+      Tax: 600
+    # 4% if >= 100,001
+    - MinimalValue: 100001
+      Tax: 400
+    # 2% if >= 10,001
+    - MinimalValue: 10001
+      Tax: 200
+
+Footer:
+  Imports:
+  - Path: conf/import/tax.yml

+ 5 - 17
src/map/buyingstore.cpp

@@ -118,9 +118,7 @@ int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
 {
 	unsigned int i, weight, listidx;
 	char message_sql[MESSAGE_SIZE*2];
-	char msg[CHAT_SIZE_MAX];
 	StringBuf buf;
-	s_tax *taxdata;
 
 	nullpo_retr(1, sd);
 
@@ -224,18 +222,6 @@ int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
 		return 7;
 	}
 
-	taxdata = tax_get(TAX_BUYING);
-	tax_buyingstore_vat(sd); // Calculate value after taxes
-
-	if (battle_config.display_tax_info && taxdata->total.size()) {
-		clif_displaymessage(sd->fd, msg_txt(sd, 778)); // [ Total Transaction Tax ]
-		for (const auto &tax : taxdata->total) {
-			memset(msg, '\0', CHAT_SIZE_MAX);
-			sprintf(msg, msg_txt(sd, 779), tax.tax / 100., tax.minimal); // Tax: %.2f%% Minimal Transaction: %u
-			clif_displaymessage(sd->fd, msg);
-		}
-	}
-
 	// success
 	sd->state.buyingstore = true;
 	sd->buyer_id = buyingstore_getuid();
@@ -243,6 +229,8 @@ int8 buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
 	sd->buyingstore.slots = i;  // store actual amount of items
 	safestrncpy(sd->message, storename, sizeof(sd->message));
 
+	tax_db.setBuyingstoreTax(sd);
+
 	Sql_EscapeString( mmysql_handle, message_sql, sd->message );
 
 	if( Sql_Query( mmysql_handle, "INSERT INTO `%s`(`id`, `account_id`, `char_id`, `sex`, `map`, `x`, `y`, `title`, `limit`, `autotrade`, `body_direction`, `head_direction`, `sit`) "
@@ -338,12 +326,12 @@ void buyingstore_open(struct map_session_data* sd, uint32 account_id)
  * @return Taxed price
  */
 static unsigned short buyinstore_tax_intotal(struct map_session_data* sd, const uint8* itemlist, int count) {
-	s_tax *tax = tax_get(TAX_BUYING);
+	std::shared_ptr<s_tax> tax = tax_db.find(TAX_BUYING);
 
 	double total = 0;
 	int i;
 
-	if (tax->total.size() == 0)
+	if (tax == nullptr || tax->total.empty())
 		return 0;
 
 	for (i = 0; i < count; i++) {
@@ -364,7 +352,7 @@ static unsigned short buyinstore_tax_intotal(struct map_session_data* sd, const
 		total += ((double)sd->buyingstore.items[listidx].price * amount);
 	}
 
-	return tax->get_tax(tax->total, total);
+	return tax->taxPercentage(tax->total, total);
 }
 
 /**

+ 2 - 2
src/map/buyingstore.hpp

@@ -15,10 +15,10 @@ struct map_session_data;
 
 struct s_buyingstore_item
 {
-	int price; ///< Value
+	unsigned int price; ///< Value
 	unsigned short amount; ///< Amount of items in Buyingstore
 	unsigned short nameid; ///< Item ID
-	size_t price_vat; ///< Value after tax
+	unsigned int price_vat; ///< Value after tax
 };
 
 struct s_buyingstore

+ 0 - 2
src/map/map.cpp

@@ -4106,8 +4106,6 @@ int map_config_read(const char *cfgName)
 			console_msg_log = atoi(w2);//[Ind]
 		else if (strcmpi(w1, "console_log_filepath") == 0)
 			safestrncpy(console_log_filepath, w2, sizeof(console_log_filepath));
-		else if (strcmpi(w1, "tax_conf") == 0)
-			tax_set_conf(w2);
 		else if (strcmpi(w1, "import") == 0)
 			map_config_read(w2);
 		else

+ 1 - 0
src/map/script.cpp

@@ -60,6 +60,7 @@
 #include "pet.hpp"
 #include "quest.hpp"
 #include "storage.hpp"
+#include "tax.hpp" // e_tax_type
 
 struct eri *array_ers;
 DBMap *st_db;

+ 4 - 0
src/map/script_constants.hpp

@@ -7216,6 +7216,10 @@
 	/* timer related */
 	export_constant(INFINITE_TICK);
 
+	/* tax related */
+	export_constant(TAX_SELLING);
+	export_constant(TAX_BUYING);
+
 	/* block action */
 	export_constant(PCBLOCK_MOVE);
 	export_constant(PCBLOCK_ATTACK);

+ 161 - 107
src/map/tax.cpp

@@ -17,8 +17,125 @@
 #include "pc.hpp"
 #include "vending.hpp"
 
-static struct s_tax TaxDB[TAX_MAX];
-std::string tax_conf = "conf/store_tax.yml";
+/*
+* Tax Database
+*/
+TaxDatabase tax_db;
+
+const std::string TaxDatabase::getDefaultLocation() {
+	return "conf/tax.yml";
+}
+
+/**
+* Reads and parses an entry from the tax_db.
+* @param node: YAML node containing the entry.
+* @return count of successfully parsed rows
+*/
+uint64 TaxDatabase::parseBodyNode(const YAML::Node &node) {
+	int type = 0;
+	std::string type_str;
+
+	if (!this->nodeExists(node, "Type")) {
+		return 0;
+	}
+
+	this->asString(node, "Type", type_str);
+	if (!script_get_constant(type_str.c_str(), &type)) {
+		this->invalidWarning(node, "Invalid type '%s'.\n", type_str.c_str());
+		return 0;
+	}
+
+	std::shared_ptr<s_tax> taxdata = this->find(type);
+	bool exists = taxdata != nullptr;
+
+	if (!exists) {
+		taxdata = std::make_shared<s_tax>();
+	}
+
+	if (this->nodeExists(node, "InTotal")) {
+		taxdata->total.clear();
+
+		for (const auto &taxNode : node["InTotal"]) {
+			if (this->nodeExists(taxNode, "MinimalValue") && this->nodeExists(taxNode, "Tax")) {
+				struct s_tax_entry entry = { 0 };
+
+				if (!this->asUInt64(taxNode, "MinimalValue", entry.minimal)) {
+					this->invalidWarning(taxNode, "Invalid value specified for \"MinimalValue\", defaulting to 0.");
+					entry.minimal = 0;
+				}
+
+				if (!this->asUInt16(taxNode, "Tax", entry.tax)) {
+					this->invalidWarning(taxNode, "Invalid value specified for \"Tax\", defaulting to 0.");
+					entry.tax = 0;
+				}
+
+				taxdata->total.push_back(entry);
+
+				std::sort(taxdata->total.begin(), taxdata->total.end(),
+					[](const s_tax_entry &a, const s_tax_entry &b) -> bool { return a.minimal > b.minimal; });
+			}
+		}
+	}
+
+	if (this->nodeExists(node, "EachEntry")) {
+		taxdata->each.clear();
+
+		for (const auto &taxNode : node["EachEntry"]) {
+			if (this->nodeExists(taxNode, "MinimalValue") && this->nodeExists(taxNode, "Tax")) {
+				struct s_tax_entry entry = { 0 };
+
+				if (!this->asUInt64(taxNode, "MinimalValue", entry.minimal)) {
+					this->invalidWarning(taxNode, "Invalid value specified for \"MinimalValue\", defaulting to 0.");
+					entry.minimal = 0;
+				}
+
+				if (!this->asUInt16(taxNode, "Tax", entry.tax)) {
+					this->invalidWarning(taxNode, "Invalid value specified for \"Tax\", defaulting to 0.");
+					entry.tax = 0;
+				}
+
+				taxdata->each.push_back(entry);
+
+				std::sort(taxdata->each.begin(), taxdata->each.end(),
+					[](const s_tax_entry &a, const s_tax_entry &b) -> bool { return a.minimal > b.minimal; });
+			}
+		}
+	}
+
+	if (!exists) {
+		this->put(type, taxdata);
+	}
+
+	return 1;
+}
+
+/*
+* Set vending tax to a player
+* @param sd Player
+*/
+void TaxDatabase::setVendingTax(map_session_data *sd)
+{
+	std::shared_ptr<s_tax> taxdata = this->find(TAX_SELLING);
+
+	if (taxdata != nullptr) {
+		taxdata->vendingVAT(sd); // Calculate value after taxes
+		taxdata->inTotalInfo(sd);
+	}
+}
+
+/*
+* Set buyingstore tax to a player
+* @param sd Player
+*/
+void TaxDatabase::setBuyingstoreTax(map_session_data *sd)
+{
+	std::shared_ptr<s_tax> taxdata = this->find(TAX_BUYING);
+
+	if (taxdata != nullptr) {
+		taxdata->buyingstoreVAT(sd); // Calculate value after taxes
+		taxdata->inTotalInfo(sd);
+	}
+}
 
 /**
  * Returns the tax rate of a given amount.
@@ -26,46 +143,31 @@ std::string tax_conf = "conf/store_tax.yml";
  * @param price: Value of item.
  * @return Tax rate
  */
-unsigned short s_tax::get_tax(const std::vector <struct s_tax_entry> entry, double price) {
+uint16 s_tax::taxPercentage(const std::vector <struct s_tax_entry> entry, double price) {
 	const auto &tax = std::find_if(entry.begin(), entry.end(),
 		[&price](const s_tax_entry &e) { return price >= e.minimal; });
 	return tax != entry.end() ? tax->tax : 0;
 }
 
-/**
- * Returns the tax type based on selling or buying.
- * @param type: Tax type.
- * @return Tax data.
- */
-struct s_tax *tax_get(enum e_tax_type type) {
-	if (type < TAX_SELLING || type >= TAX_MAX)
-		return NULL;
-	return &TaxDB[type];
-}
-
 /**
  * Calculates the value after tax for Vendors.
  * @param sd: Player data
  */
-void tax_vending_vat(struct map_session_data *sd) {
-	s_tax *taxdata;
+void s_tax::vendingVAT(map_session_data *sd) {
+	char msg[CHAT_SIZE_MAX];
 
 	nullpo_retv(sd);
 
 	if (battle_config.display_tax_info)
 		clif_displaymessage(sd->fd, msg_txt(sd, 776)); // [ Tax Information ]
 
-	taxdata = tax_get(TAX_SELLING);
-
-	for (int i = 0; i < ARRAYLENGTH(sd->vending); i++) {
-		char msg[CHAT_SIZE_MAX];
-		unsigned short tax;
-
+	for (int i = 0; i < sd->vend_num; i++) {
 		if (!sd->vending[i].amount)
 			continue;
 
-		tax = taxdata->get_tax(taxdata->each, sd->vending[i].value);
-		sd->vending[i].value_vat = tax ? (size_t)(sd->vending[i].value - sd->vending[i].value / 10000. * tax) : sd->vending[i].value;
+		uint16 tax = this->taxPercentage(this->each, sd->vending[i].value);
+
+		sd->vending[i].value_vat = tax ? (unsigned int)(sd->vending[i].value - sd->vending[i].value / 10000. * tax) : sd->vending[i].value;
 
 		if (battle_config.display_tax_info) {
 			memset(msg, '\0', CHAT_SIZE_MAX);
@@ -79,24 +181,21 @@ void tax_vending_vat(struct map_session_data *sd) {
  * Calculates the value after tax for Buyingstores.
  * @param sd: Player data
  */
-void tax_buyingstore_vat(struct map_session_data *sd) {
-	s_tax *taxdata;
+void s_tax::buyingstoreVAT(map_session_data *sd) {
+	char msg[CHAT_SIZE_MAX];
+
 	nullpo_retv(sd);
 
 	if (battle_config.display_tax_info)
 		clif_displaymessage(sd->fd, msg_txt(sd, 776)); // [ Tax Information ]
 
-	taxdata = tax_get(TAX_BUYING);
-
-	for (int i = 0; i < ARRAYLENGTH(sd->buyingstore.items); i++) {
-		char msg[CHAT_SIZE_MAX];
-		unsigned short tax;
-
+	for (int i = 0; i < sd->buyingstore.slots; i++) {
 		if (!sd->buyingstore.items[i].nameid)
 			continue;
 
-		tax = taxdata->get_tax(taxdata->each, sd->buyingstore.items[i].price);
-		sd->buyingstore.items[i].price_vat = (size_t)(sd->buyingstore.items[i].price + sd->buyingstore.items[i].price / 10000. * tax);
+		uint16 tax = this->taxPercentage(this->each, sd->buyingstore.items[i].price);
+
+		sd->buyingstore.items[i].price_vat = tax ? (unsigned int)(sd->buyingstore.items[i].price + sd->buyingstore.items[i].price / 10000. * tax) : sd->buyingstore.items[i].price;
 
 		if (battle_config.display_tax_info) {
 			memset(msg, '\0', CHAT_SIZE_MAX);
@@ -106,65 +205,24 @@ void tax_buyingstore_vat(struct map_session_data *sd) {
 	}
 }
 
-/**
- * Reads and parses an entry from the tax database.
- * @param node: YAML node containing the entry.
- * @param taxdata: Tax data.
- * @param count: The sequential index of the current entry.
- * @param source: The source YAML file.
- */
-static void tax_readdb_sub(const YAML::Node &node, struct s_tax *taxdata, int *count, const std::string &source) {
-	if (node["InTotal"].IsDefined()) {
-		for (const auto &tax : node["InTotal"]) {
-			if (tax["MinimalValue"].IsDefined() && tax["Tax"].IsDefined()) {
-				struct s_tax_entry entry;
-
-				entry.minimal = tax["MinimalValue"].as<size_t>();
-				entry.tax = tax["Tax"].as<unsigned short>();
-				taxdata->total.push_back(entry);
-				std::sort(taxdata->total.begin(), taxdata->total.end(),
-					[](const s_tax_entry &a, const s_tax_entry &b) -> bool { return a.minimal > b.minimal; });
-				(*count)++;
-			}
-		}
-	}
-	if (node["EachEntry"].IsDefined()) {
-		for (const auto &tax : node["EachEntry"]) {
-			if (tax["MinimalValue"].IsDefined() && tax["Tax"].IsDefined()) {
-				struct s_tax_entry entry;
-
-				entry.minimal = tax["MinimalValue"].as<size_t>();
-				entry.tax = tax["Tax"].as<unsigned short>();
-				taxdata->each.push_back(entry);
-				std::sort(taxdata->each.begin(), taxdata->each.end(),
-					[](const s_tax_entry &a, const s_tax_entry &b) -> bool { return a.minimal > b.minimal; });
-				(*count)++;
-			}
-		}
-	}
-}
-
-/**
- * Loads taxes from the tax database.
- */
-void tax_readdb(void) {
-	YAML::Node config;
+/*
+* Show selling/buying tax for total purchase value
+* @param sd Vendor or buyer data
+*/
+void s_tax::inTotalInfo(map_session_data *sd)
+{
+	char msg[CHAT_SIZE_MAX];
 
-	try {
-		config = YAML::LoadFile(tax_conf);
-	}
-	catch (...) {
-		ShowError("tax_read_db: Cannot read '" CL_WHITE "%s" CL_RESET "'.\n", tax_conf.c_str());
+	if (!battle_config.display_tax_info || this->total.empty())
 		return;
-	}
 
-	int count = 0;
-	if (config["Selling"].IsDefined())
-		tax_readdb_sub(config["Selling"], &TaxDB[TAX_SELLING], &count, tax_conf);
-	if (config["Buying"].IsDefined())
-		tax_readdb_sub(config["Buying"], &TaxDB[TAX_BUYING], &count, tax_conf);
+	clif_displaymessage(sd->fd, msg_txt(sd, 778)); // [ Total Transaction Tax ]
 
-	ShowStatus("Done reading '" CL_WHITE "%d" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'\n", count, tax_conf.c_str());
+	for (const auto &tax : this->total) {
+		memset(msg, '\0', CHAT_SIZE_MAX);
+		sprintf(msg, msg_txt(sd, 779), tax.tax / 100., tax.minimal); // Tax: %.2f%% Minimal Transaction: %u
+		clif_displaymessage(sd->fd, msg);
+	}
 }
 
 /**
@@ -172,25 +230,24 @@ void tax_readdb(void) {
  */
 void tax_reload_vat(void) {
 	struct map_session_data *sd = NULL;
-	struct s_mapiterator *iter = NULL;
+	struct s_mapiterator *iter = mapit_getallusers();
+
+	std::shared_ptr<s_tax> vending_tax = tax_db.find(TAX_SELLING);
+	std::shared_ptr<s_tax> buyingstore_tax = tax_db.find(TAX_BUYING);
 
-	iter = mapit_getallusers();
 	for (sd = (TBL_PC*)mapit_first(iter); mapit_exists(iter); sd = (TBL_PC*)mapit_next(iter)) {
-		if (sd->state.vending)
-			tax_vending_vat(sd);
-		else if (sd->state.buyingstore)
-			tax_buyingstore_vat(sd);
+		if (sd->state.vending && vending_tax != nullptr) {
+			vending_tax->vendingVAT(sd);
+			vending_tax->inTotalInfo(sd);
+		}
+		else if (sd->state.buyingstore && buyingstore_tax != nullptr) {
+			buyingstore_tax->buyingstoreVAT(sd);
+			buyingstore_tax->inTotalInfo(sd);
+		}
 	}
 	mapit_free(iter);
 }
 
-/**
- * Sets the tax database file name from the map_athena.conf
- */
- void tax_set_conf(const std::string filename) {
-	tax_conf = filename;
-}
-
 /**
  * Reloads the tax database
  */
@@ -204,15 +261,12 @@ void tax_db_reload(void) {
  * Initializes the tax database
  */
 void do_init_tax(void) {
-	tax_readdb();
+	tax_db.load();
 }
 
 /**
  * Finalizes the tax database
  */
 void do_final_tax(void) {
-	for (int i = 0; i < TAX_MAX; i++) {
-		TaxDB[i].total.clear();
-		TaxDB[i].each.clear();
-	}
+	tax_db.clear();
 }

+ 24 - 13
src/map/tax.hpp

@@ -8,36 +8,47 @@
 #include <vector>
 
 #include "../common/cbasetypes.hpp"
+#include "../common/database.hpp"
 
-#pragma once
+#include "pc.hpp"
 
-enum e_tax_type : unsigned char {
+enum e_tax_type : uint8 {
 	TAX_SELLING = 0,
 	TAX_BUYING,
 	TAX_MAX,
 };
 
 struct s_tax_entry {
-	size_t minimal;
-	unsigned short tax;
+	uint64 minimal;
+	uint16 tax;
 };
 
 struct s_tax {
-	std::vector <s_tax_entry> each;
-	std::vector <s_tax_entry> total;
+	std::vector<s_tax_entry> each;
+	std::vector<s_tax_entry> total;
 
-	unsigned short get_tax(const std::vector <s_tax_entry>, double);
+	uint16 taxPercentage(const std::vector <struct s_tax_entry> entry, double price);
+	void vendingVAT(map_session_data * sd);
+	void buyingstoreVAT(map_session_data * sd);
+	void inTotalInfo(map_session_data *sd);
 };
 
-struct s_tax *tax_get(enum e_tax_type type);
+class TaxDatabase : public TypesafeYamlDatabase<uint64, s_tax> {
+public:
+	TaxDatabase() : TypesafeYamlDatabase("TAX_DB", 1) {
 
-void tax_vending_vat(struct map_session_data *sd);
-void tax_buyingstore_vat(struct map_session_data *sd);
+	}
 
-void tax_readdb(void);
-void tax_reload_vat(void);
-void tax_set_conf(const std::string filename);
+	const std::string getDefaultLocation();
+	uint64 parseBodyNode(const YAML::Node& node);
+
+	void setVendingTax(map_session_data *sd);
+	void setBuyingstoreTax(map_session_data *sd);
+};
 
+extern TaxDatabase tax_db;
+
+void tax_reload_vat(void);
 void tax_db_reload(void);
 void do_init_tax(void);
 void do_final_tax(void);

+ 5 - 17
src/map/vending.cpp

@@ -106,11 +106,11 @@ void vending_vendinglistreq(struct map_session_data* sd, int id)
  * @return Total price after taxes
  */
 static unsigned short vending_tax_intotal(struct map_session_data* vsd, const uint8* data, int count) {
-	s_tax *tax = tax_get(TAX_SELLING);
+	std::shared_ptr<s_tax> tax = tax_db.find(TAX_SELLING);
 	double total = 0;
 	int i, vend_list[MAX_VENDING]; // against duplicate packets
 
-	if (tax->total.size() == 0)
+	if (tax == nullptr || tax->total.empty())
 		return 0;
 
 	for (i = 0; i < count; i++) {
@@ -134,7 +134,7 @@ static unsigned short vending_tax_intotal(struct map_session_data* vsd, const ui
 		total += ((double)vsd->vending[j].value * amount);
 	}
 
-	return tax->get_tax(tax->total, total);
+	return tax->taxPercentage(tax->total, total);
 }
 
 /**
@@ -340,9 +340,7 @@ int8 vending_openvending(struct map_session_data* sd, const char* message, const
 	int i, j;
 	int vending_skill_lvl;
 	char message_sql[MESSAGE_SIZE*2];
-	char msg[CHAT_SIZE_MAX];
 	StringBuf buf;
-	s_tax *taxdata;
 
 	nullpo_retr(false,sd);
 
@@ -401,24 +399,14 @@ int8 vending_openvending(struct map_session_data* sd, const char* message, const
 		return 5;
 	}
 
-	taxdata = tax_get(TAX_SELLING);
-	tax_vending_vat(sd); // Calculate value after taxes
-
-	if (battle_config.display_tax_info && taxdata->total.size()) {
-		clif_displaymessage(sd->fd, msg_txt(sd, 778)); // [ Total Transaction Tax ]
-		for (const auto &tax : taxdata->total) {
-			memset(msg, '\0', CHAT_SIZE_MAX);
-			sprintf(msg, msg_txt(sd, 779), tax.tax / 100., tax.minimal); // Tax: %.2f%% Minimal Transaction: %u
-			clif_displaymessage(sd->fd, msg);
-		}
-	}
-
 	sd->state.prevend = 0;
 	sd->state.vending = true;
 	sd->state.workinprogress = WIP_DISABLE_NONE;
 	sd->vender_id = vending_getuid();
 	sd->vend_num = i;
 	safestrncpy(sd->message, message, MESSAGE_SIZE);
+
+	tax_db.setVendingTax(sd);
 	
 	Sql_EscapeString( mmysql_handle, message_sql, sd->message );
 

+ 1 - 1
src/map/vending.hpp

@@ -15,7 +15,7 @@ struct s_vending {
 	short index; ///< Cart index (return item data)
 	short amount; ///< Amount of the item for vending
 	unsigned int value; ///< Price
-	size_t value_vat; ///< Value after tax
+	unsigned int value_vat; ///< Value after tax
 };
 
 DBMap * vending_getdb();