diff options
Diffstat (limited to 'src/char')
-rw-r--r-- | src/char/HPMchar.c | 1 | ||||
-rw-r--r-- | src/char/Makefile.in | 4 | ||||
-rw-r--r-- | src/char/char.c | 4 | ||||
-rw-r--r-- | src/char/char.h | 2 | ||||
-rw-r--r-- | src/char/int_rodex.c | 536 | ||||
-rw-r--r-- | src/char/int_rodex.h | 47 | ||||
-rw-r--r-- | src/char/inter.c | 6 | ||||
-rw-r--r-- | src/char/mapif.c | 21 | ||||
-rw-r--r-- | src/char/mapif.h | 9 |
9 files changed, 627 insertions, 3 deletions
diff --git a/src/char/HPMchar.c b/src/char/HPMchar.c index e0f81c61f..3a74f443d 100644 --- a/src/char/HPMchar.c +++ b/src/char/HPMchar.c @@ -36,6 +36,7 @@ #include "char/int_party.h" #include "char/int_pet.h" #include "char/int_quest.h" +#include "char/int_rodex.h" #include "char/int_storage.h" #include "char/loginif.h" #include "char/mapif.h" diff --git a/src/char/Makefile.in b/src/char/Makefile.in index 7806ce2bb..1a7d067a4 100644 --- a/src/char/Makefile.in +++ b/src/char/Makefile.in @@ -42,11 +42,11 @@ MT19937AR_H = $(MT19937AR_D)/mt19937ar.h CHAR_C = char.c HPMchar.c loginif.c mapif.c geoip.c inter.c int_auction.c int_elemental.c int_guild.c \ int_homun.c int_mail.c int_mercenary.c int_party.c int_pet.c \ - int_quest.c int_storage.c pincode.c + int_quest.c int_rodex.c int_storage.c pincode.c CHAR_OBJ = $(addprefix obj_sql/, $(patsubst %.c,%.o,$(CHAR_C))) CHAR_H = char.h HPMchar.h loginif.h mapif.h geoip.h inter.h int_auction.h int_elemental.h int_guild.h \ int_homun.h int_mail.h int_mercenary.h int_party.h int_pet.h \ - int_quest.h int_storage.h pincode.h + int_quest.h int_rodex.h int_storage.h pincode.h CHAR_PH = HAVE_MYSQL=@HAVE_MYSQL@ diff --git a/src/char/char.c b/src/char/char.c index f66108c00..4687d4d6b 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -34,6 +34,7 @@ #include "char/int_party.h" #include "char/int_pet.h" #include "char/int_quest.h" +#include "char/int_rodex.h" #include "char/int_storage.h" #include "char/inter.h" #include "char/loginif.h" @@ -97,6 +98,8 @@ char auction_db[256] = "auction"; // Auctions System char friend_db[256] = "friends"; char hotkey_db[256] = "hotkey"; char quest_db[256] = "quest"; +char rodex_db[256] = "rodex_mail"; +char rodex_item_db[256] = "rodex_items"; char homunculus_db[256] = "homunculus"; char skill_homunculus_db[256] = "skill_homunculus"; char mercenary_db[256] = "mercenary"; @@ -6412,6 +6415,7 @@ void char_load_defaults(void) inter_pet_defaults(); inter_quest_defaults(); inter_storage_defaults(); + inter_rodex_defaults(); inter_defaults(); geoip_defaults(); } diff --git a/src/char/char.h b/src/char/char.h index 6b081e536..3689690c7 100644 --- a/src/char/char.h +++ b/src/char/char.h @@ -328,6 +328,8 @@ extern char pet_db[256]; extern char mail_db[256]; extern char auction_db[256]; extern char quest_db[256]; +extern char rodex_db[256]; +extern char rodex_item_db[256]; extern char homunculus_db[256]; extern char skill_homunculus_db[256]; extern char mercenary_db[256]; diff --git a/src/char/int_rodex.c b/src/char/int_rodex.c new file mode 100644 index 000000000..12ab54290 --- /dev/null +++ b/src/char/int_rodex.c @@ -0,0 +1,536 @@ +/** + * This file is part of Hercules. + * http://herc.ws - http://github.com/HerculesWS/Hercules + * + * Copyright (C) 2017 Hercules Dev Team + * + * Hercules 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/>. + */ +#define HERCULES_CORE + +#include "int_rodex.h" + +#include "char/char.h" +#include "char/inter.h" +#include "char/mapif.h" +#include "common/db.h" +#include "common/memmgr.h" +#include "common/mmo.h" +#include "common/nullpo.h" +#include "common/showmsg.h" +#include "common/socket.h" +#include "common/sql.h" +#include "common/strlib.h" +#include "common/timer.h" + +#include <stdio.h> +#include <stdlib.h> + +struct inter_rodex_interface inter_rodex_s; +struct inter_rodex_interface *inter_rodex; + +// Loads new mails of this char_id/account_id +static int inter_rodex_fromsql(int char_id, int account_id, int8 opentype, int64 mail_id, struct rodex_maillist *mails) +{ + int i, count = 0; + struct rodex_message msg = { 0 }; + struct SqlStmt *stmt; + struct SqlStmt *stmt_items; + + nullpo_retr(-1, mails); + + stmt = SQL->StmtMalloc(inter->sql_handle); + + switch (opentype) { + case RODEX_OPENTYPE_MAIL: + if (SQL_ERROR == SQL->StmtPrepare(stmt, + "SELECT `mail_id`, `sender_name`, `sender_id`, `receiver_name`, `receiver_id`, `receiver_accountid`," + "`title`, `body`, `zeny`, `type`, `is_read`, `send_date`, `expire_date`, `weight`" + "FROM `%s` WHERE `expire_date` > '%d' AND `receiver_id` = '%d' AND `mail_id` > '%"PRId64"'" + "ORDER BY `mail_id` ASC", rodex_db, (int)time(NULL), char_id, mail_id) + ) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return -1; + } + break; + + case RODEX_OPENTYPE_ACCOUNT: + if (SQL_ERROR == SQL->StmtPrepare(stmt, + "SELECT `mail_id`, `sender_name`, `sender_id`, `receiver_name`, `receiver_id`, `receiver_accountid`," + "`title`, `body`, `zeny`, `type`, `is_read`, `send_date`, `expire_date`, `weight`" + "FROM `%s` WHERE " + "`expire_date` > '%d' AND `receiver_accountid` = '%d' AND `mail_id` > '%"PRId64"'" + "ORDER BY `mail_id` ASC", rodex_db, (int)time(NULL), account_id, mail_id) + ) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return -1; + } + break; + + case RODEX_OPENTYPE_RETURN: + if (SQL_ERROR == SQL->StmtPrepare(stmt, + "SELECT `mail_id`, `sender_name`, `sender_id`, `receiver_name`, `receiver_id`, `receiver_accountid`," + "`title`, `body`, `zeny`, `type`, `is_read`, `send_date`, `expire_date`, `weight`" + "FROM `%s` WHERE (`sender_id` = '%d' AND `expire_date` <= '%d' AND `send_date` + '%d' > '%d' AND `mail_id` > '%"PRId64"')" + "ORDER BY `mail_id` ASC", rodex_db, char_id, (int)time(NULL), 2 * RODEX_EXPIRE, (int)time(NULL), mail_id) + ) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return -1; + } + break; + } + + if (SQL_ERROR == SQL->StmtExecute(stmt) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT64, &msg.id, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_STRING, &msg.sender_name, sizeof(msg.sender_name), NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_INT, &msg.sender_id, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_STRING, &msg.receiver_name, sizeof(msg.receiver_name), NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_INT, &msg.receiver_id, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_INT, &msg.receiver_accountid, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_STRING, &msg.title, sizeof(msg.title), NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_STRING, &msg.body, sizeof(msg.body), NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_INT, &msg.zeny, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_UINT8, &msg.type, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_INT8, &msg.is_read, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 11, SQLDT_INT, &msg.send_date, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 12, SQLDT_INT, &msg.expire_date, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 13, SQLDT_INT, &msg.weight, 0, NULL, NULL) + ) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return -1; + } + + stmt_items = SQL->StmtMalloc(inter->sql_handle); + if (stmt_items == NULL) { + SQL->StmtFreeResult(stmt); + SQL->StmtFree(stmt); + return -1; + } + + // Read mails + while (SQL_SUCCESS == SQL->StmtNextRow(stmt)) { + struct item it = { 0 }; + + if (msg.type & MAIL_TYPE_ITEM) { + if (SQL_ERROR == SQL->StmtPrepare(stmt_items, "SELECT `nameid`, `amount`, `equip`, `identify`," + "`refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `opt_idx0`, `opt_val0`," + "`opt_idx1`, `opt_val1`, `opt_idx2`, `opt_val2`, `opt_idx3`, `opt_val3`, `opt_idx4`, `opt_val4`," + "`expire_time`, `bound`, `unique_id`" + "FROM `%s` WHERE mail_id = '%"PRId64"' ORDER BY `mail_id` ASC", rodex_item_db, msg.id) + || SQL_ERROR == SQL->StmtExecute(stmt_items) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 0, SQLDT_INT, &it.nameid, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 1, SQLDT_INT, &it.amount, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 2, SQLDT_UINT, &it.equip, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 3, SQLDT_INT8, &it.identify, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 4, SQLDT_INT8, &it.refine, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 5, SQLDT_INT8, &it.attribute, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 6, SQLDT_INT16, &it.card[0], 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 7, SQLDT_INT16, &it.card[1], 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 8, SQLDT_INT16, &it.card[2], 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 9, SQLDT_INT16, &it.card[3], 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 10, SQLDT_INT16, &it.option[0].index, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 11, SQLDT_INT16, &it.option[0].value, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 12, SQLDT_INT16, &it.option[1].index, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 13, SQLDT_INT16, &it.option[1].value, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 14, SQLDT_INT16, &it.option[2].index, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 15, SQLDT_INT16, &it.option[2].value, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 16, SQLDT_INT16, &it.option[3].index, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 17, SQLDT_INT16, &it.option[3].value, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 18, SQLDT_INT16, &it.option[4].index, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 19, SQLDT_INT16, &it.option[4].value, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 20, SQLDT_INT, &it.expire_time, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 21, SQLDT_UINT8, &it.bound, 0, NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt_items, 22, SQLDT_UINT64, &it.unique_id, 0, NULL, NULL)) { + SqlStmt_ShowDebug(stmt_items); + } + + for (i = 0; i < RODEX_MAX_ITEM && SQL_SUCCESS == SQL->StmtNextRow(stmt_items); ++i) { + msg.items[i].item = it; + msg.items_count++; + } + } + + if (msg.items_count == 0) { + msg.type &= ~MAIL_TYPE_ITEM; + } + + if (msg.zeny == 0) { + msg.type &= ~MAIL_TYPE_ZENY; + } + + msg.opentype = opentype; +#if PACKETVER < 20160601 + // NPC Message Type isn't supported in old clients + msg.type &= ~MAIL_TYPE_NPC; +#endif + + ++count; + VECTOR_ENSURE(*mails, 1, 1); + VECTOR_PUSH(*mails, msg); + memset(&msg, 0, sizeof(struct rodex_message)); + } + + SQL->StmtFreeResult(stmt); + SQL->StmtFreeResult(stmt_items); + + SQL->StmtFree(stmt); + SQL->StmtFree(stmt_items); + + ShowInfo("rodex load complete from DB - id: %d (total: %d)\n", char_id, count); + return count; +} + +// Checks if user has non-read mails +static bool inter_rodex_hasnew(int char_id, int account_id) +{ + int count = 0; + char *data; + + if (SQL_ERROR == SQL->Query(inter->sql_handle, + "SELECT count(*) FROM `%s` WHERE (" + "(`expire_date` > '%d' AND (`receiver_id` = '%d' OR `receiver_accountid` = '%d')) OR" + "(`sender_id` = '%d' AND `expire_date` <= '%d' AND `send_date` + '%d' > '%d')" + ") AND (`is_read` = 0 OR (`type` > 0 AND `type` != 8))", + rodex_db, (int)time(NULL), char_id, account_id, + char_id, (int)time(NULL), 2 * RODEX_EXPIRE, (int)time(NULL)) + ) { + Sql_ShowDebug(inter->sql_handle); + return -1; + } + + if (SQL_SUCCESS != SQL->NextRow(inter->sql_handle)) + return false; + + SQL->GetData(inter->sql_handle, 0, &data, NULL); + count = atoi(data); + SQL->FreeResult(inter->sql_handle); + + return count > 0; +} + +/// Checks player name and retrieves some data +static bool inter_rodex_checkname(const char *name, int *target_char_id, short *target_class, int *target_level) +{ + char esc_name[NAME_LENGTH * 2 + 1]; + bool found = false; + + nullpo_retr(false, name); + nullpo_retr(false, target_char_id); + nullpo_retr(false, target_class); + nullpo_retr(false, target_level); + + // Try to find the Dest Char by Name + SQL->EscapeStringLen(inter->sql_handle, esc_name, name, strnlen(name, NAME_LENGTH)); + if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `char_id`, `class`, `base_level` FROM `%s` WHERE `name` = '%s'", char_db, esc_name)) { + Sql_ShowDebug(inter->sql_handle); + } else { + if (SQL_SUCCESS == SQL->NextRow(inter->sql_handle)) { + char *data; + SQL->GetData(inter->sql_handle, 0, &data, NULL); *target_char_id = atoi(data); + SQL->GetData(inter->sql_handle, 1, &data, NULL); *target_class = (short)atoi(data); + SQL->GetData(inter->sql_handle, 2, &data, NULL); *target_level = atoi(data); + found = true; + } + } + SQL->FreeResult(inter->sql_handle); + + return found; +} + +/// Stores a single message in the database. +/// Returns the message's ID if successful (or 0 if it fails). +int64 inter_rodex_savemessage(struct rodex_message* msg) +{ + char sender_name[NAME_LENGTH * 2 + 1]; + char receiver_name[NAME_LENGTH * 2 + 1]; + char body[RODEX_BODY_LENGTH * 2 + 1]; + char title[RODEX_TITLE_LENGTH * 2 + 1]; + int i; + + nullpo_retr(false, msg); + + SQL->EscapeStringLen(inter->sql_handle, sender_name, msg->sender_name, strnlen(msg->sender_name, NAME_LENGTH)); + SQL->EscapeStringLen(inter->sql_handle, receiver_name, msg->receiver_name, strnlen(msg->receiver_name, NAME_LENGTH)); + SQL->EscapeStringLen(inter->sql_handle, body, msg->body, strnlen(msg->body, RODEX_BODY_LENGTH)); + SQL->EscapeStringLen(inter->sql_handle, title, msg->title, strnlen(msg->title, RODEX_TITLE_LENGTH)); + + if (SQL_ERROR == SQL->Query(inter->sql_handle, "INSERT INTO `%s` (`sender_name`, `sender_id`, `receiver_name`, `receiver_id`, `receiver_accountid`, `title`, `body`," + "`zeny`, `type`, `is_read`, `send_date`, `expire_date`, `weight`) VALUES " + "('%s', '%d', '%s', '%d', '%d', '%s', '%s', '%"PRId64"', '%d', '%d', '%d', '%d', '%d')", + rodex_db, sender_name, msg->sender_id, receiver_name, msg->receiver_id, msg->receiver_accountid, + title, body, msg->zeny, msg->type, msg->is_read == true ? 1 : 0, msg->send_date, msg->expire_date, msg->weight)) { + Sql_ShowDebug(inter->sql_handle); + return 0; + } + + msg->id = (int64)SQL->LastInsertId(inter->sql_handle); + + for (i = 0; i < RODEX_MAX_ITEM; ++i) { + // Should we use statement here? [KIRIEZ] + struct item *it = &msg->items[i].item; + if (it->nameid == 0) + continue; + + if (SQL_ERROR == SQL->Query(inter->sql_handle, "INSERT INTO `%s` (`mail_id`, `nameid`, `amount`, `equip`, `identify`," + "`refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `opt_idx0`, `opt_val0`, `opt_idx1`, `opt_val1`, `opt_idx2`," + "`opt_val2`, `opt_idx3`, `opt_val3`, `opt_idx4`, `opt_val4`,`expire_time`, `bound`, `unique_id`) VALUES " + "('%"PRId64"', '%d', '%d', '%u', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%u', '%"PRIu64"')", + rodex_item_db, msg->id, it->nameid, it->amount, it->equip, it->identify, it->refine, it->attribute, it->card[0], it->card[1], it->card[2], it->card[3], + it->option[0].index, it->option[0].value, it->option[1].index, it->option[1].value, it->option[2].index, it->option[2].value, it->option[3].index, + it->option[3].value, it->option[4].index, it->option[4].value, it->expire_time, it->bound, it->unique_id) + ) { + Sql_ShowDebug(inter->sql_handle); + continue; + } + } + + return msg->id; +} + +/*========================================== + * Inbox Request + *------------------------------------------*/ +void mapif_rodex_sendinbox(int fd, int char_id, int8 opentype, int8 flag, int count, struct rodex_maillist *mails) +{ + int per_packet = (UINT16_MAX - 15) / sizeof(struct rodex_message); + int sent = 0; + nullpo_retv(mails); + Assert_retv(char_id > 0); + Assert_retv(count >= 0); + + do { + int i = 15, j, size, limit; + bool is_last = true; + + if (count <= per_packet) { + size = count * sizeof(struct rodex_message) + 15; + limit = count; + is_last = true; + } else { + int to_send = count - sent; + limit = min(to_send, per_packet); + if (limit != to_send) { + is_last = false; + } + size = limit * sizeof(struct rodex_message) + 15; + } + + WFIFOHEAD(fd, size); + WFIFOW(fd, 0) = 0x3895; + WFIFOW(fd, 2) = size; + WFIFOL(fd, 4) = char_id; + WFIFOB(fd, 8) = opentype; + WFIFOB(fd, 9) = flag; + WFIFOB(fd, 10) = is_last; + WFIFOL(fd, 11) = count; + for (j = 0; j < limit; ++j, ++sent, i += sizeof(struct rodex_message)) { + memcpy(WFIFOP(fd, i), &VECTOR_INDEX(*mails, sent), sizeof(struct rodex_message)); + } + WFIFOSET(fd, size); + } while (sent < count); +} + +void mapif_parse_rodex_requestinbox(int fd) +{ + int count; + int char_id = RFIFOL(fd,2); + int account_id = RFIFOL(fd, 6); + int8 flag = RFIFOB(fd, 10); + int8 opentype = RFIFOB(fd, 11); + int64 mail_id = RFIFOQ(fd, 12); + struct rodex_maillist mails = { 0 }; + + VECTOR_INIT(mails); + if (flag == 0) + count = inter_rodex->fromsql(char_id, account_id, opentype, 0, &mails); + else + count = inter_rodex->fromsql(char_id, account_id, opentype, mail_id, &mails); + mapif->rodex_sendinbox(fd, char_id, opentype, flag, count, &mails); + VECTOR_CLEAR(mails); +} + +/*========================================== +* Checks if there are new mails +*------------------------------------------*/ +void mapif_rodex_sendhasnew(int fd, int char_id, bool has_new) +{ + Assert_retv(char_id > 0); + + WFIFOHEAD(fd, 7); + WFIFOW(fd, 0) = 0x3896; + WFIFOL(fd, 2) = char_id; + WFIFOB(fd, 6) = has_new; + WFIFOSET(fd, 7); +} + +void mapif_parse_rodex_checkhasnew(int fd) +{ + int char_id = RFIFOL(fd, 2); + int account_id = RFIFOL(fd, 6); + bool has_new; + + Assert_retv(account_id >= START_ACCOUNT_NUM && account_id <= END_ACCOUNT_NUM); + Assert_retv(char_id >= START_CHAR_NUM); + + has_new = inter_rodex->hasnew(char_id, account_id); + mapif->rodex_sendhasnew(fd, char_id, has_new); +} + +/*========================================== + * Update/Delete mail + *------------------------------------------*/ +void mapif_parse_rodex_updatemail(int fd) +{ + int64 mail_id = RFIFOL(fd, 2); + int8 flag = RFIFOB(fd, 10); + + Assert_retv(mail_id > 0); + Assert_retv(flag >= 0 && flag <= 3); + + switch (flag) { + case 0: // Read + if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `is_read` = 1 WHERE `mail_id` = '%"PRId64"'", rodex_db, mail_id)) + Sql_ShowDebug(inter->sql_handle); + break; + + case 1: // Get Zeny + if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `zeny` = 0, `type` = `type` & (~2) WHERE `mail_id` = '%"PRId64"'", rodex_db, mail_id)) + Sql_ShowDebug(inter->sql_handle); + break; + + case 2: // Get Items + if (SQL_ERROR == SQL->Query(inter->sql_handle, "DELETE FROM `%s` WHERE `mail_id` = '%"PRId64"'", rodex_item_db, mail_id)) + Sql_ShowDebug(inter->sql_handle); + if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `zeny` = 0, `type` = `type` & (~4) WHERE `mail_id` = '%"PRId64"'", rodex_db, mail_id)) + Sql_ShowDebug(inter->sql_handle); + break; + + case 3: // Delete Mail + if (SQL_ERROR == SQL->Query(inter->sql_handle, "DELETE FROM `%s` WHERE `mail_id` = '%"PRId64"'", rodex_db, mail_id)) + Sql_ShowDebug(inter->sql_handle); + if (SQL_ERROR == SQL->Query(inter->sql_handle, "DELETE FROM `%s` WHERE `mail_id` = '%"PRId64"'", rodex_item_db, mail_id)) + Sql_ShowDebug(inter->sql_handle); + break; + } +} + +/*========================================== + * Send Mail + *------------------------------------------*/ +void mapif_rodex_send(int fd, int sender_id, int receiver_id, int receiver_accountid, bool result) +{ + Assert_retv(sender_id >= 0); + Assert_retv(receiver_id + receiver_accountid > 0); + + WFIFOHEAD(fd,15); + WFIFOW(fd,0) = 0x3897; + WFIFOL(fd,2) = sender_id; + WFIFOL(fd,6) = receiver_id; + WFIFOL(fd,10) = receiver_accountid; + WFIFOB(fd,14) = result; + WFIFOSET(fd,15); +} + +void mapif_parse_rodex_send(int fd) +{ + struct rodex_message msg = { 0 }; + + if (RFIFOW(fd,2) != 4 + sizeof(struct rodex_message)) + return; + + memcpy(&msg, RFIFOP(fd,4), sizeof(struct rodex_message)); + if (msg.receiver_id > 0 || msg.receiver_accountid > 0) + msg.id = inter_rodex->savemessage(&msg); + + mapif->rodex_send(fd, msg.sender_id, msg.receiver_id, msg.receiver_accountid, msg.id > 0 ? true : false); +} + +/*------------------------------------------ + * Check Player + *------------------------------------------*/ +void mapif_rodex_checkname(int fd, int reqchar_id, int target_char_id, short target_class, int target_level, char name[NAME_LENGTH]) +{ + nullpo_retv(name); + Assert_retv(reqchar_id > 0); + Assert_retv(target_char_id >= 0); + + WFIFOHEAD(fd, 16 + NAME_LENGTH); + WFIFOW(fd, 0) = 0x3898; + WFIFOL(fd, 2) = reqchar_id; + WFIFOL(fd, 6) = target_char_id; + WFIFOW(fd, 10) = target_class; + WFIFOL(fd, 12) = target_level; + safestrncpy(WFIFOP(fd, 16), name, NAME_LENGTH); + WFIFOSET(fd, 16 + NAME_LENGTH); +} + +void mapif_parse_rodex_checkname(int fd) +{ + int reqchar_id = RFIFOL(fd, 2); + char name[NAME_LENGTH]; + int target_char_id, target_level; + short target_class; + + safestrncpy(name, RFIFOP(fd, 6), NAME_LENGTH); + + if (inter_rodex->checkname(name, &target_char_id, &target_class, &target_level) == true) + mapif->rodex_checkname(fd, reqchar_id, target_char_id, target_class, target_level, name); + else + mapif->rodex_checkname(fd, reqchar_id, 0, 0, 0, name); +} + +/*========================================== + * Packets From Map Server + *------------------------------------------*/ +int inter_rodex_parse_frommap(int fd) +{ + switch(RFIFOW(fd,0)) + { + case 0x3095: mapif->parse_rodex_requestinbox(fd); break; + case 0x3096: mapif->parse_rodex_checkhasnew(fd); break; + case 0x3097: mapif->parse_rodex_updatemail(fd); break; + case 0x3098: mapif->parse_rodex_send(fd); break; + case 0x3099: mapif->parse_rodex_checkname(fd); break; + default: + return 0; + } + return 1; +} + +int inter_rodex_sql_init(void) +{ + return 1; +} + +void inter_rodex_sql_final(void) +{ + return; +} + +void inter_rodex_defaults(void) +{ + inter_rodex = &inter_rodex_s; + + inter_rodex->savemessage = inter_rodex_savemessage; + inter_rodex->parse_frommap = inter_rodex_parse_frommap; + inter_rodex->sql_init = inter_rodex_sql_init; + inter_rodex->sql_final = inter_rodex_sql_final; + inter_rodex->fromsql = inter_rodex_fromsql; + inter_rodex->hasnew = inter_rodex_hasnew; + inter_rodex->checkname = inter_rodex_checkname; +} diff --git a/src/char/int_rodex.h b/src/char/int_rodex.h new file mode 100644 index 000000000..801ebcb89 --- /dev/null +++ b/src/char/int_rodex.h @@ -0,0 +1,47 @@ +/** + * This file is part of Hercules. + * http://herc.ws - http://github.com/HerculesWS/Hercules + * + * Copyright (C) 2017 Hercules Dev Team + * + * Hercules 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/>. + */ +#ifndef CHAR_INT_RODEX_H +#define CHAR_INT_RODEX_H + +#include "common/mmo.h" +#include "common/db.h" + +struct item; + +/** + * inter_rodex interface + **/ +struct inter_rodex_interface { + int (*sql_init) (void); + void (*sql_final) (void); + int (*parse_frommap) (int fd); + int (*fromsql) (int char_id, int account_id, int8 opentype, int64 mail_id, struct rodex_maillist *mails); + bool (*hasnew) (int char_id, int account_id); + bool (*checkname) (const char *name, int *target_char_id, short *target_class, int *target_level); + int64 (*savemessage) (struct rodex_message* msg); +}; + +#ifdef HERCULES_CORE +void inter_rodex_defaults(void); +#endif // HERCULES_CORE + +HPShared struct inter_rodex_interface *inter_rodex; + +#endif /* CHAR_INT_RODEX_H */ diff --git a/src/char/inter.c b/src/char/inter.c index cfbc0fd4d..557ee5313 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -33,6 +33,7 @@ #include "char/int_party.h" #include "char/int_pet.h" #include "char/int_quest.h" +#include "char/int_rodex.h" #include "char/int_storage.h" #include "char/mapif.h" #include "common/cbasetypes.h" @@ -76,7 +77,7 @@ int inter_recv_packet_length[] = { 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3060- Quest system [Kevin] [Inkfish] -1,10, 6,-1, 0, 0, 0, 0, 0, 0, 0, 0, -1,10, 6,-1, // 3070- Mercenary packets [Zephyrus], Elemental packets [pakpil] 48,14,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3080- - -1,10,-1, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator] + -1,10,-1, 6, 0, 20,10,11, -1,6 + NAME_LENGTH, 0, 0, 0, 0, 0, 0, // 3090- Homunculus packets [albator], RoDEX packets }; struct WisData { @@ -974,6 +975,7 @@ int inter_init_sql(const char *file) inter_elemental->sql_init(); inter_mail->sql_init(); inter_auction->sql_init(); + inter_rodex->sql_init(); geoip->init(); inter->msg_config_read("conf/messages.conf", false); @@ -994,6 +996,7 @@ void inter_final(void) inter_elemental->sql_final(); inter_mail->sql_final(); inter_auction->sql_final(); + inter_rodex->sql_final(); geoip->final(true); inter->do_final_msg(); @@ -1416,6 +1419,7 @@ int inter_parse_frommap(int fd) || inter_mail->parse_frommap(fd) || inter_auction->parse_frommap(fd) || inter_quest->parse_frommap(fd) + || inter_rodex->parse_frommap(fd) ) break; else diff --git a/src/char/mapif.c b/src/char/mapif.c index 5fff96ba8..b71171e23 100644 --- a/src/char/mapif.c +++ b/src/char/mapif.c @@ -26,6 +26,7 @@ #include "char/int_auction.h" #include "char/int_guild.h" #include "char/int_homun.h" +#include "char/int_rodex.h" #include "common/cbasetypes.h" #include "common/mmo.h" #include "common/random.h" @@ -182,6 +183,16 @@ void mapif_quest_save_ack(int fd, int char_id, bool success); int mapif_parse_quest_save(int fd); void mapif_send_quests(int fd, int char_id, struct quest *tmp_questlog, int num_quests); int mapif_parse_quest_load(int fd); +/* RoDEX */ +int mapif_parse_rodex_requestinbox(int fd); +void mapif_rodex_sendinbox(int fd, int char_id, int8 opentype, int8 flag, int count, struct rodex_maillist *mails); +int mapif_parse_rodex_checkhasnew(int fd); +void mapif_rodex_sendhasnew(int fd, int char_id, bool has_new); +int mapif_parse_rodex_updatemail(int fd); +int mapif_parse_rodex_send(int fd); +void mapif_rodex_send(int fd, int sender_id, int receiver_id, int receiver_accountid, bool result); +int mapif_parse_rodex_checkname(int fd); +void mapif_rodex_checkname(int fd, int reqchar_id, int target_char_id, short target_class, int target_level, char name[NAME_LENGTH]); int mapif_load_guild_storage(int fd,int account_id,int guild_id, char flag); int mapif_save_guild_storage_ack(int fd, int account_id, int guild_id, int fail); int mapif_parse_LoadGuildStorage(int fd); @@ -363,6 +374,16 @@ void mapif_defaults(void) { mapif->parse_quest_save = mapif_parse_quest_save; mapif->send_quests = mapif_send_quests; mapif->parse_quest_load = mapif_parse_quest_load; + /* RoDEX */ + mapif->parse_rodex_requestinbox = mapif_parse_rodex_requestinbox; + mapif->rodex_sendinbox = mapif_rodex_sendinbox; + mapif->parse_rodex_checkhasnew = mapif_parse_rodex_checkhasnew; + mapif->rodex_sendhasnew = mapif_rodex_sendhasnew; + mapif->parse_rodex_updatemail = mapif_parse_rodex_updatemail; + mapif->parse_rodex_send = mapif_parse_rodex_send; + mapif->rodex_send = mapif_rodex_send; + mapif->parse_rodex_checkname = mapif_parse_rodex_checkname; + mapif->rodex_checkname = mapif_rodex_checkname; mapif->load_guild_storage = mapif_load_guild_storage; mapif->save_guild_storage_ack = mapif_save_guild_storage_ack; mapif->parse_LoadGuildStorage = mapif_parse_LoadGuildStorage; diff --git a/src/char/mapif.h b/src/char/mapif.h index 07fbed6c6..353da7ab0 100644 --- a/src/char/mapif.h +++ b/src/char/mapif.h @@ -176,6 +176,15 @@ struct mapif_interface { int (*parse_quest_save) (int fd); void (*send_quests) (int fd, int char_id, struct quest *tmp_questlog, int num_quests); int (*parse_quest_load) (int fd); + int(*parse_rodex_requestinbox) (int fd); + void(*rodex_sendinbox) (int fd, int char_id, int8 opentype, int8 flag, int count, struct rodex_maillist *mails); + int(*parse_rodex_checkhasnew) (int fd); + void(*rodex_sendhasnew) (int fd, int char_id, bool has_new); + int(*parse_rodex_updatemail) (int fd); + int(*parse_rodex_send) (int fd); + void(*rodex_send) (int fd, int sender_id, int receiver_id, int receiver_accountid, bool result); + int(*parse_rodex_checkname) (int fd); + void(*rodex_checkname) (int fd, int reqchar_id, int target_char_id, short target_class, int target_level, char name[NAME_LENGTH]); int (*load_guild_storage) (int fd, int account_id, int guild_id, char flag); int (*save_guild_storage_ack) (int fd, int account_id, int guild_id, int fail); int (*parse_LoadGuildStorage) (int fd); |