Converted cash shop database to YAML (#6299)
Co-authored-by: Atemo <Atemo@users.noreply.github.com> Co-authored-by: Aleos <aleos89@users.noreply.github.com>
This commit is contained in:
parent
503b57dbef
commit
9dda166c0e
@ -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
|
||||
|
33
db/import-tmpl/item_cash.yml
Normal file
33
db/import-tmpl/item_cash.yml
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
###########################################################################
|
||||
# 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
|
@ -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).
|
37
db/item_cash.yml
Normal file
37
db/item_cash.yml
Normal file
@ -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 <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
###########################################################################
|
||||
# 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
|
@ -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).
|
@ -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).
|
12
doc/yaml/db/item_cash.yml
Normal file
12
doc/yaml/db/item_cash.yml
Normal file
@ -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).
|
||||
###########################################################################
|
@ -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.
|
||||
|
@ -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;
|
@ -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;
|
@ -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
|
||||
|
@ -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<e_cash_shop_tab>( constant );
|
||||
|
||||
std::shared_ptr<s_cash_item_tab> entry = this->find( tab );
|
||||
bool exists = entry != nullptr;
|
||||
|
||||
if( !exists ){
|
||||
if( !this->nodesExist( node, { "Items" } ) ){
|
||||
return 0;
|
||||
}
|
||||
|
||||
entry = std::make_shared<s_cash_item_tab>();
|
||||
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_data> 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<s_cash_item> cash_item = nullptr;
|
||||
bool cash_item_exists = false;
|
||||
|
||||
for( std::shared_ptr<s_cash_item> 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<s_cash_item>();
|
||||
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<s_cash_item> CashShopDatabase::findItemInTab( e_cash_shop_tab tab, t_itemid nameid ){
|
||||
std::shared_ptr<s_cash_item_tab> 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<s_cash_item> 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<s_cash_item> cash_item = cash_shop_db.findItemInTab( static_cast<e_cash_shop_tab>( 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<item_data> 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();
|
||||
}
|
||||
|
@ -4,9 +4,13 @@
|
||||
#ifndef CASHSHOP_HPP
|
||||
#define CASHSHOP_HPP
|
||||
|
||||
#include <memory> // std::shared_ptr
|
||||
#include <vector> // 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<std::shared_ptr<s_cash_item>> items;
|
||||
};
|
||||
|
||||
extern struct cash_item_db cash_shop_items[CASHSHOP_TAB_MAX];
|
||||
extern bool cash_shop_defined;
|
||||
class CashShopDatabase : public TypesafeYamlDatabase<e_cash_shop_tab, s_cash_item_tab>{
|
||||
public:
|
||||
CashShopDatabase() : TypesafeYamlDatabase( "ITEM_CASH_DB", 1 ){
|
||||
|
||||
}
|
||||
|
||||
const std::string getDefaultLocation();
|
||||
uint64 parseBodyNode( const ryml::NodeRef& node );
|
||||
|
||||
// Additional
|
||||
std::shared_ptr<s_cash_item> findItemInTab( e_cash_shop_tab tab, t_itemid nameid );
|
||||
};
|
||||
|
||||
extern CashShopDatabase cash_shop_db;
|
||||
|
||||
enum e_sale_add_result {
|
||||
SALE_ADD_SUCCESS = 0,
|
||||
|
114
src/map/clif.cpp
114
src/map/clif.cpp
@ -17000,26 +17000,46 @@ void clif_parse_cashshop_close( int fd, map_session_data* sd ){
|
||||
//0846 <tabid>.W (CZ_REQ_SE_CASH_TAB_CODE))
|
||||
//08c0 <len>.W <openIdentity>.L <itemcount>.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<s_cash_item_tab> tab = cash_shop_db.find( static_cast<e_cash_shop_tab>( 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<s_cash_item> 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<s_cash_item_tab> 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<s_cash_item> 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 <result>.W <item id>.W <price>.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<s_cash_item> 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<item_data> 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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -333,7 +333,7 @@
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\homun_skill_tree.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\homun_skill_tree.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\homunculus_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\homunculus_db.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\instance_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\instance_db.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_cash_db.txt" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_cash_db.txt')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_cash.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_cash.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_combos.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_combos.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_db.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_db.yml')" />
|
||||
<Copy SourceFiles="$(SolutionDir)db\import-tmpl\item_enchant.yml" DestinationFolder="$(SolutionDir)db\import\" ContinueOnError="true" Condition="!Exists('$(SolutionDir)db\import\item_enchant.yml')" />
|
||||
|
@ -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 )
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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"
|
||||
|
@ -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
|
||||
|
@ -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<Csv2YamlTool>( argc, argv );
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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"
|
||||
|
@ -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."
|
||||
|
Loading…
x
Reference in New Issue
Block a user