int_auction.c 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485
  1. // Copyright (c) Athena Dev Teams - Licensed under GNU GPL
  2. // For more information, see LICENCE in the main folder
  3. #include "../common/mmo.h"
  4. #include "../common/malloc.h"
  5. #include "../common/db.h"
  6. #include "../common/showmsg.h"
  7. #include "../common/socket.h"
  8. #include "../common/strlib.h"
  9. #include "../common/sql.h"
  10. #include "../common/timer.h"
  11. #include "char.h"
  12. #include "inter.h"
  13. #include "int_mail.h"
  14. #include <stdio.h>
  15. #include <string.h>
  16. #include <stdlib.h>
  17. static DBMap* auction_db_ = NULL; // int auction_id -> struct auction_data*
  18. void auction_delete(struct auction_data *auction);
  19. static int auction_end_timer(int tid, unsigned int tick, int id, intptr data);
  20. static int auction_count(int char_id, bool buy)
  21. {
  22. int i = 0;
  23. struct auction_data *auction;
  24. DBIterator* iter;
  25. DBKey key;
  26. iter = auction_db_->iterator(auction_db_);
  27. for( auction = (struct auction_data*)iter->first(iter,&key); iter->exists(iter); auction = (struct auction_data*)iter->next(iter,&key) )
  28. {
  29. if( (buy && auction->buyer_id == char_id) || (!buy && auction->seller_id == char_id) )
  30. i++;
  31. }
  32. iter->destroy(iter);
  33. return i;
  34. }
  35. void auction_save(struct auction_data *auction)
  36. {
  37. int j;
  38. StringBuf buf;
  39. SqlStmt* stmt;
  40. if( !auction )
  41. return;
  42. StringBuf_Init(&buf);
  43. StringBuf_Printf(&buf, "UPDATE `%s` SET `seller_id` = '%d', `seller_name` = ?, `buyer_id` = '%d', `buyer_name` = ?, `price` = '%d', `buynow` = '%d', `hours` = '%d', `timestamp` = '%lu', `nameid` = '%d', `item_name` = ?, `type` = '%d', `refine` = '%d', `attribute` = '%d'",
  44. auction_db, auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute);
  45. for( j = 0; j < MAX_SLOTS; j++ )
  46. StringBuf_Printf(&buf, ", `card%d` = '%d'", j, auction->item.card[j]);
  47. StringBuf_Printf(&buf, " WHERE `auction_id` = '%d'", auction->auction_id);
  48. stmt = SqlStmt_Malloc(sql_handle);
  49. if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
  50. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))
  51. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH))
  52. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH))
  53. || SQL_SUCCESS != SqlStmt_Execute(stmt) )
  54. {
  55. SqlStmt_ShowDebug(stmt);
  56. }
  57. SqlStmt_Free(stmt);
  58. StringBuf_Destroy(&buf);
  59. }
  60. unsigned int auction_create(struct auction_data *auction)
  61. {
  62. int j;
  63. StringBuf buf;
  64. SqlStmt* stmt;
  65. if( !auction )
  66. return false;
  67. auction->timestamp = time(NULL) + (auction->hours * 3600);
  68. StringBuf_Init(&buf);
  69. StringBuf_Printf(&buf, "INSERT INTO `%s` (`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`", auction_db);
  70. for( j = 0; j < MAX_SLOTS; j++ )
  71. StringBuf_Printf(&buf, ",`card%d`", j);
  72. StringBuf_Printf(&buf, ") VALUES ('%d',?,'%d',?,'%d','%d','%d','%lu','%d',?,'%d','%d','%d'",
  73. auction->seller_id, auction->buyer_id, auction->price, auction->buynow, auction->hours, (unsigned long)auction->timestamp, auction->item.nameid, auction->type, auction->item.refine, auction->item.attribute);
  74. for( j = 0; j < MAX_SLOTS; j++ )
  75. StringBuf_Printf(&buf, ",'%d'", auction->item.card[j]);
  76. StringBuf_AppendStr(&buf, ")");
  77. stmt = SqlStmt_Malloc(sql_handle);
  78. if( SQL_SUCCESS != SqlStmt_PrepareStr(stmt, StringBuf_Value(&buf))
  79. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 0, SQLDT_STRING, auction->seller_name, strnlen(auction->seller_name, NAME_LENGTH))
  80. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 1, SQLDT_STRING, auction->buyer_name, strnlen(auction->buyer_name, NAME_LENGTH))
  81. || SQL_SUCCESS != SqlStmt_BindParam(stmt, 2, SQLDT_STRING, auction->item_name, strnlen(auction->item_name, ITEM_NAME_LENGTH))
  82. || SQL_SUCCESS != SqlStmt_Execute(stmt) )
  83. {
  84. SqlStmt_ShowDebug(stmt);
  85. auction->auction_id = 0;
  86. }
  87. else
  88. {
  89. struct auction_data *auction_;
  90. unsigned int tick = auction->hours * 3600000;
  91. auction->item.amount = 1;
  92. auction->item.identify = 1;
  93. auction->auction_id = (unsigned int)SqlStmt_LastInsertId(stmt);
  94. auction->auction_end_timer = add_timer( gettick() + tick , auction_end_timer, auction->auction_id, 0);
  95. ShowInfo("New Auction %u | time left %u ms | By %s.\n", auction->auction_id, tick, auction->seller_name);
  96. CREATE(auction_, struct auction_data, 1);
  97. memcpy(auction_, auction, sizeof(struct auction_data));
  98. idb_put(auction_db_, auction_->auction_id, auction_);
  99. }
  100. SqlStmt_Free(stmt);
  101. StringBuf_Destroy(&buf);
  102. return auction->auction_id;
  103. }
  104. static void mapif_Auction_message(int char_id, unsigned char result)
  105. {
  106. unsigned char buf[74];
  107. WBUFW(buf,0) = 0x3854;
  108. WBUFL(buf,2) = char_id;
  109. WBUFL(buf,6) = result;
  110. mapif_sendall(buf,7);
  111. }
  112. static int auction_end_timer(int tid, unsigned int tick, int id, intptr data)
  113. {
  114. struct auction_data *auction;
  115. if( (auction = (struct auction_data *)idb_get(auction_db_, id)) != NULL )
  116. {
  117. if( auction->buyer_id )
  118. {
  119. mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Thanks, you won the auction!.", 0, &auction->item);
  120. mapif_Auction_message(auction->buyer_id, 6); // You have won the auction
  121. mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->price, NULL);
  122. }
  123. else
  124. mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "No buyers have been found for your auction.", 0, &auction->item);
  125. ShowInfo("Auction End: id %u.\n", auction->auction_id);
  126. auction->auction_end_timer = -1;
  127. auction_delete(auction);
  128. }
  129. return 0;
  130. }
  131. void auction_delete(struct auction_data *auction)
  132. {
  133. unsigned int auction_id = auction->auction_id;
  134. if( SQL_ERROR == Sql_Query(sql_handle, "DELETE FROM `%s` WHERE `auction_id` = '%d'", auction_db, auction_id) )
  135. Sql_ShowDebug(sql_handle);
  136. if( auction->auction_end_timer != -1 )
  137. delete_timer(auction->auction_end_timer, auction_end_timer);
  138. idb_remove(auction_db_, auction_id);
  139. }
  140. void inter_auctions_fromsql(void)
  141. {
  142. int i;
  143. struct auction_data *auction;
  144. struct item *item;
  145. char *data;
  146. StringBuf buf;
  147. unsigned int tick = gettick(), endtick;
  148. time_t now = time(NULL);
  149. StringBuf_Init(&buf);
  150. StringBuf_AppendStr(&buf, "SELECT `auction_id`,`seller_id`,`seller_name`,`buyer_id`,`buyer_name`,"
  151. "`price`,`buynow`,`hours`,`timestamp`,`nameid`,`item_name`,`type`,`refine`,`attribute`");
  152. for( i = 0; i < MAX_SLOTS; i++ )
  153. StringBuf_Printf(&buf, ",`card%d`", i);
  154. StringBuf_Printf(&buf, " FROM `%s` ORDER BY `auction_id` DESC", auction_db);
  155. if( SQL_ERROR == Sql_Query(sql_handle, StringBuf_Value(&buf)) )
  156. Sql_ShowDebug(sql_handle);
  157. StringBuf_Destroy(&buf);
  158. while( SQL_SUCCESS == Sql_NextRow(sql_handle) )
  159. {
  160. CREATE(auction, struct auction_data, 1);
  161. Sql_GetData(sql_handle, 0, &data, NULL); auction->auction_id = atoi(data);
  162. Sql_GetData(sql_handle, 1, &data, NULL); auction->seller_id = atoi(data);
  163. Sql_GetData(sql_handle, 2, &data, NULL); safestrncpy(auction->seller_name, data, NAME_LENGTH);
  164. Sql_GetData(sql_handle, 3, &data, NULL); auction->buyer_id = atoi(data);
  165. Sql_GetData(sql_handle, 4, &data, NULL); safestrncpy(auction->buyer_name, data, NAME_LENGTH);
  166. Sql_GetData(sql_handle, 5, &data, NULL); auction->price = atoi(data);
  167. Sql_GetData(sql_handle, 6, &data, NULL); auction->buynow = atoi(data);
  168. Sql_GetData(sql_handle, 7, &data, NULL); auction->hours = atoi(data);
  169. Sql_GetData(sql_handle, 8, &data, NULL); auction->timestamp = atoi(data);
  170. item = &auction->item;
  171. Sql_GetData(sql_handle, 9, &data, NULL); item->nameid = atoi(data);
  172. Sql_GetData(sql_handle,10, &data, NULL); safestrncpy(auction->item_name, data, ITEM_NAME_LENGTH);
  173. Sql_GetData(sql_handle,11, &data, NULL); auction->type = atoi(data);
  174. Sql_GetData(sql_handle,12, &data, NULL); item->refine = atoi(data);
  175. Sql_GetData(sql_handle,13, &data, NULL); item->attribute = atoi(data);
  176. item->identify = 1;
  177. item->amount = 1;
  178. for( i = 0; i < MAX_SLOTS; i++ )
  179. {
  180. Sql_GetData(sql_handle, 14 + i, &data, NULL);
  181. item->card[i] = atoi(data);
  182. }
  183. if( auction->timestamp > now )
  184. endtick = ((unsigned int)(auction->timestamp - now) * 1000) + tick;
  185. else
  186. endtick = tick + 10000; // 10 Second's to process ended auctions
  187. auction->auction_end_timer = add_timer(endtick, auction_end_timer, auction->auction_id, 0);
  188. idb_put(auction_db_, auction->auction_id, auction);
  189. }
  190. Sql_FreeResult(sql_handle);
  191. }
  192. static void mapif_Auction_sendlist(int fd, int char_id, short count, short pages, unsigned char *buf)
  193. {
  194. int len = (sizeof(struct auction_data) * count) + 12;
  195. WFIFOHEAD(fd, len);
  196. WFIFOW(fd,0) = 0x3850;
  197. WFIFOW(fd,2) = len;
  198. WFIFOL(fd,4) = char_id;
  199. WFIFOW(fd,8) = count;
  200. WFIFOW(fd,10) = pages;
  201. memcpy(WFIFOP(fd,12), buf, len - 12);
  202. WFIFOSET(fd,len);
  203. }
  204. static void mapif_parse_Auction_requestlist(int fd)
  205. {
  206. char searchtext[NAME_LENGTH];
  207. int char_id = RFIFOL(fd,4), len = sizeof(struct auction_data);
  208. int price = RFIFOL(fd,10);
  209. short type = RFIFOW(fd,8), page = max(1,RFIFOW(fd,14));
  210. unsigned char buf[5 * sizeof(struct auction_data)];
  211. DBIterator* iter;
  212. DBKey key;
  213. struct auction_data *auction;
  214. short i = 0, j = 0, pages = 1;
  215. memcpy(searchtext, RFIFOP(fd,16), NAME_LENGTH);
  216. iter = auction_db_->iterator(auction_db_);
  217. for( auction = (struct auction_data*)iter->first(iter,&key); iter->exists(iter); auction = (struct auction_data*)iter->next(iter,&key) )
  218. {
  219. if( (type == 0 && auction->type != IT_ARMOR && auction->type != IT_PETARMOR) ||
  220. (type == 1 && auction->type != IT_WEAPON) ||
  221. (type == 2 && auction->type != IT_CARD) ||
  222. (type == 3 && auction->type != IT_ETC) ||
  223. (type == 4 && !strstr(auction->item_name, searchtext)) ||
  224. (type == 5 && auction->price > price) ||
  225. (type == 6 && auction->seller_id != char_id) ||
  226. (type == 7 && auction->buyer_id != char_id) )
  227. continue;
  228. i++;
  229. if( i > 5 )
  230. { // Counting Pages of Total Results (5 Results per Page)
  231. pages++;
  232. i = 1; // First Result of This Page
  233. }
  234. if( page != pages )
  235. continue; // This is not the requested Page
  236. memcpy(WBUFP(buf, j * len), auction, len);
  237. j++; // Found Results
  238. }
  239. iter->destroy(iter);
  240. mapif_Auction_sendlist(fd, char_id, j, pages, buf);
  241. }
  242. static void mapif_Auction_register(int fd, struct auction_data *auction)
  243. {
  244. int len = sizeof(struct auction_data) + 4;
  245. WFIFOHEAD(fd,len);
  246. WFIFOW(fd,0) = 0x3851;
  247. WFIFOW(fd,2) = len;
  248. memcpy(WFIFOP(fd,4), auction, sizeof(struct auction_data));
  249. WFIFOSET(fd,len);
  250. }
  251. static void mapif_parse_Auction_register(int fd)
  252. {
  253. struct auction_data auction;
  254. if( RFIFOW(fd,2) != sizeof(struct auction_data) + 4 )
  255. return;
  256. memcpy(&auction, RFIFOP(fd,4), sizeof(struct auction_data));
  257. if( auction_count(auction.seller_id, false) < 5 )
  258. auction.auction_id = auction_create(&auction);
  259. mapif_Auction_register(fd, &auction);
  260. }
  261. static void mapif_Auction_cancel(int fd, int char_id, unsigned char result)
  262. {
  263. WFIFOHEAD(fd,7);
  264. WFIFOW(fd,0) = 0x3852;
  265. WFIFOL(fd,2) = char_id;
  266. WFIFOB(fd,6) = result;
  267. WFIFOSET(fd,7);
  268. }
  269. static void mapif_parse_Auction_cancel(int fd)
  270. {
  271. int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6);
  272. struct auction_data *auction;
  273. if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL )
  274. {
  275. mapif_Auction_cancel(fd, char_id, 1); // Bid Number is Incorrect
  276. return;
  277. }
  278. if( auction->seller_id != char_id )
  279. {
  280. mapif_Auction_cancel(fd, char_id, 2); // You cannot end the auction
  281. return;
  282. }
  283. if( auction->buyer_id > 0 )
  284. {
  285. mapif_Auction_cancel(fd, char_id, 3); // An auction with at least one bidder cannot be canceled
  286. return;
  287. }
  288. mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction canceled.", 0, &auction->item);
  289. auction_delete(auction);
  290. mapif_Auction_cancel(fd, char_id, 0); // The auction has been canceled
  291. }
  292. static void mapif_Auction_close(int fd, int char_id, unsigned char result)
  293. {
  294. WFIFOHEAD(fd,7);
  295. WFIFOW(fd,0) = 0x3853;
  296. WFIFOL(fd,2) = char_id;
  297. WFIFOB(fd,6) = result;
  298. WFIFOSET(fd,7);
  299. }
  300. static void mapif_parse_Auction_close(int fd)
  301. {
  302. int char_id = RFIFOL(fd,2), auction_id = RFIFOL(fd,6);
  303. struct auction_data *auction;
  304. if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL )
  305. {
  306. mapif_Auction_close(fd, char_id, 2); // Bid Number is Incorrect
  307. return;
  308. }
  309. if( auction->buyer_id == 0 )
  310. {
  311. mapif_Auction_close(fd, char_id, 1); // You cannot end the auction
  312. return;
  313. }
  314. // Send Money to Seller
  315. mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Auction closed.", auction->price, NULL);
  316. // Send Item to Buyer
  317. mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Auction winner.", 0, &auction->item);
  318. mapif_Auction_message(auction->buyer_id, 6); // You have won the auction
  319. auction_delete(auction);
  320. mapif_Auction_close(fd, char_id, 0); // You have ended the auction
  321. }
  322. static void mapif_Auction_bid(int fd, int char_id, int bid, unsigned char result)
  323. {
  324. WFIFOHEAD(fd,11);
  325. WFIFOW(fd,0) = 0x3855;
  326. WFIFOL(fd,2) = char_id;
  327. WFIFOL(fd,6) = bid; // To Return Zeny
  328. WFIFOB(fd,10) = result;
  329. WFIFOSET(fd,11);
  330. }
  331. static void mapif_parse_Auction_bid(int fd)
  332. {
  333. int char_id = RFIFOL(fd,4), bid = RFIFOL(fd,12);
  334. unsigned int auction_id = RFIFOL(fd,8);
  335. struct auction_data *auction;
  336. if( (auction = (struct auction_data *)idb_get(auction_db_, auction_id)) == NULL || auction->price >= bid || auction->seller_id == char_id )
  337. {
  338. mapif_Auction_bid(fd, char_id, bid, 0); // You have failed to bid in the auction
  339. return;
  340. }
  341. if( auction_count(char_id, true) > 4 && bid < auction->buynow && auction->buyer_id != char_id )
  342. {
  343. mapif_Auction_bid(fd, char_id, bid, 9); // You cannot place more than 5 bids at a time
  344. return;
  345. }
  346. if( auction->buyer_id > 0 )
  347. { // Send Money back to the previous Buyer
  348. if( auction->buyer_id != char_id )
  349. {
  350. mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "Someone has placed a higher bid.", auction->price, NULL);
  351. mapif_Auction_message(auction->buyer_id, 7); // You have failed to win the auction
  352. }
  353. else
  354. mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have placed a higher bid.", auction->price, NULL);
  355. }
  356. auction->buyer_id = char_id;
  357. safestrncpy(auction->buyer_name, (char*)RFIFOP(fd,16), NAME_LENGTH);
  358. auction->price = bid;
  359. if( bid >= auction->buynow )
  360. { // Automatic won the auction
  361. mapif_Auction_bid(fd, char_id, bid - auction->buynow, 1); // You have successfully bid in the auction
  362. mail_sendmail(0, "Auction Manager", auction->buyer_id, auction->buyer_name, "Auction", "You have won the auction.", 0, &auction->item);
  363. mapif_Auction_message(char_id, 6); // You have won the auction
  364. mail_sendmail(0, "Auction Manager", auction->seller_id, auction->seller_name, "Auction", "Payment for your auction!.", auction->buynow, NULL);
  365. auction_delete(auction);
  366. return;
  367. }
  368. auction_save(auction);
  369. mapif_Auction_bid(fd, char_id, 0, 1); // You have successfully bid in the auction
  370. }
  371. /*==========================================
  372. * Packets From Map Server
  373. *------------------------------------------*/
  374. int inter_auction_parse_frommap(int fd)
  375. {
  376. switch(RFIFOW(fd,0))
  377. {
  378. case 0x3050: mapif_parse_Auction_requestlist(fd); break;
  379. case 0x3051: mapif_parse_Auction_register(fd); break;
  380. case 0x3052: mapif_parse_Auction_cancel(fd); break;
  381. case 0x3053: mapif_parse_Auction_close(fd); break;
  382. case 0x3055: mapif_parse_Auction_bid(fd); break;
  383. default:
  384. return 0;
  385. }
  386. return 1;
  387. }
  388. int inter_auction_sql_init(void)
  389. {
  390. auction_db_ = idb_alloc(DB_OPT_RELEASE_DATA);
  391. inter_auctions_fromsql();
  392. return 0;
  393. }
  394. void inter_auction_sql_final(void)
  395. {
  396. auction_db_->destroy(auction_db_,NULL);
  397. return;
  398. }