From 9dda166c0ebbf77003c2ac33debabda15c0c835c Mon Sep 17 00:00:00 2001 From: Lemongrass3110 Date: Thu, 5 Jan 2023 18:30:07 +0100 Subject: [PATCH] Converted cash shop database to YAML (#6299) Co-authored-by: Atemo Co-authored-by: Aleos --- conf/inter_athena.conf | 2 - db/import-tmpl/item_cash.yml | 33 ++++ db/import-tmpl/item_cash_db.txt | 19 --- db/item_cash.yml | 37 +++++ db/pre-re/item_cash_db.txt | 19 --- db/re/item_cash_db.txt | 19 --- doc/yaml/db/item_cash.yml | 12 ++ sql-files/README.md | 2 - sql-files/item_cash_db.sql | 7 - sql-files/item_cash_db2.sql | 7 - src/common/mmo.hpp | 6 + src/map/cashshop.cpp | 273 ++++++++++++++------------------ src/map/cashshop.hpp | 45 ++++-- src/map/clif.cpp | 114 +++++++------ src/map/clif_packetdb.hpp | 5 +- src/map/map-server.vcxproj | 2 +- src/map/map.cpp | 6 - src/map/packets.hpp | 25 +++ src/map/pc.cpp | 22 +-- src/map/script.cpp | 1 + src/map/script_constants.hpp | 11 ++ src/tool/csv2yaml.cpp | 52 ++++++ src/tool/csv2yaml.hpp | 1 + src/tool/yaml.hpp | 1 + src/tool/yaml2sql.cpp | 1 + tools/ci/sql.bat | 2 - tools/ci/sql.sh | 2 - 27 files changed, 407 insertions(+), 319 deletions(-) create mode 100644 db/import-tmpl/item_cash.yml delete mode 100644 db/import-tmpl/item_cash_db.txt create mode 100644 db/item_cash.yml delete mode 100644 db/pre-re/item_cash_db.txt delete mode 100644 db/re/item_cash_db.txt create mode 100644 doc/yaml/db/item_cash.yml delete mode 100644 sql-files/item_cash_db.sql delete mode 100644 sql-files/item_cash_db2.sql diff --git a/conf/inter_athena.conf b/conf/inter_athena.conf index aca5da4274..7a6b695380 100644 --- a/conf/inter_athena.conf +++ b/conf/inter_athena.conf @@ -147,8 +147,6 @@ item_table: item_db renewal-item_table: item_db_re item2_table: item_db2 renewal-item2_table: item_db2_re -item_cash_table: item_cash_db -item_cash2_table: item_cash_db2 mob_table: mob_db renewal-mob_table: mob_db_re mob2_table: mob_db2 diff --git a/db/import-tmpl/item_cash.yml b/db/import-tmpl/item_cash.yml new file mode 100644 index 0000000000..9d505dbc6f --- /dev/null +++ b/db/import-tmpl/item_cash.yml @@ -0,0 +1,33 @@ +# This file is a part of rAthena. +# Copyright(C) 2022 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 . +# +########################################################################### +# Item Cash Database +########################################################################### +# +# Item Cash Settings +# +########################################################################### +# - Tab Cash shop tab. Available tabs are New, Hot, Limited, Rental, Permanent, Scrolls, Consumables, Other, Sale. +# Items: List of possible items. +# - Item Item name. +# Price Item cost in cash points (#CASHPOINTS). +########################################################################### + +Header: + Type: ITEM_CASH_DB + Version: 1 diff --git a/db/import-tmpl/item_cash_db.txt b/db/import-tmpl/item_cash_db.txt deleted file mode 100644 index 63489a8c90..0000000000 --- a/db/import-tmpl/item_cash_db.txt +++ /dev/null @@ -1,19 +0,0 @@ -// Cash Shop Database -// Contains the items sold in the ingame cash shop. -// -// Structure of Database: -// Type,ItemID,Price -// -// Type: -// 0: New -// 1: Hot -// 2: Limited -// 3: Rental -// 4: Gear -// 5: Buff -// 6: Heal -// 7: Other -// 8: Sale -// -// Price: -// Item cost, in cash points (#CASHPOINTS). diff --git a/db/item_cash.yml b/db/item_cash.yml new file mode 100644 index 0000000000..f8b67eb2ce --- /dev/null +++ b/db/item_cash.yml @@ -0,0 +1,37 @@ +# This file is a part of rAthena. +# Copyright(C) 2022 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 . +# +########################################################################### +# Item Cash Database +########################################################################### +# +# Item Cash Settings +# +########################################################################### +# - Tab Cash shop tab. Available tabs are New, Hot, Limited, Rental, Permanent, Scrolls, Consumables, Other, Sale. +# Items: List of possible items. +# - Item Item name. +# Price Item cost in cash points (#CASHPOINTS). +########################################################################### + +Header: + Type: ITEM_CASH_DB + Version: 1 + +Footer: + Imports: + - Path: db/import/item_cash.yml diff --git a/db/pre-re/item_cash_db.txt b/db/pre-re/item_cash_db.txt deleted file mode 100644 index 63489a8c90..0000000000 --- a/db/pre-re/item_cash_db.txt +++ /dev/null @@ -1,19 +0,0 @@ -// Cash Shop Database -// Contains the items sold in the ingame cash shop. -// -// Structure of Database: -// Type,ItemID,Price -// -// Type: -// 0: New -// 1: Hot -// 2: Limited -// 3: Rental -// 4: Gear -// 5: Buff -// 6: Heal -// 7: Other -// 8: Sale -// -// Price: -// Item cost, in cash points (#CASHPOINTS). diff --git a/db/re/item_cash_db.txt b/db/re/item_cash_db.txt deleted file mode 100644 index 63489a8c90..0000000000 --- a/db/re/item_cash_db.txt +++ /dev/null @@ -1,19 +0,0 @@ -// Cash Shop Database -// Contains the items sold in the ingame cash shop. -// -// Structure of Database: -// Type,ItemID,Price -// -// Type: -// 0: New -// 1: Hot -// 2: Limited -// 3: Rental -// 4: Gear -// 5: Buff -// 6: Heal -// 7: Other -// 8: Sale -// -// Price: -// Item cost, in cash points (#CASHPOINTS). diff --git a/doc/yaml/db/item_cash.yml b/doc/yaml/db/item_cash.yml new file mode 100644 index 0000000000..75d0d34516 --- /dev/null +++ b/doc/yaml/db/item_cash.yml @@ -0,0 +1,12 @@ +########################################################################### +# Item Cash Database +########################################################################### +# +# Item Cash Settings +# +########################################################################### +# - Tab Cash shop tab. Available tabs are New, Hot, Limited, Rental, Permanent, Scrolls, Consumables, Other, Sale. +# Items: List of possible items. +# - Item Item name. +# Price Item cost in cash points (#CASHPOINTS). +########################################################################### diff --git a/sql-files/README.md b/sql-files/README.md index 5b36f09717..d8c0909323 100644 --- a/sql-files/README.md +++ b/sql-files/README.md @@ -21,8 +21,6 @@ Note: The schema name is defined in `conf/inter_athena.conf::log_db_db`. If your server is setup to read SQL database data, import the following into the main schema: Note: If `conf/inter_athena.conf::use_sql_db` is set to yes continue with these imports else these can be skipped. Not all files have to be imported, only the ones that apply to the same mode as the server being ran. -* item_cash_db.sql - Used for client's cash shop. -* item_cash_db2.sql - Used for client's cash shop (import). * item_db.sql - Contains __pre-renewal__ item data table structure. * item_db_equip.sql - Contains __pre-renewal__ equipment item data. * item_db_etc.sql - Contains __pre-renewal__ etcetera item data. diff --git a/sql-files/item_cash_db.sql b/sql-files/item_cash_db.sql deleted file mode 100644 index c7340a95b6..0000000000 --- a/sql-files/item_cash_db.sql +++ /dev/null @@ -1,7 +0,0 @@ -DROP TABLE IF EXISTS `item_cash_db`; -CREATE TABLE `item_cash_db` ( - `tab` smallint(6) NOT NULL, - `item_id` int(10) unsigned NOT NULL, - `price` mediumint(10) unsigned NOT NULL DEFAULT '0', - PRIMARY KEY (`tab`,`item_id`) -) ENGINE=MyISAM; diff --git a/sql-files/item_cash_db2.sql b/sql-files/item_cash_db2.sql deleted file mode 100644 index 42c050e968..0000000000 --- a/sql-files/item_cash_db2.sql +++ /dev/null @@ -1,7 +0,0 @@ -DROP TABLE IF EXISTS `item_cash_db2`; -CREATE TABLE `item_cash_db2` ( - `tab` smallint(6) NOT NULL, - `item_id` int(10) unsigned NOT NULL, - `price` mediumint(10) unsigned NOT NULL DEFAULT '0', - PRIMARY KEY (`tab`,`item_id`) -) ENGINE=MyISAM; diff --git a/src/common/mmo.hpp b/src/common/mmo.hpp index b01cb54ac5..588c4af61a 100644 --- a/src/common/mmo.hpp +++ b/src/common/mmo.hpp @@ -81,6 +81,12 @@ typedef uint32 t_itemid; #define MAX_AMOUNT 30000 ////Max amount of a single stacked item #define MAX_ZENY INT_MAX ///Max zeny #define MAX_BANK_ZENY SINT32_MAX ///Max zeny in Bank +#ifndef MAX_CASHPOINT + #define MAX_CASHPOINT INT_MAX +#endif +#ifndef MAX_KAFRAPOINT + #define MAX_KAFRAPOINT INT_MAX +#endif #define MAX_FAME 1000000000 ///Max fame points #define MAX_CART 100 ///Maximum item in cart #define MAX_SKILL 1454 ///Maximum skill can be hold by Player, Homunculus, & Mercenary (skill list) AND skill_db limit diff --git a/src/map/cashshop.cpp b/src/map/cashshop.cpp index e6366fa321..1263ee1614 100644 --- a/src/map/cashshop.cpp +++ b/src/map/cashshop.cpp @@ -15,144 +15,132 @@ #include "pc.hpp" // s_map_session_data #include "pet.hpp" // pet_create_egg -struct cash_item_db cash_shop_items[CASHSHOP_TAB_MAX]; #if PACKETVER_SUPPORTS_SALES struct sale_item_db sale_items; #endif -bool cash_shop_defined = false; -extern char item_cash_table[32]; -extern char item_cash2_table[32]; extern char sales_table[32]; -/* - * Reads one line from database and assigns it to RAM. - * return - * 0 = failure - * 1 = success - */ -static bool cashshop_parse_dbrow(char* fields[], int columns, int current) { - uint16 tab = atoi(fields[0]); - t_itemid nameid = strtoul(fields[1], nullptr, 10); - uint32 price = atoi(fields[2]); - int j; - struct cash_item_data* cid; +const std::string CashShopDatabase::getDefaultLocation(){ + return std::string( db_path ) + "/item_cash.yml"; +} - if( !item_db.exists( nameid ) ){ - ShowWarning( "cashshop_parse_dbrow: Invalid ID %u in line '%d', skipping...\n", nameid, current ); +uint64 CashShopDatabase::parseBodyNode( const ryml::NodeRef& node ){ + std::string name; + + if( !this->asString( node, "Tab", name ) ){ return 0; } - if( tab >= CASHSHOP_TAB_MAX ){ - ShowWarning( "cashshop_parse_dbrow: Invalid tab %d in line '%d', skipping...\n", tab, current ); - return 0; - }else if( price < 1 ){ - ShowWarning( "cashshop_parse_dbrow: Invalid price %d in line '%d', skipping...\n", price, current ); + std::string tab_constant = "CASHSHOP_TAB_" + name; + int64 constant; + + if( !script_get_constant( tab_constant.c_str(), &constant ) ){ + this->invalidWarning( node["Tab"], "Invalid tab %s, skipping.\n", tab_constant.c_str() ); return 0; } - ARR_FIND( 0, cash_shop_items[tab].count, j, nameid == cash_shop_items[tab].item[j]->nameid ); - - if( j == cash_shop_items[tab].count ){ - RECREATE( cash_shop_items[tab].item, struct cash_item_data *, ++cash_shop_items[tab].count ); - CREATE( cash_shop_items[tab].item[ cash_shop_items[tab].count - 1], struct cash_item_data, 1 ); - cid = cash_shop_items[tab].item[ cash_shop_items[tab].count - 1]; - }else{ - cid = cash_shop_items[tab].item[j]; + if( constant < CASHSHOP_TAB_NEW || constant >= CASHSHOP_TAB_MAX ){ + this->invalidWarning( node["Tab"], "Tab %" PRId64 " is out of range, skipping.\n", constant ); + return 0; } - cid->nameid = nameid; - cid->price = price; - cash_shop_defined = true; + e_cash_shop_tab tab = static_cast( constant ); + + std::shared_ptr entry = this->find( tab ); + bool exists = entry != nullptr; + + if( !exists ){ + if( !this->nodesExist( node, { "Items" } ) ){ + return 0; + } + + entry = std::make_shared(); + entry->tab = tab; + } + + for( const ryml::NodeRef& it : node["Items"] ){ + std::string item_name; + + if( !this->asString( it, "Item", item_name ) ){ + return 0; + } + + std::shared_ptr item = item_db.search_aegisname( item_name.c_str() ); + + if( item == nullptr ){ + this->invalidWarning( it["Item"], "Cash item %s does not exist, skipping.\n", item_name.c_str() ); + continue; + } + + std::shared_ptr cash_item = nullptr; + bool cash_item_exists = false; + + for( std::shared_ptr cash_it : entry->items ){ + if( cash_it->nameid == item->nameid ){ + cash_item = cash_it; + cash_item_exists = true; + break; + } + } + + if( !cash_item_exists ){ + cash_item = std::make_shared(); + cash_item->nameid = item->nameid; + } + + uint32 price; + + if( !this->asUInt32( it, "Price", price ) ){ + return 0; + } + + if( price == 0 ){ + this->invalidWarning( it["Price"], "Price has to be greater than zero." ); + return 0; + } + + if( price > MAX_CASHPOINT ){ + this->invalidWarning( it["Price"], "Price has to be lower than MAX_CASHPOINT(%d).", MAX_CASHPOINT ); + return 0; + } + + cash_item->price = price; + + if( !cash_item_exists ){ + entry->items.push_back( cash_item ); + } + } + + if( !exists ){ + this->put( tab, entry ); + } return 1; } -/* - * Reads database from TXT format, - * parses lines and sends them to parse_dbrow. - */ -static void cashshop_read_db_txt( void ){ - const char* dbsubpath[] = { - "", - "/" DBIMPORT, - }; - int fi; +std::shared_ptr CashShopDatabase::findItemInTab( e_cash_shop_tab tab, t_itemid nameid ){ + std::shared_ptr cash_tab = this->find( tab ); - for( fi = 0; fi < ARRAYLENGTH( dbsubpath ); ++fi ){ - uint8 n1 = (uint8)(strlen(db_path)+strlen(dbsubpath[fi])+1); - uint8 n2 = (uint8)(strlen(db_path)+strlen(DBPATH)+strlen(dbsubpath[fi])+1); - char* dbsubpath1 = (char*)aMalloc(n1+1); - char* dbsubpath2 = (char*)aMalloc(n2+1); - - if(fi==0) { - safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[fi]); - safesnprintf(dbsubpath2,n2,"%s/%s%s",db_path,DBPATH,dbsubpath[fi]); - } - else { - safesnprintf(dbsubpath1,n1,"%s%s",db_path,dbsubpath[fi]); - safesnprintf(dbsubpath2,n1,"%s%s",db_path,dbsubpath[fi]); - } - - sv_readdb(dbsubpath2, "item_cash_db.txt", ',', 3, 3, -1, &cashshop_parse_dbrow, fi > 0); - - aFree(dbsubpath1); - aFree(dbsubpath2); - } -} - -/* - * Reads database from SQL format, - * parses line and sends them to parse_dbrow. - */ -static int cashshop_read_db_sql( void ){ - const char* cash_db_name[] = { item_cash_table, item_cash2_table }; - int fi; - - for( fi = 0; fi < ARRAYLENGTH( cash_db_name ); ++fi ){ - uint32 lines = 0, count = 0; - - if( SQL_ERROR == Sql_Query( mmysql_handle, "SELECT `tab`, `item_id`, `price` FROM `%s`", cash_db_name[fi] ) ){ - Sql_ShowDebug( mmysql_handle ); - continue; - } - - - while( SQL_SUCCESS == Sql_NextRow( mmysql_handle ) ){ - char* str[3]; - char dummy[256] = ""; - int i; - - ++lines; - - for( i = 0; i < 3; ++i ){ - Sql_GetData( mmysql_handle, i, &str[i], NULL ); - - if( str[i] == NULL ){ - str[i] = dummy; - } - } - - if( !cashshop_parse_dbrow( str, 3, lines ) ) { - ShowError("cashshop_read_db_sql: Cannot process table '%s' at line '%d', skipping...\n", cash_db_name[fi], lines); - continue; - } - - ++count; - } - - Sql_FreeResult( mmysql_handle ); - - ShowStatus( "Done reading '" CL_WHITE "%u" CL_RESET "' entries in '" CL_WHITE "%s" CL_RESET "'.\n", count, cash_db_name[fi] ); + if( cash_tab == nullptr ){ + return nullptr; } - return 0; + for( std::shared_ptr cash_it : cash_tab->items ){ + if( cash_it->nameid == nameid ){ + return cash_it; + } + } + + return nullptr; } +CashShopDatabase cash_shop_db; + #if PACKETVER_SUPPORTS_SALES static bool sale_parse_dbrow( char* fields[], int columns, int current ){ t_itemid nameid = strtoul(fields[0], nullptr, 10); - int start = atoi(fields[1]), end = atoi(fields[2]), amount = atoi(fields[3]), i; + int start = atoi(fields[1]), end = atoi(fields[2]), amount = atoi(fields[3]); time_t now = time(NULL); struct sale_item_data* sale_item = NULL; @@ -161,10 +149,9 @@ static bool sale_parse_dbrow( char* fields[], int columns, int current ){ return false; } - ARR_FIND( 0, cash_shop_items[CASHSHOP_TAB_SALE].count, i, cash_shop_items[CASHSHOP_TAB_SALE].item[i]->nameid == nameid ); - - if( i == cash_shop_items[CASHSHOP_TAB_SALE].count ){ - ShowWarning( "sale_parse_dbrow: ID %u is not registered in the limited tab in line '%d', skipping...\n", nameid, current ); + // Check if the item exists in the sales tab + if( cash_shop_db.findItemInTab( CASHSHOP_TAB_SALE, nameid ) == nullptr ){ + ShowWarning( "sale_parse_dbrow: ID %u is not registered in the Sale tab in line '%d', skipping...\n", nameid, current ); return false; } @@ -268,14 +255,8 @@ static TIMER_FUNC(sale_start_timer){ } enum e_sale_add_result sale_add_item( t_itemid nameid, int32 count, time_t from, time_t to ){ - int i; - struct sale_item_data* sale_item; - // Check if the item exists in the sales tab - ARR_FIND( 0, cash_shop_items[CASHSHOP_TAB_SALE].count, i, cash_shop_items[CASHSHOP_TAB_SALE].item[i]->nameid == nameid ); - - // Item does not exist in the sales tab - if( i == cash_shop_items[CASHSHOP_TAB_SALE].count ){ + if( cash_shop_db.findItemInTab( CASHSHOP_TAB_SALE, nameid ) == nullptr ){ return SALE_ADD_FAILED; } @@ -306,7 +287,7 @@ enum e_sale_add_result sale_add_item( t_itemid nameid, int32 count, time_t from, RECREATE(sale_items.item, struct sale_item_data *, ++sale_items.count); CREATE(sale_items.item[sale_items.count - 1], struct sale_item_data, 1); - sale_item = sale_items.item[sale_items.count - 1]; + struct sale_item_data* sale_item = sale_items.item[sale_items.count - 1]; sale_item->nameid = nameid; sale_item->start = from; @@ -421,23 +402,13 @@ void sale_notify_login( map_session_data* sd ){ } #endif -/* - * Determines whether to read TXT or SQL database - * based on 'db_use_sqldbs' in conf/map_athena.conf. - */ static void cashshop_read_db( void ){ + cash_shop_db.load(); + #if PACKETVER_SUPPORTS_SALES int i; time_t now = time(NULL); -#endif - if( db_use_sqldbs ){ - cashshop_read_db_sql(); - } else { - cashshop_read_db_txt(); - } - -#if PACKETVER_SUPPORTS_SALES sale_read_db_sql(); // Clean outdated sales @@ -472,7 +443,7 @@ bool cashshop_buylist( map_session_data* sd, uint32 kafrapoints, int n, struct P uint32 totalweight = 0; int i,new_; - if( sd == NULL || item_list == NULL || !cash_shop_defined){ + if( sd == NULL || item_list == NULL ){ clif_cashshop_result( sd, 0, CASHSHOP_RESULT_ERROR_UNKNOWN ); return false; }else if( sd->state.trading ){ @@ -486,21 +457,19 @@ bool cashshop_buylist( map_session_data* sd, uint32 kafrapoints, int n, struct P t_itemid nameid = item_list[i].itemId; uint32 quantity = item_list[i].amount; uint16 tab = item_list[i].tab; - int j; if( tab >= CASHSHOP_TAB_MAX ){ clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_UNKNOWN ); return false; } - ARR_FIND( 0, cash_shop_items[tab].count, j, nameid == cash_shop_items[tab].item[j]->nameid || nameid == itemdb_viewid(cash_shop_items[tab].item[j]->nameid) ); + std::shared_ptr cash_item = cash_shop_db.findItemInTab( static_cast( tab ), nameid ); - if( j == cash_shop_items[tab].count ){ + if( cash_item == nullptr ){ clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_UNKONWN_ITEM ); return false; } - nameid = item_list[i].itemId = cash_shop_items[tab].item[j]->nameid; //item_avail replacement std::shared_ptr id = item_db.find(nameid); @@ -515,8 +484,8 @@ bool cashshop_buylist( map_session_data* sd, uint32 kafrapoints, int n, struct P return false; } -#if PACKETVER_SUPPORTS_SALES if( tab == CASHSHOP_TAB_SALE ){ +#if PACKETVER_SUPPORTS_SALES struct sale_item_data* sale = sale_find_item( nameid, true ); if( sale == NULL ){ @@ -532,8 +501,11 @@ bool cashshop_buylist( map_session_data* sd, uint32 kafrapoints, int n, struct P clif_sale_amount( sale, &sd->bl, SELF ); return false; } - } +#else + clif_cashshop_result( sd, nameid, CASHSHOP_RESULT_ERROR_UNKNOWN ); + return false; #endif + } switch( pc_checkadditem( sd, nameid, quantity ) ){ case CHKADDITEM_EXIST: @@ -548,7 +520,7 @@ bool cashshop_buylist( map_session_data* sd, uint32 kafrapoints, int n, struct P return false; } - totalcash += cash_shop_items[tab].item[j]->price * quantity; + totalcash += cash_item->price * quantity; totalweight += itemdb_weight( nameid ) * quantity; } @@ -664,19 +636,11 @@ void cashshop_reloaddb( void ){ * Closes all and cleanup. */ void do_final_cashshop( void ){ - int tab, i; - - for( tab = CASHSHOP_TAB_NEW; tab < CASHSHOP_TAB_MAX; tab++ ){ - for( i = 0; i < cash_shop_items[tab].count; i++ ){ - aFree( cash_shop_items[tab].item[i] ); - } - aFree( cash_shop_items[tab].item ); - } - memset( cash_shop_items, 0, sizeof( cash_shop_items ) ); + cash_shop_db.clear(); #if PACKETVER_SUPPORTS_SALES if( sale_items.count > 0 ){ - for( i = 0; i < sale_items.count; i++ ){ + for( int i = 0; i < sale_items.count; i++ ){ struct sale_item_data* it = sale_items.item[i]; if( it->timer_start != INVALID_TIMER ){ @@ -702,10 +666,7 @@ void do_final_cashshop( void ){ /* * Initializes cashshop class. - * return - * 0 : success */ void do_init_cashshop( void ){ - cash_shop_defined = false; cashshop_read_db(); } diff --git a/src/map/cashshop.hpp b/src/map/cashshop.hpp index b9a37aa945..5bea492c8d 100644 --- a/src/map/cashshop.hpp +++ b/src/map/cashshop.hpp @@ -4,9 +4,13 @@ #ifndef CASHSHOP_HPP #define CASHSHOP_HPP +#include // std::shared_ptr +#include // std::vector + #include "../config/core.hpp" #include "../common/cbasetypes.hpp" // uint16, uint32 +#include "../common/database.hpp" // TypesafeYamlDatabase #include "../common/mmo.hpp" // t_itemid #include "../common/timer.hpp" // ShowWarning, ShowStatus @@ -17,20 +21,17 @@ void do_final_cashshop( void ); void cashshop_reloaddb( void ); bool cashshop_buylist( map_session_data* sd, uint32 kafrapoints, int n, struct PACKET_CZ_SE_PC_BUY_CASHITEM_LIST_sub* item_list ); -// Taken from AEGIS -enum CASH_SHOP_TAB_CODE -{ +// Taken from AEGIS (CASH_SHOP_TAB_CODE) +enum e_cash_shop_tab : uint16{ CASHSHOP_TAB_NEW = 0x0, - CASHSHOP_TAB_POPULAR, + CASHSHOP_TAB_HOT, CASHSHOP_TAB_LIMITED, CASHSHOP_TAB_RENTAL, - CASHSHOP_TAB_PERPETUITY, - CASHSHOP_TAB_BUFF, - CASHSHOP_TAB_RECOVERY, - CASHSHOP_TAB_ETC, -#if PACKETVER_SUPPORTS_SALES + CASHSHOP_TAB_PERMANENT, + CASHSHOP_TAB_SCROLLS, + CASHSHOP_TAB_CONSUMABLES, + CASHSHOP_TAB_OTHER, CASHSHOP_TAB_SALE, -#endif CASHSHOP_TAB_MAX }; @@ -52,18 +53,30 @@ enum CASHSHOP_BUY_RESULT CASHSHOP_RESULT_ERROR_BUSY = 0xc, }; -struct cash_item_data{ +struct s_cash_item{ t_itemid nameid; uint32 price; }; -struct cash_item_db{ - struct cash_item_data** item; - uint32 count; +struct s_cash_item_tab{ + e_cash_shop_tab tab; + std::vector> items; }; -extern struct cash_item_db cash_shop_items[CASHSHOP_TAB_MAX]; -extern bool cash_shop_defined; +class CashShopDatabase : public TypesafeYamlDatabase{ +public: + CashShopDatabase() : TypesafeYamlDatabase( "ITEM_CASH_DB", 1 ){ + + } + + const std::string getDefaultLocation(); + uint64 parseBodyNode( const ryml::NodeRef& node ); + + // Additional + std::shared_ptr findItemInTab( e_cash_shop_tab tab, t_itemid nameid ); +}; + +extern CashShopDatabase cash_shop_db; enum e_sale_add_result { SALE_ADD_SUCCESS = 0, diff --git a/src/map/clif.cpp b/src/map/clif.cpp index b5cab4320b..9f91ee40c9 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -17000,26 +17000,46 @@ void clif_parse_cashshop_close( int fd, map_session_data* sd ){ //0846 .W (CZ_REQ_SE_CASH_TAB_CODE)) //08c0 .W .L .W (ZC_ACK_SE_CASH_ITEM_LIST2) void clif_parse_CashShopReqTab(int fd, map_session_data *sd) { +#if PACKETVER_MAIN_NUM >= 20100824 || PACKETVER_RE_NUM >= 20100824 || defined(PACKETVER_ZERO) + struct PACKET_CZ_REQ_SE_CASH_TAB_CODE* p_in = (struct PACKET_CZ_REQ_SE_CASH_TAB_CODE*)RFIFOP( fd, 0 ); + +// TODO: most likely wrong answer packet. Most likely HEADER_ZC_ACK_SE_CASH_ITEM_LIST (0x847) would be correct [Lemongrass] // [4144] packet exists only in 2011 and was dropped after #if PACKETVER >= 20110222 && PACKETVER < 20120000 - short tab = RFIFOW(fd, packet_db[RFIFOW(fd,0)].pos[0]); - int j; + std::shared_ptr tab = cash_shop_db.find( static_cast( p_in->tab ) ); - if( tab < 0 || tab >= CASHSHOP_TAB_MAX ) + if( tab == nullptr ){ return; - - WFIFOHEAD(fd, 10 + ( cash_shop_items[tab].count * 6 ) ); - WFIFOW(fd, 0) = 0x8c0; - WFIFOW(fd, 2) = 10 + ( cash_shop_items[tab].count * 6 ); - WFIFOL(fd, 4) = tab; - WFIFOW(fd, 8) = cash_shop_items[tab].count; - - for( j = 0; j < cash_shop_items[tab].count; j++ ) { - WFIFOW(fd, 10 + ( 6 * j ) ) = client_nameid( cash_shop_items[tab].item[j]->nameid ); - WFIFOL(fd, 12 + ( 6 * j ) ) = cash_shop_items[tab].item[j]->price; } - WFIFOSET(fd, 10 + ( cash_shop_items[tab].count * 6 )); + // Skip empty tabs, the client only expects filled ones + if( tab->items.empty() ){ + return; + } + +#if !(PACKETVER_SUPPORTS_SALES) + if( tab->tab == CASHSHOP_TAB_SALE ){ + return; + } +#endif + + struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2* p = (struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2*)packet_buffer; + + p->packetType = HEADER_ZC_ACK_SE_CASH_ITEM_LIST2; + p->packetLength = sizeof( struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2 ); + p->tab = tab->tab; + p->count = 0; + + for( std::shared_ptr item : tab->items ){ + p->items[p->count].itemId = client_nameid( item->nameid ); + p->items[p->count].price = item->price; + + p->packetLength += sizeof( struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2_sub ); + p->count++; + } + + clif_send( p, p->packetLength, &sd->bl, SELF ); +#endif #endif } @@ -17027,44 +17047,46 @@ void clif_parse_CashShopReqTab(int fd, map_session_data *sd) { void clif_cashshop_list( map_session_data* sd ){ nullpo_retv( sd ); - int fd = sd->fd; + for( const auto& pair : cash_shop_db ){ + std::shared_ptr tab = pair.second; - if( !session_isActive( fd ) ){ - return; - } - - for( int tab = CASHSHOP_TAB_NEW; tab < CASHSHOP_TAB_MAX; tab++ ){ // Skip empty tabs, the client only expects filled ones - if( cash_shop_items[tab].count == 0 ){ + if( tab->items.empty() ){ continue; } - int len = sizeof( struct PACKET_ZC_ACK_SCHEDULER_CASHITEM ) + ( cash_shop_items[tab].count * sizeof( struct PACKET_ZC_ACK_SCHEDULER_CASHITEM_sub ) ); - WFIFOHEAD( fd, len ); - struct PACKET_ZC_ACK_SCHEDULER_CASHITEM *p = (struct PACKET_ZC_ACK_SCHEDULER_CASHITEM *)WFIFOP( fd, 0 ); +#if !(PACKETVER_SUPPORTS_SALES) + if( tab->tab == CASHSHOP_TAB_SALE ){ + continue; + } +#endif - p->packetType = 0x8ca; - p->packetLength = len; - p->count = cash_shop_items[tab].count; - p->tabNum = tab; + struct PACKET_ZC_ACK_SCHEDULER_CASHITEM *p = (struct PACKET_ZC_ACK_SCHEDULER_CASHITEM *)packet_buffer; - for( int i = 0; i < cash_shop_items[tab].count; i++ ){ - p->items[i].itemId = client_nameid( cash_shop_items[tab].item[i]->nameid ); - p->items[i].price = cash_shop_items[tab].item[i]->price; + p->packetType = HEADER_ZC_ACK_SCHEDULER_CASHITEM; + p->count = 0; + p->tabNum = tab->tab; + + for( std::shared_ptr item : tab->items ){ + p->items[p->count].itemId = client_nameid( item->nameid ); + p->items[p->count].price = item->price; #ifdef ENABLE_CASHSHOP_PREVIEW_PATCH - struct item_data* id = itemdb_search( cash_shop_items[tab].item[i]->nameid ); + struct item_data* id = itemdb_search( item->nameid ); if( id == nullptr ){ - p->items[i].location = 0; - p->items[i].viewSprite = 0; + p->items[p->count].location = 0; + p->items[p->count].viewSprite = 0; }else{ - p->items[i].location = pc_equippoint_sub( sd, id ); - p->items[i].viewSprite = id->look; + p->items[p->count].location = pc_equippoint_sub( sd, id ); + p->items[p->count].viewSprite = id->look; } #endif + p->count++; } - WFIFOSET( fd, len ); + p->packetLength = sizeof( struct PACKET_ZC_ACK_SCHEDULER_CASHITEM ) + p->count * sizeof( struct PACKET_ZC_ACK_SCHEDULER_CASHITEM_sub ); + + clif_send( p, p->packetLength, &sd->bl, SELF ); } } @@ -21178,7 +21200,7 @@ void clif_parse_sale_close(int fd, map_session_data* sd) { /// Reply to a item search request for item sale administration. /// 09ad .W .W .L (ZC_ACK_CASH_BARGAIN_SALE_ITEM_INFO) -void clif_sale_search_reply( map_session_data* sd, struct cash_item_data* item ){ +void clif_sale_search_reply( map_session_data* sd, std::shared_ptr item ){ #if PACKETVER_SUPPORTS_SALES struct PACKET_ZC_ACK_CASH_BARGAIN_SALE_ITEM_INFO p; @@ -21218,19 +21240,13 @@ void clif_parse_sale_search( int fd, map_session_data* sd ){ std::shared_ptr id = item_db.searchname( item_name ); - if( id ){ - int i; - - for( i = 0; i < cash_shop_items[CASHSHOP_TAB_SALE].count; i++ ){ - if( cash_shop_items[CASHSHOP_TAB_SALE].item[i]->nameid == id->nameid ){ - clif_sale_search_reply( sd, cash_shop_items[CASHSHOP_TAB_SALE].item[i] ); - return; - } - } + // not found + if( id == nullptr ){ + clif_sale_search_reply( sd, nullptr ); + return; } - // not found - clif_sale_search_reply( sd, NULL ); + clif_sale_search_reply( sd, cash_shop_db.findItemInTab( CASHSHOP_TAB_SALE, id->nameid ) ); #endif } diff --git a/src/map/clif_packetdb.hpp b/src/map/clif_packetdb.hpp index 33dfc21a33..966077d2d3 100644 --- a/src/map/clif_packetdb.hpp +++ b/src/map/clif_packetdb.hpp @@ -1747,6 +1747,10 @@ parseable_packet(0x0843,6,clif_parse_GMRemove2,2); #endif +#if PACKETVER_MAIN_NUM >= 20100824 || PACKETVER_RE_NUM >= 20100824 || defined(PACKETVER_ZERO) + parseable_packet( HEADER_CZ_REQ_SE_CASH_TAB_CODE, sizeof( struct PACKET_CZ_REQ_SE_CASH_TAB_CODE ), clif_parse_CashShopReqTab, 0 ); +#endif + // 2010-11-24aRagexeRE #if PACKETVER >= 20101124 parseable_packet(0x0288,-1,clif_parse_npccashshop_buy,2,4,8,10); @@ -1783,7 +1787,6 @@ parseable_packet(0x0439,8,clif_parse_UseItem,2,4); packet(0x08d2,10); packet(0x08d1,7); - parseable_packet(0x0846,4,clif_parse_CashShopReqTab,2); //2011-07-18 #endif // 2011-11-02aRagexe diff --git a/src/map/map-server.vcxproj b/src/map/map-server.vcxproj index 8896928162..804b273974 100644 --- a/src/map/map-server.vcxproj +++ b/src/map/map-server.vcxproj @@ -333,7 +333,7 @@ - + diff --git a/src/map/map.cpp b/src/map/map.cpp index f4f86b3fe8..04be885f7f 100644 --- a/src/map/map.cpp +++ b/src/map/map.cpp @@ -70,8 +70,6 @@ int db_use_sqldbs = 0; char barter_table[32] = "barter"; char buyingstores_table[32] = "buyingstores"; char buyingstore_items_table[32] = "buyingstore_items"; -char item_cash_table[32] = "item_cash_db"; -char item_cash2_table[32] = "item_cash_db2"; #ifdef RENEWAL char item_table[32] = "item_db_re"; char item2_table[32] = "item_db2_re"; @@ -4162,10 +4160,6 @@ int inter_config_read(const char *cfgName) safestrncpy(mob_skill_table,w2,sizeof(mob_skill_table)); else if(strcmpi(w1,"mob_skill2_table")==0) safestrncpy(mob_skill2_table,w2,sizeof(mob_skill2_table)); - else if( strcmpi( w1, "item_cash_table" ) == 0 ) - safestrncpy( item_cash_table, w2, sizeof(item_cash_table) ); - else if( strcmpi( w1, "item_cash2_table" ) == 0 ) - safestrncpy( item_cash2_table, w2, sizeof(item_cash2_table) ); else if( strcmpi( w1, "vending_db" ) == 0 ) safestrncpy( vendings_table, w2, sizeof(vendings_table) ); else if( strcmpi( w1, "vending_items_table" ) == 0 ) diff --git a/src/map/packets.hpp b/src/map/packets.hpp index 2055fa8448..5f1f66d30e 100644 --- a/src/map/packets.hpp +++ b/src/map/packets.hpp @@ -453,6 +453,28 @@ struct PACKET_ZC_PARTY_JOIN_REQ_ACK_FROM_MASTER{ uint32 refused; } __attribute__((packed)); +struct PACKET_CZ_REQ_SE_CASH_TAB_CODE{ + int16 packetType; + int16 tab; +} __attribute__((packed)); + +struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2_sub{ +#if PACKETVER_MAIN_NUM >= 20181121 || PACKETVER_RE_NUM >= 20180704 || PACKETVER_ZERO_NUM >= 20181114 + uint32 itemId; +#else + uint16 itemId; +#endif + int32 price; +} __attribute__((packed)); + +struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2{ + int16 packetType; + int16 packetLength; + uint32 tab; + int16 count; + struct PACKET_ZC_ACK_SE_CASH_ITEM_LIST2_sub items[]; +} __attribute__((packed)); + // NetBSD 5 and Solaris don't like pragma pack but accept the packed attribute #if !defined( sun ) && ( !defined( __NETBSD__ ) || __NetBSD_Version__ >= 600000000 ) #pragma pack( pop ) @@ -489,6 +511,9 @@ DEFINE_PACKET_HEADER(ZC_CASH_ITEM_DELETE, 0x299) DEFINE_PACKET_HEADER(ZC_NOTIFY_BIND_ON_EQUIP, 0x2d3) DEFINE_PACKET_HEADER(ZC_FAILED_TRADE_BUYING_STORE_TO_SELLER, 0x824) DEFINE_PACKET_HEADER(CZ_SSILIST_ITEM_CLICK, 0x83c) +DEFINE_PACKET_HEADER(CZ_REQ_SE_CASH_TAB_CODE, 0x846) +DEFINE_PACKET_HEADER(ZC_ACK_SE_CASH_ITEM_LIST2, 0x8c0) +DEFINE_PACKET_HEADER(ZC_ACK_SCHEDULER_CASHITEM, 0x8ca) DEFINE_PACKET_HEADER(ZC_CLEAR_DIALOG, 0x8d6) DEFINE_PACKET_HEADER(ZC_ENTRY_QUEUE_INIT, 0x90e); DEFINE_PACKET_HEADER(ZC_BANKING_CHECK, 0x9a6) diff --git a/src/map/pc.cpp b/src/map/pc.cpp index d5696b8354..d95248a10a 100755 --- a/src/map/pc.cpp +++ b/src/map/pc.cpp @@ -5623,7 +5623,7 @@ int pc_paycash(map_session_data *sd, int price, int points, e_log_pick_type type int cash; nullpo_retr(-1,sd); - points = cap_value(points, 0, MAX_ZENY); //prevent command UB + points = cap_value(points, 0, MAX_KAFRAPOINT); //prevent command UB cash = price-points; @@ -5669,14 +5669,14 @@ int pc_getcash(map_session_data *sd, int cash, int points, e_log_pick_type type) nullpo_retr(-1,sd); - cash = cap_value(cash, 0, MAX_ZENY); //prevent command UB - points = cap_value(points, 0, MAX_ZENY); //prevent command UB + cash = cap_value(cash, 0, MAX_CASHPOINT); //prevent command UB + points = cap_value(points, 0, MAX_KAFRAPOINT); //prevent command UB if( cash > 0 ) { - if( cash > MAX_ZENY-sd->cashPoints ) + if( cash > MAX_CASHPOINT-sd->cashPoints ) { ShowWarning("pc_getcash: Cash point overflow (cash=%d, have cash=%d, account_id=%d, char_id=%d).\n", cash, sd->cashPoints, sd->status.account_id, sd->status.char_id); - cash = MAX_ZENY-sd->cashPoints; + cash = MAX_CASHPOINT-sd->cashPoints; } pc_setaccountreg(sd, add_str(CASHPOINT_VAR), sd->cashPoints+cash); @@ -5693,10 +5693,10 @@ int pc_getcash(map_session_data *sd, int cash, int points, e_log_pick_type type) if( points > 0 ) { - if( points > MAX_ZENY-sd->kafraPoints ) + if( points > MAX_KAFRAPOINT-sd->kafraPoints ) { ShowWarning("pc_getcash: Kafra point overflow (points=%d, have points=%d, account_id=%d, char_id=%d).\n", points, sd->kafraPoints, sd->status.account_id, sd->status.char_id); - points = MAX_ZENY-sd->kafraPoints; + points = MAX_KAFRAPOINT-sd->kafraPoints; } pc_setaccountreg(sd, add_str(KAFRAPOINT_VAR), sd->kafraPoints+points); @@ -10278,16 +10278,16 @@ bool pc_setparam(map_session_data *sd,int64 type,int64 val_tmp) if (val < 0) return false; if (!sd->state.connect_new) - log_cash(sd, LOG_TYPE_SCRIPT, LOG_CASH_TYPE_CASH, -(sd->cashPoints - cap_value(val, 0, MAX_ZENY))); - sd->cashPoints = cap_value(val, 0, MAX_ZENY); + log_cash(sd, LOG_TYPE_SCRIPT, LOG_CASH_TYPE_CASH, -(sd->cashPoints - cap_value(val, 0, MAX_CASHPOINT))); + sd->cashPoints = cap_value(val, 0, MAX_CASHPOINT); pc_setaccountreg(sd, add_str(CASHPOINT_VAR), sd->cashPoints); return true; case SP_KAFRAPOINTS: if (val < 0) return false; if (!sd->state.connect_new) - log_cash(sd, LOG_TYPE_SCRIPT, LOG_CASH_TYPE_KAFRA, -(sd->kafraPoints - cap_value(val, 0, MAX_ZENY))); - sd->kafraPoints = cap_value(val, 0, MAX_ZENY); + log_cash(sd, LOG_TYPE_SCRIPT, LOG_CASH_TYPE_KAFRA, -(sd->kafraPoints - cap_value(val, 0, MAX_KAFRAPOINT))); + sd->kafraPoints = cap_value(val, 0, MAX_KAFRAPOINT); pc_setaccountreg(sd, add_str(KAFRAPOINT_VAR), sd->kafraPoints); return true; case SP_PCDIECOUNTER: diff --git a/src/map/script.cpp b/src/map/script.cpp index 5aeebe2283..9a0ca776f7 100644 --- a/src/map/script.cpp +++ b/src/map/script.cpp @@ -35,6 +35,7 @@ #include "atcommand.hpp" #include "battle.hpp" #include "battleground.hpp" +#include "cashshop.hpp" #include "channel.hpp" #include "chat.hpp" #include "chrif.hpp" diff --git a/src/map/script_constants.hpp b/src/map/script_constants.hpp index 868a0e6782..c785c80945 100644 --- a/src/map/script_constants.hpp +++ b/src/map/script_constants.hpp @@ -9927,6 +9927,17 @@ export_constant(ENCHANTGRADE_A); export_constant(MAX_ENCHANTGRADE); + /* cash shop tabs */ + export_constant(CASHSHOP_TAB_NEW); + export_constant(CASHSHOP_TAB_HOT); + export_constant(CASHSHOP_TAB_LIMITED); + export_constant(CASHSHOP_TAB_RENTAL); + export_constant(CASHSHOP_TAB_PERMANENT); + export_constant(CASHSHOP_TAB_SCROLLS); + export_constant(CASHSHOP_TAB_CONSUMABLES); + export_constant(CASHSHOP_TAB_OTHER); + export_constant(CASHSHOP_TAB_SALE); + #undef export_constant #undef export_constant2 #undef export_parameter diff --git a/src/tool/csv2yaml.cpp b/src/tool/csv2yaml.cpp index a08deae749..aadbe6e3a6 100644 --- a/src/tool/csv2yaml.cpp +++ b/src/tool/csv2yaml.cpp @@ -540,6 +540,12 @@ bool Csv2YamlTool::initialize( int argc, char* argv[] ){ return false; } + if( !process( "ITEM_CASH_DB", 1, root_paths, "item_cash_db", []( const std::string& path, const std::string& name_ext ) -> bool { + return sv_readdb( path.c_str(), name_ext.c_str(), ',', 3, 3, -1, &cashshop_parse_dbrow, false ); + }, "item_cash" ) ){ + return 0; + } + // TODO: add implementations ;-) return true; @@ -4918,6 +4924,52 @@ static bool itemdb_read_combos(const char* file) { return true; } +// Copied and adjusted from cashshop.cpp +static bool cashshop_parse_dbrow( char* fields[], int columns, int current ){ + uint16 tab = atoi( fields[0] ); + t_itemid nameid = strtoul( fields[1], nullptr, 10 ); + uint32 price = atoi( fields[2] ); + + std::string* item_name = util::umap_find( aegis_itemnames, nameid ); + + if( item_name == nullptr ){ + ShowWarning( "cashshop_parse_dbrow: Invalid item id %u.\n", nameid ); + return false; + } + + if( tab >= CASHSHOP_TAB_MAX ){ + ShowWarning( "cashshop_parse_dbrow: Invalid tab %d in line '%d', skipping...\n", tab, current ); + return false; + }else if( price < 1 ){ + ShowWarning( "cashshop_parse_dbrow: Invalid price %d in line '%d', skipping...\n", price, current ); + return false; + } + + const char* constant_ptr = constant_lookup( tab, "CASHSHOP_TAB_" ); + + if( constant_ptr == nullptr ){ + ShowError( "cashshop_parse_dbrow: CASHSHOP_TAB constant for tab %hu was not found, skipping...\n", tab ); + return false; + } + + std::string constant = constant_ptr; + constant.erase( 0, 13 ); + constant = name2Upper( constant ); + + body << YAML::BeginMap; + body << YAML::Key << "Tab" << YAML::Value << constant; + body << YAML::Key << "Items"; + body << YAML::BeginSeq; + body << YAML::BeginMap; + body << YAML::Key << "Item" << YAML::Value << *item_name; + body << YAML::Key << "Price" << YAML::Value << price; + body << YAML::EndMap; + body << YAML::EndSeq; + body << YAML::EndMap; + + return true; +} + int main( int argc, char *argv[] ){ return main_core( argc, argv ); } diff --git a/src/tool/csv2yaml.hpp b/src/tool/csv2yaml.hpp index 2e59b7ff14..465d9bb457 100644 --- a/src/tool/csv2yaml.hpp +++ b/src/tool/csv2yaml.hpp @@ -530,5 +530,6 @@ static bool mercenary_readdb(char* str[], int columns, int current); static bool pc_readdb_skilltree(char* str[], int columns, int current); static bool pc_readdb_skilltree_yaml(void); static bool itemdb_read_combos(const char* file); +static bool cashshop_parse_dbrow( char* fields[], int columns, int current ); #endif /* CSV2YAML_HPP */ diff --git a/src/tool/yaml.hpp b/src/tool/yaml.hpp index 0ade5f95c5..2531f12e86 100644 --- a/src/tool/yaml.hpp +++ b/src/tool/yaml.hpp @@ -40,6 +40,7 @@ #include "../map/achievement.hpp" #include "../map/battle.hpp" #include "../map/battleground.hpp" +#include "../map/cashshop.hpp" #include "../map/channel.hpp" #include "../map/chat.hpp" #include "../map/date.hpp" diff --git a/src/tool/yaml2sql.cpp b/src/tool/yaml2sql.cpp index 2426c225b2..b5cbd4eb5c 100644 --- a/src/tool/yaml2sql.cpp +++ b/src/tool/yaml2sql.cpp @@ -37,6 +37,7 @@ #include "../map/achievement.hpp" #include "../map/battle.hpp" #include "../map/battleground.hpp" +#include "../map/cashshop.hpp" #include "../map/channel.hpp" #include "../map/chat.hpp" #include "../map/date.hpp" diff --git a/tools/ci/sql.bat b/tools/ci/sql.bat index 536d1b82dd..cbf8f3c998 100644 --- a/tools/ci/sql.bat +++ b/tools/ci/sql.bat @@ -8,8 +8,6 @@ set MYSQL_PWD=%DB_ROOTPW% %MYSQL% -u %DB_ROOT% -e "CREATE DATABASE %DB_NAME%;" %MYSQL% -u %DB_ROOT% %DB_NAME% -e "source sql-files\main.sql" %MYSQL% -u %DB_ROOT% %DB_NAME% -e "source sql-files\logs.sql" -%MYSQL% -u %DB_ROOT% %DB_NAME% -e "source sql-files\item_cash_db.sql" -%MYSQL% -u %DB_ROOT% %DB_NAME% -e "source sql-files\item_cash_db2.sql" %MYSQL% -u %DB_ROOT% %DB_NAME% -e "source sql-files\item_db.sql" %MYSQL% -u %DB_ROOT% %DB_NAME% -e "source sql-files\item_db_usable.sql" %MYSQL% -u %DB_ROOT% %DB_NAME% -e "source sql-files\item_db_equip.sql" diff --git a/tools/ci/sql.sh b/tools/ci/sql.sh index b3ac493351..9eba844048 100755 --- a/tools/ci/sql.sh +++ b/tools/ci/sql.sh @@ -17,8 +17,6 @@ DB_PASS=ragnarok mysql -u $DB_ROOT -p$DB_ROOTPW -e "CREATE DATABASE $DB_NAME;" || aborterror "Unable to create database." mysql -u $DB_ROOT -p$DB_ROOTPW $DB_NAME < sql-files/main.sql || aborterror "Unable to import main database." mysql -u $DB_ROOT -p$DB_ROOTPW $DB_NAME < sql-files/logs.sql || aborterror "Unable to import logs database." -mysql -u $DB_ROOT -p$DB_ROOTPW $DB_NAME < sql-files/item_cash_db.sql || aborterror "Unable to import cash item table." -mysql -u $DB_ROOT -p$DB_ROOTPW $DB_NAME < sql-files/item_cash_db2.sql || aborterror "Unable to import cash item 2 table." mysql -u $DB_ROOT -p$DB_ROOTPW $DB_NAME < sql-files/item_db.sql || aborterror "Unable to import pre-renewal item table structure." mysql -u $DB_ROOT -p$DB_ROOTPW $DB_NAME < sql-files/item_db_usable.sql || aborterror "Unable to import pre-renewal usable item table." mysql -u $DB_ROOT -p$DB_ROOTPW $DB_NAME < sql-files/item_db_equip.sql || aborterror "Unable to import pre-renewal equip item table."