diff options
Diffstat (limited to 'src/map/clif.c')
-rw-r--r-- | src/map/clif.c | 670 |
1 files changed, 503 insertions, 167 deletions
diff --git a/src/map/clif.c b/src/map/clif.c index 17faf02c8..4f98d2c9c 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -29,6 +29,7 @@ #include "map/channel.h" #include "map/chat.h" #include "map/chrif.h" +#include "map/clan.h" #include "map/elemental.h" #include "map/guild.h" #include "map/homunculus.h" @@ -419,8 +420,14 @@ bool clif_send(const void* buf, int len, struct block_list* bl, enum send_target sd = BL_CAST(BL_PC, bl); - switch(type) { + if (sd != NULL && pc_isinvisible(sd)) { + if (type == AREA || type == BG || type == BG_AREA) + type = SELF; + else if (type == AREA_WOS || type == BG_WOS || type == BG_AREA_WOS) + return true; + } + switch(type) { case ALL_CLIENT: //All player clients. iter = mapit_getallusers(); while ((tsd = BL_UCAST(BL_PC, mapit->next(iter))) != NULL) { @@ -659,6 +666,22 @@ bool clif_send(const void* buf, int len, struct block_list* bl, enum send_target } break; + case CLAN: + if (sd && sd->status.clan_id) { + struct clan *c = clan->search(sd->status.clan_id); + + nullpo_retr(false, c); + + for (i = 0; i < VECTOR_LENGTH(c->members); i++) { + if (VECTOR_INDEX(c->members, i).online == 0 || (sd = VECTOR_INDEX(c->members, i).sd) == NULL || (fd = sd->fd) <= 0) + continue; + WFIFOHEAD(fd, len); + memcpy(WFIFOP(fd, 0), buf, len); + WFIFOSET(fd, len); + } + } + break; + default: ShowError("clif_send: Unrecognized type %u\n", type); return false; @@ -796,7 +819,15 @@ void clif_dropflooritem(struct flooritem_data* fitem) { p.subX = fitem->subx; p.subY = fitem->suby; p.count = fitem->item_data.amount; - +#ifdef PACKETVER_ZERO + if (fitem->showdropeffect) { + p.showdropeffect = itemdb_showdropeffect(fitem->item_data.nameid); + p.dropeffectmode = itemdb_dropeffectmode(fitem->item_data.nameid); + } else { + p.showdropeffect = 0; + p.dropeffectmode = 0; + } +#endif clif->send(&p, sizeof(p), &fitem->bl, AREA); } @@ -1526,6 +1557,8 @@ bool clif_spawn(struct block_list *bl) clif->specialeffect(&nd->bl,423,AREA); else if (nd->size == SZ_MEDIUM) clif->specialeffect(&nd->bl,421,AREA); + if (nd->clan_id > 0) + clif->sc_load(&nd->bl, nd->bl.id, AREA, status->dbs->IconChangeTable[SC_CLAN_INFO], 0, nd->clan_id, 0); } break; case BL_PET: @@ -1902,19 +1935,25 @@ void clif_changemap(struct map_session_data *sd, short m, int x, int y) { /// Notifies the client of a position change to coordinates on given map, which is on another map-server (ZC_NPCACK_SERVERMOVE). /// 0092 <map name>.16B <x>.W <y>.W <ip>.L <port>.W +/// 0ac7 <map name>.16B <x>.W <y>.W <ip>.L <port>.W <zero>.128B void clif_changemapserver(struct map_session_data* sd, unsigned short map_index, int x, int y, uint32 ip, uint16 port) { int fd; +#if PACKETVER >= 20170315 + const int cmd = 0xac7; +#else + const int cmd = 0x92; +#endif nullpo_retv(sd); fd = sd->fd; - WFIFOHEAD(fd,packet_len(0x92)); - WFIFOW(fd,0) = 0x92; - mapindex->getmapname_ext(mapindex_id2name(map_index), WFIFOP(fd,2)); - WFIFOW(fd,18) = x; - WFIFOW(fd,20) = y; - WFIFOL(fd,22) = htonl(ip); - WFIFOW(fd,26) = sockt->ntows(htons(port)); // [!] LE byte order here [!] - WFIFOSET(fd,packet_len(0x92)); + WFIFOHEAD(fd, packet_len(cmd)); + WFIFOW(fd, 0) = cmd; + mapindex->getmapname_ext(mapindex_id2name(map_index), WFIFOP(fd, 2)); + WFIFOW(fd, 18) = x; + WFIFOW(fd, 20) = y; + WFIFOL(fd, 22) = htonl(ip); + WFIFOW(fd, 26) = sockt->ntows(htons(port)); // [!] LE byte order here [!] + WFIFOSET(fd, packet_len(cmd)); } void clif_blown(struct block_list *bl) @@ -4374,6 +4413,8 @@ void clif_getareachar_unit(struct map_session_data* sd,struct block_list *bl) { clif->specialeffect_single(bl,423,sd->fd); else if (nd->size == SZ_MEDIUM) clif->specialeffect_single(bl,421,sd->fd); + if (nd->clan_id > 0) + clif->sc_load(&nd->bl, nd->bl.id, AREA, status->dbs->IconChangeTable[SC_CLAN_INFO], 0, nd->clan_id, 0); } break; case BL_MOB: @@ -6047,14 +6088,29 @@ void clif_wis_end(int fd, int flag) { /// Returns character name requested by char_id (ZC_ACK_REQNAME_BYGID). /// 0194 <char id>.L <name>.24B +/// 0af7 <flag>.W <char id>.L <name>.24B void clif_solved_charname(int fd, int charid, const char* name) { nullpo_retv(name); - WFIFOHEAD(fd,packet_len(0x194)); - WFIFOW(fd,0)=0x194; - WFIFOL(fd,2)=charid; - safestrncpy(WFIFOP(fd,6), name, NAME_LENGTH); - WFIFOSET(fd,packet_len(0x194)); +#if !defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221)) + WFIFOHEAD(fd, packet_len(0x0af7)); + WFIFOW(fd, 0) = 0xaf7; + if (*name == 0) { + WFIFOW(fd, 2) = 2; + memset(WFIFOP(fd, 8), 0, NAME_LENGTH); + } else { + WFIFOW(fd, 2) = 3; + safestrncpy(WFIFOP(fd, 8), name, NAME_LENGTH); + } + WFIFOL(fd, 4) = charid; + WFIFOSET(fd, packet_len(0x0af7)); +#else + WFIFOHEAD(fd, packet_len(0x194)); + WFIFOW(fd, 0) = 0x194; + WFIFOL(fd, 2) = charid; + safestrncpy(WFIFOP(fd, 6), name, NAME_LENGTH); + WFIFOSET(fd, packet_len(0x194)); +#endif } /// Presents a list of items that can be carded/composed (ZC_ITEMCOMPOSITION_LIST). @@ -6580,9 +6636,6 @@ void clif_party_created(struct map_session_data *sd,int result) } /// Adds new member to a party. -/// 0104 <account id>.L <role>.L <x>.W <y>.W <state>.B <party name>.24B <char name>.24B <map name>.16B (ZC_ADD_MEMBER_TO_GROUP) -/// 01e9 <account id>.L <role>.L <x>.W <y>.W <state>.B <party name>.24B <char name>.24B <map name>.16B <item pickup rule>.B <item share rule>.B (ZC_ADD_MEMBER_TO_GROUP2) -/// 0a43 <account id>.L <role>.L <class>.W <base level>.W <x>.W <y>.W <state>.B <party name>.24B <char name>.24B <map name>.16B <item pickup rule>.B <item share rule>.B (ZC_ADD_MEMBER_TO_GROUP3) /// role: /// 0 = leader /// 1 = normal @@ -6592,19 +6645,12 @@ void clif_party_created(struct map_session_data *sd,int result) void clif_party_member_info(struct party_data *p, struct map_session_data *sd) { int i; -#if PACKETVER < 20170502 - unsigned char buf[81]; - const int cmd = 0x1e9; - const int offset = 0; -#else - unsigned char buf[85]; -// [4144] probably 0xa43 packet can works on older clients because in client was added in 2015-10-07 - const int cmd = 0xa43; - int offset = 4; -#endif + struct PACKET_ZC_ADD_MEMBER_TO_GROUP packet; nullpo_retv(p); nullpo_retv(sd); + + memset(&packet, 0, sizeof(packet)); if (!sd) { //Pick any party member (this call is used when changing item share rules) ARR_FIND(0, MAX_PARTY, i, p->data[i].sd != 0); } else { @@ -6614,27 +6660,28 @@ void clif_party_member_info(struct party_data *p, struct map_session_data *sd) return; //Should never happen... sd = p->data[i].sd; - WBUFW(buf, 0) = cmd; - WBUFL(buf, 2) = sd->status.account_id; - WBUFL(buf, 6) = (p->party.member[i].leader) ? 0 : 1; + packet.packetType = partymemberinfo; + packet.AID = sd->status.account_id; +#if PACKETVER >= 20171207 + packet.GID = sd->status.char_id; +#endif + packet.leader = (p->party.member[i].leader) ? 0 : 1; #if PACKETVER >= 20170502 - WBUFW(buf, 10) = sd->status.class; - WBUFW(buf, 12) = sd->status.base_level; + packet.class = sd->status.class; + packet.baseLevel = sd->status.base_level; #endif - WBUFW(buf, offset + 10) = sd->bl.x; - WBUFW(buf, offset + 12) = sd->bl.y; - WBUFB(buf, offset + 14) = (p->party.member[i].online) ? 0 : 1; - memcpy(WBUFP(buf, offset + 15), p->party.name, NAME_LENGTH); - memcpy(WBUFP(buf, offset + 39), sd->status.name, NAME_LENGTH); - mapindex->getmapname_ext(map->list[sd->bl.m].custom_name ? map->list[map->list[sd->bl.m].instance_src_map].name : map->list[sd->bl.m].name, WBUFP(buf, offset + 63)); - WBUFB(buf, offset + 79) = (p->party.item & 1) ? 1 : 0; - WBUFB(buf, offset + 80) = (p->party.item & 2) ? 1 : 0; - clif->send(buf, packet_len(cmd), &sd->bl, PARTY); + packet.x = sd->bl.x; + packet.y = sd->bl.y; + packet.offline = (p->party.member[i].online) ? 0 : 1; + memcpy(packet.partyName, p->party.name, NAME_LENGTH); + memcpy(packet.playerName, sd->status.name, NAME_LENGTH); + mapindex->getmapname_ext(map->list[sd->bl.m].custom_name ? map->list[map->list[sd->bl.m].instance_src_map].name : map->list[sd->bl.m].name, packet.mapName); + packet.sharePickup = (p->party.item & 1) ? 1 : 0; + packet.shareLoot = (p->party.item & 2) ? 1 : 0; + clif->send(&packet, sizeof(packet), &sd->bl, PARTY); } /// Sends party information (ZC_GROUP_LIST). -/// 00fb <packet len>.W <party name>.24B { <account id>.L <nick>.24B <map name>.16B <role>.B <state>.B }* -/// 0a44 <packet len>.W <party name>.24B { <account id>.L <nick>.24B <map name>.16B <role>.B <state>.B <class>.W <base level>.W }* <item pickup rule>.B <item share rule>.B <unknown>.L /// role: /// 0 = leader /// 1 = normal @@ -6643,23 +6690,16 @@ void clif_party_member_info(struct party_data *p, struct map_session_data *sd) /// 1 = disconnected void clif_party_info(struct party_data* p, struct map_session_data *sd) { + struct PACKET_ZC_GROUP_LIST *packet; struct map_session_data* party_sd = NULL; int i, c; -#if PACKETVER < 20170502 - const int cmd = 0xfb; - const int size = 46; - unsigned char buf[2 + 2 + NAME_LENGTH + 46 * MAX_PARTY]; -#else -// [4144] probably 0xa44 packet can works on older clients because in client was added in 2015-10-07 - const int cmd = 0xa44; - const int size = 50; - unsigned char buf[2 + 2 + NAME_LENGTH + 50 * MAX_PARTY + 6]; -#endif - + unsigned char buf[sizeof(*packet) + sizeof(struct PACKET_ZC_GROUP_LIST_SUB) * MAX_PARTY]; nullpo_retv(p); - WBUFW(buf, 0) = cmd; - memcpy(WBUFP(buf, 4), p->party.name, NAME_LENGTH); + memset(buf, 0, sizeof(buf)); + packet = (struct PACKET_ZC_GROUP_LIST *)buf; + packet->packetType = partyinfo; + memcpy(packet->partyName, p->party.name, NAME_LENGTH); for(i = 0, c = 0; i < MAX_PARTY; i++) { struct party_member *m = &p->party.member[i]; @@ -6669,30 +6709,26 @@ void clif_party_info(struct party_data* p, struct map_session_data *sd) if (party_sd == NULL) party_sd = p->data[i].sd; - WBUFL(buf, 28 + c * size) = m->account_id; - memcpy(WBUFP(buf, 28 + c * size + 4), m->name, NAME_LENGTH); - mapindex->getmapname_ext(mapindex_id2name(m->map), WBUFP(buf, 28 + c * size + 28)); - WBUFB(buf, 28 + c * size + 44) = (m->leader) ? 0 : 1; - WBUFB(buf, 28 + c * size + 45) = (m->online) ? 0 : 1; + packet->members[c].AID = m->account_id; +#if PACKETVER >= 20171207 + packet->members[c].GID = m->char_id; +#endif + memcpy(packet->members[c].playerName, m->name, NAME_LENGTH); + mapindex->getmapname_ext(mapindex_id2name(m->map), packet->members[c].mapName); + packet->members[c].leader = (m->leader) ? 0 : 1; + packet->members[c].offline = (m->online) ? 0 : 1; #if PACKETVER >= 20170502 - WBUFW(buf, 28 + c * size + 46) = m->class; - WBUFW(buf, 28 + c * size + 48) = m->lv; + packet->members[c].class = m->class; + packet->members[c].baseLevel = m->lv; #endif c++; } -#if PACKETVER < 20170502 - WBUFW(buf, 2) = 28 + c * size; -#else - WBUFB(buf, 28 + c * size) = (p->party.item & 1) ? 1 : 0; - WBUFB(buf, 28 + c * size + 1) = (p->party.item & 2) ? 1 : 0; - WBUFL(buf, 28 + c * size + 2) = 0; // unknown - WBUFW(buf, 2) = 28 + c * size + 6; -#endif + packet->packetLen = sizeof(*packet) + c * sizeof(struct PACKET_ZC_GROUP_LIST_SUB); if (sd) { // send only to self - clif->send(buf, WBUFW(buf, 2), &sd->bl, SELF); + clif->send(buf, packet->packetLen, &sd->bl, SELF); } else if (party_sd) { // send to whole party - clif->send(buf, WBUFW(buf, 2), &party_sd->bl, PARTY); + clif->send(buf, packet->packetLen, &party_sd->bl, PARTY); } } @@ -7388,7 +7424,7 @@ void clif_mvp_item(struct map_session_data *sd,int nameid) /// 010b <exp>.L void clif_mvp_exp(struct map_session_data *sd, unsigned int exp) { -#if PACKETVER >= 20131223 // Kro removed this packet [Napster] +#if PACKETVER >= 20131223 // Kro removed this packet [Napster] if (battle_config.mvp_exp_reward_message) { char e_msg[CHAT_SIZE_MAX]; sprintf(e_msg, msg_txt(855), exp); @@ -9915,7 +9951,6 @@ void clif_parse_Hotkey(int fd, struct map_session_data *sd) { /// Displays cast-like progress bar (ZC_PROGRESS). /// 02f0 <color>.L <time>.L -/* TODO ZC_PROGRESS_ACTOR <account_id>.L */ void clif_progressbar(struct map_session_data * sd, unsigned int color, unsigned int second) { int fd; @@ -9944,6 +9979,30 @@ void clif_progressbar_abort(struct map_session_data * sd) WFIFOSET(fd,packet_len(0x2f2)); } +/** +* Displays cast-like progress bar on a unit. +* 09d1 <id>.L <color>.L <time>.L +* +* @param bl Source block list. +* @param color Message color (RGB format: 0xRRGGBB). +* @param time Time in seconds. +*/ +void clif_progressbar_unit(struct block_list *bl, uint32 color, uint32 time) +{ +#if PACKETVER >= 20130821 + struct ZC_PROGRESS_ACTOR p; + nullpo_retv(bl); + + p.PacketType = progressbarunit; + p.GID = bl->id; + p.color = color; + p.time = time; + clif->send(&p, sizeof(p), bl, AREA); +#else + ShowWarning("clif_progressbar_unit: Using progressbar with units available for PACKETVER >= 20130821 only."); +#endif +} + void clif_parse_progressbar(int fd, struct map_session_data * sd) __attribute__((nonnull (2))); /// Notification from the client, that the progress bar has reached 100% (CZ_PROGRESS). /// 02f1 @@ -10955,13 +11014,21 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) __attribute_ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) { int len = RFIFOW(fd,2)-15; - int limit = RFIFOW(fd,4); - bool pub = (RFIFOB(fd,6) != 0); - const char *password = RFIFOP(fd,7); //not zero-terminated - const char *title = RFIFOP(fd,15); // not zero-terminated + int limit; + bool pub; + const char *password; //not zero-terminated + const char *title; // not zero-terminated char s_password[CHATROOM_PASS_SIZE]; char s_title[CHATROOM_TITLE_SIZE]; + if (len < 1) + return; + + limit = RFIFOW(fd, 4); + pub = (RFIFOB(fd, 6) != 0); + password = RFIFOP(fd, 7); //not zero-terminated + title = RFIFOP(fd, 15); // not zero-terminated + if (pc_ismuted(&sd->sc, MANNER_NOROOM)) return; if(battle_config.basic_skill_check && !pc->check_basicskill(sd, 4)) { @@ -10977,9 +11044,6 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) return; } - if( len <= 0 ) - return; // invalid input - safestrncpy(s_password, password, CHATROOM_PASS_SIZE); safestrncpy(s_title, title, min(len+1,CHATROOM_TITLE_SIZE)); //NOTE: assumes that safestrncpy will not access the len+1'th byte @@ -11006,15 +11070,20 @@ void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data* sd) __attr void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data* sd) { int len = RFIFOW(fd,2)-15; - int limit = RFIFOW(fd,4); - bool pub = (RFIFOB(fd,6) != 0); - const char *password = RFIFOP(fd,7); // not zero-terminated - const char *title = RFIFOP(fd,15); // not zero-terminated + int limit; + bool pub; + const char *password; // not zero-terminated + const char *title; // not zero-terminated char s_password[CHATROOM_PASS_SIZE]; char s_title[CHATROOM_TITLE_SIZE]; - if( len <= 0 ) - return; // invalid input + if (len < 1) + return; + + limit = RFIFOW(fd, 4); + pub = (RFIFOB(fd, 6) != 0); + password = RFIFOP(fd, 7); // not zero-terminated + title = RFIFOP(fd, 15); // not zero-terminated safestrncpy(s_password, password, CHATROOM_PASS_SIZE); safestrncpy(s_title, title, min(len+1,CHATROOM_TITLE_SIZE)); //NOTE: assumes that safestrncpy will not access the len+1'th byte @@ -11030,7 +11099,7 @@ void clif_parse_ChangeChatOwner(int fd, struct map_session_data* sd) __attribute /// 1 = normal void clif_parse_ChangeChatOwner(int fd, struct map_session_data* sd) { - chat->change_owner(sd, RFIFOP(fd,6)); + chat->change_owner(sd, RFIFOP(fd,6)); // non null terminated } void clif_parse_KickFromChat(int fd,struct map_session_data *sd) __attribute__((nonnull (2))); @@ -11038,7 +11107,7 @@ void clif_parse_KickFromChat(int fd,struct map_session_data *sd) __attribute__(( /// 00e2 <name>.24B void clif_parse_KickFromChat(int fd,struct map_session_data *sd) { - chat->kick(sd, RFIFOP(fd,2)); + chat->kick(sd, RFIFOP(fd,2)); // non null terminated } void clif_parse_ChatLeave(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); @@ -11797,17 +11866,21 @@ void clif_parse_NpcStringInput(int fd, struct map_session_data* sd) __attribute_ /// 01d5 <packet len>.W <npc id>.L <string>.?B void clif_parse_NpcStringInput(int fd, struct map_session_data* sd) { + int len = RFIFOW(fd, 2); // [4144] can't confirm exact client version. At least >= correct for 20150513 #if PACKETVER >= 20151029 - int message_len = RFIFOW(fd, 2) - 7; + int message_len = len - 7; #else - int message_len = RFIFOW(fd, 2) - 8; + int message_len = len - 8; #endif - int npcid = RFIFOL(fd,4); - const char *message = RFIFOP(fd,8); + int npcid; + const char *message; + + if (len < 9) + return; - if( message_len <= 0 ) - return; // invalid input + npcid = RFIFOL(fd, 4); + message = RFIFOP(fd, 8); safestrncpy(sd->npc_str, message, min(message_len,CHATBOX_SIZE)); npc->scriptcont(sd, npcid, false); @@ -11845,8 +11918,8 @@ void clif_parse_ItemIdentify(int fd,struct map_session_data *sd) clif_menuskill_clear(sd); } -/// Identifying item with right-click (CZ_REQ_ONECLICK_ITEMIDENTIFY). -/// 0A35 <index>.W +/// Identifying item with right-click (CZ_REQ_ONECLICK_ITEMIDENTIFY). +/// 0A35 <index>.W void clif_parse_OneClick_ItemIdentify(int fd, struct map_session_data *sd) { int cmd = RFIFOW(fd,0); @@ -12961,9 +13034,15 @@ void clif_parse_PurchaseReq(int fd, struct map_session_data* sd) __attribute__(( /// 0134 <packet len>.W <account id>.L { <amount>.W <index>.W }* void clif_parse_PurchaseReq(int fd, struct map_session_data* sd) { - int len = (int)RFIFOW(fd,2) - 8; - int id = RFIFOL(fd,4); - const uint8 *data = RFIFOP(fd,8); + int len = (int)RFIFOW(fd, 2) - 8; + int id; + const uint8 *data; + + if (len < 1) + return; + + id = RFIFOL(fd, 4); + data = RFIFOP(fd, 8); vending->purchase(sd, id, sd->vended_id, data, len/4); @@ -12976,10 +13055,16 @@ void clif_parse_PurchaseReq2(int fd, struct map_session_data* sd) __attribute__( /// 0801 <packet len>.W <account id>.L <unique id>.L { <amount>.W <index>.W }* void clif_parse_PurchaseReq2(int fd, struct map_session_data* sd) { - int len = (int)RFIFOW(fd,2) - 12; - int aid = RFIFOL(fd,4); - int uid = RFIFOL(fd,8); - const uint8 *data = RFIFOP(fd,12); + int len = (int)RFIFOW(fd, 2) - 12; + int aid; + int uid; + const uint8 *data; + + if (len < 1) + return; + aid = RFIFOL(fd, 4); + uid = RFIFOL(fd, 8); + data = RFIFOP(fd, 12); vending->purchase(sd, aid, uid, data, len/4); @@ -12996,9 +13081,16 @@ void clif_parse_OpenVending(int fd, struct map_session_data* sd) __attribute__(( /// 1 = open void clif_parse_OpenVending(int fd, struct map_session_data* sd) { short len = (short)RFIFOW(fd,2) - 85; - const char *message = RFIFOP(fd,4); - bool flag = (RFIFOB(fd,84) != 0) ? true : false; - const uint8 *data = RFIFOP(fd,85); + const char *message; + bool flag; + const uint8 *data; + + if (len < 1) + return; + + message = RFIFOP(fd,4); + flag = (RFIFOB(fd,84) != 0) ? true : false; + data = RFIFOP(fd,85); if( !flag ) sd->state.prevend = sd->state.workinprogress = 0; @@ -13091,12 +13183,14 @@ void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd) __a void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd) { int i; + int count = (RFIFOW(fd, 2) - 4) / 40; - if(!sd->state.gmaster_flag) + if (!sd->state.gmaster_flag) return; - for(i = 4; i < RFIFOW(fd,2); i += 40 ){ - guild->change_position(sd->status.guild_id, RFIFOL(fd,i), RFIFOL(fd,i+4), RFIFOL(fd,i+12), RFIFOP(fd,i+16)); + for (i = 0; i < count; i ++ ) { + int idx = i * 40 + 4; + guild->change_position(sd->status.guild_id, RFIFOL(fd, idx), RFIFOL(fd, idx + 4), RFIFOL(fd, idx + 12), RFIFOP(fd, idx + 16)); } } @@ -13107,6 +13201,7 @@ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd) { int i; int len = RFIFOW(fd, 2); + int count = (len - 4) / 12; if(!sd->state.gmaster_flag) return; @@ -13117,10 +13212,11 @@ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd) return; } - for(i=4;i<RFIFOW(fd,2);i+=12){ - int position = RFIFOL(fd, i + 8); - if (position > 0) { - guild->change_memberposition(sd->status.guild_id, RFIFOL(fd, i), RFIFOL(fd, i + 4), position); + for (i = 0; i < count; i++) { + int idx = i * 12 + 4; + int position = RFIFOL(fd, idx + 8); + if (position > 0 && position < MAX_GUILDPOSITION) { + guild->change_memberposition(sd->status.guild_id, RFIFOL(fd, idx), RFIFOL(fd, idx + 4), position); } } } @@ -13323,6 +13419,12 @@ bool clif_sub_guild_invite(int fd, struct map_session_data *sd, struct map_sessi return false; } + // Players in a clan can't join a guild + if (t_sd->clan != NULL) { + clif->message(fd, msg_fd(fd, 140)); // You can't join in a clan if you're in a guild. + return false; + } + guild->invite(sd,t_sd); return true; } @@ -13498,12 +13600,15 @@ void clif_parse_GuildBreak(int fd, struct map_session_data *sd) __attribute__((n /// key: /// now guild name; might have been (intended) email, since the /// field name and size is same as the one in CH_DELETE_CHAR. -void clif_parse_GuildBreak(int fd, struct map_session_data *sd) { +void clif_parse_GuildBreak(int fd, struct map_session_data *sd) +{ + char key[40]; if( map->list[sd->bl.m].flag.guildlock ) { clif->message(fd, msg_fd(fd,228)); // Guild modification is disabled in this map. return; } - guild->dobreak(sd, RFIFOP(fd,2)); + safestrncpy(key, RFIFOP(fd, 2), 40); + guild->dobreak(sd, key); } /// Pet @@ -14092,6 +14197,7 @@ void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd) /// Toggles a single friend online/offline [Skotlex] (ZC_FRIENDS_STATE). /// 0206 <account id>.L <char id>.L <state>.B +/// 0206 <account id>.L <char id>.L <state>.B <name>.24B /// state: /// 0 = online /// 1 = offline @@ -14111,7 +14217,13 @@ void clif_friendslist_toggle(struct map_session_data *sd,int account_id, int cha WFIFOW(fd, 0) = 0x206; WFIFOL(fd, 2) = sd->status.friends[i].account_id; WFIFOL(fd, 6) = sd->status.friends[i].char_id; - WFIFOB(fd,10) = !online; //Yeah, a 1 here means "logged off", go figure... + WFIFOB(fd, 10) = !online; //Yeah, a 1 here means "logged off", go figure... +#ifndef PACKETVER_ZERO +#if PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221) + memcpy(WFIFOP(fd, 11), sd->status.friends[i].name, NAME_LENGTH); +#endif +#endif // PACKETVER_ZERO + WFIFOSET(fd, packet_len(0x206)); } @@ -14128,22 +14240,30 @@ int clif_friendslist_toggle_sub(struct map_session_data *sd,va_list ap) /// Sends the whole friends list (ZC_FRIENDS_LIST). /// 0201 <packet len>.W { <account id>.L <char id>.L <name>.24B }* +/// 0201 <packet len>.W { <account id>.L <char id>.L }* void clif_friendslist_send(struct map_session_data *sd) { int i = 0, n, fd = sd->fd; +#if !defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221)) + const int offset = 8; +#else + const int offset = 32; +#endif nullpo_retv(sd); // Send friends list - WFIFOHEAD(fd, MAX_FRIENDS * 32 + 4); + WFIFOHEAD(fd, MAX_FRIENDS * offset + 4); WFIFOW(fd, 0) = 0x201; for(i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id; i++) { - WFIFOL(fd, 4 + 32 * i + 0) = sd->status.friends[i].account_id; - WFIFOL(fd, 4 + 32 * i + 4) = sd->status.friends[i].char_id; - memcpy(WFIFOP(fd, 4 + 32 * i + 8), &sd->status.friends[i].name, NAME_LENGTH); + WFIFOL(fd, 4 + offset * i + 0) = sd->status.friends[i].account_id; + WFIFOL(fd, 4 + offset * i + 4) = sd->status.friends[i].char_id; +#if !(!defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221))) + memcpy(WFIFOP(fd, 4 + offset * i + 8), &sd->status.friends[i].name, NAME_LENGTH); +#endif } if (i) { - WFIFOW(fd,2) = 4 + 32 * i; + WFIFOW(fd,2) = 4 + offset * i; WFIFOSET(fd, WFIFOW(fd,2)); } @@ -15252,17 +15372,19 @@ void clif_parse_Mail_winopen(int fd, struct map_session_data *sd) void clif_parse_Mail_send(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); /// Request to send mail (CZ_MAIL_SEND). /// 0248 <packet len>.W <recipient>.24B <title>.40B <body len>.B <body>.?B + void clif_parse_Mail_send(int fd, struct map_session_data *sd) { struct mail_message msg; int body_len; + int len = RFIFOW(fd, 2); if( !chrif->isconnected() ) return; if( sd->state.trading ) return; - if( RFIFOW(fd,2) < 69 ) { + if (len < 69) { ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id); return; } @@ -15278,6 +15400,11 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd) if (body_len > MAIL_BODY_LENGTH) body_len = MAIL_BODY_LENGTH; + if (body_len + 69 > len) { + ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id); + return; + } + memset(&msg, 0, sizeof(msg)); if (!mail->setattachment(sd, &msg)) { // Invalid Append condition clif->mail_send(sd->fd, true); // fail @@ -15783,15 +15910,24 @@ void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) fail = npc->cashshop_buy(sd, nameid, amount, points); #else int len = RFIFOW(fd,2); - int points = RFIFOL(fd,4); - int count = RFIFOW(fd,8); + int points; + int count; struct itemlist item_list = { 0 }; int i; - if( len < 10 || len != 10 + count * 4) { + if (len < 10) { + ShowWarning("Player %d sent incorrect cash shop buy packet (len %d)!\n", sd->status.char_id, len); + return; + } + + points = RFIFOL(fd, 4); + count = RFIFOW(fd, 8); + + if (len != 10 + count * 4) { ShowWarning("Player %d sent incorrect cash shop buy packet (len %d:%d)!\n", sd->status.char_id, len, 10 + count * 4); return; } + VECTOR_INIT(item_list); VECTOR_ENSURE(item_list, count, 1); for (i = 0; i < count; i++) { @@ -16516,15 +16652,15 @@ void clif_bg_message(struct battleground_data *bgd, int src_id, const char *name return; len = (int)strlen(mes); - Assert_retv(len <= INT16_MAX - NAME_LENGTH - 8); - buf = (unsigned char*)aMalloc((len + NAME_LENGTH + 8)*sizeof(unsigned char)); + Assert_retv(len <= INT16_MAX - NAME_LENGTH - 9); + buf = (unsigned char *)aCalloc(len + NAME_LENGTH + 9, sizeof(unsigned char)); - WBUFW(buf,0) = 0x2dc; - WBUFW(buf,2) = len + NAME_LENGTH + 8; - WBUFL(buf,4) = src_id; - memcpy(WBUFP(buf,8), name, NAME_LENGTH); - memcpy(WBUFP(buf,32), mes, len); // [!] no NUL terminator - clif->send(buf,WBUFW(buf,2), &sd->bl, BG); + WBUFW(buf, 0) = 0x2dc; + WBUFW(buf, 2) = len + NAME_LENGTH + 9; + WBUFL(buf, 4) = src_id; + safestrncpy(WBUFP(buf, 8), name, NAME_LENGTH); + safestrncpy(WBUFP(buf, 32), mes, len + 1); + clif->send(buf, WBUFW(buf, 2), &sd->bl, BG); aFree(buf); } @@ -16829,7 +16965,7 @@ void clif_parse_ItemListWindowSelected(int fd, struct map_session_data *sd) __at /// S 07e4 <length>.w <option>.l <val>.l {<index>.w <amount>.w).4b* void clif_parse_ItemListWindowSelected(int fd, struct map_session_data *sd) { - int n = ((int)RFIFOW(fd,2) - 12) / 4; + int n = ((int)RFIFOW(fd, 2) - 12) / 4; int type = RFIFOL(fd,4); int flag = RFIFOL(fd,8); // Button clicked: 0 = Cancel, 1 = OK struct itemlist item_list = { 0 }; @@ -16960,7 +17096,7 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) { char storename[MESSAGE_SIZE]; unsigned char result; int zenylimit; - unsigned int count, packet_len; + int count, packet_len; struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; packet_len = RFIFOW(fd,info->pos[0]); @@ -16968,7 +17104,7 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) { // TODO: Make this check global for all variable length packets. if( packet_len < 89 ) {// minimum packet length - ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 89U, packet_len, sd->bl.id); + ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 89U, packet_len, sd->bl.id); return; } @@ -16980,9 +17116,12 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) { // so that buyingstore_create knows, how many elements it has access to packet_len-= info->pos[4]; + if (packet_len < 0) + return; + if( packet_len%blocksize ) { - ShowError("clif_parse_ReqOpenBuyingStore: Unexpected item list size %u (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); + ShowError("clif_parse_ReqOpenBuyingStore: Unexpected item list size %d (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); return; } count = packet_len/blocksize; @@ -17151,14 +17290,15 @@ void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data* sd) { const unsigned int blocksize = 6; const uint8 *itemlist; int account_id; - unsigned int count, packet_len, buyer_id; + unsigned int buyer_id; + int count, packet_len; struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; packet_len = RFIFOW(fd,info->pos[0]); if( packet_len < 12 ) {// minimum packet length - ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 12U, packet_len, sd->bl.id); + ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 12U, packet_len, sd->bl.id); return; } @@ -17168,10 +17308,12 @@ void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data* sd) { // so that buyingstore_trade knows, how many elements it has access to packet_len-= info->pos[3]; + if (packet_len < 0) + return; if( packet_len%blocksize ) { - ShowError("clif_parse_ReqTradeBuyingStore: Unexpected item list size %u (account_id=%d, buyer_id=%d, block size=%u)\n", packet_len, sd->bl.id, account_id, blocksize); + ShowError("clif_parse_ReqTradeBuyingStore: Unexpected item list size %d (account_id=%d, buyer_id=%d, block size=%u)\n", packet_len, sd->bl.id, account_id, blocksize); return; } count = packet_len/blocksize; @@ -17290,14 +17432,15 @@ void clif_parse_SearchStoreInfo(int fd, struct map_session_data* sd) { const uint8* itemlist; const uint8* cardlist; unsigned char type; - unsigned int min_price, max_price, packet_len, count, item_count, card_count; + unsigned int min_price, max_price; + int packet_len, count, item_count, card_count; struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; packet_len = RFIFOW(fd,info->pos[0]); if( packet_len < 15 ) {// minimum packet length - ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 15U, packet_len, sd->bl.id); + ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 15U, packet_len, sd->bl.id); return; } @@ -17307,24 +17450,28 @@ void clif_parse_SearchStoreInfo(int fd, struct map_session_data* sd) { item_count = RFIFOB(fd,info->pos[4]); card_count = RFIFOB(fd,info->pos[5]); itemlist = RFIFOP(fd,info->pos[6]); - cardlist = RFIFOP(fd,info->pos[6]+blocksize*item_count); // check, if there is enough data for the claimed count of items packet_len-= info->pos[6]; + if (packet_len < 0) + return; + if( packet_len%blocksize ) { - ShowError("clif_parse_SearchStoreInfo: Unexpected item list size %u (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); + ShowError("clif_parse_SearchStoreInfo: Unexpected item list size %d (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); return; } count = packet_len/blocksize; if( count < item_count+card_count ) { - ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected count=%u, count=%u, account_id=%d).\n", item_count+card_count, count, sd->bl.id); + ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected count=%d, count=%d, account_id=%d).\n", item_count+card_count, count, sd->bl.id); return; } + cardlist = RFIFOP(fd, info->pos[6] + blocksize * item_count); + searchstore->query(sd, type, min_price, max_price, (const unsigned short*)itemlist, item_count, (const unsigned short*)cardlist, card_count); } @@ -17944,16 +18091,30 @@ void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd) #endif } +/// R 0848 <len>.W <limit>.W <kafra pay>.L (<item id>.L <amount>.L <tab>.W)* void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { - unsigned short limit = RFIFOW(fd, 4), i, j; - unsigned int kafra_pay = RFIFOL(fd, 6);// [Ryuuzaki] - These are free cash points (strangely #CASH = main cash currently for us, confusing) + int len = RFIFOW(fd, 2); + unsigned short limit, i, j; + unsigned int kafra_pay; + int count; if (map->list[sd->bl.m].flag.nocashshop) { clif->messagecolor_self(fd, COLOR_RED, msg_fd(fd,1489)); //Cash Shop is disabled in this map return; } + if (len < 10) + return; + + limit = RFIFOW(fd, 4); + kafra_pay = RFIFOL(fd, 6); // [Ryuuzaki] - These are free cash points (strangely #CASH = main cash currently for us, confusing) + count = (len - 10) / 10; + if (count != limit) { + ShowError("Wrong cash shop limit: %d\n", limit); + return; + } + for(i = 0; i < limit; i++) { int qty = RFIFOL(fd, 14 + ( i * 10 )); int id = RFIFOL(fd, 10 + ( i * 10 )); @@ -18425,19 +18586,19 @@ void clif_parse_BankWithdraw(int fd, struct map_session_data *sd) void clif_parse_BankCheck(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); void clif_parse_BankCheck(int fd, struct map_session_data* sd) { -#if PACKETVER >= 20130313 +#if PACKETVER >= 20130320 struct packet_banking_check p; + p.PacketType = banking_checkType; if (!battle_config.feature_banking) { - clif->messagecolor_self(fd, COLOR_RED, msg_fd(fd,1483)); - return; + p.Money = 0; + p.Reason = (short)1; + } else { + p.Money = (int)sd->status.bank_vault; + p.Reason = (short)0; } - p.PacketType = banking_checkType; - p.Money = (int)sd->status.bank_vault; - p.Reason = (short)0; - - clif->send(&p,sizeof(p), &sd->bl, SELF); + clif->send(&p, sizeof(p), &sd->bl, SELF); #endif } @@ -19265,6 +19426,156 @@ const char *clif_get_bl_name(const struct block_list *bl) return name; } +/** + * Clan System: Sends the basic clan informations to client. + * 098a <length>.W <clan id>.L <clan name>.24B <clan master>.24B <clan map>.16B <alliance count>.B + * <antagonist count>.B { <alliance>.24B } * alliance count { <antagonist>.24B } * antagonist count (ZC_CLANINFO) + */ +void clif_clan_basicinfo(struct map_session_data *sd) +{ +#if PACKETVER >= 20120716 + int len, i, fd; + struct clan *c, *ally, *antagonist; + struct PACKET_ZC_CLANINFO *packet = NULL; + + nullpo_retv(sd); + nullpo_retv(c = sd->clan); + + len = sizeof(struct PACKET_ZC_CLANINFO); + fd = sd->fd; + + WFIFOHEAD(fd, len); + packet = WFIFOP(fd, 0); + + packet->PacketType = clanBasicInfo; + packet->ClanID = c->clan_id; + + safestrncpy(packet->ClanName, c->name, NAME_LENGTH); + safestrncpy(packet->MasterName, c->master, NAME_LENGTH); + + mapindex->getmapname_ext(c->map, packet->Map); + + packet->AllyCount = VECTOR_LENGTH(c->allies); + packet->AntagonistCount = VECTOR_LENGTH(c->antagonists); + + // All allies and antagonists are assumed as valid entries + // since it only gets inside the vector after the validation + // on clan->config_read + for (i = 0; i < VECTOR_LENGTH(c->allies); i++) { + struct clan_relationship *al = &VECTOR_INDEX(c->allies, i); + + if ((ally = clan->search(al->clan_id)) != NULL) { + safestrncpy(WFIFOP(fd, len), ally->name, NAME_LENGTH); + len += NAME_LENGTH; + } + } + + for (i = 0; i < VECTOR_LENGTH(c->antagonists); i++) { + struct clan_relationship *an = &VECTOR_INDEX(c->antagonists, i); + + if ((antagonist = clan->search(an->clan_id)) != NULL) { + safestrncpy(WFIFOP(fd, len), antagonist->name, NAME_LENGTH); + len += NAME_LENGTH; + } + } + + packet->PacketLength = len; + WFIFOSET(fd, len); +#endif +} + +/** + * Clan System: Updates the online and maximum player count of a clan. + * 0988 <online count>.W <maximum member amount>.W (ZC_NOTIFY_CLAN_CONNECTINFO) + */ +void clif_clan_onlinecount(struct clan *c) +{ +#if PACKETVER >= 20120716 + struct map_session_data *sd; + struct PACKET_ZC_NOTIFY_CLAN_CONNECTINFO p; + + nullpo_retv(c); + + p.PacketType = clanOnlineCount; + p.NumConnect = c->connect_member; + p.NumTotal = c->max_member; + + if ((sd = clan->getonlinesd(c)) != NULL) { + clif->send(&p, sizeof(p), &sd->bl, CLAN); + } +#endif +} + +/** +* Clan System: Notifies the client that the player has left his clan. +* 0989 (ZC_ACK_CLAN_LEAVE) +**/ +void clif_clan_leave(struct map_session_data* sd) +{ +#if PACKETVER >= 20131223 + struct PACKET_ZC_ACK_CLAN_LEAVE p; + + nullpo_retv(sd); + + p.PacketType = clanLeave; + + clif->send(&p, sizeof(p), &sd->bl, SELF); +#endif +} + +/** + * Clan System: Sends a clan message to a player + * 098e <length>.W <name>.24B <message>.?B (ZC_NOTIFY_CLAN_CHAT) + */ +void clif_clan_message(struct clan *c, const char *mes, int len) +{ +#if PACKETVER >= 20120716 + struct map_session_data *sd; + struct PACKET_ZC_NOTIFY_CLAN_CHAT *p; + unsigned int max_len = CHAT_SIZE_MAX - 5 - NAME_LENGTH; + int packet_length; + + nullpo_retv(c); + nullpo_retv(mes); + + if (len == 0) { + return; + } else if (len > max_len) { + ShowWarning("clif_clan_message: Truncated message '%s' (len=%d, max=%u, clan_id=%d).\n", mes, len, max_len, c->clan_id); + len = max_len; + } + + packet_length = sizeof(*p) + len + 1; + p = (struct PACKET_ZC_NOTIFY_CLAN_CHAT *)aMalloc(packet_length); + p->PacketType = clanMessage; + p->PacketLength = packet_length; + // p->MemberName is being ignored on the client side. + safestrncpy(p->Message, mes, len + 1); + + if ((sd = clan->getonlinesd(c)) != NULL) + clif->send(p, packet_length, &sd->bl, CLAN); + aFree(p); +#endif +} + +void clif_parse_ClanMessage(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); +/** + * Clan System: Parses a clan message from a player. + * 098d <length>.W <text>.?B (<name> : <message>) (CZ_CLAN_CHAT) + */ +void clif_parse_ClanMessage(int fd, struct map_session_data *sd) +{ +#if PACKETVER >= 20120716 + const struct packet_chat_message *packet = RP2PTR(fd); + char message[CHAT_SIZE_MAX + NAME_LENGTH + 3 + 1]; + + if (clif->process_chat_message(sd, packet, message, sizeof(message)) == NULL) + return; + + clan->send_message(sd, message); +#endif +} + /* */ unsigned short clif_decrypt_cmd( int cmd, struct map_session_data *sd ) { if( sd ) { @@ -19520,7 +19831,7 @@ void clif_rodex_send_maillist(int fd, struct map_session_data *sd, int8 open_typ continue; inner->MailID = msg->id; - inner->Isread = msg->is_read == true ? 1 : 0; + inner->Isread = (msg->is_read == true || msg->sender_read == true) ? 1 : 0; inner->type = msg->type; #if PACKETVER >= 20170419 inner->openType = msg->opentype; @@ -19552,7 +19863,7 @@ void clif_rodex_send_maillist(int fd, struct map_session_data *sd, int8 open_typ #endif } -void clif_rodex_send_mails_all(int fd, struct map_session_data *sd) +void clif_rodex_send_mails_all(int fd, struct map_session_data *sd, int64 mail_id) { #if PACKETVER >= 20170419 struct PACKET_ZC_MAIL_LIST *packet; @@ -19560,18 +19871,24 @@ void clif_rodex_send_mails_all(int fd, struct map_session_data *sd) int16 size = sizeof(*packet); int packetMailCount = 0; int mailListCount = 0; - int mailsSize = VECTOR_LENGTH(sd->rodex.messages); - int i; + int mailsSize, i; + int j = -1; nullpo_retv(sd); + mailsSize = VECTOR_LENGTH(sd->rodex.messages); + + if (mail_id > 0) + ARR_FIND(0, VECTOR_LENGTH(sd->rodex.messages), j, (VECTOR_INDEX(sd->rodex.messages, j)).id == mail_id); + WFIFOHEAD(fd, sizeof(*packet) + (sizeof(*inner) + RODEX_TITLE_LENGTH) * RODEX_MAIL_PER_PAGE); packet = WFIFOP(fd, 0); packet->PacketType = rodexmailList; inner = WFIFOP(fd, size); i = mailsSize - 1; - while (i >= 0) { + mailsSize -= (j + 1); + while (i > j) { struct rodex_message *msg = &VECTOR_INDEX(sd->rodex.messages, i); --i; @@ -19579,7 +19896,7 @@ void clif_rodex_send_mails_all(int fd, struct map_session_data *sd) continue; inner->MailID = msg->id; - inner->Isread = msg->is_read == true ? 1 : 0; + inner->Isread = (msg->is_read == true || msg->sender_read == true) ? 1 : 0; inner->type = msg->type; inner->openType = msg->opentype; inner->expireDateTime = msg->expire_date - (int)time(NULL); @@ -19646,7 +19963,7 @@ void clif_rodex_send_refresh(int fd, struct map_session_data *sd, int8 open_type continue; inner->MailID = msg->id; - inner->Isread = msg->is_read == true ? 1 : 0; + inner->Isread = (msg->is_read == true || msg->sender_read == true) ? 1 : 0; inner->type = msg->type; #if PACKETVER >= 20170419 inner->openType = msg->opentype; @@ -20117,10 +20434,22 @@ void packetdb_loaddb(void) { #define packet(id, size, ...) packetdb_addpacket((id), (size), ##__VA_ARGS__, 0xFFFF) #include "packets.h" /* load structure data */ -#include "packets_shuffle.h" +#ifdef PACKETVER_ZERO +#include "packets_shuffle_zero.h" +#else // PACKETVER_ZERO +#include "packets_shuffle_main.h" +#endif // PACKETVER_ZERO #undef packet #define packetKeys(a,b,c) do { clif->cryptKey[0] = (a); clif->cryptKey[1] = (b); clif->cryptKey[2] = (c); } while(0) -#include "packets_keys.h" +#if defined(OBFUSCATIONKEY1) && defined(OBFUSCATIONKEY2) && defined(OBFUSCATIONKEY3) + packetKeys(OBFUSCATIONKEY1,OBFUSCATIONKEY2,OBFUSCATIONKEY3); +#else // defined(OBFUSCATIONKEY1) && defined(OBFUSCATIONKEY2) && defined(OBFUSCATIONKEY3) +#ifdef PACKETVER_ZERO +#include "packets_keys_zero.h" +#else // PACKETVER_ZERO +#include "packets_keys_main.h" +#endif // PACKETVER_ZERO +#endif // defined(OBFUSCATIONKEY1) && defined(OBFUSCATIONKEY2) && defined(OBFUSCATIONKEY3) #undef packetKeys } void clif_bc_ready(void) { @@ -20367,6 +20696,7 @@ void clif_defaults(void) { clif->font = clif_font; clif->progressbar = clif_progressbar; clif->progressbar_abort = clif_progressbar_abort; + clif->progressbar_unit = clif_progressbar_unit; clif->showdigit = clif_showdigit; clif->elementalconverter_list = clif_elementalconverter_list; clif->spellbook_list = clif_spellbook_list; @@ -20976,4 +21306,10 @@ void clif_defaults(void) { clif->rodex_icon = clif_rodex_icon; clif->rodex_send_mails_all = clif_rodex_send_mails_all; clif->skill_scale = clif_skill_scale; + // -- Clan system + clif->clan_basicinfo = clif_clan_basicinfo; + clif->clan_onlinecount = clif_clan_onlinecount; + clif->clan_leave = clif_clan_leave; + clif->clan_message = clif_clan_message; + clif->pClanMessage = clif_parse_ClanMessage; } |