@@ -3,6 +3,7 @@
#include " ../common/cbasetypes.h"
#include " ../common/db.h" // ARR_FIND
#include " ../common/malloc.h" // aMalloc, aFree
#include " ../common/showmsg.h" // ShowWarning
#include " ../common/socket.h" // RBUF*
#include " ../common/strlib.h" // safestrncpy
@@ -14,6 +15,32 @@
#include " pc.h" // struct map_session_data
#include " chrif.h"
// / Struct for buyingstore entry of autotrader
struct s_autotrade_entry {
uint16 amount;
int price;
uint16 item_id;
};
// / Struct of autotrader
struct s_autotrade {
int account_id;
int char_id;
int buyer_id;
int m;
uint16 x, y;
unsigned char sex;
char title[MESSAGE_SIZE];
int limit;
uint16 count;
struct s_autotrade_entry **entries;
struct map_session_data *sd;
};
// Autotrader
static struct s_autotrade **autotraders; // /Autotraders Storage
static uint16 autotrader_count; // /Autotrader count
static void do_final_buyingstore_autotrade (void );
// / constants (client-side restrictions)
#define BUYINGSTORE_MAX_PRICE 99990000
@@ -83,6 +110,7 @@ bool buyingstore_setup(struct map_session_data* sd, unsigned char slots){
void buyingstore_create (struct map_session_data* sd, int zenylimit, unsigned char result, const char * storename, const uint8* itemlist, unsigned int count)
{
unsigned int i, weight, listidx;
char message_sql[MESSAGE_SIZE*2 ];
if ( !result || count == 0 )
{// canceled, or no items
@@ -190,6 +218,19 @@ void buyingstore_create(struct map_session_data* sd, int zenylimit, unsigned cha
sd->buyingstore .zenylimit = zenylimit;
sd->buyingstore .slots = i; // store actual amount of items
safestrncpy (sd->message , storename, sizeof (sd->message ));
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`) VALUES( %d , %d , %d , '%c ', '%s ', %d , %d , '%s ', %d , %d );" , buyingstore_db, sd->buyer_id , sd->status .account_id , sd->status .char_id , sd->status .sex == 0 ? ' F' : ' M' , map[sd->bl .m ].name , sd->bl .x , sd->bl .y , message_sql, sd->buyingstore .zenylimit , sd->state .autotrade ) != SQL_SUCCESS ){
Sql_ShowDebug (mmysql_handle);
}
for ( i = 0 ; i < sd->buyingstore .slots ; i++ ){
if ( Sql_Query ( mmysql_handle, " INSERT INTO `%s `(`buyingstore_id`,`index`,`item_id`,`amount`,`price`) VALUES( %d , %d , %d , %d , %d );" , buyingstore_items_db, sd->buyer_id , i, sd->buyingstore .items [i].nameid , sd->buyingstore .items [i].amount , sd->buyingstore .items [i].price ) != SQL_SUCCESS ){
Sql_ShowDebug (mmysql_handle);
}
}
clif_buyingstore_myitemlist (sd);
clif_buyingstore_entry (sd);
}
@@ -199,6 +240,13 @@ void buyingstore_close(struct map_session_data* sd)
{
if ( sd->state .buyingstore )
{
if (
!sd->state .autotrade &&
Sql_Query ( mmysql_handle, " DELETE FROM `%s ` WHERE buyingstore_id = %d ;" , buyingstore_items_db, sd->buyer_id ) != SQL_SUCCESS ||
Sql_Query ( mmysql_handle, " DELETE FROM `%s ` WHERE `id` = %d ;" , buyingstore_db, sd->buyer_id ) != SQL_SUCCESS ){
Sql_ShowDebug (mmysql_handle);
}
// invalidate data
sd->state .buyingstore = false ;
memset (&sd->buyingstore , 0 , sizeof (sd->buyingstore ));
@@ -370,6 +418,16 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int
pc_delitem (sd, index , amount, 1 , 0 , LOG_TYPE_BUYING_STORE);
pl_sd->buyingstore .items [listidx].amount -= amount;
if ( pl_sd->buyingstore .items [listidx].amount > 0 ){
if ( Sql_Query ( mmysql_handle, " UPDATE `%s ` SET `amount` = %d WHERE `buyingstore_id` = %d AND `index` = %d ;" , buyingstore_items_db, pl_sd->buyingstore .items [listidx].amount , pl_sd->buyer_id , listidx ) != SQL_SUCCESS ){
Sql_ShowDebug ( mmysql_handle );
}
}else {
if ( Sql_Query ( mmysql_handle, " DELETE FROM `%s ` WHERE `buyingstore_id` = %d AND `index` = %d ;" , buyingstore_items_db, pl_sd->buyer_id , listidx ) != SQL_SUCCESS ){
Sql_ShowDebug ( mmysql_handle );
}
}
// pay up
pc_payzeny (pl_sd, zeny, LOG_TYPE_BUYING_STORE, sd);
pc_getzeny (sd, zeny, LOG_TYPE_BUYING_STORE, pl_sd);
@@ -397,6 +455,10 @@ void buyingstore_trade(struct map_session_data* sd, int account_id, unsigned int
}
else
{// continue buying
if ( Sql_Query ( mmysql_handle, " UPDATE `%s ` SET `limit` = %d WHERE `id` = %d ;" , buyingstore_db, pl_sd->buyingstore .zenylimit , pl_sd->buyer_id ) != SQL_SUCCESS ){
Sql_ShowDebug ( mmysql_handle );
}
return ;
}
@@ -475,3 +537,205 @@ bool buyingstore_searchall(struct map_session_data* sd, const struct s_search_st
return true ;
}
/* * Open vending for Autotrader
* @param sd Player as autotrader
*/
void buyingstore_reopen ( struct map_session_data* sd ){
if (!sd || !autotrader_count || !autotraders)
return ;
else { // Ready to open vending for this char
uint16 i;
uint8 *data, *p;
uint16 j, count;
ARR_FIND (0 ,autotrader_count,i,autotraders[i] && autotraders[i]->char_id == sd->status .char_id );
if (i >= autotrader_count) {
return ;
}
// Init vending data for autotrader
CREATE (data, uint8, autotraders[i]->count * 8 );
for (j = 0 , p = data, count = autotraders[i]->count ; j < autotraders[i]->count ; j++) {
struct s_autotrade_entry *entry = autotraders[i]->entries [j];
uint16 *item_id = (uint16*)(p + 0 );
uint16 *amount = (uint16*)(p + 2 );
uint32 *price = (uint32*)(p + 4 );
*item_id = entry->item_id ;
*amount = entry->amount ;
*price = entry->price ;
p += 8 ;
}
// Open the shop again
buyingstore_setup ( sd, (unsigned char )autotraders[i]->count );
buyingstore_create ( sd, autotraders[i]->limit , 1 , autotraders[i]->title , data, autotraders[i]->count );
aFree (data);
ShowInfo (" Loaded autotrade buyingstore data for '" CL_WHITE" %s " CL_RESET" ' with '" CL_WHITE" %d " CL_RESET" ' items at " CL_WHITE" %s (%d ,%d )" CL_RESET" \n " ,
sd->status .name ,count,mapindex_id2name (sd->mapindex ),sd->bl .x ,sd->bl .y );
// Set him to autotrade
if (Sql_Query ( mmysql_handle, " UPDATE `%s ` SET `autotrade` = 1 WHERE `id` = %d ;" ,
buyingstore_db, sd->buyer_id ) != SQL_SUCCESS )
{
Sql_ShowDebug ( mmysql_handle );
}
// Make him look perfect
unit_setdir (&sd->bl ,battle_config.feature_autotrade_direction );
if ( battle_config.feature_autotrade_sit )
pc_setsit (sd);
// If the last autotrade is loaded, clear autotraders [Cydh]
if (i+1 >= autotrader_count)
do_final_buyingstore_autotrade ();
}
}
/* *
* Initializing autotraders from table
*/
void do_init_buyingstore_autotrade ( void ) {
if (battle_config.feature_autotrade ) {
uint16 i, items = 0 ;
autotrader_count = 0 ;
// Get autotrader from table. `map`, `x`, and `y`, aren't used here
// Just read player that has data at vending_items [Cydh]
if (Sql_Query (mmysql_handle,
" SELECT `id`, `account_id`, `char_id`, `sex`, `title`, `limit` "
" FROM `%s ` "
" WHERE `autotrade` = 1 AND (SELECT COUNT(`buyingstore_id`) FROM `%s ` WHERE `buyingstore_id` = `id`) > 0;" ,
buyingstore_db, buyingstore_items_db ) != SQL_SUCCESS )
{
Sql_ShowDebug (mmysql_handle);
return ;
}
if (!(autotrader_count = (uint32)Sql_NumRows (mmysql_handle))) // Nothing to do
return ;
// Init autotraders
CREATE (autotraders, struct s_autotrade *, autotrader_count);
// Init each autotrader data
i = 0 ;
while (SQL_SUCCESS == Sql_NextRow (mmysql_handle) && i < autotrader_count) {
size_t len;
char * data;
CREATE (autotraders[i], struct s_autotrade, 1 );
Sql_GetData (mmysql_handle, 0 , &data, NULL ); autotraders[i]->buyer_id = atoi (data);
Sql_GetData (mmysql_handle, 1 , &data, NULL ); autotraders[i]->account_id = atoi (data);
Sql_GetData (mmysql_handle, 2 , &data, NULL ); autotraders[i]->char_id = atoi (data);
Sql_GetData (mmysql_handle, 3 , &data, NULL ); autotraders[i]->sex = (data[0 ] == ' F' ) ? 0 : 1 ;
Sql_GetData (mmysql_handle, 4 , &data, &len); safestrncpy (autotraders[i]->title , data, min (len + 1 , MESSAGE_SIZE));
Sql_GetData (mmysql_handle, 5 , &data, NULL ); autotraders[i]->limit = atoi (data);
autotraders[i]->count = 0 ;
// initialize player
CREATE (autotraders[i]->sd , struct map_session_data, 1 );
pc_setnewpc (autotraders[i]->sd , autotraders[i]->account_id , autotraders[i]->char_id , 0 , gettick (), autotraders[i]->sex , 0 );
autotraders[i]->sd ->state .autotrade = 1 ;
chrif_authreq (autotraders[i]->sd , true );
i++;
}
Sql_FreeResult (mmysql_handle);
if (autotraders == NULL ) { // This is shouldn't happen [Cydh]
ShowError (" Failed to initialize autotraders!\n " );
do_final_buyingstore_autotrade ();
return ;
}
// Init items on vending list each autotrader
for (i = 0 ; i < autotrader_count; i++){
struct s_autotrade *at = NULL ;
uint16 j;
if (autotraders[i] == NULL )
continue ;
at = autotraders[i];
if (SQL_ERROR == Sql_Query (mmysql_handle,
" SELECT `item_id`, `amount`, `price` "
" FROM `%s ` "
" WHERE `buyingstore_id` = %d "
" ORDER BY `index` ASC;" , buyingstore_items_db, at->buyer_id ) )
{
Sql_ShowDebug (mmysql_handle);
continue ;
}
if (!(at->count = (uint32)Sql_NumRows (mmysql_handle))) {
map_quit (at->sd );
continue ;
}
// Init the list
CREATE (at->entries , struct s_autotrade_entry *,at->count );
// Add the item into list
j = 0 ;
while (SQL_SUCCESS == Sql_NextRow (mmysql_handle) && j < at->count ) {
char * data;
CREATE (at->entries [j], struct s_autotrade_entry, 1 );
Sql_GetData (mmysql_handle, 0 , &data, NULL ); at->entries [j]->item_id = atoi (data);
Sql_GetData (mmysql_handle, 1 , &data, NULL ); at->entries [j]->amount = atoi (data);
Sql_GetData (mmysql_handle, 2 , &data, NULL ); at->entries [j]->price = atoi (data);
j++;
}
items += j;
Sql_FreeResult (mmysql_handle);
}
ShowStatus (" Done loading '" CL_WHITE" %d " CL_RESET" ' autotraders with '" CL_WHITE" %d " CL_RESET" ' items.\n " , autotrader_count, items);
}
// Everything is loaded fine, their entries will be reinserted once they are loaded
if (Sql_Query ( mmysql_handle, " DELETE FROM `%s `;" , buyingstore_db ) != SQL_SUCCESS ||
Sql_Query ( mmysql_handle, " DELETE FROM `%s `;" , buyingstore_items_db ) != SQL_SUCCESS)
{
Sql_ShowDebug (mmysql_handle);
}
}
/* *
* Clear all autotraders
* @author [Cydh]
*/
void do_final_buyingstore_autotrade (void ) {
if (!autotrader_count || !autotraders)
return ;
else {
uint16 i = 0 ;
while (i < autotrader_count) { // Free the autotrader
if (autotraders[i] == NULL )
continue ;
if (autotraders[i]->count ) {
uint16 j = 0 ;
while (j < autotraders[i]->count ) { // Free the autotrade entries
if (autotraders[i]->entries == NULL )
continue ;
if (autotraders[i]->entries [j])
aFree (autotraders[i]->entries [j]);
j++;
}
aFree (autotraders[i]->entries );
}
aFree (autotraders[i]);
i++;
}
aFree (autotraders);
autotrader_count = 0 ;
}
}