|
@@ -23,30 +23,36 @@
|
|
|
#include <stdlib.h> // atoi
|
|
|
#include <string.h>
|
|
|
|
|
|
-struct vending_entry{
|
|
|
+/// Struct for vending entry of autotrader
|
|
|
+struct s_autotrade_entry {
|
|
|
int cartinventory_id;
|
|
|
- int amount;
|
|
|
+ uint16 amount;
|
|
|
int price;
|
|
|
- int index;
|
|
|
+ uint16 index;
|
|
|
};
|
|
|
|
|
|
-struct vending{
|
|
|
+/// Struct of autotrader
|
|
|
+struct s_autotrade {
|
|
|
int account_id;
|
|
|
int char_id;
|
|
|
int vendor_id;
|
|
|
int m;
|
|
|
- int x;
|
|
|
- int y;
|
|
|
+ uint16 x,
|
|
|
+ y;
|
|
|
unsigned char sex;
|
|
|
char title[MESSAGE_SIZE];
|
|
|
- uint32 count;
|
|
|
- struct vending_entry** entries;
|
|
|
+ uint16 count;
|
|
|
+ struct s_autotrade_entry **entries;
|
|
|
struct map_session_data *sd;
|
|
|
};
|
|
|
|
|
|
static int vending_nextid = 0; ///Vending_id counter
|
|
|
static DBMap *vending_db; ///Db holder the vender : charid -> map_session_data
|
|
|
-static DBMap *autotrade_db;
|
|
|
+
|
|
|
+//Autotrader
|
|
|
+static struct s_autotrade **autotraders; ///Autotraders Storage
|
|
|
+static uint16 autotrader_count; ///Autotrader count
|
|
|
+static void do_final_vending_autotrade(void);
|
|
|
|
|
|
/**
|
|
|
* Lookup to get the vending_db outside module
|
|
@@ -453,40 +459,42 @@ bool vending_searchall(struct map_session_data* sd, const struct s_search_store_
|
|
|
return true;
|
|
|
}
|
|
|
|
|
|
+/** Open vending for Autotrader
|
|
|
+* @param sd Player as autotrader
|
|
|
+*/
|
|
|
void vending_reopen( struct map_session_data* sd ){
|
|
|
- int i, count;
|
|
|
- uint8 *data, *p;
|
|
|
- uint16 *index, *amount;
|
|
|
- uint32 *value;
|
|
|
- struct vending *vending;
|
|
|
- struct vending_entry *entry;
|
|
|
-
|
|
|
- vending = (struct vending*)idb_get( autotrade_db, sd->status.char_id );
|
|
|
-
|
|
|
- if( !vending ){
|
|
|
- map_quit(sd);
|
|
|
+ if (!sd || !autotrader_count || !autotraders)
|
|
|
return;
|
|
|
- }
|
|
|
-
|
|
|
- if( vending->count > 0 ){
|
|
|
- data = (uint8*)aMalloc( vending->count * 8 );
|
|
|
-
|
|
|
- for( i = 0, p = data, count = vending->count; i < vending->count; i++ ){
|
|
|
- entry = vending->entries[i];
|
|
|
+ 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) { //This is shouldn't happen [Cydh]
|
|
|
+ ShowError("vending_reopen: Player not found as autotrader (aid:%d cid:%d)\n",sd->status.account_id,sd->status.char_id);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Init vending data for autotrader
|
|
|
+ CREATE(data, uint8, autotraders[i]->count * 8);
|
|
|
|
|
|
- index = (uint16*)(p + 0);
|
|
|
- amount = (uint16*)(p + 2);
|
|
|
- value = (uint32*)(p + 4);
|
|
|
+ for (j = 0, p = data, count = autotraders[i]->count; j < autotraders[i]->count; j++) {
|
|
|
+ struct s_autotrade_entry *entry = autotraders[i]->entries[j];
|
|
|
+ uint16 *index = (uint16*)(p + 0);
|
|
|
+ uint16 *amount = (uint16*)(p + 2);
|
|
|
+ uint32 *value = (uint32*)(p + 4);
|
|
|
|
|
|
- ARR_FIND( 0, MAX_CART, entry->index, sd->status.cart[entry->index].id == entry->cartinventory_id );
|
|
|
+ // Find item position in cart
|
|
|
+ ARR_FIND(0, MAX_CART, entry->index, sd->status.cart[entry->index].id == entry->cartinventory_id);
|
|
|
|
|
|
- if( entry->index == MAX_CART ){
|
|
|
+ if (entry->index == MAX_CART) {
|
|
|
count--;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
*index = entry->index + 2;
|
|
|
- *amount = entry->amount;
|
|
|
+ *amount = min(entry->amount, sd->status.cart[entry->index].amount); // Limit the vending amount
|
|
|
*value = entry->price;
|
|
|
|
|
|
p += 8;
|
|
@@ -496,154 +504,180 @@ void vending_reopen( struct map_session_data* sd ){
|
|
|
sd->state.prevend = 1;
|
|
|
|
|
|
// Open the shop again
|
|
|
- vending_openvending( sd, vending->title, data, count );
|
|
|
+ vending_openvending(sd, autotraders[i]->title, data, count);
|
|
|
+ aFree(data);
|
|
|
+
|
|
|
+ ShowInfo("Autotrader loaded: '"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;", vendings_db, sd->vender_id ) != SQL_SUCCESS ){
|
|
|
+ if (Sql_Query( mmysql_handle, "UPDATE `%s` SET `autotrade` = 1 WHERE `id` = %d;",
|
|
|
+ vendings_db, sd->vender_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 ){
|
|
|
+ if( battle_config.feature_autotrade_sit )
|
|
|
pc_setsit(sd);
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- aFree(data);
|
|
|
-
|
|
|
- idb_remove( autotrade_db, sd->status.char_id );
|
|
|
|
|
|
- for( i = 0; i < vending->count; i++ ){
|
|
|
- aFree( vending->entries[i] );
|
|
|
- }
|
|
|
-
|
|
|
- aFree(vending->entries);
|
|
|
- aFree(vending);
|
|
|
-
|
|
|
- if( !count ){
|
|
|
- map_quit(sd);
|
|
|
+ //If the last autotrade is loaded, clear autotraders [Cydh]
|
|
|
+ if (i+1 >= autotrader_count)
|
|
|
+ do_final_vending_autotrade();
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-void do_init_vending_autotrade( void ){
|
|
|
- if( battle_config.feature_autotrade ){
|
|
|
- struct vending **autotraders;
|
|
|
- struct vending *vending;
|
|
|
- struct vending_entry *entry;
|
|
|
- uint32 count;
|
|
|
- int i, j;
|
|
|
-
|
|
|
- if( Sql_Query(mmysql_handle,
|
|
|
- "SELECT `id`, `account_id`, `char_id`, `sex`, `map`, `x`, `y`, `title`"
|
|
|
- "FROM `%s`"
|
|
|
- "WHERE `autotrade` = 1;", vendings_db ) != SQL_SUCCESS ) {
|
|
|
+/**
|
|
|
+* Initializing autotraders from table
|
|
|
+*/
|
|
|
+void do_init_vending_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` "
|
|
|
+ "FROM `%s` "
|
|
|
+ "WHERE `autotrade` = 1 AND (SELECT COUNT(`vending_id`) FROM `%s` WHERE `vending_id` = `id`) > 0;",
|
|
|
+ vendings_db, vending_items_db ) != SQL_SUCCESS )
|
|
|
+ {
|
|
|
Sql_ShowDebug(mmysql_handle);
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
- count = (uint32)Sql_NumRows(mmysql_handle);
|
|
|
-
|
|
|
- if( count <= 0 ){
|
|
|
+ if (!(autotrader_count = (uint32)Sql_NumRows(mmysql_handle))) //Nothing to do
|
|
|
return;
|
|
|
- }
|
|
|
+
|
|
|
+ // Init autotraders
|
|
|
+ CREATE(autotraders, struct s_autotrade *, autotrader_count);
|
|
|
|
|
|
- autotraders = (struct vending**)aMalloc( sizeof( struct vending* ) * count );
|
|
|
+ // Init each autotrader data
|
|
|
i = 0;
|
|
|
-
|
|
|
- while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) ) {
|
|
|
+ while (SQL_SUCCESS == Sql_NextRow(mmysql_handle) && i < autotrader_count) {
|
|
|
size_t len;
|
|
|
char* data;
|
|
|
|
|
|
- vending = autotraders[i] = (struct vending *)aMalloc( sizeof( struct vending ) );
|
|
|
-
|
|
|
- Sql_GetData( mmysql_handle, 0, &data, NULL ); vending->vendor_id = atoi(data);
|
|
|
- Sql_GetData( mmysql_handle, 1, &data, NULL ); vending->account_id = atoi(data);
|
|
|
- Sql_GetData( mmysql_handle, 2, &data, NULL ); vending->char_id = atoi(data);
|
|
|
- Sql_GetData( mmysql_handle, 3, &data, NULL ); vending->sex = data[0];
|
|
|
- Sql_GetData( mmysql_handle, 4, &data, NULL ); vending->m = map_mapname2mapid( data );
|
|
|
- Sql_GetData( mmysql_handle, 5, &data, NULL ); vending->x = atoi(data);
|
|
|
- Sql_GetData( mmysql_handle, 6, &data, NULL ); vending->y = atoi(data);
|
|
|
- Sql_GetData( mmysql_handle, 7, &data, &len ); safestrncpy( vending->title, data, min( len + 1, MESSAGE_SIZE ) );
|
|
|
+ CREATE(autotraders[i], struct s_autotrade, 1);
|
|
|
|
|
|
- vending->count = 0;
|
|
|
+ Sql_GetData(mmysql_handle, 0, &data, NULL); autotraders[i]->vendor_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));
|
|
|
+ autotraders[i]->count = 0;
|
|
|
|
|
|
- idb_put( autotrade_db, vending->char_id, vending );
|
|
|
-
|
|
|
// initialize player
|
|
|
- CREATE(vending->sd, TBL_PC, 1);
|
|
|
-
|
|
|
- pc_setnewpc( vending->sd, vending->account_id, vending->char_id, 0, gettick(), vending->sex == 'F' ? 0 : 1, 0 );
|
|
|
-
|
|
|
- vending->sd->state.autotrade = 1;
|
|
|
-
|
|
|
- chrif_authreq( vending->sd, true );
|
|
|
-
|
|
|
+ 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_vending_autotrade();
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- Sql_FreeResult( mmysql_handle );
|
|
|
+ //Init items on vending list each autotrader
|
|
|
+ for (i = 0; i < autotrader_count; i++){
|
|
|
+ struct s_autotrade *at = NULL;
|
|
|
+ uint16 j;
|
|
|
|
|
|
- for( i = 0; i < count; i++ ){
|
|
|
- vending = autotraders[i];
|
|
|
+ if (autotraders[i] == NULL)
|
|
|
+ continue;
|
|
|
+ at = autotraders[i];
|
|
|
|
|
|
- if( SQL_ERROR == Sql_Query(mmysql_handle,
|
|
|
- "SELECT `cartinventory_id`, `amount`, `price`"
|
|
|
- "FROM `%s`"
|
|
|
+ if (SQL_ERROR == Sql_Query(mmysql_handle,
|
|
|
+ "SELECT `cartinventory_id`, `amount`, `price` "
|
|
|
+ "FROM `%s` "
|
|
|
"WHERE `vending_id` = %d "
|
|
|
- "ORDER BY `index` ASC;", vending_items_db, vending->vendor_id ) ) {
|
|
|
+ "ORDER BY `index` ASC;", vending_items_db, at->vendor_id ) )
|
|
|
+ {
|
|
|
Sql_ShowDebug(mmysql_handle);
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
- vending->count = (uint32)Sql_NumRows(mmysql_handle);
|
|
|
-
|
|
|
- if( vending->count <= 0 ){
|
|
|
- // Player was not correctly deleted, must not be set online
|
|
|
- idb_remove( autotrade_db, vending->char_id );
|
|
|
- map_quit(vending->sd);
|
|
|
- aFree(vending);
|
|
|
+ if (!(at->count = (uint32)Sql_NumRows(mmysql_handle))) {
|
|
|
+ map_quit(at->sd);
|
|
|
continue;
|
|
|
}
|
|
|
-
|
|
|
- vending->entries = (struct vending_entry**)aMalloc( sizeof( struct vending_entry* ) * vending->count );
|
|
|
- j = 0;
|
|
|
+
|
|
|
+ //Init the list
|
|
|
+ CREATE(at->entries, struct s_autotrade_entry *,at->count);
|
|
|
|
|
|
- while( SQL_SUCCESS == Sql_NextRow(mmysql_handle) ) {
|
|
|
+ //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);
|
|
|
|
|
|
- entry = vending->entries[j] = (struct vending_entry*)aMalloc( sizeof( struct vending_entry ) );
|
|
|
-
|
|
|
- Sql_GetData( mmysql_handle, 0, &data, NULL ); entry->cartinventory_id = atoi(data);
|
|
|
- Sql_GetData( mmysql_handle, 1, &data, NULL ); entry->amount = atoi(data);
|
|
|
- Sql_GetData( mmysql_handle, 2, &data, NULL ); entry->price = atoi(data);
|
|
|
-
|
|
|
+ Sql_GetData(mmysql_handle, 0, &data, NULL); at->entries[j]->cartinventory_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++;
|
|
|
}
|
|
|
-
|
|
|
- Sql_FreeResult( mmysql_handle );
|
|
|
+ items += j;
|
|
|
+ Sql_FreeResult(mmysql_handle);
|
|
|
}
|
|
|
|
|
|
- aFree(autotraders);
|
|
|
-
|
|
|
- ShowStatus("Done reading '"CL_WHITE"%d"CL_RESET"' autotraders.\n",count);
|
|
|
+ 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`;", vendings_db ) != SQL_SUCCESS ||
|
|
|
- Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vending_items_db ) != SQL_SUCCESS ){
|
|
|
+ if (Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vendings_db ) != SQL_SUCCESS ||
|
|
|
+ Sql_Query( mmysql_handle, "DELETE FROM `%s`;", vending_items_db ) != SQL_SUCCESS)
|
|
|
+ {
|
|
|
Sql_ShowDebug(mmysql_handle);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+* Clear all autotraders
|
|
|
+* @author [Cydh]
|
|
|
+*/
|
|
|
+void do_final_vending_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;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Initialise the vending module
|
|
|
* called in map::do_init
|
|
|
*/
|
|
|
void do_final_vending(void) {
|
|
|
db_destroy(vending_db);
|
|
|
- db_destroy(autotrade_db);
|
|
|
+ do_final_vending_autotrade(); //Make sure everything is cleared [Cydh]
|
|
|
}
|
|
|
|
|
|
/**
|
|
@@ -652,6 +686,5 @@ void do_final_vending(void) {
|
|
|
*/
|
|
|
void do_init_vending(void) {
|
|
|
vending_db = idb_alloc(DB_OPT_BASE);
|
|
|
- autotrade_db = idb_alloc(DB_OPT_BASE);
|
|
|
vending_nextid = 0;
|
|
|
}
|