diff options
Diffstat (limited to 'src/map/clif.cpp')
-rw-r--r-- | src/map/clif.cpp | 4498 |
1 files changed, 2337 insertions, 2161 deletions
diff --git a/src/map/clif.cpp b/src/map/clif.cpp index eb008e4..e7557c8 100644 --- a/src/map/clif.cpp +++ b/src/map/clif.cpp @@ -20,29 +20,35 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. -#include <arpa/inet.h> - -#include <cstdlib> -#include <cstring> +#include <cassert> #include <ctime> -#include "../compat/alg.hpp" +#include <algorithm> + #include "../compat/attr.hpp" #include "../compat/fun.hpp" #include "../compat/nullpo.hpp" +#include "../ints/cmp.hpp" + #include "../strings/astring.hpp" #include "../strings/zstring.hpp" #include "../strings/xstring.hpp" -#include "../generic/random.hpp" - #include "../io/cxxstdio.hpp" #include "../io/write.hpp" +#include "../net/ip.hpp" +#include "../net/packets.hpp" +#include "../net/socket.hpp" +#include "../net/timer.hpp" + +#include "../proto2/any-user.hpp" +#include "../proto2/char-map.hpp" +#include "../proto2/map-user.hpp" + #include "../mmo/md5more.hpp" -#include "../mmo/socket.hpp" -#include "../mmo/timer.hpp" +#include "../mmo/utils.hpp" #include "../mmo/version.hpp" #include "atcommand.hpp" @@ -51,6 +57,7 @@ #include "intif.hpp" #include "itemdb.hpp" #include "magic.hpp" +#include "magic-stmt.hpp" #include "map.hpp" #include "npc.hpp" #include "party.hpp" @@ -62,8 +69,9 @@ #include "../poison.hpp" -#define DUMP_UNKNOWN_PACKET 1 +namespace tmwa +{ constexpr int EMOTE_IGNORED = 0x0e; // functions list. Rate is how many milliseconds are required between @@ -71,20 +79,20 @@ constexpr int EMOTE_IGNORED = 0x0e; // map.h must be the same length as this table. rate 0 is default // rate -1 is unlimited -typedef void (*clif_func)(Session *s, dumb_ptr<map_session_data> sd); +typedef RecvResult (*clif_func)(Session *s, dumb_ptr<map_session_data> sd); struct func_table { interval_t rate; - int len; + uint16_t len_unused; clif_func func; // ctor exists because interval_t must be explicit - func_table(int r, int l, clif_func f) - : rate(r), len(l), func(f) + func_table(int r, uint16_t l, clif_func f) + : rate(r), len_unused(l), func(f) {} }; -constexpr int VAR = -1; +constexpr uint16_t VAR = 1; extern // not really - defined below func_table clif_parse_func_table[0x0220]; @@ -107,36 +115,6 @@ enum class SendWho SELF, }; -inline -void WBUFPOS(uint8_t *p, size_t pos, uint16_t x, uint16_t y) -{ - p += pos; - p[0] = x >> 2; - p[1] = (x << 6) | ((y >> 4) & 0x3f); - p[2] = y << 4; -} -inline -void WBUFPOS2(uint8_t *p, size_t pos, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) -{ - p += pos; - p[0] = x0 >> 2; - p[1] = (x0 << 6) | ((y0 >> 4) & 0x3f); - p[2] = (y0 << 4) | ((x1 >> 6) & 0x0f); - p[3] = (x1 << 2) | ((y1 >> 8) & 0x03); - p[4] = y1; -} - -inline -void WFIFOPOS(Session *s, size_t pos, uint16_t x, uint16_t y) -{ - WBUFPOS(static_cast<uint8_t *>(WFIFOP(s, pos)), 0, x, y); -} -inline -void WFIFOPOS2(Session *s, size_t pos, uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1) -{ - WBUFPOS2(static_cast<uint8_t *>(WFIFOP(s, pos)), 0, x0, y0, x1, y1); -} - static IP4Address map_ip; static @@ -159,11 +137,11 @@ void clif_delete(Session *s) pc_logout(sd); clif_quitsave(s, sd); - PRINTF("Player [%s] has logged off your server.\n", sd->status_key.name); // Player logout display [Valaris] + PRINTF("Player [%s] has logged off your server.\n"_fmt, sd->status_key.name); // Player logout display [Valaris] } else if (sd) { // not authentified! (refused by char-server or disconnect before to be authentified) - PRINTF("Player with account [%d] has logged off your server (not auth account).\n", sd->bl_id); // Player logout display [Yor] + PRINTF("Player with account [%d] has logged off your server (not auth account).\n"_fmt, sd->bl_id); // Player logout display [Yor] map_deliddb(sd); // account_id has been included in the DB before auth answer } } @@ -265,14 +243,14 @@ enum class ChatType }; static -AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type); +AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type, XString buf); /*========================================== * clif_sendでSendWho::AREA*指定時用 *------------------------------------------ */ static -void clif_send_sub(dumb_ptr<block_list> bl, const unsigned char *buf, int len, +void clif_send_sub(dumb_ptr<block_list> bl, const Buffer& buf, dumb_ptr<block_list> src_bl, SendWho type) { nullpo_retv(bl); @@ -299,14 +277,11 @@ void clif_send_sub(dumb_ptr<block_list> bl, const unsigned char *buf, int len, break; } - if (sd->sess != NULL) + if (sd->sess != nullptr) { { - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); } } } @@ -317,14 +292,14 @@ void clif_send_sub(dumb_ptr<block_list> bl, const unsigned char *buf, int len, *------------------------------------------ */ static -int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type) +int clif_send(const Buffer& buf, dumb_ptr<block_list> bl, SendWho type) { - struct party *p = NULL; + PartyPair p; int x0 = 0, x1 = 0, y0 = 0, y1 = 0; if (type != SendWho::ALL_CLIENT) { - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) { @@ -360,11 +335,8 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); if (sd && sd->state.auth) { - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); + send_buffer(s, buf); } } } @@ -378,25 +350,22 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); if (sd && sd->state.auth && sd->bl_m == bl->bl_m) { - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); + send_buffer(s, buf); } } } break; case SendWho::AREA: case SendWho::AREA_WOS: - map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, len, bl, type), + map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, bl, type), bl->bl_m, bl->bl_x - AREA_SIZE, bl->bl_y - AREA_SIZE, bl->bl_x + AREA_SIZE, bl->bl_y + AREA_SIZE, BL::PC); break; case SendWho::AREA_CHAT_WOC: - map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, len, bl, SendWho::AREA_CHAT_WOC), + map_foreachinarea(std::bind(clif_send_sub, ph::_1, buf, bl, SendWho::AREA_CHAT_WOC), bl->bl_m, bl->bl_x - (AREA_SIZE), bl->bl_y - (AREA_SIZE), bl->bl_x + (AREA_SIZE), bl->bl_y + (AREA_SIZE), @@ -417,13 +386,13 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type if (bl->bl_type == BL::PC) { dumb_ptr<map_session_data> sd = bl->is_player(); - if (sd->partyspy > 0) + if (sd->partyspy) { p = party_search(sd->partyspy); } else { - if (sd->status.party_id > 0) + if (sd->status.party_id) p = party_search(sd->status.party_id); } } @@ -444,11 +413,8 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type (sd->bl_x < x0 || sd->bl_y < y0 || sd->bl_x > x1 || sd->bl_y > y1)) continue; - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); } } } @@ -460,13 +426,10 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); if (sd && sd->state.auth) { - if (sd->partyspy == p->party_id) + if (sd->partyspy == p.party_id) { - if (clif_parse_func_table[RBUFW(buf, 0)].len) { - // packet must exist - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); } } } @@ -476,18 +439,16 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type case SendWho::SELF: { dumb_ptr<map_session_data> sd = bl->is_player(); - if (clif_parse_func_table[RBUFW(buf, 0)].len) + { - // packet must exist - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); } } break; default: if (battle_config.error_log) - PRINTF("clif_send まだ作ってないよー\n"); + PRINTF("clif_send まだ作ってないよー\n"_fmt); return -1; } @@ -503,7 +464,7 @@ int clif_send(const uint8_t *buf, int len, dumb_ptr<block_list> bl, SendWho type */ int clif_authok(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); if (!sd) return 0; @@ -513,12 +474,12 @@ int clif_authok(dumb_ptr<map_session_data> sd) Session *s = sd->sess; - WFIFOW(s, 0) = 0x73; - WFIFOL(s, 2) = gettick().time_since_epoch().count(); - WFIFOPOS(s, 6, sd->bl_x, sd->bl_y); - WFIFOB(s, 9) = 5; - WFIFOB(s, 10) = 5; - WFIFOSET(s, clif_parse_func_table[0x73].len); + Packet_Fixed<0x0073> fixed_73; + fixed_73.tick = gettick(); + fixed_73.pos = Position1{static_cast<uint16_t>(sd->bl_x), static_cast<uint16_t>(sd->bl_y), DIR::S}; + fixed_73.five1 = 5; + fixed_73.five2 = 5; + send_fpacket<0x0073, 11>(s, fixed_73); return 0; } @@ -532,9 +493,9 @@ int clif_authfail_fd(Session *s, int type) if (!s) return 0; - WFIFOW(s, 0) = 0x81; - WFIFOL(s, 2) = type; - WFIFOSET(s, clif_parse_func_table[0x81].len); + Packet_Fixed<0x0081> fixed_81; + fixed_81.error_code = type; + send_fpacket<0x0081, 3>(s, fixed_81); clif_setwaitclose(s); @@ -545,20 +506,20 @@ int clif_authfail_fd(Session *s, int type) * *------------------------------------------ */ -int clif_charselectok(int id) +int clif_charselectok(BlockId id) { dumb_ptr<map_session_data> sd; - if ((sd = map_id2sd(id)) == NULL) + if ((sd = map_id2sd(id)) == nullptr) return 1; if (!sd->sess) return 1; Session *s = sd->sess; - WFIFOW(s, 0) = 0xb3; - WFIFOB(s, 2) = 1; - WFIFOSET(s, clif_parse_func_table[0xb3].len); + Packet_Fixed<0x00b3> fixed_b3; + fixed_b3.one = 1; + send_fpacket<0x00b3, 3>(s, fixed_b3); return 0; } @@ -568,22 +529,21 @@ int clif_charselectok(int id) *------------------------------------------ */ static -int clif_set009e(dumb_ptr<flooritem_data> fitem, uint8_t *buf) +void clif_set009e(dumb_ptr<flooritem_data> fitem, Buffer& buf) { - nullpo_ret(fitem); + nullpo_retv(fitem); - //009e <ID>.l <name ID>.w <identify flag>.B <X>.w <Y>.w <subX>.B <subY>.B <amount>.w - WBUFW(buf, 0) = 0x9e; - WBUFL(buf, 2) = fitem->bl_id; - WBUFW(buf, 6) = fitem->item_data.nameid; - WBUFB(buf, 8) = 1; //identify; - WBUFW(buf, 9) = fitem->bl_x; - WBUFW(buf, 11) = fitem->bl_y; - WBUFB(buf, 13) = fitem->subx; - WBUFB(buf, 14) = fitem->suby; - WBUFW(buf, 15) = fitem->item_data.amount; + Packet_Fixed<0x009e> fixed_9e; + fixed_9e.block_id = fitem->bl_id; + fixed_9e.name_id = fitem->item_data.nameid; + fixed_9e.identify = 1; + fixed_9e.x = fitem->bl_x; + fixed_9e.y = fitem->bl_y; + fixed_9e.subx = fitem->subx; + fixed_9e.suby = fitem->suby; + fixed_9e.amount = fitem->item_data.amount; - return clif_parse_func_table[0x9e].len; + buf = create_fpacket<0x009e, 17>(fixed_9e); } /*========================================== @@ -592,14 +552,14 @@ int clif_set009e(dumb_ptr<flooritem_data> fitem, uint8_t *buf) */ int clif_dropflooritem(dumb_ptr<flooritem_data> fitem) { - uint8_t buf[64]; + nullpo_retz(fitem); - nullpo_ret(fitem); - - if (fitem->item_data.nameid <= 0) + if (!fitem->item_data.nameid) return 0; + + Buffer buf; clif_set009e(fitem, buf); - clif_send(buf, clif_parse_func_table[0x9e].len, fitem, SendWho::AREA); + clif_send(buf, fitem, SendWho::AREA); return 0; } @@ -610,21 +570,19 @@ int clif_dropflooritem(dumb_ptr<flooritem_data> fitem) */ int clif_clearflooritem(dumb_ptr<flooritem_data> fitem, Session *s) { - unsigned char buf[16]; - - nullpo_ret(fitem); + nullpo_retz(fitem); - WBUFW(buf, 0) = 0xa1; - WBUFL(buf, 2) = fitem->bl_id; + Packet_Fixed<0x00a1> fixed_a1; + fixed_a1.block_id = fitem->bl_id; if (!s) { - clif_send(buf, clif_parse_func_table[0xa1].len, fitem, SendWho::AREA); + Buffer buf = create_fpacket<0x00a1, 6>(fixed_a1); + clif_send(buf, fitem, SendWho::AREA); } else { - WFIFO_BUF_CLONE(s, buf, 6); - WFIFOSET(s, clif_parse_func_table[0xa1].len); + send_fpacket<0x00a1, 6>(s, fixed_a1); } return 0; @@ -636,21 +594,22 @@ int clif_clearflooritem(dumb_ptr<flooritem_data> fitem, Session *s) */ int clif_clearchar(dumb_ptr<block_list> bl, BeingRemoveWhy type) { - unsigned char buf[16]; + nullpo_retz(bl); - nullpo_ret(bl); + Packet_Fixed<0x0080> fixed_80; + fixed_80.block_id = bl->bl_id; - WBUFW(buf, 0) = 0x80; - WBUFL(buf, 2) = bl->bl_id; if (type == BeingRemoveWhy::DISGUISE) { - WBUFB(buf, 6) = static_cast<uint8_t>(BeingRemoveWhy::GONE); - clif_send(buf, clif_parse_func_table[0x80].len, bl, SendWho::AREA); + fixed_80.type = BeingRemoveWhy::GONE; + Buffer buf = create_fpacket<0x0080, 7>(fixed_80); + clif_send(buf, bl, SendWho::AREA); } else { - WBUFB(buf, 6) = static_cast<uint8_t>(type); - clif_send(buf, clif_parse_func_table[0x80].len, bl, + fixed_80.type = type; + Buffer buf = create_fpacket<0x0080, 7>(fixed_80); + clif_send(buf, bl, type == BeingRemoveWhy::DEAD ? SendWho::AREA : SendWho::AREA_WOS); } @@ -692,12 +651,12 @@ int clif_clearchar_delay(tick_t tick, * *------------------------------------------ */ -void clif_clearchar_id(int id, BeingRemoveWhy type, Session *s) +void clif_clearchar_id(BlockId id, BeingRemoveWhy type, Session *s) { - WFIFOW(s, 0) = 0x80; - WFIFOL(s, 2) = id; - WFIFOB(s, 6) = static_cast<uint8_t>(type); - WFIFOSET(s, clif_parse_func_table[0x80].len); + Packet_Fixed<0x0080> fixed_80; + fixed_80.block_id = id; + fixed_80.type = type; + send_fpacket<0x0080, 7>(s, fixed_80); } /*========================================== @@ -705,59 +664,111 @@ void clif_clearchar_id(int id, BeingRemoveWhy type, Session *s) *------------------------------------------ */ static -int clif_set0078(dumb_ptr<map_session_data> sd, unsigned char *buf) +void clif_set0078_main_1d8(dumb_ptr<map_session_data> sd, Buffer& buf) { - nullpo_ret(sd); + nullpo_retv(sd); - WBUFW(buf, 0) = 0x1d8; - WBUFL(buf, 2) = sd->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(sd->speed.count()); - WBUFW(buf, 8) = static_cast<uint16_t>(sd->opt1); - WBUFW(buf, 10) = static_cast<uint16_t>(sd->opt2); - WBUFW(buf, 12) = static_cast<uint16_t>(sd->status.option); - WBUFW(buf, 14) = sd->status.species; - WBUFW(buf, 16) = sd->status.hair; + Packet_Fixed<0x01d8> fixed_1d8; + fixed_1d8.block_id = sd->bl_id; + fixed_1d8.speed = sd->speed; + fixed_1d8.opt1 = sd->opt1; + fixed_1d8.opt2 = sd->opt2; + fixed_1d8.option = sd->status.option; + fixed_1d8.species = sd->status.species; + fixed_1d8.hair_style = sd->status.hair; + + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + if (sd->attack_spell_override) + fixed_1d8.weapon = sd->attack_spell_look_override; + else + { + if (widx.ok() && sd->inventory_data[widx]) + { + fixed_1d8.weapon = sd->status.inventory[widx].nameid; + } + else + fixed_1d8.weapon = ItemNameId(); + } + if (sidx.ok() && sidx != widx && sd->inventory_data[sidx]) + { + fixed_1d8.shield = sd->status.inventory[sidx].nameid; + } + else + fixed_1d8.shield = ItemNameId(); + fixed_1d8.head_bottom = sd->status.head_bottom; + fixed_1d8.head_top = sd->status.head_top; + fixed_1d8.head_mid = sd->status.head_mid; + fixed_1d8.hair_color = sd->status.hair_color; + fixed_1d8.clothes_color = sd->status.clothes_color; + fixed_1d8.head_dir = sd->head_dir; + fixed_1d8.guild_id = 0; + fixed_1d8.guild_emblem_id = 0; + fixed_1d8.manner = sd->status.manner; + fixed_1d8.opt3 = sd->opt3; + fixed_1d8.karma = sd->status.karma; + fixed_1d8.sex = sd->sex; + fixed_1d8.pos.x = sd->bl_x; + fixed_1d8.pos.y = sd->bl_y; + fixed_1d8.pos.dir = sd->dir; + fixed_1d8.gm_bits = pc_isGM(sd).get_public_word(); + fixed_1d8.dead_sit = sd->state.dead_sit; + fixed_1d8.unused = 0; + + buf = create_fpacket<0x01d8, 54>(fixed_1d8); +} +static +void clif_set0078_alt_1d9(dumb_ptr<map_session_data> sd, Buffer& buf) +{ + nullpo_retv(sd); - int widx = sd->equip_index_maybe[EQUIP::WEAPON]; - int sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + Packet_Fixed<0x01d9> fixed_1d8; // LIES + fixed_1d8.block_id = sd->bl_id; + fixed_1d8.speed = sd->speed; + fixed_1d8.opt1 = sd->opt1; + fixed_1d8.opt2 = sd->opt2; + fixed_1d8.option = sd->status.option; + fixed_1d8.species = sd->status.species; + fixed_1d8.hair_style = sd->status.hair; + + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; if (sd->attack_spell_override) - WBUFW(buf, 18) = sd->attack_spell_look_override; + fixed_1d8.weapon = sd->attack_spell_look_override; else { - if (widx >= 0 && sd->inventory_data[widx]) + if (widx.ok() && sd->inventory_data[widx]) { - WBUFW(buf, 18) = sd->status.inventory[widx].nameid; + fixed_1d8.weapon = sd->status.inventory[widx].nameid; } else - WBUFW(buf, 18) = 0; + fixed_1d8.weapon = ItemNameId(); } - if (sidx >= 0 && sidx != widx && sd->inventory_data[sidx]) + if (sidx.ok() && sidx != widx && sd->inventory_data[sidx]) { - WBUFW(buf, 20) = sd->status.inventory[sidx].nameid; + fixed_1d8.shield = sd->status.inventory[sidx].nameid; } else - WBUFW(buf, 20) = 0; - WBUFW(buf, 22) = sd->status.head_bottom; - WBUFW(buf, 24) = sd->status.head_top; - WBUFW(buf, 26) = sd->status.head_mid; - WBUFW(buf, 28) = sd->status.hair_color; - WBUFW(buf, 30) = sd->status.clothes_color; - WBUFW(buf, 32) = static_cast<uint8_t>(sd->head_dir); - WBUFL(buf, 34) = 0 /*guild_id*/; - WBUFW(buf, 38) = 0 /*guild_emblem_id*/; - WBUFW(buf, 40) = sd->status.manner; - WBUFW(buf, 42) = static_cast<uint16_t>(sd->opt3); - WBUFB(buf, 44) = sd->status.karma; - WBUFB(buf, 45) = static_cast<uint8_t>(sd->sex); - WBUFPOS(buf, 46, sd->bl_x, sd->bl_y); - // work around ICE in gcc 4.6 - uint8_t dir = static_cast<uint8_t>(sd->dir); - WBUFB(buf, 48) |= dir; - WBUFW(buf, 49) = (pc_isGM(sd) == 60 || pc_isGM(sd) == 99) ? 0x80 : 0; - WBUFB(buf, 51) = sd->state.dead_sit; - WBUFW(buf, 52) = 0; - - return clif_parse_func_table[0x1d8].len; + fixed_1d8.shield = ItemNameId(); + fixed_1d8.head_bottom = sd->status.head_bottom; + fixed_1d8.head_top = sd->status.head_top; + fixed_1d8.head_mid = sd->status.head_mid; + fixed_1d8.hair_color = sd->status.hair_color; + fixed_1d8.clothes_color = sd->status.clothes_color; + fixed_1d8.head_dir = sd->head_dir; + fixed_1d8.guild_id = 0; + fixed_1d8.guild_emblem_id = 0; + fixed_1d8.manner = sd->status.manner; + fixed_1d8.opt3 = sd->opt3; + fixed_1d8.karma = sd->status.karma; + fixed_1d8.sex = sd->sex; + fixed_1d8.pos.x = sd->bl_x; + fixed_1d8.pos.y = sd->bl_y; + fixed_1d8.pos.dir = sd->dir; + fixed_1d8.gm_bits = pc_isGM(sd).get_public_word(); + fixed_1d8.unused = 0; + + buf = create_fpacket<0x01d9, 53>(fixed_1d8); } /*========================================== @@ -765,51 +776,54 @@ int clif_set0078(dumb_ptr<map_session_data> sd, unsigned char *buf) *------------------------------------------ */ static -int clif_set007b(dumb_ptr<map_session_data> sd, unsigned char *buf) -{ - nullpo_ret(sd); - - WBUFW(buf, 0) = 0x1da; - WBUFL(buf, 2) = sd->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(sd->speed.count()); - WBUFW(buf, 8) = static_cast<uint16_t>(sd->opt1); - WBUFW(buf, 10) = static_cast<uint16_t>(sd->opt2); - WBUFW(buf, 12) = static_cast<uint16_t>(sd->status.option); - WBUFW(buf, 14) = sd->status.species; - WBUFW(buf, 16) = sd->status.hair; - int widx = sd->equip_index_maybe[EQUIP::WEAPON]; - int sidx = sd->equip_index_maybe[EQUIP::SHIELD]; - if (widx >= 0 && sd->inventory_data[widx]) +void clif_set007b(dumb_ptr<map_session_data> sd, Buffer& buf) +{ + nullpo_retv(sd); + + Packet_Fixed<0x01da> fixed_1da; + fixed_1da.block_id = sd->bl_id; + fixed_1da.speed = sd->speed; + fixed_1da.opt1 = sd->opt1; + fixed_1da.opt2 = sd->opt2; + fixed_1da.option = sd->status.option; + fixed_1da.species = sd->status.species; + fixed_1da.hair_style = sd->status.hair; + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + if (widx.ok() && sd->inventory_data[widx]) { - WBUFW(buf, 18) = sd->status.inventory[widx].nameid; + fixed_1da.weapon = sd->status.inventory[widx].nameid; } else - WBUFW(buf, 18) = 0; - if (sidx >= 0 && sidx != widx && sd->inventory_data[sidx]) + fixed_1da.weapon = ItemNameId(); + if (sidx.ok() && sidx != widx && sd->inventory_data[sidx]) { - WBUFW(buf, 20) = sd->status.inventory[sidx].nameid; + fixed_1da.shield = sd->status.inventory[sidx].nameid; } else - WBUFW(buf, 20) = 0; - WBUFW(buf, 22) = sd->status.head_bottom; - WBUFL(buf, 24) = gettick().time_since_epoch().count(); - WBUFW(buf, 28) = sd->status.head_top; - WBUFW(buf, 30) = sd->status.head_mid; - WBUFW(buf, 32) = sd->status.hair_color; - WBUFW(buf, 34) = sd->status.clothes_color; - WBUFW(buf, 36) = static_cast<uint8_t>(sd->head_dir); - WBUFL(buf, 38) = 0/*guild_id*/; - WBUFW(buf, 42) = 0/*guild_emblem_id*/; - WBUFW(buf, 44) = sd->status.manner; - WBUFW(buf, 46) = static_cast<uint16_t>(sd->opt3); - WBUFB(buf, 48) = sd->status.karma; - WBUFB(buf, 49) = static_cast<uint8_t>(sd->sex); - WBUFPOS2(buf, 50, sd->bl_x, sd->bl_y, sd->to_x, sd->to_y); - WBUFW(buf, 55) = pc_isGM(sd) == 60 ? 0x80 : 0; - WBUFB(buf, 57) = 5; - WBUFW(buf, 58) = 0; - - return clif_parse_func_table[0x1da].len; + fixed_1da.shield = ItemNameId(); + fixed_1da.head_bottom = sd->status.head_bottom; + fixed_1da.tick = gettick(); + fixed_1da.head_top = sd->status.head_top; + fixed_1da.head_mid = sd->status.head_mid; + fixed_1da.hair_color = sd->status.hair_color; + fixed_1da.clothes_color = sd->status.clothes_color; + fixed_1da.head_dir = sd->head_dir; + fixed_1da.guild_id = 0; + fixed_1da.guild_emblem_id = 0; + fixed_1da.manner = sd->status.manner; + fixed_1da.opt3 = sd->opt3; + fixed_1da.karma = sd->status.karma; + fixed_1da.sex = sd->sex; + fixed_1da.pos2.x0 = sd->bl_x; + fixed_1da.pos2.y0 = sd->bl_y; + fixed_1da.pos2.x1 = sd->to_x; + fixed_1da.pos2.y1 = sd->to_y; + fixed_1da.gm_bits = pc_isGM(sd).get_public_word(); + fixed_1da.five = 5; + fixed_1da.unused = 0; + + buf = create_fpacket<0x01da, 60>(fixed_1da); } /*========================================== @@ -817,30 +831,27 @@ int clif_set007b(dumb_ptr<map_session_data> sd, unsigned char *buf) *------------------------------------------ */ static -int clif_mob0078(dumb_ptr<mob_data> md, unsigned char *buf) +void clif_mob0078(dumb_ptr<mob_data> md, Buffer& buf) { - really_memset0(buf, clif_parse_func_table[0x78].len); - - nullpo_ret(md); + nullpo_retv(md); - WBUFW(buf, 0) = 0x78; - WBUFL(buf, 2) = md->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(battle_get_speed(md).count()); - WBUFW(buf, 8) = static_cast<uint16_t>(md->opt1); - WBUFW(buf, 10) = static_cast<uint16_t>(md->opt2); - WBUFW(buf, 12) = static_cast<uint16_t>(md->option); - WBUFW(buf, 14) = md->mob_class; + Packet_Fixed<0x0078> fixed_78; + fixed_78.block_id = md->bl_id; + fixed_78.speed = battle_get_speed(md); + fixed_78.opt1 = md->opt1; + fixed_78.opt2 = md->opt2; + fixed_78.option = md->option; + fixed_78.species = md->mob_class; // snip: stuff do do with disguise as a PC - WBUFPOS(buf, 46, md->bl_x, md->bl_y); - // work around ICE in gcc 4.6 - uint8_t dir = static_cast<uint8_t>(md->dir); - WBUFB(buf, 48) |= dir; - WBUFB(buf, 49) = 5; - WBUFB(buf, 50) = 5; + fixed_78.pos.x = md->bl_x; + fixed_78.pos.y = md->bl_y; + fixed_78.pos.dir = md->dir; + fixed_78.five1 = 5; + fixed_78.five2 = 5; int level = battle_get_lv(md); - WBUFW(buf, 52) = (level > battle_config.max_lv) ? battle_config.max_lv : level; + fixed_78.level = (level > battle_config.max_lv) ? battle_config.max_lv : level; - return clif_parse_func_table[0x78].len; + buf = create_fpacket<0x0078, 54>(fixed_78); } /*========================================== @@ -848,29 +859,30 @@ int clif_mob0078(dumb_ptr<mob_data> md, unsigned char *buf) *------------------------------------------ */ static -int clif_mob007b(dumb_ptr<mob_data> md, unsigned char *buf) +void clif_mob007b(dumb_ptr<mob_data> md, Buffer& buf) { - really_memset0(buf, clif_parse_func_table[0x7b].len); - - nullpo_ret(md); + nullpo_retv(md); - WBUFW(buf, 0) = 0x7b; - WBUFL(buf, 2) = md->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(battle_get_speed(md).count()); - WBUFW(buf, 8) = static_cast<uint16_t>(md->opt1); - WBUFW(buf, 10) = static_cast<uint16_t>(md->opt2); - WBUFW(buf, 12) = static_cast<uint16_t>(md->option); - WBUFW(buf, 14) = md->mob_class; + Packet_Fixed<0x007b> fixed_7b; + fixed_7b.block_id = md->bl_id; + fixed_7b.speed = battle_get_speed(md); + fixed_7b.opt1 = md->opt1; + fixed_7b.opt2 = md->opt2; + fixed_7b.option = md->option; + fixed_7b.mob_class = md->mob_class; // snip: stuff for monsters disguised as PCs - WBUFL(buf, 22) = gettick().time_since_epoch().count(); - - WBUFPOS2(buf, 50, md->bl_x, md->bl_y, md->to_x, md->to_y); - WBUFB(buf, 56) = 5; - WBUFB(buf, 57) = 5; + fixed_7b.tick_and_maybe_part_of_guild_emblem = gettick(); + + fixed_7b.pos2.x0 = md->bl_x; + fixed_7b.pos2.y0 = md->bl_y; + fixed_7b.pos2.x1 = md->to_x; + fixed_7b.pos2.y1 = md->to_y; + fixed_7b.five1 = 5; + fixed_7b.five2 = 5; int level = battle_get_lv(md); - WBUFW(buf, 58) = (level > battle_config.max_lv) ? battle_config.max_lv : level; + fixed_7b.level = (level > battle_config.max_lv) ? battle_config.max_lv : level; - return clif_parse_func_table[0x7b].len; + buf = create_fpacket<0x007b, 60>(fixed_7b); } /*========================================== @@ -878,24 +890,23 @@ int clif_mob007b(dumb_ptr<mob_data> md, unsigned char *buf) *------------------------------------------ */ static -int clif_npc0078(dumb_ptr<npc_data> nd, unsigned char *buf) +void clif_npc0078(dumb_ptr<npc_data> nd, Buffer& buf) { - nullpo_ret(nd); - - really_memset0(buf, clif_parse_func_table[0x78].len); + nullpo_retv(nd); - WBUFW(buf, 0) = 0x78; - WBUFL(buf, 2) = nd->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(nd->speed.count()); - WBUFW(buf, 14) = nd->npc_class; - WBUFPOS(buf, 46, nd->bl_x, nd->bl_y); - // work around ICE in gcc 4.6 - uint8_t dir = static_cast<uint8_t>(nd->dir); - WBUFB(buf, 48) |= dir; - WBUFB(buf, 49) = 5; - WBUFB(buf, 50) = 5; + Packet_Fixed<0x0078> fixed_78; + fixed_78.block_id = nd->bl_id; + fixed_78.speed = nd->speed; + fixed_78.species = nd->npc_class; + fixed_78.pos.x = nd->bl_x; + fixed_78.pos.y = nd->bl_y; + fixed_78.pos.dir = nd->dir; + fixed_78.five1 = 5; + fixed_78.five2 = 5; + fixed_78.zero = 0; + fixed_78.level = 0; - return clif_parse_func_table[0x78].len; + buf = create_fpacket<0x0078, 54>(fixed_78); } /* These indices are derived from equip_pos in pc.c and some guesswork */ @@ -924,15 +935,12 @@ earray<EQUIP, LOOK, LOOK::COUNT> equip_points //= */ int clif_spawnpc(dumb_ptr<map_session_data> sd) { - unsigned char buf[128]; + nullpo_retz(sd); - nullpo_ret(sd); + Buffer buf; + clif_set0078_alt_1d9(sd, buf); - clif_set0078(sd, buf); - - WBUFW(buf, 0) = 0x1d9; - WBUFW(buf, 51) = 0; - clif_send(buf, clif_parse_func_table[0x1d9].len, sd, SendWho::AREA_WOS); + clif_send(buf, sd, SendWho::AREA_WOS); if (sd->bl_m->flag.get(MapFlag::SNOW)) clif_specialeffect(sd, 162, 1); @@ -945,7 +953,7 @@ int clif_spawnpc(dumb_ptr<map_session_data> sd) if (sd->bl_m->flag.get(MapFlag::RAIN)) clif_specialeffect(sd, 161, 1); -// clif_changelook_accessories(sd, NULL); +// clif_changelook_accessories(sd, nullptr); return 0; } @@ -956,62 +964,64 @@ int clif_spawnpc(dumb_ptr<map_session_data> sd) */ int clif_spawnnpc(dumb_ptr<npc_data> nd) { - unsigned char buf[64]; - int len; - - nullpo_ret(nd); + nullpo_retz(nd); - if (nd->npc_class < 0 || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) + if (nd->npc_class == NEGATIVE_SPECIES || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) return 0; - really_memset0(buf, clif_parse_func_table[0x7c].len); + Packet_Fixed<0x007c> fixed_7c; + fixed_7c.block_id = nd->bl_id; + fixed_7c.speed = nd->speed; + fixed_7c.species = nd->npc_class; + fixed_7c.pos.x = nd->bl_x; + fixed_7c.pos.y = nd->bl_y; - WBUFW(buf, 0) = 0x7c; - WBUFL(buf, 2) = nd->bl_id; - WBUFW(buf, 6) = static_cast<uint16_t>(nd->speed.count()); - WBUFW(buf, 20) = nd->npc_class; - WBUFPOS(buf, 36, nd->bl_x, nd->bl_y); + Buffer buf = create_fpacket<0x007c, 41>(fixed_7c); + clif_send(buf, nd, SendWho::AREA); - clif_send(buf, clif_parse_func_table[0x7c].len, nd, SendWho::AREA); - - len = clif_npc0078(nd, buf); - clif_send(buf, len, nd, SendWho::AREA); + clif_npc0078(nd, buf); + clif_send(buf, nd, SendWho::AREA); return 0; } -int clif_spawn_fake_npc_for_player(dumb_ptr<map_session_data> sd, int fake_npc_id) +int clif_spawn_fake_npc_for_player(dumb_ptr<map_session_data> sd, BlockId fake_npc_id) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; if (!s) return 0; - WFIFOW(s, 0) = 0x7c; - WFIFOL(s, 2) = fake_npc_id; - WFIFOW(s, 6) = 0; - WFIFOW(s, 8) = 0; - WFIFOW(s, 10) = 0; - WFIFOW(s, 12) = 0; - WFIFOW(s, 20) = 127; - WFIFOPOS(s, 36, sd->bl_x, sd->bl_y); - WFIFOSET(s, clif_parse_func_table[0x7c].len); - - WFIFOW(s, 0) = 0x78; - WFIFOL(s, 2) = fake_npc_id; - WFIFOW(s, 6) = 0; - WFIFOW(s, 8) = 0; - WFIFOW(s, 10) = 0; - WFIFOW(s, 12) = 0; - WFIFOW(s, 14) = 127; // identifies as NPC - WFIFOW(s, 20) = 127; - WFIFOPOS(s, 46, sd->bl_x, sd->bl_y); - WFIFOPOS(s, 36, sd->bl_x, sd->bl_y); - WFIFOB(s, 49) = 5; - WFIFOB(s, 50) = 5; - WFIFOSET(s, clif_parse_func_table[0x78].len); + Packet_Fixed<0x007c> fixed_7c; + fixed_7c.block_id = fake_npc_id; + fixed_7c.speed = interval_t(); + fixed_7c.opt1 = Opt1::ZERO; + fixed_7c.opt2 = Opt2::ZERO; + fixed_7c.option = Option::ZERO; + fixed_7c.species = FAKE_NPC_CLASS; + fixed_7c.pos.x = sd->bl_x; + fixed_7c.pos.y = sd->bl_y; + send_fpacket<0x007c, 41>(s, fixed_7c); + + Packet_Fixed<0x0078> fixed_78; + fixed_78.block_id = fake_npc_id; + fixed_78.speed = interval_t(); + fixed_78.opt1 = Opt1::ZERO; + fixed_78.opt2 = Opt2::ZERO; + fixed_78.option = Option::ZERO; + fixed_78.species = FAKE_NPC_CLASS; + fixed_78.unused_head_bottom_or_species_again = unwrap<Species>(FAKE_NPC_CLASS); + fixed_78.pos.x = sd->bl_x; + fixed_78.pos.y = sd->bl_y; + fixed_78.unused_pos_again.x = sd->bl_x; + fixed_78.unused_pos_again.y = sd->bl_y; + fixed_78.five1 = 5; + fixed_78.five2 = 5; + fixed_78.zero = 0; + fixed_78.level = 0; + send_fpacket<0x0078, 54>(s, fixed_78); return 0; } @@ -1022,27 +1032,25 @@ int clif_spawn_fake_npc_for_player(dumb_ptr<map_session_data> sd, int fake_npc_i */ int clif_spawnmob(dumb_ptr<mob_data> md) { - unsigned char buf[64]; - int len; - - nullpo_ret(md); + nullpo_retz(md); { - really_memset0(buf, clif_parse_func_table[0x7c].len); - - WBUFW(buf, 0) = 0x7c; - WBUFL(buf, 2) = md->bl_id; - WBUFW(buf, 6) = md->stats[mob_stat::SPEED]; - WBUFW(buf, 8) = uint16_t(md->opt1); - WBUFW(buf, 10) = uint16_t(md->opt2); - WBUFW(buf, 12) = uint16_t(md->option); - WBUFW(buf, 20) = md->mob_class; - WBUFPOS(buf, 36, md->bl_x, md->bl_y); - clif_send(buf, clif_parse_func_table[0x7c].len, md, SendWho::AREA); + Packet_Fixed<0x007c> fixed_7c; + fixed_7c.block_id = md->bl_id; + fixed_7c.speed = interval_t(md->stats[mob_stat::SPEED]); + fixed_7c.opt1 = md->opt1; + fixed_7c.opt2 = md->opt2; + fixed_7c.option = md->option; + fixed_7c.species = md->mob_class; + fixed_7c.pos.x = md->bl_x; + fixed_7c.pos.y = md->bl_y; + Buffer buf = create_fpacket<0x007c, 41>(fixed_7c); + clif_send(buf, md, SendWho::AREA); } - len = clif_mob0078(md, buf); - clif_send(buf, len, md, SendWho::AREA); + Buffer buf; + clif_mob0078(md, buf); + clif_send(buf, md, SendWho::AREA); return 0; } @@ -1054,12 +1062,12 @@ int clif_spawnmob(dumb_ptr<mob_data> md) static int clif_servertick(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x7f; - WFIFOL(s, 2) = sd->server_tick.time_since_epoch().count(); - WFIFOSET(s, clif_parse_func_table[0x7f].len); + Packet_Fixed<0x007f> fixed_7f; + fixed_7f.tick = gettick(); + send_fpacket<0x007f, 6>(s, fixed_7f); return 0; } @@ -1070,14 +1078,17 @@ int clif_servertick(dumb_ptr<map_session_data> sd) */ int clif_walkok(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x87; - WFIFOL(s, 2) = gettick().time_since_epoch().count(); - WFIFOPOS2(s, 6, sd->bl_x, sd->bl_y, sd->to_x, sd->to_y); - WFIFOB(s, 11) = 0; - WFIFOSET(s, clif_parse_func_table[0x87].len); + Packet_Fixed<0x0087> fixed_87; + fixed_87.tick = gettick(); + fixed_87.pos2.x0 = sd->bl_x; + fixed_87.pos2.y0 = sd->bl_y; + fixed_87.pos2.x1 = sd->to_x; + fixed_87.pos2.y1 = sd->to_y; + fixed_87.zero = 0; + send_fpacket<0x0087, 12>(s, fixed_87); return 0; } @@ -1088,14 +1099,12 @@ int clif_walkok(dumb_ptr<map_session_data> sd) */ int clif_movechar(dumb_ptr<map_session_data> sd) { - int len; - unsigned char buf[256]; + nullpo_retz(sd); - nullpo_ret(sd); + Buffer buf; + clif_set007b(sd, buf); - len = clif_set007b(sd, buf); - - clif_send(buf, len, sd, SendWho::AREA_WOS); + clif_send(buf, sd, SendWho::AREA_WOS); if (battle_config.save_clothcolor == 1 && sd->status.clothes_color > 0) clif_changelook(sd, LOOK::CLOTHES_COLOR, @@ -1131,7 +1140,7 @@ void clif_waitclose(TimerData *, tick_t, Session *s) */ void clif_setwaitclose(Session *s) { - s->timed_close = Timer(gettick() + std::chrono::seconds(5), + s->timed_close = Timer(gettick() + 5_s, std::bind(clif_waitclose, ph::_1, ph::_2, s) ); @@ -1147,11 +1156,11 @@ void clif_changemap(dumb_ptr<map_session_data> sd, MapName mapname, int x, int y Session *s = sd->sess; - WFIFOW(s, 0) = 0x91; - WFIFO_STRING(s, 2, mapname, 16); - WFIFOW(s, 18) = x; - WFIFOW(s, 20) = y; - WFIFOSET(s, clif_parse_func_table[0x91].len); + Packet_Fixed<0x0091> fixed_91; + fixed_91.map_name = mapname; + fixed_91.x = x; + fixed_91.y = y; + send_fpacket<0x0091, 22>(s, fixed_91); } /*========================================== @@ -1164,13 +1173,13 @@ void clif_changemapserver(dumb_ptr<map_session_data> sd, nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x92; - WFIFO_STRING(s, 2, mapname, 16); - WFIFOW(s, 18) = x; - WFIFOW(s, 20) = y; - WFIFOIP(s, 22) = ip; - WFIFOW(s, 26) = port; - WFIFOSET(s, clif_parse_func_table[0x92].len); + Packet_Fixed<0x0092> fixed_92; + fixed_92.map_name = mapname; + fixed_92.x = x; + fixed_92.y = y; + fixed_92.ip = ip; + fixed_92.port = port; + send_fpacket<0x0092, 28>(s, fixed_92); } /*========================================== @@ -1179,30 +1188,29 @@ void clif_changemapserver(dumb_ptr<map_session_data> sd, */ void clif_fixpos(dumb_ptr<block_list> bl) { - uint8_t buf[16]; - nullpo_retv(bl); - WBUFW(buf, 0) = 0x88; - WBUFL(buf, 2) = bl->bl_id; - WBUFW(buf, 6) = bl->bl_x; - WBUFW(buf, 8) = bl->bl_y; + Packet_Fixed<0x0088> fixed_88; + fixed_88.block_id = bl->bl_id; + fixed_88.x = bl->bl_x; + fixed_88.y = bl->bl_y; - clif_send(buf, clif_parse_func_table[0x88].len, bl, SendWho::AREA); + Buffer buf = create_fpacket<0x0088, 10>(fixed_88); + clif_send(buf, bl, SendWho::AREA); } /*========================================== * *------------------------------------------ */ -int clif_npcbuysell(dumb_ptr<map_session_data> sd, int id) +int clif_npcbuysell(dumb_ptr<map_session_data> sd, BlockId id) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xc4; - WFIFOL(s, 2) = id; - WFIFOSET(s, clif_parse_func_table[0xc4].len); + Packet_Fixed<0x00c4> fixed_c4; + fixed_c4.block_id = id; + send_fpacket<0x00c4, 6>(s, fixed_c4); return 0; } @@ -1216,22 +1224,21 @@ int clif_buylist(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data_shop> nd) struct item_data *id; int i, val; - nullpo_ret(sd); - nullpo_ret(nd); + nullpo_retz(sd); + nullpo_retz(nd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xc6; + std::vector<Packet_Repeat<0x00c6>> repeat_c6(nd->shop_items.size()); for (i = 0; i < nd->shop_items.size(); i++) { id = itemdb_search(nd->shop_items[i].nameid); val = nd->shop_items[i].value; - WFIFOL(s, 4 + i * 11) = val; // base price - WFIFOL(s, 8 + i * 11) = val; // actual price - WFIFOB(s, 12 + i * 11) = uint8_t(id->type); - WFIFOW(s, 13 + i * 11) = nd->shop_items[i].nameid; + repeat_c6[i].base_price = val; // base price + repeat_c6[i].actual_price = val; // actual price + repeat_c6[i].type = id->type; + repeat_c6[i].name_id = nd->shop_items[i].nameid; } - WFIFOW(s, 2) = i * 11 + 4; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x00c6, 4, 11>(s, repeat_c6); return 0; } @@ -1242,27 +1249,25 @@ int clif_buylist(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data_shop> nd) */ int clif_selllist(dumb_ptr<map_session_data> sd) { - int i, c = 0, val; - - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xc7; - for (i = 0; i < MAX_INVENTORY; i++) + std::vector<Packet_Repeat<0x00c7>> repeat_c7; + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid > 0 && sd->inventory_data[i]) + if (sd->status.inventory[i].nameid && sd->inventory_data[i]) { - val = sd->inventory_data[i]->value_sell; + int val = sd->inventory_data[i]->value_sell; if (val < 0) continue; - WFIFOW(s, 4 + c * 10) = i + 2; - WFIFOL(s, 6 + c * 10) = val; // base price - WFIFOL(s, 10 + c * 10) = val; // actual price - c++; + Packet_Repeat<0x00c7> info; + info.ioff2 = i.shift(); + info.base_price = val; + info.actual_price = val; + repeat_c7.push_back(info); } } - WFIFOW(s, 2) = c * 10 + 4; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x00c7, 4, 10>(s, repeat_c7); return 0; } @@ -1271,166 +1276,130 @@ int clif_selllist(dumb_ptr<map_session_data> sd) * *------------------------------------------ */ -void clif_scriptmes(dumb_ptr<map_session_data> sd, int npcid, XString mes) +void clif_scriptmes(dumb_ptr<map_session_data> sd, BlockId npcid, XString mes) { nullpo_retv(sd); Session *s = sd->sess; - size_t len = mes.size() + 1; - WFIFOW(s, 0) = 0xb4; - WFIFOW(s, 2) = len + 8; - WFIFOL(s, 4) = npcid; - WFIFO_STRING(s, 8, mes, len); - WFIFOSET(s, WFIFOW(s, 2)); + Packet_Head<0x00b4> head_b4; + head_b4.block_id = npcid; + send_vpacket<0x00b4, 8, 1>(s, head_b4, mes); } /*========================================== * *------------------------------------------ */ -void clif_scriptnext(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptnext(dumb_ptr<map_session_data> sd, BlockId npcid) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xb5; - WFIFOL(s, 2) = npcid; - WFIFOSET(s, clif_parse_func_table[0xb5].len); + Packet_Fixed<0x00b5> fixed_b5; + fixed_b5.block_id = npcid; + send_fpacket<0x00b5, 6>(s, fixed_b5); } /*========================================== * *------------------------------------------ */ -void clif_scriptclose(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptclose(dumb_ptr<map_session_data> sd, BlockId npcid) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xb6; - WFIFOL(s, 2) = npcid; - WFIFOSET(s, clif_parse_func_table[0xb6].len); + Packet_Fixed<0x00b6> fixed_b6; + fixed_b6.block_id = npcid; + send_fpacket<0x00b6, 6>(s, fixed_b6); } /*========================================== * *------------------------------------------ */ -void clif_scriptmenu(dumb_ptr<map_session_data> sd, int npcid, XString mes) +void clif_scriptmenu(dumb_ptr<map_session_data> sd, BlockId npcid, XString mes) { nullpo_retv(sd); Session *s = sd->sess; - size_t len = mes.size() + 1; - WFIFOW(s, 0) = 0xb7; - WFIFOW(s, 2) = len + 8; - WFIFOL(s, 4) = npcid; - WFIFO_STRING(s, 8, mes, len); - WFIFOSET(s, WFIFOW(s, 2)); + Packet_Head<0x00b7> head_b7; + head_b7.block_id = npcid; + send_vpacket<0x00b7, 8, 1>(s, head_b7, mes); } /*========================================== * *------------------------------------------ */ -void clif_scriptinput(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptinput(dumb_ptr<map_session_data> sd, BlockId npcid) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x142; - WFIFOL(s, 2) = npcid; - WFIFOSET(s, clif_parse_func_table[0x142].len); + Packet_Fixed<0x0142> fixed_142; + fixed_142.block_id = npcid; + send_fpacket<0x0142, 6>(s, fixed_142); } /*========================================== * *------------------------------------------ */ -void clif_scriptinputstr(dumb_ptr<map_session_data> sd, int npcid) +void clif_scriptinputstr(dumb_ptr<map_session_data> sd, BlockId npcid) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x1d4; - WFIFOL(s, 2) = npcid; - WFIFOSET(s, clif_parse_func_table[0x1d4].len); + Packet_Fixed<0x01d4> fixed_1d4; + fixed_1d4.block_id = npcid; + send_fpacket<0x01d4, 6>(s, fixed_1d4); } /*========================================== * *------------------------------------------ */ -void clif_viewpoint(dumb_ptr<map_session_data> sd, int npc_id, int type, - int x, int y, int id, int color) +int clif_additem(dumb_ptr<map_session_data> sd, IOff0 n, int amount, PickupFail fail) { - nullpo_retv(sd); - - Session *s = sd->sess; - WFIFOW(s, 0) = 0x144; - WFIFOL(s, 2) = npc_id; - WFIFOL(s, 6) = type; - WFIFOL(s, 10) = x; - WFIFOL(s, 14) = y; - WFIFOB(s, 18) = id; - WFIFOL(s, 19) = color; - WFIFOSET(s, clif_parse_func_table[0x144].len); -} - -/*========================================== - * - *------------------------------------------ - */ -int clif_additem(dumb_ptr<map_session_data> sd, int n, int amount, PickupFail fail) -{ - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; + Packet_Fixed<0x00a0> fixed_a0; if (fail != PickupFail::OKAY) { - WFIFOW(s, 0) = 0xa0; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = amount; - WFIFOW(s, 6) = 0; - WFIFOB(s, 8) = 0; - WFIFOB(s, 9) = 0; - WFIFOB(s, 10) = 0; - WFIFOW(s, 11) = 0; - WFIFOW(s, 13) = 0; - WFIFOW(s, 15) = 0; - WFIFOW(s, 17) = 0; - WFIFOW(s, 19) = 0; - WFIFOB(s, 21) = 0; - WFIFOB(s, 22) = uint8_t(fail); + fixed_a0.ioff2 = n.shift(); + fixed_a0.amount = amount; + fixed_a0.name_id = ItemNameId(); + fixed_a0.pickup_fail = fail; } else { - if (n < 0 || n >= MAX_INVENTORY || sd->status.inventory[n].nameid <= 0 - || sd->inventory_data[n] == NULL) + if (!n.ok() || !sd->status.inventory[n].nameid + || sd->inventory_data[n] == nullptr) return 1; - WFIFOW(s, 0) = 0xa0; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = amount; - WFIFOW(s, 6) = sd->status.inventory[n].nameid; - WFIFOB(s, 8) = 1; //identify; - WFIFOB(s, 9) = 0; // broken or attribute; - WFIFOB(s, 10) = 0; //refine; + fixed_a0.ioff2 = n.shift(); + fixed_a0.amount = amount; + fixed_a0.name_id = sd->status.inventory[n].nameid; + fixed_a0.identify = 1; + fixed_a0.broken_or_attribute = 0; + fixed_a0.refine = 0; { - WFIFOW(s, 11) = 0; //card[0]; - WFIFOW(s, 13) = 0; //card[1]; - WFIFOW(s, 15) = 0; //card[2]; - WFIFOW(s, 17) = 0; //card[3]; + fixed_a0.card0 = 0; + fixed_a0.card1 = 0; + fixed_a0.card2 = 0; + fixed_a0.card3 = 0; } - WFIFOW(s, 19) = uint16_t(pc_equippoint(sd, n)); - WFIFOB(s, 21) = uint8_t(sd->inventory_data[n]->type == ItemType::_7 + fixed_a0.epos = pc_equippoint(sd, n); + fixed_a0.item_type = (sd->inventory_data[n]->type == ItemType::_7 ? ItemType::WEAPON : sd->inventory_data[n]->type); - WFIFOB(s, 22) = uint8_t(fail); + fixed_a0.pickup_fail = fail; } - WFIFOSET(s, clif_parse_func_table[0xa0].len); + send_fpacket<0x00a0, 23>(s, fixed_a0); return 0; } @@ -1438,16 +1407,16 @@ int clif_additem(dumb_ptr<map_session_data> sd, int n, int amount, PickupFail fa * *------------------------------------------ */ -void clif_delitem(dumb_ptr<map_session_data> sd, int n, int amount) +void clif_delitem(dumb_ptr<map_session_data> sd, IOff0 n, int amount) { nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xaf; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = amount; + Packet_Fixed<0x00af> fixed_af; + fixed_af.ioff2 = n.shift(); + fixed_af.amount = amount; - WFIFOSET(s, clif_parse_func_table[0xaf].len); + send_fpacket<0x00af, 6>(s, fixed_af); } /*========================================== @@ -1458,41 +1427,40 @@ void clif_itemlist(dumb_ptr<map_session_data> sd) { nullpo_retv(sd); - int n = 0; - int arrow = -1; + IOff0 arrow = IOff0::from(-1); Session *s = sd->sess; - WFIFOW(s, 0) = 0x1ee; - for (int i = 0; i < MAX_INVENTORY; i++) + std::vector<Packet_Repeat<0x01ee>> repeat_1ee; + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid <= 0 - || sd->inventory_data[i] == NULL + if (!sd->status.inventory[i].nameid + || sd->inventory_data[i] == nullptr || itemdb_isequip2(sd->inventory_data[i])) continue; - WFIFOW(s, n * 18 + 4) = i + 2; - WFIFOW(s, n * 18 + 6) = sd->status.inventory[i].nameid; - WFIFOB(s, n * 18 + 8) = uint8_t(sd->inventory_data[i]->type); - WFIFOB(s, n * 18 + 9) = 1; //identify; - WFIFOW(s, n * 18 + 10) = sd->status.inventory[i].amount; + Packet_Repeat<0x01ee> info; + info.ioff2 = i.shift(); + info.name_id = sd->status.inventory[i].nameid; + info.item_type = sd->inventory_data[i]->type; + info.identify = 1; + info.amount = sd->status.inventory[i].amount; if (sd->inventory_data[i]->equip == EPOS::ARROW) { - WFIFOW(s, n * 18 + 12) = uint16_t(EPOS::ARROW); + info.epos = EPOS::ARROW; if (bool(sd->status.inventory[i].equip)) - arrow = i; // ついでに矢装備チェック + arrow = i; } else - WFIFOW(s, n * 18 + 12) = uint16_t(EPOS::ZERO); - WFIFOW(s, n * 18 + 14) = 0; //card[0]; - WFIFOW(s, n * 18 + 16) = 0; //card[1]; - WFIFOW(s, n * 18 + 18) = 0; //card[2]; - WFIFOW(s, n * 18 + 20) = 0; //card[3]; - n++; + info.epos = EPOS::ZERO; + info.card0 = 0; + info.card1 = 0; + info.card2 = 0; + info.card3 = 0; + repeat_1ee.push_back(info); } - if (n) + if (!repeat_1ee.empty()) { - WFIFOW(s, 2) = 4 + n * 18; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x01ee, 4, 18>(s, repeat_1ee); } - if (arrow >= 0) + if (arrow.ok()) clif_arrowequip(sd, arrow); } @@ -1505,37 +1473,36 @@ void clif_equiplist(dumb_ptr<map_session_data> sd) nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xa4; - int n = 0; - for (int i = 0; i < MAX_INVENTORY; i++) + std::vector<Packet_Repeat<0x00a4>> repeat_a4; + for (IOff0 i : IOff0::iter()) { - if (sd->status.inventory[i].nameid <= 0 - || sd->inventory_data[i] == NULL + if (!sd->status.inventory[i].nameid + || sd->inventory_data[i] == nullptr || !itemdb_isequip2(sd->inventory_data[i])) continue; - WFIFOW(s, n * 20 + 4) = i + 2; - WFIFOW(s, n * 20 + 6) = sd->status.inventory[i].nameid; - WFIFOB(s, n * 20 + 8) = uint8_t( + Packet_Repeat<0x00a4> info; + info.ioff2 = i.shift(); + info.name_id = sd->status.inventory[i].nameid; + info.item_type = ( sd->inventory_data[i]->type == ItemType::_7 ? ItemType::WEAPON : sd->inventory_data[i]->type); - WFIFOB(s, n * 20 + 9) = 0; //identify; - WFIFOW(s, n * 20 + 10) = uint16_t(pc_equippoint(sd, i)); - WFIFOW(s, n * 20 + 12) = uint16_t(sd->status.inventory[i].equip); - WFIFOB(s, n * 20 + 14) = 0; //broken or attribute; - WFIFOB(s, n * 20 + 15) = 0; //refine; + info.identify = 0; + info.epos_pc = pc_equippoint(sd, i); + info.epos_inv = sd->status.inventory[i].equip; + info.broken_or_attribute = 0; + info.refine = 0; { - WFIFOW(s, n * 20 + 16) = 0; //card[0]; - WFIFOW(s, n * 20 + 18) = 0; //card[1]; - WFIFOW(s, n * 20 + 20) = 0; //card[2]; - WFIFOW(s, n * 20 + 22) = 0; //card[3]; + info.card0 = 0; + info.card1 = 0; + info.card2 = 0; + info.card3 = 0; } - n++; + repeat_a4.push_back(info); } - if (n) + if (!repeat_a4.empty()) { - WFIFOW(s, 2) = 4 + n * 20; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x00a4, 4, 20>(s, repeat_a4); } } @@ -1543,41 +1510,40 @@ void clif_equiplist(dumb_ptr<map_session_data> sd) * カプラさんに預けてある消耗品&収集品リスト *------------------------------------------ */ -int clif_storageitemlist(dumb_ptr<map_session_data> sd, struct storage *stor) +int clif_storageitemlist(dumb_ptr<map_session_data> sd, Storage *stor) { - nullpo_ret(sd); - nullpo_ret(stor); + nullpo_retz(sd); + nullpo_retz(stor); Session *s = sd->sess; - WFIFOW(s, 0) = 0x1f0; - int n = 0; - for (int i = 0; i < MAX_STORAGE; i++) + std::vector<Packet_Repeat<0x01f0>> repeat_1f0; + for (SOff0 i : SOff0::iter()) { - if (stor->storage_[i].nameid <= 0) + if (!stor->storage_[i].nameid) continue; struct item_data *id; id = itemdb_search(stor->storage_[i].nameid); - nullpo_ret(id); + nullpo_retz(id); if (itemdb_isequip2(id)) continue; - WFIFOW(s, n * 18 + 4) = i + 1; - WFIFOW(s, n * 18 + 6) = stor->storage_[i].nameid; - WFIFOB(s, n * 18 + 8) = uint8_t(id->type); - WFIFOB(s, n * 18 + 9) = 0; //identify; - WFIFOW(s, n * 18 + 10) = stor->storage_[i].amount; - WFIFOW(s, n * 18 + 12) = 0; - WFIFOW(s, n * 18 + 14) = 0; //card[0]; - WFIFOW(s, n * 18 + 16) = 0; //card[1]; - WFIFOW(s, n * 18 + 18) = 0; //card[2]; - WFIFOW(s, n * 18 + 20) = 0; //card[3]; - n++; + Packet_Repeat<0x01f0> info; + info.soff1 = i.shift(); + info.name_id = stor->storage_[i].nameid; + info.item_type = id->type; + info.identify = 0; + info.amount = stor->storage_[i].amount; + info.epos_zero = EPOS::ZERO; + info.card0 = 0; + info.card1 = 0; + info.card2 = 0; + info.card3 = 0; + repeat_1f0.push_back(info); } - if (n) + if (!repeat_1f0.empty()) { - WFIFOW(s, 2) = 4 + n * 18; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x01f0, 4, 18>(s, repeat_1f0); } return 0; } @@ -1586,44 +1552,43 @@ int clif_storageitemlist(dumb_ptr<map_session_data> sd, struct storage *stor) * カプラさんに預けてある装備リスト *------------------------------------------ */ -int clif_storageequiplist(dumb_ptr<map_session_data> sd, struct storage *stor) +int clif_storageequiplist(dumb_ptr<map_session_data> sd, Storage *stor) { - nullpo_ret(sd); - nullpo_ret(stor); + nullpo_retz(sd); + nullpo_retz(stor); Session *s = sd->sess; - WFIFOW(s, 0) = 0xa6; - int n = 0; - for (int i = 0; i < MAX_STORAGE; i++) + std::vector<Packet_Repeat<0x00a6>> repeat_a6; + for (SOff0 i : SOff0::iter()) { - if (stor->storage_[i].nameid <= 0) + if (!stor->storage_[i].nameid) continue; struct item_data *id; id = itemdb_search(stor->storage_[i].nameid); - nullpo_ret(id); + nullpo_retz(id); if (!itemdb_isequip2(id)) continue; - WFIFOW(s, n * 20 + 4) = i + 1; - WFIFOW(s, n * 20 + 6) = stor->storage_[i].nameid; - WFIFOB(s, n * 20 + 8) = uint8_t(id->type); - WFIFOB(s, n * 20 + 9) = 0; //identify; - WFIFOW(s, n * 20 + 10) = uint16_t(id->equip); - WFIFOW(s, n * 20 + 12) = uint16_t(stor->storage_[i].equip); - WFIFOB(s, n * 20 + 14) = 0; //broken or attribute - WFIFOB(s, n * 20 + 15) = 0; //refine; + Packet_Repeat<0x00a6> info; + info.soff1 = i.shift(); + info.name_id = stor->storage_[i].nameid; + info.item_type = id->type; + info.identify = 0; + info.epos_id = id->equip; + info.epos_stor = stor->storage_[i].equip; + info.broken_or_attribute = 0; + info.refine = 0; { - WFIFOW(s, n * 20 + 16) = 0; //card[0]; - WFIFOW(s, n * 20 + 18) = 0; //card[1]; - WFIFOW(s, n * 20 + 20) = 0; //card[2]; - WFIFOW(s, n * 20 + 22) = 0; //card[3]; + info.card0 = 0; + info.card1 = 0; + info.card2 = 0; + info.card3 = 0; } - n++; + repeat_a6.push_back(info); } - if (n) + if (!repeat_a6.empty()) { - WFIFOW(s, 2) = 4 + n * 20; - WFIFOSET(s, WFIFOW(s, 2)); + send_packet_repeatonly<0x00a6, 4, 20>(s, repeat_a6); } return 0; } @@ -1635,140 +1600,183 @@ int clif_storageequiplist(dumb_ptr<map_session_data> sd, struct storage *stor) */ int clif_updatestatus(dumb_ptr<map_session_data> sd, SP type) { - int len = 8; - - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xb0; - WFIFOW(s, 2) = static_cast<uint16_t>(type); - switch (type) { - // 00b0 + Packet_Fixed<0x00b0> fixed_b0; + fixed_b0.sp_type = type; + switch (type) + { case SP::WEIGHT: pc_checkweighticon(sd); - // is this because pc_checkweighticon can send other packets? - WFIFOW(s, 0) = 0xb0; - WFIFOW(s, 2) = static_cast<uint16_t>(type); - WFIFOL(s, 4) = sd->weight; + fixed_b0.value = sd->weight; break; case SP::MAXWEIGHT: - WFIFOL(s, 4) = sd->max_weight; + fixed_b0.value = sd->max_weight; break; case SP::SPEED: - // ... - WFIFOL(s, 4) = static_cast<uint16_t>(sd->speed.count()); + // 'speed' is actually delay, in milliseconds + fixed_b0.value = sd->speed.count(); break; case SP::BASELEVEL: - WFIFOL(s, 4) = sd->status.base_level; + fixed_b0.value = sd->status.base_level; break; case SP::JOBLEVEL: - WFIFOL(s, 4) = 0; + fixed_b0.value = sd->status.job_level; break; case SP::STATUSPOINT: - WFIFOL(s, 4) = sd->status.status_point; + fixed_b0.value = sd->status.status_point; break; case SP::SKILLPOINT: - WFIFOL(s, 4) = sd->status.skill_point; + fixed_b0.value = sd->status.skill_point; break; case SP::HIT: - WFIFOL(s, 4) = sd->hit; + fixed_b0.value = sd->hit; break; case SP::FLEE1: - WFIFOL(s, 4) = sd->flee; + fixed_b0.value = sd->flee; break; case SP::FLEE2: - WFIFOL(s, 4) = sd->flee2 / 10; + fixed_b0.value = sd->flee2 / 10; break; case SP::MAXHP: - WFIFOL(s, 4) = sd->status.max_hp; + fixed_b0.value = sd->status.max_hp; break; case SP::MAXSP: - WFIFOL(s, 4) = sd->status.max_sp; + fixed_b0.value = sd->status.max_sp; break; case SP::HP: - WFIFOL(s, 4) = sd->status.hp; + fixed_b0.value = sd->status.hp; break; case SP::SP: - WFIFOL(s, 4) = sd->status.sp; + fixed_b0.value = sd->status.sp; break; case SP::ASPD: - WFIFOL(s, 4) = static_cast<uint16_t>(sd->aspd.count()); + fixed_b0.value = sd->aspd.count(); break; case SP::ATK1: - WFIFOL(s, 4) = sd->base_atk + sd->watk; + fixed_b0.value = sd->base_atk + sd->watk; break; case SP::DEF1: - WFIFOL(s, 4) = sd->def; + fixed_b0.value = sd->def; break; case SP::MDEF1: - WFIFOL(s, 4) = sd->mdef; + fixed_b0.value = sd->mdef; break; case SP::ATK2: - WFIFOL(s, 4) = sd->watk2; + fixed_b0.value = sd->watk2; break; case SP::DEF2: - WFIFOL(s, 4) = sd->def2; + fixed_b0.value = sd->def2; break; case SP::MDEF2: - WFIFOL(s, 4) = sd->mdef2; + fixed_b0.value = sd->mdef2; break; case SP::CRITICAL: - WFIFOL(s, 4) = sd->critical / 10; + fixed_b0.value = sd->critical / 10; break; case SP::MATK1: - WFIFOL(s, 4) = sd->matk1; + fixed_b0.value = sd->matk1; break; case SP::MATK2: - WFIFOL(s, 4) = sd->matk2; + fixed_b0.value = sd->matk2; + break; + case SP::GM: + fixed_b0.value = pc_isGM(sd).get_all_bits(); break; + default: + goto not_b0; + } + + send_fpacket<0x00b0, 8>(s, fixed_b0); + return 0; + } +not_b0: + + { + Packet_Fixed<0x00b1> fixed_b1; + fixed_b1.sp_type = type; + switch (type) + { case SP::ZENY: trade_verifyzeny(sd); - WFIFOW(s, 0) = 0xb1; if (sd->status.zeny < 0) sd->status.zeny = 0; - WFIFOL(s, 4) = sd->status.zeny; + fixed_b1.value = sd->status.zeny; break; + case SP::BASEEXP: - WFIFOW(s, 0) = 0xb1; - WFIFOL(s, 4) = sd->status.base_exp; + fixed_b1.value = sd->status.base_exp; break; case SP::JOBEXP: - WFIFOW(s, 0) = 0xb1; - WFIFOL(s, 4) = sd->status.job_exp; + fixed_b1.value = sd->status.job_exp; break; case SP::NEXTBASEEXP: - WFIFOW(s, 0) = 0xb1; - WFIFOL(s, 4) = pc_nextbaseexp(sd); + fixed_b1.value = pc_nextbaseexp(sd); break; case SP::NEXTJOBEXP: - WFIFOW(s, 0) = 0xb1; - WFIFOL(s, 4) = pc_nextjobexp(sd); + fixed_b1.value = pc_nextjobexp(sd); break; - // 00be 終了 + default: + goto not_b1; + } + + send_fpacket<0x00b1, 8>(s, fixed_b1); + return 0; + } +not_b1: + + { + Packet_Fixed<0x00be> fixed_be; + fixed_be.sp_type = type; + switch (type) + { case SP::USTR: case SP::UAGI: case SP::UVIT: case SP::UINT: case SP::UDEX: case SP::ULUK: - WFIFOW(s, 0) = 0xbe; - WFIFOB(s, 4) = pc_need_status_point(sd, usp_to_sp(type)); - len = 5; + fixed_be.value = pc_need_status_point(sd, usp_to_sp(type)); break; - // 013a 終了 + default: + goto not_be; + } + + send_fpacket<0x00be, 5>(s, fixed_be); + return 0; + } +not_be: + + { + Packet_Fixed<0x013a> fixed_13a; + switch (type) + { case SP::ATTACKRANGE: - WFIFOW(s, 0) = 0x13a; - WFIFOW(s, 2) = (sd->attack_spell_override) - ? sd->attack_spell_range : sd->attackrange; - len = 4; + fixed_13a.attack_range = (sd->attack_spell_override + ? sd->attack_spell_range + : sd->attackrange); break; - // 0141 終了 + default: + goto not_13a; + } + + send_fpacket<0x013a, 4>(s, fixed_13a); + return 0; + } +not_13a: + + { + Packet_Fixed<0x00141> fixed_141; + fixed_141.sp_type = type; + switch (type) + { case SP::STR: case SP::AGI: case SP::VIT: @@ -1777,27 +1785,28 @@ int clif_updatestatus(dumb_ptr<map_session_data> sd, SP type) case SP::LUK: { ATTR attr = sp_to_attr(type); - WFIFOW(s, 0) = 0x141; - WFIFOL(s, 2) = uint16_t(type); - WFIFOL(s, 6) = sd->status.attrs[attr]; - WFIFOL(s, 10) = sd->paramb[attr] + sd->parame[attr]; - len = 14; + fixed_141.value_status = sd->status.attrs[attr]; + fixed_141.value_b_e = sd->paramb[attr] + sd->parame[attr]; } break; - case SP::GM: - WFIFOL(s, 4) = pc_isGM(sd); - break; - default: + goto not_141; + } + + send_fpacket<0x0141, 14>(s, fixed_141); + return 0; + } + +not_141: + { + { if (battle_config.error_log) - PRINTF("clif_updatestatus : make %d routine\n", + PRINTF("clif_updatestatus : make %d routine\n"_fmt, type); return 1; + } } - WFIFOSET(s, len); - - return 0; } /*========================================== @@ -1806,16 +1815,15 @@ int clif_updatestatus(dumb_ptr<map_session_data> sd, SP type) */ int clif_changelook(dumb_ptr<block_list> bl, LOOK type, int val) { - return clif_changelook_towards(bl, type, val, NULL); + return clif_changelook_towards(bl, type, val, nullptr); } int clif_changelook_towards(dumb_ptr<block_list> bl, LOOK type, int val, dumb_ptr<map_session_data> dstsd) { - unsigned char buf[32]; - dumb_ptr<map_session_data> sd = NULL; + dumb_ptr<map_session_data> sd = nullptr; - nullpo_ret(bl); + nullpo_retz(bl); if (bl->bl_type == BL::PC) sd = bl->is_player(); @@ -1826,61 +1834,65 @@ int clif_changelook_towards(dumb_ptr<block_list> bl, LOOK type, int val, if (sd && (type == LOOK::WEAPON || type == LOOK::SHIELD || type >= LOOK::SHOES)) { - WBUFW(buf, 0) = 0x1d7; - WBUFL(buf, 2) = bl->bl_id; + Packet_Fixed<0x01d7> fixed_1d7; + fixed_1d7.block_id = bl->bl_id; if (type >= LOOK::SHOES) { EQUIP equip_point = equip_points[type]; - WBUFB(buf, 6) = uint16_t(type); - int idx = sd->equip_index_maybe[equip_point]; - if (idx >= 0 && sd->inventory_data[idx]) + fixed_1d7.look_type = type; + IOff0 idx = sd->equip_index_maybe[equip_point]; + if (idx.ok() && sd->inventory_data[idx]) { - WBUFW(buf, 7) = sd->status.inventory[idx].nameid; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(sd->status.inventory[idx].nameid); } else - WBUFW(buf, 7) = 0; - WBUFW(buf, 9) = 0; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(ItemNameId()); + fixed_1d7.shield = ItemNameId(); } else { - WBUFB(buf, 6) = 2; - int widx = sd->equip_index_maybe[EQUIP::WEAPON]; - int sidx = sd->equip_index_maybe[EQUIP::SHIELD]; + fixed_1d7.look_type = LOOK::WEAPON; + IOff0 widx = sd->equip_index_maybe[EQUIP::WEAPON]; + IOff0 sidx = sd->equip_index_maybe[EQUIP::SHIELD]; if (sd->attack_spell_override) - WBUFW(buf, 7) = sd->attack_spell_look_override; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(sd->attack_spell_look_override); else { - if (widx >= 0 && sd->inventory_data[widx]) + if (widx.ok() && sd->inventory_data[widx]) { - WBUFW(buf, 7) = sd->status.inventory[widx].nameid; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(sd->status.inventory[widx].nameid); } else - WBUFW(buf, 7) = 0; + fixed_1d7.weapon_or_name_id_or_value = unwrap<ItemNameId>(ItemNameId()); } - if (sidx >= 0 && sidx != widx && sd->inventory_data[sidx]) + if (sidx.ok() && sidx != widx && sd->inventory_data[sidx]) { - WBUFW(buf, 9) = sd->status.inventory[sidx].nameid; + fixed_1d7.shield = sd->status.inventory[sidx].nameid; } else - WBUFW(buf, 9) = 0; + fixed_1d7.shield = ItemNameId(); } + + Buffer buf = create_fpacket<0x01d7, 11>(fixed_1d7); if (dstsd) - clif_send(buf, clif_parse_func_table[0x1d7].len, dstsd, SendWho::SELF); + clif_send(buf, dstsd, SendWho::SELF); else - clif_send(buf, clif_parse_func_table[0x1d7].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); } else { - WBUFW(buf, 0) = 0x1d7; - WBUFL(buf, 2) = bl->bl_id; - WBUFB(buf, 6) = uint8_t(type); - WBUFW(buf, 7) = val; - WBUFW(buf, 9) = 0; + Packet_Fixed<0x01d7> fixed_1d7; + fixed_1d7.block_id = bl->bl_id; + fixed_1d7.look_type = type; + fixed_1d7.weapon_or_name_id_or_value = val; + fixed_1d7.shield = ItemNameId(); + + Buffer buf = create_fpacket<0x01d7, 11>(fixed_1d7); if (dstsd) - clif_send(buf, clif_parse_func_table[0x1d7].len, dstsd, SendWho::SELF); + clif_send(buf, dstsd, SendWho::SELF); else - clif_send(buf, clif_parse_func_table[0x1d7].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); } return 0; } @@ -1892,42 +1904,42 @@ int clif_changelook_towards(dumb_ptr<block_list> bl, LOOK type, int val, static int clif_initialstatus(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xbd; - WFIFOW(s, 2) = sd->status.status_point; - - WFIFOB(s, 4) = min(sd->status.attrs[ATTR::STR], 255); - WFIFOB(s, 5) = pc_need_status_point(sd, SP::STR); - WFIFOB(s, 6) = min(sd->status.attrs[ATTR::AGI], 255); - WFIFOB(s, 7) = pc_need_status_point(sd, SP::AGI); - WFIFOB(s, 8) = min(sd->status.attrs[ATTR::VIT], 255); - WFIFOB(s, 9) = pc_need_status_point(sd, SP::VIT); - WFIFOB(s, 10) = min(sd->status.attrs[ATTR::INT], 255); - WFIFOB(s, 11) = pc_need_status_point(sd, SP::INT); - WFIFOB(s, 12) = min(sd->status.attrs[ATTR::DEX], 255); - WFIFOB(s, 13) = pc_need_status_point(sd, SP::DEX); - WFIFOB(s, 14) = min(sd->status.attrs[ATTR::LUK], 255); - WFIFOB(s, 15) = pc_need_status_point(sd, SP::LUK); - - WFIFOW(s, 16) = sd->base_atk + sd->watk; - WFIFOW(s, 18) = sd->watk2; //atk bonus - WFIFOW(s, 20) = sd->matk1; - WFIFOW(s, 22) = sd->matk2; - WFIFOW(s, 24) = sd->def; // def - WFIFOW(s, 26) = sd->def2; - WFIFOW(s, 28) = sd->mdef; // mdef - WFIFOW(s, 30) = sd->mdef2; - WFIFOW(s, 32) = sd->hit; - WFIFOW(s, 34) = sd->flee; - WFIFOW(s, 36) = sd->flee2 / 10; - WFIFOW(s, 38) = sd->critical / 10; - WFIFOW(s, 40) = sd->status.karma; - WFIFOW(s, 42) = sd->status.manner; - - WFIFOSET(s, clif_parse_func_table[0xbd].len); + Packet_Fixed<0x00bd> fixed_bd; + fixed_bd.status_point = sd->status.status_point; + + fixed_bd.str_attr = saturate<uint8_t>(sd->status.attrs[ATTR::STR]); + fixed_bd.str_upd = pc_need_status_point(sd, SP::STR); + fixed_bd.agi_attr = saturate<uint8_t>(sd->status.attrs[ATTR::AGI]); + fixed_bd.agi_upd = pc_need_status_point(sd, SP::AGI); + fixed_bd.vit_attr = saturate<uint8_t>(sd->status.attrs[ATTR::VIT]); + fixed_bd.vit_upd = pc_need_status_point(sd, SP::VIT); + fixed_bd.int_attr = saturate<uint8_t>(sd->status.attrs[ATTR::INT]); + fixed_bd.int_upd = pc_need_status_point(sd, SP::INT); + fixed_bd.dex_attr = saturate<uint8_t>(sd->status.attrs[ATTR::DEX]); + fixed_bd.dex_upd = pc_need_status_point(sd, SP::DEX); + fixed_bd.luk_attr = saturate<uint8_t>(sd->status.attrs[ATTR::LUK]); + fixed_bd.luk_upd = pc_need_status_point(sd, SP::LUK); + + fixed_bd.atk_sum = sd->base_atk + sd->watk; + fixed_bd.watk2 = sd->watk2; //atk bonus + fixed_bd.matk1 = sd->matk1; + fixed_bd.matk2 = sd->matk2; + fixed_bd.def = sd->def; + fixed_bd.def2 = sd->def2; + fixed_bd.mdef = sd->mdef; + fixed_bd.mdef2 = sd->mdef2; + fixed_bd.hit = sd->hit; + fixed_bd.flee = sd->flee; + fixed_bd.flee2 = sd->flee2 / 10; + fixed_bd.critical = sd->critical / 10; + fixed_bd.karma = sd->status.karma; + fixed_bd.manner = sd->status.manner; + + send_fpacket<0x00bd, 44>(s, fixed_bd); clif_updatestatus(sd, SP::STR); clif_updatestatus(sd, SP::AGI); @@ -1946,18 +1958,16 @@ int clif_initialstatus(dumb_ptr<map_session_data> sd) *矢装備 *------------------------------------------ */ -int clif_arrowequip(dumb_ptr<map_session_data> sd, int val) +int clif_arrowequip(dumb_ptr<map_session_data> sd, IOff0 val) { - nullpo_ret(sd); + nullpo_retz(sd); - if (sd->attacktarget && sd->attacktarget > 0) // [Valaris] - sd->attacktarget = 0; + sd->attacktarget = BlockId(); Session *s = sd->sess; - WFIFOW(s, 0) = 0x013c; - WFIFOW(s, 2) = val + 2; //矢のアイテムID - - WFIFOSET(s, clif_parse_func_table[0x013c].len); + Packet_Fixed<0x013c> fixed_13c; + fixed_13c.ioff2 = val.shift(); + send_fpacket<0x013c, 4>(s, fixed_13c); return 0; } @@ -1968,14 +1978,13 @@ int clif_arrowequip(dumb_ptr<map_session_data> sd, int val) */ int clif_arrow_fail(dumb_ptr<map_session_data> sd, int type) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x013b; - WFIFOW(s, 2) = type; - - WFIFOSET(s, clif_parse_func_table[0x013b].len); + Packet_Fixed<0x013b> fixed_13b; + fixed_13b.type = type; + send_fpacket<0x013b, 4>(s, fixed_13b); return 0; } @@ -1986,14 +1995,14 @@ int clif_arrow_fail(dumb_ptr<map_session_data> sd, int type) */ int clif_statusupack(dumb_ptr<map_session_data> sd, SP type, int ok, int val) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xbc; - WFIFOW(s, 2) = uint16_t(type); - WFIFOB(s, 4) = ok; - WFIFOB(s, 5) = val; - WFIFOSET(s, clif_parse_func_table[0xbc].len); + Packet_Fixed<0x00bc> fixed_bc; + fixed_bc.sp_type = type; + fixed_bc.ok = ok; + fixed_bc.val = val; + send_fpacket<0x00bc, 6>(s, fixed_bc); return 0; } @@ -2002,16 +2011,16 @@ int clif_statusupack(dumb_ptr<map_session_data> sd, SP type, int ok, int val) * *------------------------------------------ */ -int clif_equipitemack(dumb_ptr<map_session_data> sd, int n, EPOS pos, int ok) +int clif_equipitemack(dumb_ptr<map_session_data> sd, IOff0 n, EPOS pos, int ok) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xaa; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = uint16_t(pos); - WFIFOB(s, 6) = ok; - WFIFOSET(s, clif_parse_func_table[0xaa].len); + Packet_Fixed<0x00aa> fixed_aa; + fixed_aa.ioff2 = n.shift(); + fixed_aa.epos = pos; + fixed_aa.ok = ok; + send_fpacket<0x00aa, 7>(s, fixed_aa); return 0; } @@ -2020,16 +2029,16 @@ int clif_equipitemack(dumb_ptr<map_session_data> sd, int n, EPOS pos, int ok) * *------------------------------------------ */ -int clif_unequipitemack(dumb_ptr<map_session_data> sd, int n, EPOS pos, int ok) +int clif_unequipitemack(dumb_ptr<map_session_data> sd, IOff0 n, EPOS pos, int ok) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xac; - WFIFOW(s, 2) = n + 2; - WFIFOW(s, 4) = uint16_t(pos); - WFIFOB(s, 6) = ok; - WFIFOSET(s, clif_parse_func_table[0xac].len); + Packet_Fixed<0x00ac> fixed_ac; + fixed_ac.ioff2 = n.shift(); + fixed_ac.epos = pos; + fixed_ac.ok = ok; + send_fpacket<0x00ac, 7>(s, fixed_ac); return 0; } @@ -2040,15 +2049,14 @@ int clif_unequipitemack(dumb_ptr<map_session_data> sd, int n, EPOS pos, int ok) */ int clif_misceffect(dumb_ptr<block_list> bl, int type) { - uint8_t buf[32]; + nullpo_retz(bl); - nullpo_ret(bl); + Packet_Fixed<0x019b> fixed_19b; + fixed_19b.block_id = bl->bl_id; + fixed_19b.type = type; + Buffer buf = create_fpacket<0x019b, 10>(fixed_19b); - WBUFW(buf, 0) = 0x19b; - WBUFL(buf, 2) = bl->bl_id; - WBUFL(buf, 6) = type; - - clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); return 0; } @@ -2059,22 +2067,22 @@ int clif_misceffect(dumb_ptr<block_list> bl, int type) */ int clif_changeoption(dumb_ptr<block_list> bl) { - uint8_t buf[32]; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(bl); + nullpo_retz(bl); Option option = *battle_get_option(bl); sc_data = battle_get_sc_data(bl); - WBUFW(buf, 0) = 0x119; - WBUFL(buf, 2) = bl->bl_id; - WBUFW(buf, 6) = uint16_t(*battle_get_opt1(bl)); - WBUFW(buf, 8) = uint16_t(*battle_get_opt2(bl)); - WBUFW(buf, 10) = uint16_t(option); - WBUFB(buf, 12) = 0; // ?? + Packet_Fixed<0x0119> fixed_119; + fixed_119.block_id = bl->bl_id; + fixed_119.opt1 = *battle_get_opt1(bl); + fixed_119.opt2 = *battle_get_opt2(bl); + fixed_119.option = option; + fixed_119.zero = 0; + Buffer buf = create_fpacket<0x0119, 13>(fixed_119); - clif_send(buf, clif_parse_func_table[0x119].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); return 0; } @@ -2083,31 +2091,30 @@ int clif_changeoption(dumb_ptr<block_list> bl) * *------------------------------------------ */ -int clif_useitemack(dumb_ptr<map_session_data> sd, int index, int amount, +int clif_useitemack(dumb_ptr<map_session_data> sd, IOff0 index, int amount, int ok) { - nullpo_ret(sd); + nullpo_retz(sd); if (!ok) { Session *s = sd->sess; - WFIFOW(s, 0) = 0xa8; - WFIFOW(s, 2) = index + 2; - WFIFOW(s, 4) = amount; - WFIFOB(s, 6) = ok; - WFIFOSET(s, clif_parse_func_table[0xa8].len); + Packet_Fixed<0x00a8> fixed_a8; + fixed_a8.ioff2 = index.shift(); + fixed_a8.amount = amount; + fixed_a8.ok = ok; + send_fpacket<0x00a8, 7>(s, fixed_a8); } else { - uint8_t buf[32]; - - WBUFW(buf, 0) = 0x1c8; - WBUFW(buf, 2) = index + 2; - WBUFW(buf, 4) = sd->status.inventory[index].nameid; - WBUFL(buf, 6) = sd->bl_id; - WBUFW(buf, 10) = amount; - WBUFB(buf, 12) = ok; - clif_send(buf, clif_parse_func_table[0x1c8].len, sd, SendWho::SELF); + Packet_Fixed<0x01c8> fixed_1c8; + fixed_1c8.ioff2 = index.shift(); + fixed_1c8.name_id = sd->status.inventory[index].nameid; + fixed_1c8.block_id = sd->bl_id; + fixed_1c8.amount = amount; + fixed_1c8.ok = ok; + Buffer buf = create_fpacket<0x01c8, 13>(fixed_1c8); + clif_send(buf, sd, SendWho::SELF); } return 0; @@ -2122,9 +2129,9 @@ void clif_traderequest(dumb_ptr<map_session_data> sd, CharName name) nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xe5; - WFIFO_STRING(s, 2, name.to__actual(), 24); - WFIFOSET(s, clif_parse_func_table[0xe5].len); + Packet_Fixed<0x00e5> fixed_e5; + fixed_e5.char_name = name; + send_fpacket<0x00e5, 26>(s, fixed_e5); } /*========================================== @@ -2136,9 +2143,9 @@ void clif_tradestart(dumb_ptr<map_session_data> sd, int type) nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xe7; - WFIFOB(s, 2) = type; - WFIFOSET(s, clif_parse_func_table[0xe7].len); + Packet_Fixed<0x00e7> fixed_e7; + fixed_e7.type = type; + send_fpacket<0x00e7, 3>(s, fixed_e7); } /*========================================== @@ -2146,57 +2153,57 @@ void clif_tradestart(dumb_ptr<map_session_data> sd, int type) *------------------------------------------ */ void clif_tradeadditem(dumb_ptr<map_session_data> sd, - dumb_ptr<map_session_data> tsd, int index, int amount) + dumb_ptr<map_session_data> tsd, IOff2 index2, int amount) { nullpo_retv(sd); nullpo_retv(tsd); Session *s = tsd->sess; - WFIFOW(s, 0) = 0xe9; - WFIFOL(s, 2) = amount; - if (index == 0) + Packet_Fixed<0x00e9> fixed_e9; + fixed_e9.amount = amount; + if (!index2.ok()) { - WFIFOW(s, 6) = 0; // type id - WFIFOB(s, 8) = 0; //identify flag - WFIFOB(s, 9) = 0; // attribute - WFIFOB(s, 10) = 0; //refine - WFIFOW(s, 11) = 0; //card (4w) - WFIFOW(s, 13) = 0; //card (4w) - WFIFOW(s, 15) = 0; //card (4w) - WFIFOW(s, 17) = 0; //card (4w) + fixed_e9.name_id = ItemNameId(); + fixed_e9.identify = 0; + fixed_e9.broken_or_attribute = 0; + fixed_e9.refine = 0; + fixed_e9.card0 = 0; + fixed_e9.card1 = 0; + fixed_e9.card2 = 0; + fixed_e9.card3 = 0; } else { - index -= 2; - WFIFOW(s, 6) = sd->status.inventory[index].nameid; // type id - WFIFOB(s, 8) = 0; //identify; - WFIFOB(s, 9) = 0; //broken or attribute; - WFIFOB(s, 10) = 0; //refine; + IOff0 index0 = index2.unshift(); + fixed_e9.name_id = sd->status.inventory[index0].nameid; + fixed_e9.identify = 0; + fixed_e9.broken_or_attribute = 0; + fixed_e9.refine = 0; { - WFIFOW(s, 11) = 0; //card[0]; - WFIFOW(s, 13) = 0; //card[1]; - WFIFOW(s, 15) = 0; //card[2]; - WFIFOW(s, 17) = 0; //card[3]; + fixed_e9.card0 = 0; + fixed_e9.card1 = 0; + fixed_e9.card2 = 0; + fixed_e9.card3 = 0; } } - WFIFOSET(s, clif_parse_func_table[0xe9].len); + send_fpacket<0x00e9, 19>(s, fixed_e9); } /*========================================== * アイテム追加成功/失敗 *------------------------------------------ */ -int clif_tradeitemok(dumb_ptr<map_session_data> sd, int index, int amount, +int clif_tradeitemok(dumb_ptr<map_session_data> sd, IOff2 index2, int amount, int fail) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x1b1; - WFIFOW(s, 2) = index; - WFIFOW(s, 4) = amount; - WFIFOB(s, 6) = fail; - WFIFOSET(s, clif_parse_func_table[0x1b1].len); + Packet_Fixed<0x01b1> fixed_1b1; + fixed_1b1.ioff2 = index2; + fixed_1b1.amount = amount; + fixed_1b1.fail = fail; + send_fpacket<0x01b1, 7>(s, fixed_1b1); return 0; } @@ -2207,12 +2214,12 @@ int clif_tradeitemok(dumb_ptr<map_session_data> sd, int index, int amount, */ int clif_tradedeal_lock(dumb_ptr<map_session_data> sd, int fail) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xec; - WFIFOB(s, 2) = fail; // 0=you 1=the other person - WFIFOSET(s, clif_parse_func_table[0xec].len); + Packet_Fixed<0x00ec> fixed_ec; + fixed_ec.fail = fail; // 0=you 1=the other person + send_fpacket<0x00ec, 3>(s, fixed_ec); return 0; } @@ -2223,11 +2230,11 @@ int clif_tradedeal_lock(dumb_ptr<map_session_data> sd, int fail) */ int clif_tradecancelled(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xee; - WFIFOSET(s, clif_parse_func_table[0xee].len); + Packet_Fixed<0x00ee> fixed_ee; + send_fpacket<0x00ee, 2>(s, fixed_ee); return 0; } @@ -2238,12 +2245,12 @@ int clif_tradecancelled(dumb_ptr<map_session_data> sd) */ int clif_tradecompleted(dumb_ptr<map_session_data> sd, int fail) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf0; - WFIFOB(s, 2) = fail; - WFIFOSET(s, clif_parse_func_table[0xf0].len); + Packet_Fixed<0x00f0> fixed_f0; + fixed_f0.fail = fail; + send_fpacket<0x00f0, 3>(s, fixed_f0); return 0; } @@ -2253,16 +2260,16 @@ int clif_tradecompleted(dumb_ptr<map_session_data> sd, int fail) *------------------------------------------ */ int clif_updatestorageamount(dumb_ptr<map_session_data> sd, - struct storage *stor) + Storage *stor) { - nullpo_ret(sd); - nullpo_ret(stor); + nullpo_retz(sd); + nullpo_retz(stor); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf2; // update storage amount - WFIFOW(s, 2) = stor->storage_amount; //items - WFIFOW(s, 4) = MAX_STORAGE; //items max - WFIFOSET(s, clif_parse_func_table[0xf2].len); + Packet_Fixed<0x00f2> fixed_f2; + fixed_f2.current_slots = stor->storage_amount; //items + fixed_f2.max_slots = MAX_STORAGE; //items max + send_fpacket<0x00f2, 6>(s, fixed_f2); return 0; } @@ -2271,30 +2278,27 @@ int clif_updatestorageamount(dumb_ptr<map_session_data> sd, * カプラ倉庫にアイテムを追加する *------------------------------------------ */ -int clif_storageitemadded(dumb_ptr<map_session_data> sd, struct storage *stor, - int index, int amount) +int clif_storageitemadded(dumb_ptr<map_session_data> sd, Storage *stor, + SOff0 index, int amount) { - nullpo_ret(sd); - nullpo_ret(stor); + nullpo_retz(sd); + nullpo_retz(stor); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf4; // Storage item added - WFIFOW(s, 2) = index + 1; // index - WFIFOL(s, 4) = amount; // amount -/* if ((view = itemdb_viewid(stor->storage_[index].nameid)) > 0) - WFIFOW(fd,8) =view; - else*/ - WFIFOW(s, 8) = stor->storage_[index].nameid; - WFIFOB(s, 10) = 0; //identify; - WFIFOB(s, 11) = 0; //broken or attribute; - WFIFOB(s, 12) = 0; //refine; + Packet_Fixed<0x00f4> fixed_f4; + fixed_f4.soff1 = index.shift(); + fixed_f4.amount = amount; + fixed_f4.name_id = stor->storage_[index].nameid; + fixed_f4.identify = 0; + fixed_f4.broken_or_attribute = 0; + fixed_f4.refine = 0; { - WFIFOW(s, 13) = 0; //card[0]; - WFIFOW(s, 15) = 0; //card[1]; - WFIFOW(s, 17) = 0; //card[2]; - WFIFOW(s, 19) = 0; //card[3]; + fixed_f4.card0 = 0; + fixed_f4.card1 = 0; + fixed_f4.card2 = 0; + fixed_f4.card3 = 0; } - WFIFOSET(s, clif_parse_func_table[0xf4].len); + send_fpacket<0x00f4, 21>(s, fixed_f4); return 0; } @@ -2303,16 +2307,16 @@ int clif_storageitemadded(dumb_ptr<map_session_data> sd, struct storage *stor, * カプラ倉庫からアイテムを取り去る *------------------------------------------ */ -int clif_storageitemremoved(dumb_ptr<map_session_data> sd, int index, +int clif_storageitemremoved(dumb_ptr<map_session_data> sd, SOff0 index, int amount) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf6; // Storage item removed - WFIFOW(s, 2) = index + 1; - WFIFOL(s, 4) = amount; - WFIFOSET(s, clif_parse_func_table[0xf6].len); + Packet_Fixed<0x00f6> fixed_f6; + fixed_f6.soff1 = index.shift(); + fixed_f6.amount = amount; + send_fpacket<0x00f6, 8>(s, fixed_f6); return 0; } @@ -2323,11 +2327,11 @@ int clif_storageitemremoved(dumb_ptr<map_session_data> sd, int index, */ int clif_storageclose(dumb_ptr<map_session_data> sd) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xf8; // Storage Closed - WFIFOSET(s, clif_parse_func_table[0xf8].len); + Packet_Fixed<0x00f8> fixed_f8; + send_fpacket<0x00f8, 2>(s, fixed_f8); return 0; } @@ -2335,7 +2339,7 @@ int clif_storageclose(dumb_ptr<map_session_data> sd) void clif_changelook_accessories(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> dest) { - for (LOOK i = LOOK::SHOES; i < LOOK::COUNT; i = LOOK(uint8_t(i) + 1)) + for (LOOK i = LOOK::SHOES; i < LOOK::COUNT; i = LOOK(static_cast<uint8_t>(i) + 1)) clif_changelook_towards(bl, i, 0, dest); } @@ -2350,25 +2354,22 @@ static void clif_getareachar_pc(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> dstsd) { - int len; - if (bool(dstsd->status.option & Option::INVISIBILITY)) return; nullpo_retv(sd); nullpo_retv(dstsd); - uint8_t buf[256]; + Buffer buf; if (dstsd->walktimer) { - len = clif_set007b(dstsd, buf); + clif_set007b(dstsd, buf); } else { - len = clif_set0078(dstsd, buf); + clif_set0078_main_1d8(dstsd, buf); } - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_buffer(sd->sess, buf); if (battle_config.save_clothcolor == 1 && dstsd->status.clothes_color > 0) clif_changelook(dstsd, LOOK::CLOTHES_COLOR, @@ -2385,16 +2386,15 @@ void clif_getareachar_pc(dumb_ptr<map_session_data> sd, static void clif_getareachar_npc(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data> nd) { - int len; - nullpo_retv(sd); nullpo_retv(nd); - if (nd->npc_class < 0 || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) + if (nd->npc_class == NEGATIVE_SPECIES || nd->flag & 1 || nd->npc_class == INVISIBLE_CLASS) return; - len = clif_npc0078(nd, static_cast<uint8_t *>(WFIFOP(sd->sess, 0))); - WFIFOSET(sd->sess, len); + Buffer buf; + clif_npc0078(nd, buf); + send_buffer(sd->sess, buf); } /*========================================== @@ -2403,13 +2403,11 @@ void clif_getareachar_npc(dumb_ptr<map_session_data> sd, dumb_ptr<npc_data> nd) */ int clif_movemob(dumb_ptr<mob_data> md) { - unsigned char buf[256]; - int len; + nullpo_retz(md); - nullpo_ret(md); - - len = clif_mob007b(md, buf); - clif_send(buf, len, md, SendWho::AREA); + Buffer buf; + clif_mob007b(md, buf); + clif_send(buf, md, SendWho::AREA); return 0; } @@ -2420,20 +2418,19 @@ int clif_movemob(dumb_ptr<mob_data> md) */ int clif_fixmobpos(dumb_ptr<mob_data> md) { - unsigned char buf[256]; - int len; - - nullpo_ret(md); + nullpo_retz(md); if (md->state.state == MS::WALK) { - len = clif_mob007b(md, buf); - clif_send(buf, len, md, SendWho::AREA); + Buffer buf; + clif_mob007b(md, buf); + clif_send(buf, md, SendWho::AREA); } else { - len = clif_mob0078(md, buf); - clif_send(buf, len, md, SendWho::AREA); + Buffer buf; + clif_mob0078(md, buf); + clif_send(buf, md, SendWho::AREA); } return 0; @@ -2445,22 +2442,21 @@ int clif_fixmobpos(dumb_ptr<mob_data> md) */ int clif_fixpcpos(dumb_ptr<map_session_data> sd) { - unsigned char buf[256]; - int len; - - nullpo_ret(sd); + nullpo_retz(sd); if (sd->walktimer) { - len = clif_set007b(sd, buf); - clif_send(buf, len, sd, SendWho::AREA); + Buffer buf; + clif_set007b(sd, buf); + clif_send(buf, sd, SendWho::AREA); } else { - len = clif_set0078(sd, buf); - clif_send(buf, len, sd, SendWho::AREA); + Buffer buf; + clif_set0078_main_1d8(sd, buf); + clif_send(buf, sd, SendWho::AREA); } - clif_changelook_accessories(sd, NULL); + clif_changelook_accessories(sd, nullptr); return 0; } @@ -2473,25 +2469,25 @@ int clif_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, tick_t tick, interval_t sdelay, interval_t ddelay, int damage, int div, DamageType type, int damage2) { - unsigned char buf[256]; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(src); - nullpo_ret(dst); + nullpo_retz(src); + nullpo_retz(dst); sc_data = battle_get_sc_data(dst); - WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = src->bl_id; - WBUFL(buf, 6) = dst->bl_id; - WBUFL(buf, 10) = tick.time_since_epoch().count(); - WBUFL(buf, 14) = sdelay.count(); - WBUFL(buf, 18) = ddelay.count(); - WBUFW(buf, 22) = (damage > 0x7fff) ? 0x7fff : damage; - WBUFW(buf, 24) = div; - WBUFB(buf, 26) = static_cast<uint8_t>(type); - WBUFW(buf, 27) = damage2; - clif_send(buf, clif_parse_func_table[0x8a].len, src, SendWho::AREA); + Packet_Fixed<0x008a> fixed_8a; + fixed_8a.src_id = src->bl_id; + fixed_8a.dst_id = dst->bl_id; + fixed_8a.tick = tick; + fixed_8a.sdelay = sdelay; + fixed_8a.ddelay = ddelay; + fixed_8a.damage = (damage > 0x7fff) ? 0x7fff : damage; + fixed_8a.div = div; + fixed_8a.damage_type = type; + fixed_8a.damage2 = damage2; + Buffer buf = create_fpacket<0x008a, 29>(fixed_8a); + clif_send(buf, src, SendWho::AREA); return 0; } @@ -2503,19 +2499,20 @@ int clif_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, static void clif_getareachar_mob(dumb_ptr<map_session_data> sd, dumb_ptr<mob_data> md) { - int len; nullpo_retv(sd); nullpo_retv(md); if (md->state.state == MS::WALK) { - len = clif_mob007b(md, static_cast<uint8_t *>(WFIFOP(sd->sess, 0))); - WFIFOSET(sd->sess, len); + Buffer buf; + clif_mob007b(md, buf); + send_buffer(sd->sess, buf); } else { - len = clif_mob0078(md, static_cast<uint8_t *>(WFIFOP(sd->sess, 0))); - WFIFOSET(sd->sess, len); + Buffer buf; + clif_mob0078(md, buf); + send_buffer(sd->sess, buf); } } @@ -2531,18 +2528,16 @@ void clif_getareachar_item(dumb_ptr<map_session_data> sd, nullpo_retv(fitem); Session *s = sd->sess; - //009d <ID>.l <item ID>.w <identify flag>.B <X>.w <Y>.w <amount>.w <subX>.B <subY>.B - WFIFOW(s, 0) = 0x9d; - WFIFOL(s, 2) = fitem->bl_id; - WFIFOW(s, 6) = fitem->item_data.nameid; - WFIFOB(s, 8) = 0; //identify; - WFIFOW(s, 9) = fitem->bl_x; - WFIFOW(s, 11) = fitem->bl_y; - WFIFOW(s, 13) = fitem->item_data.amount; - WFIFOB(s, 15) = fitem->subx; - WFIFOB(s, 16) = fitem->suby; - - WFIFOSET(s, clif_parse_func_table[0x9d].len); + Packet_Fixed<0x009d> fixed_9d; + fixed_9d.block_id = fitem->bl_id; + fixed_9d.name_id = fitem->item_data.nameid; + fixed_9d.identify = 0; + fixed_9d.x = fitem->bl_x; + fixed_9d.y = fitem->bl_y; + fixed_9d.amount = fitem->item_data.amount; + fixed_9d.subx = fitem->subx; + fixed_9d.suby = fitem->suby; + send_fpacket<0x009d, 17>(s, fixed_9d); } /*========================================== @@ -2578,7 +2573,7 @@ void clif_getareachar(dumb_ptr<block_list> bl, dumb_ptr<map_session_data> sd) break; default: if (battle_config.error_log) - PRINTF("get area char ??? %d\n", + PRINTF("get area char ??? %d\n"_fmt, bl->bl_type); break; } @@ -2694,32 +2689,32 @@ void clif_mobinsight(dumb_ptr<block_list> bl, dumb_ptr<mob_data> md) int clif_skillinfo(dumb_ptr<map_session_data> sd, SkillID skillid, int type, int range) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; if (!sd->status.skill[skillid].lv) return 0; - WFIFOW(s, 0) = 0x147; - WFIFOW(s, 2) = static_cast<uint16_t>(skillid); + Packet_Fixed<0x0147> fixed_147; + fixed_147.info.skill_id = skillid; if (type < 0) - WFIFOW(s, 4) = skill_get_inf(skillid); + fixed_147.info.type_or_inf = skill_get_inf(skillid); else - WFIFOW(s, 4) = type; - WFIFOW(s, 6) = 0; - WFIFOW(s, 8) = sd->status.skill[skillid].lv; - WFIFOW(s, 10) = skill_get_sp(skillid, sd->status.skill[skillid].lv); + fixed_147.info.type_or_inf = type; + fixed_147.info.flags = SkillFlags::ZERO; + fixed_147.info.level = sd->status.skill[skillid].lv; + fixed_147.info.sp = skill_get_sp(skillid, sd->status.skill[skillid].lv); if (range < 0) { range = skill_get_range(skillid, sd->status.skill[skillid].lv); if (range < 0) range = battle_get_range(sd) - (range + 1); - WFIFOW(s, 12) = range; + fixed_147.info.range = range; } else - WFIFOW(s, 12) = range; - WFIFO_ZERO(s, 14, 24); - WFIFOB(s, 38) = sd->status.skill[skillid].lv < skill_get_max_raise(skillid); - WFIFOSET(s, clif_parse_func_table[0x147].len); + fixed_147.info.range = range; + fixed_147.info.unused = ""_s; + fixed_147.info.can_raise = sd->status.skill[skillid].lv < skill_get_max_raise(skillid); + send_fpacket<0x0147, 39>(s, fixed_147); return 0; } @@ -2730,35 +2725,34 @@ int clif_skillinfo(dumb_ptr<map_session_data> sd, SkillID skillid, int type, */ void clif_skillinfoblock(dumb_ptr<map_session_data> sd) { - int len = 4, range; - nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x10f; + std::vector<Packet_Repeat<0x010f>> repeat_10f; for (SkillID i : erange(SkillID(), MAX_SKILL)) { if (sd->status.skill[i].lv && sd->tmw_version >= 1) { + Packet_Repeat<0x010f> info; // [Fate] Version 1 and later don't crash because of bad skill IDs anymore - WFIFOW(s, len) = static_cast<uint16_t>(i); - WFIFOW(s, len + 2) = skill_get_inf(i); - WFIFOW(s, len + 4) = static_cast<uint16_t>( + info.info.skill_id = i; + info.info.type_or_inf = skill_get_inf(i); + info.info.flags = ( skill_db[i].poolflags | (sd->status.skill[i].flags & SkillFlags::POOL_ACTIVATED)); - WFIFOW(s, len + 6) = sd->status.skill[i].lv; - WFIFOW(s, len + 8) = skill_get_sp(i, sd->status.skill[i].lv); - range = skill_get_range(i, sd->status.skill[i].lv); + info.info.level = sd->status.skill[i].lv; + info.info.sp = skill_get_sp(i, sd->status.skill[i].lv); + int range = skill_get_range(i, sd->status.skill[i].lv); if (range < 0) range = battle_get_range(sd) - (range + 1); - WFIFOW(s, len + 10) = range; - WFIFO_ZERO(s, len + 12, 24); - WFIFOB(s, len + 36) = sd->status.skill[i].lv < skill_get_max_raise(i); - len += 37; + info.info.range = range; + info.info.unused = ""_s; + info.info.can_raise = sd->status.skill[i].lv < skill_get_max_raise(i); + + repeat_10f.push_back(info); } } - WFIFOW(s, 2) = len; - WFIFOSET(s, len); + send_packet_repeatonly<0x010f, 4, 37>(s, repeat_10f); } /*========================================== @@ -2767,21 +2761,19 @@ void clif_skillinfoblock(dumb_ptr<map_session_data> sd) */ int clif_skillup(dumb_ptr<map_session_data> sd, SkillID skill_num) { - int range; - - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0x10e; - WFIFOW(s, 2) = uint16_t(skill_num); - WFIFOW(s, 4) = sd->status.skill[skill_num].lv; - WFIFOW(s, 6) = skill_get_sp(skill_num, sd->status.skill[skill_num].lv); - range = skill_get_range(skill_num, sd->status.skill[skill_num].lv); + Packet_Fixed<0x010e> fixed_10e; + fixed_10e.skill_id = skill_num; + fixed_10e.level = sd->status.skill[skill_num].lv; + fixed_10e.sp = skill_get_sp(skill_num, sd->status.skill[skill_num].lv); + int range = skill_get_range(skill_num, sd->status.skill[skill_num].lv); if (range < 0) range = battle_get_range(sd) - (range + 1); - WFIFOW(s, 8) = range; - WFIFOB(s, 10) = sd->status.skill[skill_num].lv < skill_get_max_raise(skill_num); - WFIFOSET(s, clif_parse_func_table[0x10e].len); + fixed_10e.range = range; + fixed_10e.can_raise = sd->status.skill[skill_num].lv < skill_get_max_raise(skill_num); + send_fpacket<0x010e, 11>(s, fixed_10e); return 0; } @@ -2792,14 +2784,11 @@ int clif_skillup(dumb_ptr<map_session_data> sd, SkillID skill_num) */ int clif_skillcastcancel(dumb_ptr<block_list> bl) { - unsigned char buf[16]; - - nullpo_ret(bl); - - WBUFW(buf, 0) = 0x1b9; - WBUFL(buf, 2) = bl->bl_id; - clif_send(buf, clif_parse_func_table[0x1b9].len, bl, SendWho::AREA); + // packet 0x01b9 was being sent with length 0, + // even though there were 6 bytes involved + // and the client ignores it anyway + (void)bl; return 0; } @@ -2810,7 +2799,7 @@ int clif_skillcastcancel(dumb_ptr<block_list> bl) int clif_skill_fail(dumb_ptr<map_session_data> sd, SkillID skill_id, int type, int btype) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; @@ -2819,13 +2808,13 @@ int clif_skill_fail(dumb_ptr<map_session_data> sd, SkillID skill_id, int type, return 0; } - WFIFOW(s, 0) = 0x110; - WFIFOW(s, 2) = uint16_t(skill_id); - WFIFOW(s, 4) = btype; - WFIFOW(s, 6) = 0; - WFIFOB(s, 8) = 0; - WFIFOB(s, 9) = type; - WFIFOSET(s, clif_parse_func_table[0x110].len); + Packet_Fixed<0x0110> fixed_110; + fixed_110.skill_id = skill_id; + fixed_110.btype = btype; + fixed_110.zero1 = 0; + fixed_110.zero2 = 0; + fixed_110.type = type; + send_fpacket<0x0110, 10>(s, fixed_110); return 0; } @@ -2838,26 +2827,26 @@ int clif_skill_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, tick_t tick, interval_t sdelay, interval_t ddelay, int damage, int div, SkillID skill_id, int skill_lv, int type) { - unsigned char buf[64]; eptr<struct status_change, StatusChange, StatusChange::MAX_STATUSCHANGE> sc_data; - nullpo_ret(src); - nullpo_ret(dst); + nullpo_retz(src); + nullpo_retz(dst); sc_data = battle_get_sc_data(dst); - WBUFW(buf, 0) = 0x1de; - WBUFW(buf, 2) = uint16_t(skill_id); - WBUFL(buf, 4) = src->bl_id; - WBUFL(buf, 8) = dst->bl_id; - WBUFL(buf, 12) = static_cast<uint32_t>(tick.time_since_epoch().count()); - WBUFL(buf, 16) = static_cast<uint32_t>(sdelay.count()); - WBUFL(buf, 20) = static_cast<uint32_t>(ddelay.count()); - WBUFL(buf, 24) = damage; - WBUFW(buf, 28) = skill_lv; - WBUFW(buf, 30) = div; - WBUFB(buf, 32) = (type > 0) ? type : skill_get_hit(skill_id); - clif_send(buf, clif_parse_func_table[0x1de].len, src, SendWho::AREA); + Packet_Fixed<0x01de> fixed_1de; + fixed_1de.skill_id = skill_id; + fixed_1de.src_id = src->bl_id; + fixed_1de.dst_id = dst->bl_id; + fixed_1de.tick = tick; + fixed_1de.sdelay = sdelay; + fixed_1de.ddelay = ddelay; + fixed_1de.damage = damage; + fixed_1de.skill_level = skill_lv; + fixed_1de.div = div; + fixed_1de.type_or_hit = (type > 0) ? type : skill_get_hit(skill_id); + Buffer buf = create_fpacket<0x01de, 33>(fixed_1de); + clif_send(buf, src, SendWho::AREA); return 0; } @@ -2868,15 +2857,14 @@ int clif_skill_damage(dumb_ptr<block_list> src, dumb_ptr<block_list> dst, */ int clif_status_change(dumb_ptr<block_list> bl, StatusChange type, int flag) { - unsigned char buf[16]; - - nullpo_ret(bl); + nullpo_retz(bl); - WBUFW(buf, 0) = 0x0196; - WBUFW(buf, 2) = uint16_t(type); - WBUFL(buf, 4) = bl->bl_id; - WBUFB(buf, 8) = flag; - clif_send(buf, clif_parse_func_table[0x196].len, bl, SendWho::AREA); + Packet_Fixed<0x0196> fixed_196; + fixed_196.sc_type = type; + fixed_196.block_id = bl->bl_id; + fixed_196.flag = flag; + Buffer buf = create_fpacket<0x0196, 9>(fixed_196); + clif_send(buf, bl, SendWho::AREA); return 0; } @@ -2889,11 +2877,8 @@ void clif_displaymessage(Session *s, XString mes) if (mes) { // don't send a void message (it's not displaying on the client chat). @help can send void line. - WFIFOW(s, 0) = 0x8e; - size_t str_len = mes.size() + 1; // NUL (might not be NUL yet) - WFIFOW(s, 2) = 4 + str_len; - WFIFO_STRING(s, 4, mes, str_len); - WFIFOSET(s, 4 + str_len); + // This is untrue now ^ + send_packet_repeatonly<0x008e, 4, 1>(s, mes); } } @@ -2903,14 +2888,9 @@ void clif_displaymessage(Session *s, XString mes) */ void clif_GMmessage(dumb_ptr<block_list> bl, XString mes, int flag) { - size_t str_len = mes.size() + 1; - unsigned char buf[str_len + 4]; - - WBUFW(buf, 0) = 0x9a; - WBUFW(buf, 2) = str_len + 4; - WBUF_STRING(buf, 4, mes, str_len); + Buffer buf = create_packet_repeatonly<0x009a, 4, 1>(mes); flag &= 0x07; - clif_send(buf, WBUFW(buf, 2), bl, + clif_send(buf, bl, (flag == 1) ? SendWho::ALL_SAMEMAP : (flag == 2) ? SendWho::AREA : (flag == 3) ? SendWho::SELF : @@ -2923,15 +2903,14 @@ void clif_GMmessage(dumb_ptr<block_list> bl, XString mes, int flag) */ void clif_resurrection(dumb_ptr<block_list> bl, int type) { - uint8_t buf[16]; - nullpo_retv(bl); - WBUFW(buf, 0) = 0x148; - WBUFL(buf, 2) = bl->bl_id; - WBUFW(buf, 6) = type; + Packet_Fixed<0x0148> fixed_148; + fixed_148.block_id = bl->bl_id; + fixed_148.type = type; + Buffer buf = create_fpacket<0x0148, 8>(fixed_148); - clif_send(buf, clif_parse_func_table[0x148].len, bl, + clif_send(buf, bl, type == 1 ? SendWho::AREA : SendWho::AREA_WOS); } @@ -2941,12 +2920,9 @@ void clif_resurrection(dumb_ptr<block_list> bl, int type) */ void clif_wis_message(Session *s, CharName nick, XString mes) // R 0097 <len>.w <nick>.24B <message>.?B { - size_t mes_len = mes.size() + 1; - WFIFOW(s, 0) = 0x97; - WFIFOW(s, 2) = mes_len + 24 + 4; - WFIFO_STRING(s, 4, nick.to__actual(), 24); - WFIFO_STRING(s, 28, mes, mes_len); - WFIFOSET(s, WFIFOW(s, 2)); + Packet_Head<0x0097> head_97; + head_97.char_name = nick; + send_vpacket<0x0097, 28, 1>(s, head_97, mes); } /*========================================== @@ -2955,9 +2931,9 @@ void clif_wis_message(Session *s, CharName nick, XString mes) // R 0097 <len>. */ void clif_wis_end(Session *s, int flag) // R 0098 <type>.B: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target { - WFIFOW(s, 0) = 0x98; - WFIFOW(s, 2) = flag; - WFIFOSET(s, clif_parse_func_table[0x98].len); + Packet_Fixed<0x0098> fixed_98; + fixed_98.flag = flag; + send_fpacket<0x0098, 3>(s, fixed_98); } /*========================================== @@ -2974,12 +2950,12 @@ void clif_wis_end(Session *s, int flag) // R 0098 <type>.B: 0: success to send w */ int clif_party_created(dumb_ptr<map_session_data> sd, int flag) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xfa; - WFIFOB(s, 2) = flag; - WFIFOSET(s, clif_parse_func_table[0xfa].len); + Packet_Fixed<0x00fa> fixed_fa; + fixed_fa.flag = flag; + send_fpacket<0x00fa, 3>(s, fixed_fa); return 0; } @@ -2987,43 +2963,45 @@ int clif_party_created(dumb_ptr<map_session_data> sd, int flag) * パーティ情報送信 *------------------------------------------ */ -int clif_party_info(struct party *p, Session *s) +int clif_party_info(PartyPair p, Session *s) { - unsigned char buf[1024]; - int i, c; - dumb_ptr<map_session_data> sd = NULL; + int i; + dumb_ptr<map_session_data> sd = nullptr; - nullpo_ret(p); + nullpo_retz(p); - WBUFW(buf, 0) = 0xfb; - WBUF_STRING(buf, 4, p->name, 24); - for (i = c = 0; i < MAX_PARTY; i++) + Packet_Head<0x00fb> head_fb; + std::vector<Packet_Repeat<0x00fb>> repeat_fb; + head_fb.party_name = p->name; + for (i = 0; i < MAX_PARTY; i++) { - struct party_member *m = &p->member[i]; - if (m->account_id > 0) + PartyMember *m = &p->member[i]; + if (m->account_id) { - if (sd == NULL) + Packet_Repeat<0x00fb> info; + if (sd == nullptr) sd = dumb_ptr<map_session_data>(m->sd); - WBUFL(buf, 28 + c * 46) = m->account_id; - WBUF_STRING(buf, 28 + c * 46 + 4, m->name.to__actual(), 24); - WBUF_STRING(buf, 28 + c * 46 + 28, m->map, 16); - WBUFB(buf, 28 + c * 46 + 44) = (m->leader) ? 0 : 1; - WBUFB(buf, 28 + c * 46 + 45) = (m->online) ? 0 : 1; - c++; + + info.account_id = m->account_id; + info.char_name = m->name; + info.map_name = m->map; + info.leader = (m->leader) ? 0 : 1; + info.online = (m->online) ? 0 : 1; + repeat_fb.push_back(info); } } - size_t len = 28 + c * 46; - WBUFW(buf, 2) = len; if (s) { // If set, send only to fd. - WFIFO_BUF_CLONE(s, buf, len); - WFIFOSET(s, len); + send_vpacket<0x00fb, 28, 46>(s, head_fb, repeat_fb); return 9; } // else, send it to all the party, if they exist. - if (sd != NULL) - clif_send(buf, len, sd, SendWho::PARTY); + if (sd != nullptr) + { + Buffer buf = create_vpacket<0x00fb, 28, 46>(head_fb, repeat_fb); + clif_send(buf, sd, SendWho::PARTY); + } return 0; } @@ -3037,7 +3015,7 @@ int clif_party_info(struct party *p, Session *s) void clif_party_invite(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd) { - struct party *p; + PartyPair p; nullpo_retv(sd); nullpo_retv(tsd); @@ -3047,10 +3025,10 @@ void clif_party_invite(dumb_ptr<map_session_data> sd, if (!(p = party_search(sd->status.party_id))) return; - WFIFOW(s, 0) = 0xfe; - WFIFOL(s, 2) = sd->status_key.account_id; - WFIFO_STRING(s, 6, p->name, 24); - WFIFOSET(s, clif_parse_func_table[0xfe].len); + Packet_Fixed<0x00fe> fixed_fe; + fixed_fe.account_id = sd->status_key.account_id; + fixed_fe.party_name = p->name; + send_fpacket<0x00fe, 30>(s, fixed_fe); } /*========================================== @@ -3072,10 +3050,10 @@ void clif_party_inviteack(dumb_ptr<map_session_data> sd, CharName nick, int flag nullpo_retv(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xfd; - WFIFO_STRING(s, 2, nick.to__actual(), 24); - WFIFOB(s, 26) = flag; - WFIFOSET(s, clif_parse_func_table[0xfd].len); + Packet_Fixed<0x00fd> fixed_fd; + fixed_fd.char_name = nick; + fixed_fd.flag = flag; + send_fpacket<0x00fd, 27>(s, fixed_fd); } /*========================================== @@ -3085,32 +3063,30 @@ void clif_party_inviteack(dumb_ptr<map_session_data> sd, CharName nick, int flag * 0x100=一人にのみ送信 *------------------------------------------ */ -void clif_party_option(struct party *p, dumb_ptr<map_session_data> sd, int flag) +void clif_party_option(PartyPair p, dumb_ptr<map_session_data> sd, int flag) { - unsigned char buf[16]; - nullpo_retv(p); -// if(battle_config.etc_log) -// PRINTF("clif_party_option: %d %d %d\n",p->exp,p->item,flag); - if (sd == NULL && flag == 0) + if (sd == nullptr && flag == 0) { int i; for (i = 0; i < MAX_PARTY; i++) - if ((sd = map_id2sd(p->member[i].account_id)) != NULL) + if ((sd = map_id2sd(account_to_block(p->member[i].account_id))) != nullptr) break; } - if (sd == NULL) + if (sd == nullptr) return; - WBUFW(buf, 0) = 0x101; - WBUFW(buf, 2) = ((flag & 0x01) ? 2 : p->exp); - WBUFW(buf, 4) = ((flag & 0x10) ? 2 : p->item); + Packet_Fixed<0x0101> fixed_101; + fixed_101.exp = ((flag & 0x01) ? 2 : p->exp); + fixed_101.item = ((flag & 0x10) ? 2 : p->item); if (flag == 0) - clif_send(buf, clif_parse_func_table[0x101].len, sd, SendWho::PARTY); + { + Buffer buf = create_fpacket<0x0101, 6>(fixed_101); + clif_send(buf, sd, SendWho::PARTY); + } else { - WFIFO_BUF_CLONE(sd->sess, buf, clif_parse_func_table[0x101].len); - WFIFOSET(sd->sess, clif_parse_func_table[0x101].len); + send_fpacket<0x0101, 6>(sd->sess, fixed_101); } } @@ -3118,35 +3094,36 @@ void clif_party_option(struct party *p, dumb_ptr<map_session_data> sd, int flag) * パーティ脱退(脱退前に呼ぶこと) *------------------------------------------ */ -void clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, - int account_id, CharName name, int flag) +void clif_party_leaved(PartyPair p, dumb_ptr<map_session_data> sd, + AccountId account_id, CharName name, int flag) { - unsigned char buf[64]; int i; nullpo_retv(p); - WBUFW(buf, 0) = 0x105; - WBUFL(buf, 2) = account_id; - WBUF_STRING(buf, 6, name.to__actual(), 24); - WBUFB(buf, 30) = flag & 0x0f; + Packet_Fixed<0x0105> fixed_105; + fixed_105.account_id = account_id; + fixed_105.char_name = name; + fixed_105.flag = flag & 0x0f; if ((flag & 0xf0) == 0) { - if (sd == NULL) + if (sd == nullptr) for (i = 0; i < MAX_PARTY; i++) { sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL) + if (sd != nullptr) break; } - if (sd != NULL) - clif_send(buf, clif_parse_func_table[0x105].len, sd, SendWho::PARTY); + if (sd != nullptr) + { + Buffer buf = create_fpacket<0x0105, 31>(fixed_105); + clif_send(buf, sd, SendWho::PARTY); + } } - else if (sd != NULL) + else if (sd != nullptr) { - WFIFO_BUF_CLONE(sd->sess, buf, clif_parse_func_table[0x105].len); - WFIFOSET(sd->sess, clif_parse_func_table[0x105].len); + send_fpacket<0x0105, 31>(sd->sess, fixed_105); } } @@ -3154,7 +3131,7 @@ void clif_party_leaved(struct party *p, dumb_ptr<map_session_data> sd, * パーティメッセージ送信 *------------------------------------------ */ -void clif_party_message(struct party *p, int account_id, XString mes) +void clif_party_message(PartyPair p, AccountId account_id, XString mes) { // always set, but clang is not smart enough dumb_ptr<map_session_data> sd = nullptr; @@ -3165,18 +3142,15 @@ void clif_party_message(struct party *p, int account_id, XString mes) for (i = 0; i < MAX_PARTY; i++) { sd = dumb_ptr<map_session_data>(p->member[i].sd); - if (sd != NULL) + if (sd != nullptr) break; } - if (sd != NULL) + if (sd != nullptr) { - size_t len = mes.size() + 1; - unsigned char buf[len + 8]; - WBUFW(buf, 0) = 0x109; - WBUFW(buf, 2) = len + 8; - WBUFL(buf, 4) = account_id; - WBUF_STRING(buf, 8, mes, len); - clif_send(buf, len + 8, sd, SendWho::PARTY); + Packet_Head<0x0109> head_109; + head_109.account_id = account_id; + Buffer buf = create_vpacket<0x0109, 8, 1>(head_109, mes); + clif_send(buf, sd, SendWho::PARTY); } } @@ -3184,19 +3158,16 @@ void clif_party_message(struct party *p, int account_id, XString mes) * パーティ座標通知 *------------------------------------------ */ -int clif_party_xy(struct party *, dumb_ptr<map_session_data> sd) +int clif_party_xy(PartyPair , dumb_ptr<map_session_data> sd) { - unsigned char buf[16]; - - nullpo_ret(sd); + nullpo_retz(sd); - WBUFW(buf, 0) = 0x107; - WBUFL(buf, 2) = sd->status_key.account_id; - WBUFW(buf, 6) = sd->bl_x; - WBUFW(buf, 8) = sd->bl_y; - clif_send(buf, clif_parse_func_table[0x107].len, sd, SendWho::PARTY_SAMEMAP_WOS); -// if(battle_config.etc_log) -// PRINTF("clif_party_xy %d\n",sd->status_key.account_id); + Packet_Fixed<0x0107> fixed_107; + fixed_107.account_id = sd->status_key.account_id; + fixed_107.x = sd->bl_x; + fixed_107.y = sd->bl_y; + Buffer buf = create_fpacket<0x0107, 10>(fixed_107); + clif_send(buf, sd, SendWho::PARTY_SAMEMAP_WOS); return 0; } @@ -3204,20 +3175,17 @@ int clif_party_xy(struct party *, dumb_ptr<map_session_data> sd) * パーティHP通知 *------------------------------------------ */ -int clif_party_hp(struct party *, dumb_ptr<map_session_data> sd) +int clif_party_hp(PartyPair , dumb_ptr<map_session_data> sd) { - unsigned char buf[16]; - - nullpo_ret(sd); + nullpo_retz(sd); - WBUFW(buf, 0) = 0x106; - WBUFL(buf, 2) = sd->status_key.account_id; - WBUFW(buf, 6) = (sd->status.hp > 0x7fff) ? 0x7fff : sd->status.hp; - WBUFW(buf, 8) = + Packet_Fixed<0x0106> fixed_106; + fixed_106.account_id = sd->status_key.account_id; + fixed_106.hp = (sd->status.hp > 0x7fff) ? 0x7fff : sd->status.hp; + fixed_106.max_hp = (sd->status.max_hp > 0x7fff) ? 0x7fff : sd->status.max_hp; - clif_send(buf, clif_parse_func_table[0x106].len, sd, SendWho::PARTY_AREA_WOS); -// if(battle_config.etc_log) -// PRINTF("clif_party_hp %d\n",sd->status_key.account_id); + Buffer buf = create_fpacket<0x0106, 10>(fixed_106); + clif_send(buf, sd, SendWho::PARTY_AREA_WOS); return 0; } @@ -3227,18 +3195,18 @@ int clif_party_hp(struct party *, dumb_ptr<map_session_data> sd) */ int clif_movetoattack(dumb_ptr<map_session_data> sd, dumb_ptr<block_list> bl) { - nullpo_ret(sd); - nullpo_ret(bl); + nullpo_retz(sd); + nullpo_retz(bl); Session *s = sd->sess; - WFIFOW(s, 0) = 0x139; - WFIFOL(s, 2) = bl->bl_id; - WFIFOW(s, 6) = bl->bl_x; - WFIFOW(s, 8) = bl->bl_y; - WFIFOW(s, 10) = sd->bl_x; - WFIFOW(s, 12) = sd->bl_y; - WFIFOW(s, 14) = sd->attackrange; - WFIFOSET(s, clif_parse_func_table[0x139].len); + Packet_Fixed<0x0139> fixed_139; + fixed_139.block_id = bl->bl_id; + fixed_139.bl_x = bl->bl_x; + fixed_139.bl_y = bl->bl_y; + fixed_139.sd_x = sd->bl_x; + fixed_139.sd_y = sd->bl_y; + fixed_139.range = sd->attackrange; + send_fpacket<0x0139, 16>(s, fixed_139); return 0; } @@ -3248,13 +3216,12 @@ int clif_movetoattack(dumb_ptr<map_session_data> sd, dumb_ptr<block_list> bl) */ int clif_mvp_effect(dumb_ptr<map_session_data> sd) { - unsigned char buf[16]; + nullpo_retz(sd); - nullpo_ret(sd); - - WBUFW(buf, 0) = 0x10c; - WBUFL(buf, 2) = sd->bl_id; - clif_send(buf, clif_parse_func_table[0x10c].len, sd, SendWho::AREA); + Packet_Fixed<0x010c> fixed_10c; + fixed_10c.block_id = sd->bl_id; + Buffer buf = create_fpacket<0x010c, 6>(fixed_10c); + clif_send(buf, sd, SendWho::AREA); return 0; } @@ -3264,22 +3231,19 @@ int clif_mvp_effect(dumb_ptr<map_session_data> sd) */ void clif_emotion(dumb_ptr<block_list> bl, int type) { - unsigned char buf[8]; - nullpo_retv(bl); - WBUFW(buf, 0) = 0xc0; - WBUFL(buf, 2) = bl->bl_id; - WBUFB(buf, 6) = type; - clif_send(buf, clif_parse_func_table[0xc0].len, bl, SendWho::AREA); + Packet_Fixed<0x00c0> fixed_c0; + fixed_c0.block_id = bl->bl_id; + fixed_c0.type = type; + Buffer buf = create_fpacket<0x00c0, 7>(fixed_c0); + clif_send(buf, bl, SendWho::AREA); } static void clif_emotion_towards(dumb_ptr<block_list> bl, dumb_ptr<block_list> target, int type) { - unsigned char buf[8]; - int len = clif_parse_func_table[0xc0].len; dumb_ptr<map_session_data> sd = target->is_player(); nullpo_retv(bl); @@ -3288,12 +3252,11 @@ void clif_emotion_towards(dumb_ptr<block_list> bl, if (target->bl_type != BL::PC) return; - WBUFW(buf, 0) = 0xc0; - WBUFL(buf, 2) = bl->bl_id; - WBUFB(buf, 6) = type; + Packet_Fixed<0x00c0> fixed_c0; + fixed_c0.block_id = bl->bl_id; + fixed_c0.type = type; - WFIFO_BUF_CLONE(sd->sess, buf, len); - WFIFOSET(sd->sess, len); + send_fpacket<0x00c0, 7>(sd->sess, fixed_c0); } /*========================================== @@ -3302,14 +3265,13 @@ void clif_emotion_towards(dumb_ptr<block_list> bl, */ void clif_sitting(Session *, dumb_ptr<map_session_data> sd) { - unsigned char buf[64]; - nullpo_retv(sd); - WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = sd->bl_id; - WBUFB(buf, 26) = 2; - clif_send(buf, clif_parse_func_table[0x8a].len, sd, SendWho::AREA); + Packet_Fixed<0x008a> fixed_8a; + fixed_8a.src_id = sd->bl_id; + fixed_8a.damage_type = DamageType::SIT; + Buffer buf = create_fpacket<0x008a, 29>(fixed_8a); + clif_send(buf, sd, SendWho::AREA); } /*========================================== @@ -3317,30 +3279,30 @@ void clif_sitting(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -int clif_GM_kickack(dumb_ptr<map_session_data> sd, int id) +int clif_GM_kickack(dumb_ptr<map_session_data> sd, AccountId id) { - nullpo_ret(sd); + nullpo_retz(sd); Session *s = sd->sess; - WFIFOW(s, 0) = 0xcd; - WFIFOL(s, 2) = id; - WFIFOSET(s, clif_parse_func_table[0xcd].len); + Packet_Fixed<0x00cd> fixed_cd; + fixed_cd.account_id = id; + send_fpacket<0x00cd, 6>(s, fixed_cd); return 0; } static -void clif_parse_QuitGame(Session *s, dumb_ptr<map_session_data> sd); +void clif_do_quit_game(Session *s, dumb_ptr<map_session_data> sd); int clif_GM_kick(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd, int type) { - nullpo_ret(tsd); + nullpo_retz(tsd); if (type) clif_GM_kickack(sd, tsd->status_key.account_id); tsd->opt1 = Opt1::ZERO; tsd->opt2 = Opt2::ZERO; - clif_parse_QuitGame(tsd->sess, tsd); + clif_do_quit_game(tsd->sess, tsd); return 0; } @@ -3348,15 +3310,12 @@ int clif_GM_kick(dumb_ptr<map_session_data> sd, dumb_ptr<map_session_data> tsd, // displaying special effects (npcs, weather, etc) [Valaris] int clif_specialeffect(dumb_ptr<block_list> bl, int type, int flag) { - unsigned char buf[24]; - - nullpo_ret(bl); + nullpo_retz(bl); - WBUF_ZERO(buf, 0, clif_parse_func_table[0x19b].len); - - WBUFW(buf, 0) = 0x19b; - WBUFL(buf, 2) = bl->bl_id; - WBUFL(buf, 6) = type; + Packet_Fixed<0x019b> fixed_19b; + fixed_19b.block_id = bl->bl_id; + fixed_19b.type = type; + Buffer buf = create_fpacket<0x019b, 10>(fixed_19b); if (flag == 2) { @@ -3371,9 +3330,9 @@ int clif_specialeffect(dumb_ptr<block_list> bl, int type, int flag) } } else if (flag == 1) - clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::SELF); + clif_send(buf, bl, SendWho::SELF); else if (!flag) - clif_send(buf, clif_parse_func_table[0x19b].len, bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); return 0; @@ -3388,35 +3347,39 @@ int clif_specialeffect(dumb_ptr<block_list> bl, int type, int flag) *------------------------------------------ */ static -void clif_parse_WantToConnection(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_WantToConnection(Session *s, dumb_ptr<map_session_data> sd) { - int account_id; // account_id in the packet + AccountId account_id; // account_id in the packet if (sd) { if (battle_config.error_log) - PRINTF("clif_parse_WantToConnection : invalid request?\n"); - return; + PRINTF("clif_parse_WantToConnection : invalid request?\n"_fmt); + return RecvResult::Error; } - if (RFIFOW(s, 0) == 0x72) + Packet_Fixed<0x0072> fixed; + RecvResult rv = recv_fpacket<0x0072, 19>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + { - account_id = RFIFOL(s, 2); + account_id = fixed.account_id; } - else - return; // Not the auth packet - WFIFOL(s, 0) = account_id; - WFIFOSET(s, 4); + // formerly: account id + Packet_Payload<0x8000> special; + special.magic_packet_length = 4; + send_ppacket<0x8000>(s, special); // if same account already connected, we disconnect the 2 sessions - dumb_ptr<map_session_data> old_sd = map_id2sd(account_id); + dumb_ptr<map_session_data> old_sd = map_id2sd(account_to_block(account_id)); if (old_sd) { clif_authfail_fd(s, 2); // same id clif_authfail_fd(old_sd->sess, 2); // same id - PRINTF("clif_parse_WantToConnection: Double connection for account %d (sessions: #%d (new) and #%d (old)).\n", - account_id, s, old_sd->sess); + PRINTF("clif_parse_WantToConnection: Double connection for account %d (sessions: #%d (new) and #%d (old)).\n"_fmt, + account_id, s, old_sd->sess); } else { @@ -3424,16 +3387,16 @@ void clif_parse_WantToConnection(Session *s, dumb_ptr<map_session_data> sd) s->session_data.reset(sd.operator->()); sd->sess = s; - pc_setnewpc(sd, account_id, RFIFOL(s, 6), RFIFOL(s, 10), - tick_t(static_cast<interval_t>(RFIFOL(s, 14))), - static_cast<SEX>(RFIFOB(s, 18))); + pc_setnewpc(sd, account_id, fixed.char_id, fixed.login_id1, + fixed.client_tick, + fixed.sex); map_addiddb(sd); chrif_authreq(sd); } - return; + return RecvResult::Complete; } /*========================================== @@ -3442,12 +3405,15 @@ void clif_parse_WantToConnection(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_LoadEndAck(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + if (sd->bl_prev != nullptr) + return RecvResult::Error; - if (sd->bl_prev != NULL) - return; + Packet_Fixed<0x007d> fixed; + RecvResult rv = recv_fpacket<0x007d, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; // 接続ok時 //clif_authok(); @@ -3494,7 +3460,7 @@ void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) if (!battle_config.pk_mode) { // remove pvp stuff for pk_mode [Valaris] - sd->pvp_timer = Timer(gettick() + std::chrono::milliseconds(200), + sd->pvp_timer = Timer(gettick() + 200_ms, std::bind(pc_calc_pvprank_timer, ph::_1, ph::_2, sd->bl_id)); sd->pvp_rank = 0; @@ -3519,7 +3485,7 @@ void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) clif_changeoption(sd); // broken equipment -// clif_changelook_accessories(sd, NULL); +// clif_changelook_accessories(sd, nullptr); map_foreachinarea(std::bind(clif_getareachar, ph::_1, sd), sd->bl_m, @@ -3529,6 +3495,8 @@ void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) if (!sd->state.seen_motd) pc_show_motd(sd); + + return rv; } /*========================================== @@ -3536,13 +3504,18 @@ void clif_parse_LoadEndAck(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TickSend(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TickSend(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x007e> fixed; + RecvResult rv = recv_fpacket<0x007e, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - sd->client_tick = tick_t(static_cast<interval_t>(RFIFOL(s, 2))); - sd->server_tick = gettick(); + uint32_t client_tick = fixed.client_tick; + (void)client_tick; clif_servertick(sd); + + return rv; } /*========================================== @@ -3550,71 +3523,83 @@ void clif_parse_TickSend(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_WalkToXY(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_WalkToXY(Session *s, dumb_ptr<map_session_data> sd) { - int x, y; - - nullpo_retv(sd); + Packet_Fixed<0x0085> fixed; + RecvResult rv = recv_fpacket<0x0085, 5>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0 || sd->state.storage_open) - return; + if (sd->npc_id || sd->state.storage_open) + return rv; if (sd->canmove_tick > gettick()) - return; + return rv; // ステータス異常やハイディング中(トンネルドライブ無)で動けない if (bool(sd->opt1) && sd->opt1 != (Opt1::_stone6)) - return; + return rv; if (sd->invincible_timer) pc_delinvincibletimer(sd); pc_stopattack(sd); - x = RFIFOB(s, 2) * 4 + (RFIFOB(s, 3) >> 6); - y = ((RFIFOB(s, 3) & 0x3f) << 4) + (RFIFOB(s, 4) >> 4); + int x = fixed.pos.x; + int y = fixed.pos.y; pc_walktoxy(sd, x, y); + return rv; } /*========================================== * *------------------------------------------ */ -void clif_parse_QuitGame(Session *s, dumb_ptr<map_session_data> sd) +static +RecvResult clif_parse_QuitGame(Session *s, dumb_ptr<map_session_data> sd) { - tick_t tick = gettick(); + Packet_Fixed<0x018a> fixed; + RecvResult rv = recv_fpacket<0x018a, 4>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); + clif_do_quit_game(s, sd); + return rv; +} + +void clif_do_quit_game(Session *s, dumb_ptr<map_session_data> sd) +{ + + tick_t tick = gettick(); - WFIFOW(s, 0) = 0x18b; + Packet_Fixed<0x018b> fixed_18b; if ((!pc_isdead(sd) && (sd->opt1 != Opt1::ZERO || sd->opt2 != Opt2::ZERO)) || (tick < sd->canact_tick)) { - WFIFOW(s, 2) = 1; - WFIFOSET(s, clif_parse_func_table[0x18b].len); + fixed_18b.okay = 1; + send_fpacket<0x018b, 4>(s, fixed_18b); return; } /* Rovert's prevent logout option fixed [Valaris] */ if (!battle_config.prevent_logout - || tick >= sd->canlog_tick + std::chrono::seconds(10)) + || tick >= sd->canlog_tick + 10_s) { clif_setwaitclose(s); - WFIFOW(s, 2) = 0; + fixed_18b.okay = 0; } else { - WFIFOW(s, 2) = 1; + fixed_18b.okay = 1; } - WFIFOSET(s, clif_parse_func_table[0x18b].len); - + send_fpacket<0x018b, 4>(s, fixed_18b); } /*========================================== @@ -3622,18 +3607,23 @@ void clif_parse_QuitGame(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x0094> fixed; + RecvResult rv = recv_fpacket<0x0094, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + dumb_ptr<block_list> bl; - int account_id; + BlockId account_id; - account_id = RFIFOL(s, 2); + account_id = fixed.block_id; bl = map_id2bl(account_id); - if (bl == NULL) - return; + if (bl == nullptr) + return rv; - WFIFOW(s, 0) = 0x95; - WFIFOL(s, 2) = account_id; + Packet_Fixed<0x0095> fixed_95; + fixed_95.block_id = account_id; switch (bl->bl_type) { @@ -3641,21 +3631,21 @@ void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) { dumb_ptr<map_session_data> ssd = bl->is_player(); - nullpo_retv(ssd); + nullpo_retr(rv, ssd); if (ssd->state.shroud_active) - WFIFO_STRING(s, 6, "", 24); + fixed_95.char_name = CharName(); else - WFIFO_STRING(s, 6, ssd->status_key.name.to__actual(), 24); - WFIFOSET(s, clif_parse_func_table[0x95].len); + fixed_95.char_name = ssd->status_key.name; + send_fpacket<0x0095, 30>(s, fixed_95); - struct party *p = NULL; + PartyPair p; PartyName party_name; int send = 0; - if (ssd->status.party_id > 0 && (p = party_search(ssd->status.party_id)) != NULL) + if (ssd->status.party_id && (p = party_search(ssd->status.party_id))) { party_name = p->name; send = 1; @@ -3663,30 +3653,28 @@ void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) if (send) { - WFIFOW(s, 0) = 0x195; - WFIFOL(s, 2) = account_id; - WFIFO_STRING(s, 6, party_name, 24); - WFIFO_STRING(s, 30, "", 24); - WFIFO_STRING(s, 54, "", 24); - WFIFO_STRING(s, 78, "", 24); // We send this value twice because the client expects it - WFIFOSET(s, clif_parse_func_table[0x195].len); - + Packet_Fixed<0x0195> fixed_195; + fixed_195.block_id = account_id; + fixed_195.party_name = party_name; + fixed_195.guild_name = ""_s; + fixed_195.guild_pos = ""_s; + fixed_195.guild_pos = ""_s; // We send this value twice because the client expects it + send_fpacket<0x0195, 102>(s, fixed_195); } - if (pc_isGM(sd) >= battle_config.hack_info_GM_level) + if (pc_isGM(sd).satisfies(GmLevel::from(static_cast<uint32_t>(battle_config.hack_info_GM_level)))) { IP4Address ip = ssd->get_ip(); - WFIFOW(s, 0) = 0x20C; + Packet_Fixed<0x020c> fixed_20c; // Mask the IP using the char-server password if (battle_config.mask_ip_gms) ip = MD5_ip(ip); - WFIFOL(s, 2) = account_id; - WFIFOIP(s, 6) = ip; - WFIFOSET(s, clif_parse_func_table[0x20C].len); + fixed_20c.block_id = account_id; + fixed_20c.ip = ip; + send_fpacket<0x020c, 10>(s, fixed_20c); } - } break; case BL::NPC: @@ -3694,26 +3682,28 @@ void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) NpcName name = bl->is_npc()->name; // [fate] elim hashed out/invisible names for the client auto it = std::find(name.begin(), name.end(), '#'); - WFIFO_STRING(s, 6, name.xislice_h(it), 24); - WFIFOSET(s, clif_parse_func_table[0x95].len); + fixed_95.char_name = stringish<CharName>(name.xislice_h(it)); + send_fpacket<0x0095, 30>(s, fixed_95); } break; case BL::MOB: { dumb_ptr<mob_data> md = bl->is_mob(); - nullpo_retv(md); + nullpo_retr(rv, md); - WFIFO_STRING(s, 6, md->name, 24); - WFIFOSET(s, clif_parse_func_table[0x95].len); + fixed_95.char_name = stringish<CharName>(md->name); + send_fpacket<0x0095, 30>(s, fixed_95); } break; default: if (battle_config.error_log) - PRINTF("clif_parse_GetCharNameRequest : bad type %d (%d)\n", + PRINTF("clif_parse_GetCharNameRequest : bad type %d (%d)\n"_fmt, bl->bl_type, account_id); break; } + + return rv; } /*========================================== @@ -3724,63 +3714,60 @@ void clif_parse_GetCharNameRequest(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_GlobalMessage(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_GlobalMessage(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + AString repeat; + RecvResult rv = recv_packet_repeatonly<0x008c, 4, 1>(s, repeat); + if (rv != RecvResult::Complete) + return rv; - AString mbuf = clif_validate_chat(sd, ChatType::Global); + AString mbuf = clif_validate_chat(sd, ChatType::Global, repeat); if (!mbuf) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } - if (is_atcommand(s, sd, mbuf, 0)) - return; + if (is_atcommand(s, sd, mbuf, GmLevel())) + return rv; if (!magic_message(sd, mbuf)) { /* Don't send chat that results in an automatic ban. */ if (tmw_CheckChatSpam(sd, mbuf)) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } /* It's not a spell/magic message, so send the message to others. */ - size_t mbuf_size = mbuf.size() + 1; - uint8_t sendbuf[mbuf_size + 8]; - WBUFW(sendbuf, 0) = 0x8d; - WBUFW(sendbuf, 2) = mbuf_size + 8; /* Header(2) + length(2) + ID(4). */ - WBUFL(sendbuf, 4) = sd->bl_id; - WBUF_STRING(sendbuf, 8, mbuf, mbuf_size); - - clif_send(sendbuf, mbuf_size + 8, sd, SendWho::AREA_CHAT_WOC); + Packet_Head<0x008d> head_8d; + head_8d.block_id = sd->bl_id; + XString repeat_8d = mbuf; + Buffer sendbuf = create_vpacket<0x008d, 8, 1>(head_8d, repeat_8d); + + clif_send(sendbuf, sd, SendWho::AREA_CHAT_WOC); } /* Send the message back to the speaker. */ - size_t len = RFIFOW(s, 2); - RFIFO_WFIFO_CLONE(s, s, len); - WFIFOW(s, 0) = 0x8e; - WFIFOSET(s, len); + send_packet_repeatonly<0x008e, 4, 1>(s, repeat); + + return rv; } void clif_message(dumb_ptr<block_list> bl, XString msg) { size_t msg_len = msg.size() + 1; - uint8_t buf[512]; - if (msg_len + 16 > 512) return; nullpo_retv(bl); - WBUFW(buf, 0) = 0x8d; - WBUFW(buf, 2) = msg_len + 8; - WBUFL(buf, 4) = bl->bl_id; - WBUF_STRING(buf, 8, msg, msg_len); + Packet_Head<0x008d> head_8d; + head_8d.block_id = bl->bl_id; + Buffer buf = create_vpacket<0x008d, 8, 1>(head_8d, msg); - clif_send(buf, WBUFW(buf, 2), bl, SendWho::AREA); + clif_send(buf, bl, SendWho::AREA); } /*========================================== @@ -3788,16 +3775,17 @@ void clif_message(dumb_ptr<block_list> bl, XString msg) *------------------------------------------ */ static -void clif_parse_ChangeDir(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_ChangeDir(Session *s, dumb_ptr<map_session_data> sd) { - unsigned char buf[64]; + Packet_Fixed<0x009b> fixed; + RecvResult rv = recv_fpacket<0x009b, 5>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); - - // RFIFOW(fd, 2) and WBUFW(buf, 6) are always 0 + // RFIFOW(fd,2) and WBUFW(buf,6) are always 0 // TODO perhaps we could use that to remove this hack? DIR dir; - uint8_t client_dir = RFIFOB(s, 4); + uint8_t client_dir = fixed.client_dir; // the client uses a diffenent direction enum ... ugh switch (client_dir) { @@ -3810,21 +3798,22 @@ void clif_parse_ChangeDir(Session *s, dumb_ptr<map_session_data> sd) case 0 | 8: dir = DIR::E; break; // right case 1 | 8: dir = DIR::SE; break; default: - return; + return rv; } if (dir == sd->dir) - return; + return rv; pc_setdir(sd, dir); - WBUFW(buf, 0) = 0x9c; - WBUFL(buf, 2) = sd->bl_id; - WBUFW(buf, 6) = 0; - WBUFB(buf, 8) = client_dir; + Packet_Fixed<0x009c> fixed_9c; + fixed_9c.block_id = sd->bl_id; + fixed_9c.client_dir = client_dir; + Buffer buf = create_fpacket<0x009c, 9>(fixed_9c); - clif_send(buf, clif_parse_func_table[0x9c].len, sd, SendWho::AREA_WOS); + clif_send(buf, sd, SendWho::AREA_WOS); + return rv; } /*========================================== @@ -3832,23 +3821,27 @@ void clif_parse_ChangeDir(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_Emotion(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_Emotion(Session *s, dumb_ptr<map_session_data> sd) { - unsigned char buf[64]; - - nullpo_retv(sd); + Packet_Fixed<0x00bf> fixed; + RecvResult rv = recv_fpacket<0x00bf, 3>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, SkillID::NV_EMOTE) >= 1) { - uint8_t emote = RFIFOB(s, 2); - WBUFW(buf, 0) = 0xc0; - WBUFL(buf, 2) = sd->bl_id; - WBUFB(buf, 6) = emote; - clif_send(buf, clif_parse_func_table[0xc0].len, sd, SendWho::AREA); + uint8_t emote = fixed.emote; + Packet_Fixed<0x00c0> fixed_c0; + fixed_c0.block_id = sd->bl_id; + fixed_c0.type = emote; + Buffer buf = create_fpacket<0x00c0, 7>(fixed_c0); + clif_send(buf, sd, SendWho::AREA); } else clif_skill_fail(sd, SkillID::ONE, 0, 1); + + return rv; } /*========================================== @@ -3856,11 +3849,18 @@ void clif_parse_Emotion(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_HowManyConnections(Session *s, dumb_ptr<map_session_data>) +RecvResult clif_parse_HowManyConnections(Session *s, dumb_ptr<map_session_data>) { - WFIFOW(s, 0) = 0xc2; - WFIFOL(s, 2) = map_getusers(); - WFIFOSET(s, clif_parse_func_table[0xc2].len); + Packet_Fixed<0x00c1> fixed; + RecvResult rv = recv_fpacket<0x00c1, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + Packet_Fixed<0x00c2> fixed_c2; + fixed_c2.users = map_getusers(); + send_fpacket<0x00c2, 6>(s, fixed_c2); + + return rv; } /*========================================== @@ -3868,64 +3868,69 @@ void clif_parse_HowManyConnections(Session *s, dumb_ptr<map_session_data>) *------------------------------------------ */ static -void clif_parse_ActionRequest(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_ActionRequest(Session *s, dumb_ptr<map_session_data> sd) { - unsigned char buf[64]; - int action_type, target_id; + Packet_Fixed<0x0089> fixed; + RecvResult rv = recv_fpacket<0x0089, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); + DamageType action_type; + BlockId target_id; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0 + if (sd->npc_id || bool(sd->opt1) || sd->state.storage_open) - return; + return rv; tick_t tick = gettick(); pc_stop_walking(sd, 0); pc_stopattack(sd); - target_id = RFIFOL(s, 2); - action_type = RFIFOB(s, 6); + target_id = fixed.target_id; + action_type = fixed.action; switch (action_type) { - case 0x00: // once attack - case 0x07: // continuous attack + case DamageType::NORMAL: + case DamageType::CONTINUOUS: if (bool(sd->status.option & Option::HIDE)) - return; + return rv; if (!battle_config.skill_delay_attack_enable) { if (tick < sd->canact_tick) { clif_skill_fail(sd, SkillID::ONE, 4, 0); - return; + return rv; } } if (sd->invincible_timer) pc_delinvincibletimer(sd); - if (sd->attacktarget > 0) // [Valaris] - sd->attacktarget = 0; - pc_attack(sd, target_id, action_type != 0); + sd->attacktarget = BlockId(); + pc_attack(sd, target_id, action_type != DamageType::NORMAL); break; - case 0x02: // sitdown + case DamageType::SIT: pc_stop_walking(sd, 1); pc_setsit(sd); clif_sitting(s, sd); break; - case 0x03: // standup + case DamageType::STAND: pc_setstand(sd); - WBUFW(buf, 0) = 0x8a; - WBUFL(buf, 2) = sd->bl_id; - WBUFB(buf, 26) = 3; - clif_send(buf, clif_parse_func_table[0x8a].len, sd, SendWho::AREA); + Packet_Fixed<0x008a> fixed_8a; + fixed_8a.src_id = sd->bl_id; + fixed_8a.damage_type = DamageType::STAND; + Buffer buf = create_fpacket<0x008a, 29>(fixed_8a); + clif_send(buf, sd, SendWho::AREA); break; } + + return rv; } /*========================================== @@ -3933,11 +3938,14 @@ void clif_parse_ActionRequest(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_Restart(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_Restart(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00b2> fixed; + RecvResult rv = recv_fpacket<0x00b2, 3>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - switch (RFIFOB(s, 2)) + switch (fixed.flag) { case 0x00: if (pc_isdead(sd)) @@ -3961,19 +3969,21 @@ void clif_parse_Restart(Session *s, dumb_ptr<map_session_data> sd) case 0x01: /* Rovert's Prevent logout option - Fixed [Valaris] */ if (!battle_config.prevent_logout - || gettick() >= sd->canlog_tick + std::chrono::seconds(10)) + || gettick() >= sd->canlog_tick + 10_s) { chrif_charselectreq(sd); } else { - WFIFOW(s, 0) = 0x18b; - WFIFOW(s, 2) = 1; + Packet_Fixed<0x018b> fixed_18b; + fixed_18b.okay = 1; - WFIFOSET(s, clif_parse_func_table[0x018b].len); + send_fpacket<0x018b, 4>(s, fixed_18b); } break; } + + return rv; } /*========================================== @@ -3987,29 +3997,33 @@ void clif_parse_Restart(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) { - dumb_ptr<map_session_data> dstsd = NULL; + Packet_Head<0x0096> head; + AString repeat; + RecvResult rv = recv_vpacket<0x0096, 28, 1>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); + dumb_ptr<map_session_data> dstsd = nullptr; - AString mbuf = clif_validate_chat(sd, ChatType::Whisper); + AString mbuf = clif_validate_chat(sd, ChatType::Whisper, repeat); if (!mbuf) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } - if (is_atcommand(s, sd, mbuf, 0)) + if (is_atcommand(s, sd, mbuf, GmLevel())) { - return; + return rv; } /* Don't send chat that results in an automatic ban. */ if (tmw_CheckChatSpam(sd, mbuf)) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } /* @@ -4018,7 +4032,7 @@ void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) * conflict (for instance, "Test" versus "test"), the char-server must * settle the discrepancy. */ - CharName tname = stringish<CharName>(RFIFO_STRING<24>(s, 4)); + CharName tname = head.target_name; if (!(dstsd = map_nick2sd(tname)) || dstsd->status_key.name != tname) intif_wis_message(sd, tname, mbuf); @@ -4027,7 +4041,7 @@ void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) /* Refuse messages addressed to self. */ if (dstsd->sess == s) { - ZString mes = "You cannot page yourself."; + ZString mes = "You cannot page yourself."_s; clif_wis_message(s, wisp_server_name, mes); } else @@ -4042,6 +4056,8 @@ void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) } } } + + return rv; } /*========================================== @@ -4049,37 +4065,41 @@ void clif_parse_Wis(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TakeItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TakeItem(Session *s, dumb_ptr<map_session_data> sd) { - dumb_ptr<flooritem_data> fitem; - int map_object_id; + Packet_Fixed<0x009f> fixed; + RecvResult rv = recv_fpacket<0x009f, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); + dumb_ptr<flooritem_data> fitem; - map_object_id = RFIFOL(s, 2); + BlockId map_object_id = fixed.object_id; fitem = map_id_is_item(map_object_id); if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0 + if (sd->npc_id || sd->opt1 != Opt1::ZERO) //会話禁止 - return; + return rv; - if (fitem == NULL || fitem->bl_m != sd->bl_m) - return; + if (fitem == nullptr || fitem->bl_m != sd->bl_m) + return rv; if (abs(sd->bl_x - fitem->bl_x) >= 2 || abs(sd->bl_y - fitem->bl_y) >= 2) - return; // too far away to pick up + return rv; // too far away to pick up if (sd->state.shroud_active && sd->state.shroud_disappears_on_pickup) magic_unshroud(sd); pc_takeitem(sd, fitem); + + return rv; } /*========================================== @@ -4087,33 +4107,38 @@ void clif_parse_TakeItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_DropItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_DropItem(Session *s, dumb_ptr<map_session_data> sd) { - int item_index, item_amount; - - nullpo_retv(sd); + Packet_Fixed<0x00a2> fixed; + RecvResult rv = recv_fpacket<0x00a2, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } if (sd->bl_m->flag.get(MapFlag::NO_PLAYER_DROPS)) { - clif_displaymessage(sd->sess, "Can't drop items here."); - return; + clif_displaymessage(sd->sess, "Can't drop items here."_s); + return rv; } - if (sd->npc_id != 0 + if (sd->npc_id || sd->opt1 != Opt1::ZERO) { - clif_displaymessage(sd->sess, "Can't drop items right now."); - return; + clif_displaymessage(sd->sess, "Can't drop items right now."_s); + return rv; } - item_index = RFIFOW(s, 2) - 2; - item_amount = RFIFOW(s, 4); + if (!fixed.ioff2.ok()) + return RecvResult::Error; + IOff0 item_index = fixed.ioff2.unshift(); + int item_amount = fixed.amount; pc_dropitem(sd, item_index, item_amount); + + return rv; } /*========================================== @@ -4121,23 +4146,30 @@ void clif_parse_DropItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_UseItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_UseItem(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00a7> fixed; + RecvResult rv = recv_fpacket<0x00a7, 8>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0 + if (sd->npc_id || sd->opt1 != Opt1::ZERO) //会話禁止 - return; + return rv; if (sd->invincible_timer) pc_delinvincibletimer(sd); - pc_useitem(sd, RFIFOW(s, 2) - 2); + if (!fixed.ioff2.ok()) + return RecvResult::Error; + pc_useitem(sd, fixed.ioff2.unshift()); + + return rv; } /*========================================== @@ -4145,30 +4177,35 @@ void clif_parse_UseItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_EquipItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_EquipItem(Session *s, dumb_ptr<map_session_data> sd) { - int index; - - nullpo_retv(sd); + Packet_Fixed<0x00a9> fixed; + RecvResult rv = recv_fpacket<0x00a9, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - index = RFIFOW(s, 2) - 2; - if (sd->npc_id != 0) - return; + if (!fixed.ioff2.ok()) + return RecvResult::Error; + IOff0 index = fixed.ioff2.unshift(); + if (sd->npc_id) + return rv; if (sd->inventory_data[index]) { - EPOS epos = EPOS(RFIFOW(s, 4)); + EPOS epos = fixed.epos_ignored; if (sd->inventory_data[index]->type == ItemType::ARROW) epos = EPOS::ARROW; // Note: the EPOS argument to pc_equipitem is actually ignored pc_equipitem(sd, index, epos); } + + return rv; } /*========================================== @@ -4176,23 +4213,28 @@ void clif_parse_EquipItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_UnequipItem(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_UnequipItem(Session *s, dumb_ptr<map_session_data> sd) { - int index; - - nullpo_retv(sd); + Packet_Fixed<0x00ab> fixed; + RecvResult rv = recv_fpacket<0x00ab, 4>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - index = RFIFOW(s, 2) - 2; + if (!fixed.ioff2.ok()) + return RecvResult::Error; + IOff0 index = fixed.ioff2.unshift(); - if (sd->npc_id != 0 + if (sd->npc_id || sd->opt1 != Opt1::ZERO) - return; + return rv; pc_unequipitem(sd, index, CalcStatus::NOW); + + return rv; } /*========================================== @@ -4200,18 +4242,23 @@ void clif_parse_UnequipItem(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcClicked(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcClicked(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x0090> fixed; + RecvResult rv = recv_fpacket<0x0090, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (pc_isdead(sd)) { clif_clearchar(sd, BeingRemoveWhy::DEAD); - return; + return rv; } - if (sd->npc_id != 0) - return; - npc_click(sd, RFIFOL(s, 2)); + if (sd->npc_id) + return rv; + npc_click(sd, fixed.block_id); + + return rv; } /*========================================== @@ -4219,9 +4266,16 @@ void clif_parse_NpcClicked(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcBuySellSelected(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcBuySellSelected(Session *s, dumb_ptr<map_session_data> sd) { - npc_buysellsel(sd, RFIFOL(s, 2), RFIFOB(s, 6)); + Packet_Fixed<0x00c5> fixed; + RecvResult rv = recv_fpacket<0x00c5, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + npc_buysellsel(sd, fixed.block_id, fixed.type); + + return rv; } /*========================================== @@ -4229,17 +4283,20 @@ void clif_parse_NpcBuySellSelected(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcBuyListSend(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcBuyListSend(Session *s, dumb_ptr<map_session_data> sd) { - int n = (RFIFOW(s, 2) - 4) / 4; - // really an array of pairs of uint16_t - const uint16_t *item_list = static_cast<const uint16_t *>(RFIFOP(s, 4)); + std::vector<Packet_Repeat<0x00c8>> repeat; + RecvResult rv = recv_packet_repeatonly<0x00c8, 4, 4>(s, repeat); + if (rv != RecvResult::Complete) + return rv; - int fail = npc_buylist(sd, n, item_list); + int fail = npc_buylist(sd, repeat); - WFIFOW(s, 0) = 0xca; - WFIFOB(s, 2) = fail; - WFIFOSET(s, clif_parse_func_table[0xca].len); + Packet_Fixed<0x00ca> fixed_ca; + fixed_ca.fail = fail; + send_fpacket<0x00ca, 3>(s, fixed_ca); + + return rv; } /*========================================== @@ -4247,17 +4304,20 @@ void clif_parse_NpcBuyListSend(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcSellListSend(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcSellListSend(Session *s, dumb_ptr<map_session_data> sd) { - int n = (RFIFOW(s, 2) - 4) / 4; - // really an array of pairs of uint16_t - const uint16_t *item_list = static_cast<const uint16_t *>(RFIFOP(s, 4)); + std::vector<Packet_Repeat<0x00c9>> repeat; + RecvResult rv = recv_packet_repeatonly<0x00c9, 4, 4>(s, repeat); + if (rv != RecvResult::Complete) + return rv; + + int fail = npc_selllist(sd, repeat); - int fail = npc_selllist(sd, n, item_list); + Packet_Fixed<0x00cb> fixed_cb; + fixed_cb.fail = fail; + send_fpacket<0x00cb, 3>(s, fixed_cb); - WFIFOW(s, 0) = 0xcb; - WFIFOB(s, 2) = fail; - WFIFOSET(s, clif_parse_func_table[0xcb].len); + return rv; } /*========================================== @@ -4265,17 +4325,22 @@ void clif_parse_NpcSellListSend(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeRequest(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeRequest(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00e4> fixed; + RecvResult rv = recv_fpacket<0x00e4, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, SkillID::NV_TRADE) >= 1) { - trade_traderequest(sd, RFIFOL(sd->sess, 2)); + trade_traderequest(sd, fixed.block_id); } else clif_skill_fail(sd, SkillID::ONE, 0, 0); + + return rv; } /*========================================== @@ -4283,11 +4348,16 @@ void clif_parse_TradeRequest(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeAck(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeAck(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00e6> fixed; + RecvResult rv = recv_fpacket<0x00e6, 3>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - trade_tradeack(sd, RFIFOB(sd->sess, 2)); + trade_tradeack(sd, fixed.type); + + return rv; } /*========================================== @@ -4295,11 +4365,18 @@ void clif_parse_TradeAck(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeAddItem(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeAddItem(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00e8> fixed; + RecvResult rv = recv_fpacket<0x00e8, 8>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - trade_tradeadditem(sd, RFIFOW(sd->sess, 2), RFIFOL(sd->sess, 4)); + if (fixed.zeny_or_ioff2.index != 0 && !fixed.zeny_or_ioff2.ok()) + return RecvResult::Error; + trade_tradeadditem(sd, fixed.zeny_or_ioff2, fixed.amount); + + return rv; } /*========================================== @@ -4307,9 +4384,16 @@ void clif_parse_TradeAddItem(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeOk(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeOk(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00eb> fixed; + RecvResult rv = recv_fpacket<0x00eb, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + trade_tradeok(sd); + + return rv; } /*========================================== @@ -4317,9 +4401,16 @@ void clif_parse_TradeOk(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeCansel(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeCansel(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00ed> fixed; + RecvResult rv = recv_fpacket<0x00ed, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + trade_tradecancel(sd); + + return rv; } /*========================================== @@ -4327,9 +4418,16 @@ void clif_parse_TradeCansel(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_TradeCommit(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_TradeCommit(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00ef> fixed; + RecvResult rv = recv_fpacket<0x00ef, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + trade_tradecommit(sd); + + return rv; } /*========================================== @@ -4337,9 +4435,16 @@ void clif_parse_TradeCommit(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_StopAttack(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_StopAttack(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x0118> fixed; + RecvResult rv = recv_fpacket<0x0118, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + pc_stopattack(sd); + + return rv; } /*========================================== @@ -4347,9 +4452,16 @@ void clif_parse_StopAttack(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_StatusUp(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_StatusUp(Session *s, dumb_ptr<map_session_data> sd) { - pc_statusup(sd, SP(RFIFOW(s, 2))); + Packet_Fixed<0x00bb> fixed; + RecvResult rv = recv_fpacket<0x00bb, 5>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + pc_statusup(sd, fixed.asp); + + return rv; } /*========================================== @@ -4357,9 +4469,16 @@ void clif_parse_StatusUp(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_SkillUp(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_SkillUp(Session *s, dumb_ptr<map_session_data> sd) { - pc_skillup(sd, SkillID(RFIFOW(s, 2))); + Packet_Fixed<0x0112> fixed; + RecvResult rv = recv_fpacket<0x0112, 4>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + pc_skillup(sd, fixed.skill_id); + + return rv; } /*========================================== @@ -4367,12 +4486,17 @@ void clif_parse_SkillUp(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcSelectMenu(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcSelectMenu(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00b8> fixed; + RecvResult rv = recv_fpacket<0x00b8, 7>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + sd->npc_menu = fixed.menu_entry; + map_scriptcont(sd, fixed.npc_id); - sd->npc_menu = RFIFOB(s, 6); - map_scriptcont(sd, RFIFOL(s, 2)); + return rv; } /*========================================== @@ -4380,9 +4504,16 @@ void clif_parse_NpcSelectMenu(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcNextClicked(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcNextClicked(Session *s, dumb_ptr<map_session_data> sd) { - map_scriptcont(sd, RFIFOL(s, 2)); + Packet_Fixed<0x00b9> fixed; + RecvResult rv = recv_fpacket<0x00b9, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + map_scriptcont(sd, fixed.npc_id); + + return rv; } /*========================================== @@ -4390,12 +4521,17 @@ void clif_parse_NpcNextClicked(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcAmountInput(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcAmountInput(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x0143> fixed; + RecvResult rv = recv_fpacket<0x0143, 10>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - sd->npc_amount = RFIFOL(s, 6); - map_scriptcont(sd, RFIFOL(s, 2)); + sd->npc_amount = fixed.input_int_value; + map_scriptcont(sd, fixed.block_id); + + return rv; } /*========================================== @@ -4405,22 +4541,19 @@ void clif_parse_NpcAmountInput(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcStringInput(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcStringInput(Session *s, dumb_ptr<map_session_data> sd) { - int len; - nullpo_retv(sd); + Packet_Head<0x01d5> head; + AString repeat; + RecvResult rv = recv_vpacket<0x01d5, 8, 1>(s, head, repeat); + if (rv != RecvResult::Complete) + return rv; - len = RFIFOW(s, 2) - 8; + sd->npc_str = repeat; - /* - * If we check for equal to 0, too, we'll freeze clients that send (or - * claim to have sent) an "empty" message. - */ - if (len < 0) - return; - sd->npc_str = RFIFO_STRING(s, 8, len); + map_scriptcont(sd, head.block_id); - map_scriptcont(sd, RFIFOL(s, 4)); + return rv; } /*========================================== @@ -4428,9 +4561,16 @@ void clif_parse_NpcStringInput(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_NpcCloseClicked(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_NpcCloseClicked(Session *s, dumb_ptr<map_session_data> sd) { - map_scriptcont(sd, RFIFOL(s, 2)); + Packet_Fixed<0x0146> fixed; + RecvResult rv = recv_fpacket<0x0146, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + map_scriptcont(sd, fixed.block_id); + + return rv; } /*========================================== @@ -4438,21 +4578,26 @@ void clif_parse_NpcCloseClicked(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_MoveToKafra(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_MoveToKafra(Session *s, dumb_ptr<map_session_data> sd) { - int item_index, item_amount; + Packet_Fixed<0x00f3> fixed; + RecvResult rv = recv_fpacket<0x00f3, 8>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - nullpo_retv(sd); - - item_index = RFIFOW(s, 2) - 2; - item_amount = RFIFOL(s, 4); + if (!fixed.ioff2.ok()) + return RecvResult::Error; + IOff0 item_index = fixed.ioff2.unshift(); + int item_amount = fixed.amount; - if ((sd->npc_id != 0 && !sd->npc_flags.storage) || sd->trade_partner != 0 + if ((sd->npc_id && !sd->npc_flags.storage) || sd->trade_partner || !sd->state.storage_open) - return; + return rv; if (sd->state.storage_open) storage_storageadd(sd, item_index, item_amount); + + return rv; } /*========================================== @@ -4460,21 +4605,26 @@ void clif_parse_MoveToKafra(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_MoveFromKafra(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_MoveFromKafra(Session *s, dumb_ptr<map_session_data> sd) { - int item_index, item_amount; - - nullpo_retv(sd); + Packet_Fixed<0x00f5> fixed; + RecvResult rv = recv_fpacket<0x00f5, 8>(s, fixed); + if (rv != RecvResult::Complete) + return rv; - item_index = RFIFOW(s, 2) - 1; - item_amount = RFIFOL(s, 4); + if (!fixed.soff1.ok()) + return RecvResult::Error; + SOff0 item_index = fixed.soff1.unshift(); + int item_amount = fixed.amount; - if ((sd->npc_id != 0 && !sd->npc_flags.storage) || sd->trade_partner != 0 + if ((sd->npc_id && !sd->npc_flags.storage) || sd->trade_partner || !sd->state.storage_open) - return; + return rv; if (sd->state.storage_open) storage_storageget(sd, item_index, item_amount); + + return rv; } /*========================================== @@ -4482,12 +4632,17 @@ void clif_parse_MoveFromKafra(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_CloseKafra(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_CloseKafra(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + Packet_Fixed<0x00f7> fixed; + RecvResult rv = recv_fpacket<0x00f7, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; if (sd->state.storage_open) storage_storageclose(sd); + + return rv; } /*========================================== @@ -4498,16 +4653,23 @@ void clif_parse_CloseKafra(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_CreateParty(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_CreateParty(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00f9> fixed; + RecvResult rv = recv_fpacket<0x00f9, 26>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, SkillID::NV_PARTY) >= 2) { - PartyName name = stringish<PartyName>(RFIFO_STRING<24>(s, 2)); + PartyName name = fixed.party_name; party_create(sd, name); } else clif_skill_fail(sd, SkillID::ONE, 0, 4); + + return rv; } /*========================================== @@ -4518,9 +4680,16 @@ void clif_parse_CreateParty(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_PartyInvite(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_PartyInvite(Session *s, dumb_ptr<map_session_data> sd) { - party_invite(sd, RFIFOL(s, 2)); + Packet_Fixed<0x00fc> fixed; + RecvResult rv = recv_fpacket<0x00fc, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + party_invite(sd, fixed.account_id); + + return rv; } /*========================================== @@ -4531,18 +4700,25 @@ void clif_parse_PartyInvite(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_ReplyPartyInvite(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_ReplyPartyInvite(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x00ff> fixed; + RecvResult rv = recv_fpacket<0x00ff, 10>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + if (battle_config.basic_skill_check == 0 || pc_checkskill(sd, SkillID::NV_PARTY) >= 1) { - party_reply_invite(sd, RFIFOL(s, 2), RFIFOL(s, 6)); + party_reply_invite(sd, fixed.account_id, fixed.flag); } else { - party_reply_invite(sd, RFIFOL(s, 2), 0); + party_reply_invite(sd, fixed.account_id, 0); clif_skill_fail(sd, SkillID::ONE, 0, 4); } + + return rv; } /*========================================== @@ -4550,9 +4726,16 @@ void clif_parse_ReplyPartyInvite(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_LeaveParty(Session *, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_LeaveParty(Session *s, dumb_ptr<map_session_data> sd) { + Packet_Fixed<0x0100> fixed; + RecvResult rv = recv_fpacket<0x0100, 2>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + party_leave(sd); + + return rv; } /*========================================== @@ -4560,11 +4743,18 @@ void clif_parse_LeaveParty(Session *, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_RemovePartyMember(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_RemovePartyMember(Session *s, dumb_ptr<map_session_data> sd) { - int account_id = RFIFOL(s, 2); - // unused RFIFO_STRING<24>(fd, 6); + Packet_Fixed<0x0103> fixed; + RecvResult rv = recv_fpacket<0x0103, 30>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + AccountId account_id = fixed.account_id; + // unused fixed.unusedchar_name; party_removemember(sd, account_id); + + return rv; } /*========================================== @@ -4572,9 +4762,16 @@ void clif_parse_RemovePartyMember(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_PartyChangeOption(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_PartyChangeOption(Session *s, dumb_ptr<map_session_data> sd) { - party_changeoption(sd, RFIFOW(s, 2), RFIFOW(s, 4)); + Packet_Fixed<0x0102> fixed; + RecvResult rv = recv_fpacket<0x0102, 6>(s, fixed); + if (rv != RecvResult::Complete) + return rv; + + party_changeoption(sd, fixed.exp, fixed.item); + + return rv; } /*========================================== @@ -4586,582 +4783,604 @@ void clif_parse_PartyChangeOption(Session *s, dumb_ptr<map_session_data> sd) *------------------------------------------ */ static -void clif_parse_PartyMessage(Session *s, dumb_ptr<map_session_data> sd) +RecvResult clif_parse_PartyMessage(Session *s, dumb_ptr<map_session_data> sd) { - nullpo_retv(sd); + AString repeat; + RecvResult rv = recv_packet_repeatonly<0x0108, 4, 1>(s, repeat); + if (rv != RecvResult::Complete) + return rv; - AString mbuf = clif_validate_chat(sd, ChatType::Party); + AString mbuf = clif_validate_chat(sd, ChatType::Party, repeat); if (!mbuf) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } - if (is_atcommand(s, sd, mbuf, 0)) - return; + if (is_atcommand(s, sd, mbuf, GmLevel())) + return rv; /* Don't send chat that results in an automatic ban. */ if (tmw_CheckChatSpam(sd, mbuf)) { - clif_displaymessage(s, "Your message could not be sent."); - return; + clif_displaymessage(s, "Your message could not be sent."_s); + return rv; } party_send_message(sd, mbuf); + + return rv; } func_table clif_parse_func_table[0x0220] = { - {0, 10, NULL, }, // 0x0000 - {0, 0, NULL, }, // 0x0001 - {0, 0, NULL, }, // 0x0002 - {0, 0, NULL, }, // 0x0003 - {0, 0, NULL, }, // 0x0004 - {0, 0, NULL, }, // 0x0005 - {0, 0, NULL, }, // 0x0006 - {0, 0, NULL, }, // 0x0007 - {0, 0, NULL, }, // 0x0008 - {0, 0, NULL, }, // 0x0009 - {0, 0, NULL, }, // 0x000a - {0, 0, NULL, }, // 0x000b - {0, 0, NULL, }, // 0x000c - {0, 0, NULL, }, // 0x000d - {0, 0, NULL, }, // 0x000e - {0, 0, NULL, }, // 0x000f - {0, 0, NULL, }, // 0x0010 - {0, 0, NULL, }, // 0x0011 - {0, 0, NULL, }, // 0x0012 - {0, 0, NULL, }, // 0x0013 - {0, 0, NULL, }, // 0x0014 - {0, 0, NULL, }, // 0x0015 - {0, 0, NULL, }, // 0x0016 - {0, 0, NULL, }, // 0x0017 - {0, 0, NULL, }, // 0x0018 - {0, 0, NULL, }, // 0x0019 - {0, 0, NULL, }, // 0x001a - {0, 0, NULL, }, // 0x001b - {0, 0, NULL, }, // 0x001c - {0, 0, NULL, }, // 0x001d - {0, 0, NULL, }, // 0x001e - {0, 0, NULL, }, // 0x001f - {0, 0, NULL, }, // 0x0020 - {0, 0, NULL, }, // 0x0021 - {0, 0, NULL, }, // 0x0022 - {0, 0, NULL, }, // 0x0023 - {0, 0, NULL, }, // 0x0024 - {0, 0, NULL, }, // 0x0025 - {0, 0, NULL, }, // 0x0026 - {0, 0, NULL, }, // 0x0027 - {0, 0, NULL, }, // 0x0028 - {0, 0, NULL, }, // 0x0029 - {0, 0, NULL, }, // 0x002a - {0, 0, NULL, }, // 0x002b - {0, 0, NULL, }, // 0x002c - {0, 0, NULL, }, // 0x002d - {0, 0, NULL, }, // 0x002e - {0, 0, NULL, }, // 0x002f - {0, 0, NULL, }, // 0x0030 - {0, 0, NULL, }, // 0x0031 - {0, 0, NULL, }, // 0x0032 - {0, 0, NULL, }, // 0x0033 - {0, 0, NULL, }, // 0x0034 - {0, 0, NULL, }, // 0x0035 - {0, 0, NULL, }, // 0x0036 - {0, 0, NULL, }, // 0x0037 - {0, 0, NULL, }, // 0x0038 - {0, 0, NULL, }, // 0x0039 - {0, 0, NULL, }, // 0x003a - {0, 0, NULL, }, // 0x003b - {0, 0, NULL, }, // 0x003c - {0, 0, NULL, }, // 0x003d - {0, 0, NULL, }, // 0x003e - {0, 0, NULL, }, // 0x003f - {0, 0, NULL, }, // 0x0040 - {0, 0, NULL, }, // 0x0041 - {0, 0, NULL, }, // 0x0042 - {0, 0, NULL, }, // 0x0043 - {0, 0, NULL, }, // 0x0044 - {0, 0, NULL, }, // 0x0045 - {0, 0, NULL, }, // 0x0046 - {0, 0, NULL, }, // 0x0047 - {0, 0, NULL, }, // 0x0048 - {0, 0, NULL, }, // 0x0049 - {0, 0, NULL, }, // 0x004a - {0, 0, NULL, }, // 0x004b - {0, 0, NULL, }, // 0x004c - {0, 0, NULL, }, // 0x004d - {0, 0, NULL, }, // 0x004e - {0, 0, NULL, }, // 0x004f - {0, 0, NULL, }, // 0x0050 - {0, 0, NULL, }, // 0x0051 - {0, 0, NULL, }, // 0x0052 - {0, 0, NULL, }, // 0x0053 - {0, 0, NULL, }, // 0x0054 - {0, 0, NULL, }, // 0x0055 - {0, 0, NULL, }, // 0x0056 - {0, 0, NULL, }, // 0x0057 - {0, 0, NULL, }, // 0x0058 - {0, 0, NULL, }, // 0x0059 - {0, 0, NULL, }, // 0x005a - {0, 0, NULL, }, // 0x005b - {0, 0, NULL, }, // 0x005c - {0, 0, NULL, }, // 0x005d - {0, 0, NULL, }, // 0x005e - {0, 0, NULL, }, // 0x005f - {0, 0, NULL, }, // 0x0060 - {0, 0, NULL, }, // 0x0061 - {0, 0, NULL, }, // 0x0062 - {0, VAR,NULL, }, // 0x0063 - {0, 55, NULL, }, // 0x0064 - {0, 17, NULL, }, // 0x0065 - {0, 3, NULL, }, // 0x0066 - {0, 37, NULL, }, // 0x0067 - {0, 46, NULL, }, // 0x0068 - {0, VAR,NULL, }, // 0x0069 - {0, 23, NULL, }, // 0x006a - {0, VAR,NULL, }, // 0x006b - {0, 3, NULL, }, // 0x006c - {0, 108,NULL, }, // 0x006d - {0, 3, NULL, }, // 0x006e - {0, 2, NULL, }, // 0x006f - {0, 3, NULL, }, // 0x0070 - {0, 28, NULL, }, // 0x0071 + {0, 10, nullptr, }, // 0x0000 + {0, 0, nullptr, }, // 0x0001 + {0, 0, nullptr, }, // 0x0002 + {0, 0, nullptr, }, // 0x0003 + {0, 0, nullptr, }, // 0x0004 + {0, 0, nullptr, }, // 0x0005 + {0, 0, nullptr, }, // 0x0006 + {0, 0, nullptr, }, // 0x0007 + {0, 0, nullptr, }, // 0x0008 + {0, 0, nullptr, }, // 0x0009 + {0, 0, nullptr, }, // 0x000a + {0, 0, nullptr, }, // 0x000b + {0, 0, nullptr, }, // 0x000c + {0, 0, nullptr, }, // 0x000d + {0, 0, nullptr, }, // 0x000e + {0, 0, nullptr, }, // 0x000f + {0, 0, nullptr, }, // 0x0010 + {0, 0, nullptr, }, // 0x0011 + {0, 0, nullptr, }, // 0x0012 + {0, 0, nullptr, }, // 0x0013 + {0, 0, nullptr, }, // 0x0014 + {0, 0, nullptr, }, // 0x0015 + {0, 0, nullptr, }, // 0x0016 + {0, 0, nullptr, }, // 0x0017 + {0, 0, nullptr, }, // 0x0018 + {0, 0, nullptr, }, // 0x0019 + {0, 0, nullptr, }, // 0x001a + {0, 0, nullptr, }, // 0x001b + {0, 0, nullptr, }, // 0x001c + {0, 0, nullptr, }, // 0x001d + {0, 0, nullptr, }, // 0x001e + {0, 0, nullptr, }, // 0x001f + {0, 0, nullptr, }, // 0x0020 + {0, 0, nullptr, }, // 0x0021 + {0, 0, nullptr, }, // 0x0022 + {0, 0, nullptr, }, // 0x0023 + {0, 0, nullptr, }, // 0x0024 + {0, 0, nullptr, }, // 0x0025 + {0, 0, nullptr, }, // 0x0026 + {0, 0, nullptr, }, // 0x0027 + {0, 0, nullptr, }, // 0x0028 + {0, 0, nullptr, }, // 0x0029 + {0, 0, nullptr, }, // 0x002a + {0, 0, nullptr, }, // 0x002b + {0, 0, nullptr, }, // 0x002c + {0, 0, nullptr, }, // 0x002d + {0, 0, nullptr, }, // 0x002e + {0, 0, nullptr, }, // 0x002f + {0, 0, nullptr, }, // 0x0030 + {0, 0, nullptr, }, // 0x0031 + {0, 0, nullptr, }, // 0x0032 + {0, 0, nullptr, }, // 0x0033 + {0, 0, nullptr, }, // 0x0034 + {0, 0, nullptr, }, // 0x0035 + {0, 0, nullptr, }, // 0x0036 + {0, 0, nullptr, }, // 0x0037 + {0, 0, nullptr, }, // 0x0038 + {0, 0, nullptr, }, // 0x0039 + {0, 0, nullptr, }, // 0x003a + {0, 0, nullptr, }, // 0x003b + {0, 0, nullptr, }, // 0x003c + {0, 0, nullptr, }, // 0x003d + {0, 0, nullptr, }, // 0x003e + {0, 0, nullptr, }, // 0x003f + {0, 0, nullptr, }, // 0x0040 + {0, 0, nullptr, }, // 0x0041 + {0, 0, nullptr, }, // 0x0042 + {0, 0, nullptr, }, // 0x0043 + {0, 0, nullptr, }, // 0x0044 + {0, 0, nullptr, }, // 0x0045 + {0, 0, nullptr, }, // 0x0046 + {0, 0, nullptr, }, // 0x0047 + {0, 0, nullptr, }, // 0x0048 + {0, 0, nullptr, }, // 0x0049 + {0, 0, nullptr, }, // 0x004a + {0, 0, nullptr, }, // 0x004b + {0, 0, nullptr, }, // 0x004c + {0, 0, nullptr, }, // 0x004d + {0, 0, nullptr, }, // 0x004e + {0, 0, nullptr, }, // 0x004f + {0, 0, nullptr, }, // 0x0050 + {0, 0, nullptr, }, // 0x0051 + {0, 0, nullptr, }, // 0x0052 + {0, 0, nullptr, }, // 0x0053 + {0, 0, nullptr, }, // 0x0054 + {0, 0, nullptr, }, // 0x0055 + {0, 0, nullptr, }, // 0x0056 + {0, 0, nullptr, }, // 0x0057 + {0, 0, nullptr, }, // 0x0058 + {0, 0, nullptr, }, // 0x0059 + {0, 0, nullptr, }, // 0x005a + {0, 0, nullptr, }, // 0x005b + {0, 0, nullptr, }, // 0x005c + {0, 0, nullptr, }, // 0x005d + {0, 0, nullptr, }, // 0x005e + {0, 0, nullptr, }, // 0x005f + {0, 0, nullptr, }, // 0x0060 + {0, 0, nullptr, }, // 0x0061 + {0, 0, nullptr, }, // 0x0062 + {0, VAR,nullptr, }, // 0x0063 + {0, 55, nullptr, }, // 0x0064 + {0, 17, nullptr, }, // 0x0065 + {0, 3, nullptr, }, // 0x0066 + {0, 37, nullptr, }, // 0x0067 + {0, 46, nullptr, }, // 0x0068 + {0, VAR,nullptr, }, // 0x0069 + {0, 23, nullptr, }, // 0x006a + {0, VAR,nullptr, }, // 0x006b + {0, 3, nullptr, }, // 0x006c + {0, 108,nullptr, }, // 0x006d + {0, 3, nullptr, }, // 0x006e + {0, 2, nullptr, }, // 0x006f + {0, 3, nullptr, }, // 0x0070 + {0, 28, nullptr, }, // 0x0071 {0, 19, clif_parse_WantToConnection, }, // 0x0072 - {0, 11, NULL, }, // 0x0073 - {0, 3, NULL, }, // 0x0074 - {0, VAR,NULL, }, // 0x0075 - {0, 9, NULL, }, // 0x0076 - {0, 5, NULL, }, // 0x0077 - {0, 54, NULL, }, // 0x0078 - {0, 53, NULL, }, // 0x0079 - {0, 58, NULL, }, // 0x007a - {0, 60, NULL, }, // 0x007b - {0, 41, NULL, }, // 0x007c + {0, 11, nullptr, }, // 0x0073 + {0, 3, nullptr, }, // 0x0074 + {0, VAR,nullptr, }, // 0x0075 + {0, 9, nullptr, }, // 0x0076 + {0, 5, nullptr, }, // 0x0077 + {0, 54, nullptr, }, // 0x0078 + {0, 53, nullptr, }, // 0x0079 + {0, 58, nullptr, }, // 0x007a + {0, 60, nullptr, }, // 0x007b + {0, 41, nullptr, }, // 0x007c {-1, 2, clif_parse_LoadEndAck, }, // 0x007d {0, 6, clif_parse_TickSend, }, // 0x007e - {0, 6, NULL, }, // 0x007f - {0, 7, NULL, }, // 0x0080 - {0, 3, NULL, }, // 0x0081 - {0, 2, NULL, }, // 0x0082 - {0, 2, NULL, }, // 0x0083 - {0, 2, NULL, }, // 0x0084 + {0, 6, nullptr, }, // 0x007f + {0, 7, nullptr, }, // 0x0080 + {0, 3, nullptr, }, // 0x0081 + {0, 2, nullptr, }, // 0x0082 + {0, 2, nullptr, }, // 0x0083 + {0, 2, nullptr, }, // 0x0084 {-1, 5, clif_parse_WalkToXY, }, // 0x0085 Walk code limits this on it's own - {0, 16, NULL, }, // 0x0086 - {0, 12, NULL, }, // 0x0087 - {0, 10, NULL, }, // 0x0088 + {0, 16, nullptr, }, // 0x0086 + {0, 12, nullptr, }, // 0x0087 + {0, 10, nullptr, }, // 0x0088 {1000, 7, clif_parse_ActionRequest, }, // 0x0089 Special case - see below - {0, 29, NULL, }, // 0x008a - {0, 23, NULL, }, // 0x008b unknown... size 2 or 23? + {0, 29, nullptr, }, // 0x008a + {0, 23, nullptr, }, // 0x008b unknown... size 2 or 23? {300, VAR,clif_parse_GlobalMessage, }, // 0x008c - {0, VAR,NULL, }, // 0x008d - {0, VAR,NULL, }, // 0x008e - {0, 0, NULL, }, // 0x008f + {0, VAR,nullptr, }, // 0x008d + {0, VAR,nullptr, }, // 0x008e + {0, 0, nullptr, }, // 0x008f {500, 7, clif_parse_NpcClicked, }, // 0x0090 - {0, 22, NULL, }, // 0x0091 - {0, 28, NULL, }, // 0x0092 - {0, 2, NULL, }, // 0x0093 + {0, 22, nullptr, }, // 0x0091 + {0, 28, nullptr, }, // 0x0092 + {0, 2, nullptr, }, // 0x0093 {-1, 6, clif_parse_GetCharNameRequest, }, // 0x0094 - {0, 30, NULL, }, // 0x0095 + {0, 30, nullptr, }, // 0x0095 {300, VAR,clif_parse_Wis, }, // 0x0096 - {0, VAR,NULL, }, // 0x0097 - {0, 3, NULL, }, // 0x0098 - {300, VAR,NULL, }, // 0x0099 - {0, VAR,NULL, }, // 0x009a + {0, VAR,nullptr, }, // 0x0097 + {0, 3, nullptr, }, // 0x0098 + {300, VAR,nullptr, }, // 0x0099 + {0, VAR,nullptr, }, // 0x009a {-1, 5, clif_parse_ChangeDir, }, // 0x009b - {0, 9, NULL, }, // 0x009c - {0, 17, NULL, }, // 0x009d - {0, 17, NULL, }, // 0x009e + {0, 9, nullptr, }, // 0x009c + {0, 17, nullptr, }, // 0x009d + {0, 17, nullptr, }, // 0x009e {400, 6, clif_parse_TakeItem, }, // 0x009f - {0, 23, NULL, }, // 0x00a0 - {0, 6, NULL, }, // 0x00a1 + {0, 23, nullptr, }, // 0x00a0 + {0, 6, nullptr, }, // 0x00a1 {50, 6, clif_parse_DropItem, }, // 0x00a2 - {0, VAR,NULL, }, // 0x00a3 - {0, VAR,NULL, }, // 0x00a4 - {0, VAR,NULL, }, // 0x00a5 - {0, VAR,NULL, }, // 0x00a6 + {0, VAR,nullptr, }, // 0x00a3 + {0, VAR,nullptr, }, // 0x00a4 + {0, VAR,nullptr, }, // 0x00a5 + {0, VAR,nullptr, }, // 0x00a6 {0, 8, clif_parse_UseItem, }, // 0x00a7 - {0, 7, NULL, }, // 0x00a8 + {0, 7, nullptr, }, // 0x00a8 {-1, 6, clif_parse_EquipItem, }, // 0x00a9 Special case - outfit window (not implemented yet - needs to allow bursts) - {0, 7, NULL, }, // 0x00aa + {0, 7, nullptr, }, // 0x00aa {-1, 4, clif_parse_UnequipItem, }, // 0x00ab Special case - outfit window (not implemented yet - needs to allow bursts) - {0, 7, NULL, }, // 0x00ac - {0, 0, NULL, }, // 0x00ad - {0, VAR,NULL, }, // 0x00ae - {0, 6, NULL, }, // 0x00af - {0, 8, NULL, }, // 0x00b0 - {0, 8, NULL, }, // 0x00b1 + {0, 7, nullptr, }, // 0x00ac + {0, 0, nullptr, }, // 0x00ad + {0, VAR,nullptr, }, // 0x00ae + {0, 6, nullptr, }, // 0x00af + {0, 8, nullptr, }, // 0x00b0 + {0, 8, nullptr, }, // 0x00b1 {0, 3, clif_parse_Restart, }, // 0x00b2 - {0, 3, NULL, }, // 0x00b3 - {0, VAR,NULL, }, // 0x00b4 - {0, 6, NULL, }, // 0x00b5 - {0, 6, NULL, }, // 0x00b6 - {0, VAR,NULL, }, // 0x00b7 + {0, 3, nullptr, }, // 0x00b3 + {0, VAR,nullptr, }, // 0x00b4 + {0, 6, nullptr, }, // 0x00b5 + {0, 6, nullptr, }, // 0x00b6 + {0, VAR,nullptr, }, // 0x00b7 {0, 7, clif_parse_NpcSelectMenu, }, // 0x00b8 {-1, 6, clif_parse_NpcNextClicked, }, // 0x00b9 - {0, 2, NULL, }, // 0x00ba + {0, 2, nullptr, }, // 0x00ba {-1, 5, clif_parse_StatusUp, }, // 0x00bb People click this very quickly - {0, 6, NULL, }, // 0x00bc - {0, 44, NULL, }, // 0x00bd - {0, 5, NULL, }, // 0x00be + {0, 6, nullptr, }, // 0x00bc + {0, 44, nullptr, }, // 0x00bd + {0, 5, nullptr, }, // 0x00be {1000, 3, clif_parse_Emotion, }, // 0x00bf - {0, 7, NULL, }, // 0x00c0 + {0, 7, nullptr, }, // 0x00c0 {0, 2, clif_parse_HowManyConnections, }, // 0x00c1 - {0, 6, NULL, }, // 0x00c2 - {0, 8, NULL, }, // 0x00c3 - {0, 6, NULL, }, // 0x00c4 + {0, 6, nullptr, }, // 0x00c2 + {0, 8, nullptr, }, // 0x00c3 + {0, 6, nullptr, }, // 0x00c4 {0, 7, clif_parse_NpcBuySellSelected, }, // 0x00c5 - {0, VAR,NULL, }, // 0x00c6 - {0, VAR,NULL, }, // 0x00c7 + {0, VAR,nullptr, }, // 0x00c6 + {0, VAR,nullptr, }, // 0x00c7 {-1, VAR,clif_parse_NpcBuyListSend, }, // 0x00c8 {-1, VAR,clif_parse_NpcSellListSend, }, // 0x00c9 Selling multiple 1-slot items - {0, 3, NULL, }, // 0x00ca - {0, 3, NULL, }, // 0x00cb - {0, 6, NULL, }, // 0x00cc - {0, 6, NULL, }, // 0x00cd - {0, 2, NULL, }, // 0x00ce - {0, 27, NULL, }, // 0x00cf - {0, 3, NULL, }, // 0x00d0 - {0, 4, NULL, }, // 0x00d1 - {0, 4, NULL, }, // 0x00d2 - {0, 2, NULL, }, // 0x00d3 - {0, VAR,NULL, }, // 0x00d4 - {0, VAR,NULL, }, // 0x00d5 - {0, 3, NULL, }, // 0x00d6 - {0, VAR,NULL, }, // 0x00d7 - {0, 6, NULL, }, // 0x00d8 - {0, 14, NULL, }, // 0x00d9 - {0, 3, NULL, }, // 0x00da - {0, VAR,NULL, }, // 0x00db - {0, 28, NULL, }, // 0x00dc - {0, 29, NULL, }, // 0x00dd - {0, VAR,NULL, }, // 0x00de - {0, VAR,NULL, }, // 0x00df - {0, 30, NULL, }, // 0x00e0 - {0, 30, NULL, }, // 0x00e1 - {0, 26, NULL, }, // 0x00e2 - {0, 2, NULL, }, // 0x00e3 + {0, 3, nullptr, }, // 0x00ca + {0, 3, nullptr, }, // 0x00cb + {0, 6, nullptr, }, // 0x00cc + {0, 6, nullptr, }, // 0x00cd + {0, 2, nullptr, }, // 0x00ce + {0, 27, nullptr, }, // 0x00cf + {0, 3, nullptr, }, // 0x00d0 + {0, 4, nullptr, }, // 0x00d1 + {0, 4, nullptr, }, // 0x00d2 + {0, 2, nullptr, }, // 0x00d3 + {0, VAR,nullptr, }, // 0x00d4 + {0, VAR,nullptr, }, // 0x00d5 + {0, 3, nullptr, }, // 0x00d6 + {0, VAR,nullptr, }, // 0x00d7 + {0, 6, nullptr, }, // 0x00d8 + {0, 14, nullptr, }, // 0x00d9 + {0, 3, nullptr, }, // 0x00da + {0, VAR,nullptr, }, // 0x00db + {0, 28, nullptr, }, // 0x00dc + {0, 29, nullptr, }, // 0x00dd + {0, VAR,nullptr, }, // 0x00de + {0, VAR,nullptr, }, // 0x00df + {0, 30, nullptr, }, // 0x00e0 + {0, 30, nullptr, }, // 0x00e1 + {0, 26, nullptr, }, // 0x00e2 + {0, 2, nullptr, }, // 0x00e3 {2000, 6, clif_parse_TradeRequest, }, // 0x00e4 - {0, 26, NULL, }, // 0x00e5 + {0, 26, nullptr, }, // 0x00e5 {0, 3, clif_parse_TradeAck, }, // 0x00e6 - {0, 3, NULL, }, // 0x00e7 + {0, 3, nullptr, }, // 0x00e7 {0, 8, clif_parse_TradeAddItem, }, // 0x00e8 - {0, 19, NULL, }, // 0x00e9 - {0, 5, NULL, }, // 0x00ea + {0, 19, nullptr, }, // 0x00e9 + {0, 5, nullptr, }, // 0x00ea {0, 2, clif_parse_TradeOk, }, // 0x00eb - {0, 3, NULL, }, // 0x00ec + {0, 3, nullptr, }, // 0x00ec {0, 2, clif_parse_TradeCansel, }, // 0x00ed - {0, 2, NULL, }, // 0x00ee + {0, 2, nullptr, }, // 0x00ee {0, 2, clif_parse_TradeCommit, }, // 0x00ef - {0, 3, NULL, }, // 0x00f0 - {0, 2, NULL, }, // 0x00f1 - {0, 6, NULL, }, // 0x00f2 + {0, 3, nullptr, }, // 0x00f0 + {0, 2, nullptr, }, // 0x00f1 + {0, 6, nullptr, }, // 0x00f2 {-1, 8, clif_parse_MoveToKafra, }, // 0x00f3 - {0, 21, NULL, }, // 0x00f4 + {0, 21, nullptr, }, // 0x00f4 {-1, 8, clif_parse_MoveFromKafra, }, // 0x00f5 - {0, 8, NULL, }, // 0x00f6 + {0, 8, nullptr, }, // 0x00f6 {0, 2, clif_parse_CloseKafra, }, // 0x00f7 - {0, 2, NULL, }, // 0x00f8 + {0, 2, nullptr, }, // 0x00f8 {2000, 26, clif_parse_CreateParty, }, // 0x00f9 - {0, 3, NULL, }, // 0x00fa - {0, VAR,NULL, }, // 0x00fb + {0, 3, nullptr, }, // 0x00fa + {0, VAR,nullptr, }, // 0x00fb {2000, 6, clif_parse_PartyInvite, }, // 0x00fc - {0, 27, NULL, }, // 0x00fd - {0, 30, NULL, }, // 0x00fe + {0, 27, nullptr, }, // 0x00fd + {0, 30, nullptr, }, // 0x00fe {0, 10, clif_parse_ReplyPartyInvite, }, // 0x00ff {0, 2, clif_parse_LeaveParty, }, // 0x0100 - {0, 6, NULL, }, // 0x0101 + {0, 6, nullptr, }, // 0x0101 {0, 6, clif_parse_PartyChangeOption, }, // 0x0102 {0, 30, clif_parse_RemovePartyMember, }, // 0x0103 - {0, 79, NULL, }, // 0x0104 - {0, 31, NULL, }, // 0x0105 - {0, 10, NULL, }, // 0x0106 - {0, 10, NULL, }, // 0x0107 + {0, 79, nullptr, }, // 0x0104 + {0, 31, nullptr, }, // 0x0105 + {0, 10, nullptr, }, // 0x0106 + {0, 10, nullptr, }, // 0x0107 {300, VAR,clif_parse_PartyMessage, }, // 0x0108 - {0, VAR,NULL, }, // 0x0109 - {0, 4, NULL, }, // 0x010a - {0, 6, NULL, }, // 0x010b - {0, 6, NULL, }, // 0x010c - {0, 2, NULL, }, // 0x010d - {0, 11, NULL, }, // 0x010e - {0, VAR,NULL, }, // 0x010f - {0, 10, NULL, }, // 0x0110 - {0, 39, NULL, }, // 0x0111 + {0, VAR,nullptr, }, // 0x0109 + {0, 4, nullptr, }, // 0x010a + {0, 6, nullptr, }, // 0x010b + {0, 6, nullptr, }, // 0x010c + {0, 2, nullptr, }, // 0x010d + {0, 11, nullptr, }, // 0x010e + {0, VAR,nullptr, }, // 0x010f + {0, 10, nullptr, }, // 0x0110 + {0, 39, nullptr, }, // 0x0111 {-1, 4, clif_parse_SkillUp, }, // 0x0112 - {0, 10, NULL, }, // 0x0113 - {0, 31, NULL, }, // 0x0114 - {0, 35, NULL, }, // 0x0115 - {0, 10, NULL, }, // 0x0116 - {0, 18, NULL, }, // 0x0117 + {0, 10, nullptr, }, // 0x0113 + {0, 31, nullptr, }, // 0x0114 + {0, 35, nullptr, }, // 0x0115 + {0, 10, nullptr, }, // 0x0116 + {0, 18, nullptr, }, // 0x0117 {0, 2, clif_parse_StopAttack, }, // 0x0118 - {0, 13, NULL, }, // 0x0119 - {0, 15, NULL, }, // 0x011a - {0, 20, NULL, }, // 0x011b - {0, 68, NULL, }, // 0x011c - {0, 2, NULL, }, // 0x011d - {0, 3, NULL, }, // 0x011e - {0, 16, NULL, }, // 0x011f - {0, 6, NULL, }, // 0x0120 - {0, 14, NULL, }, // 0x0121 - {0, VAR,NULL, }, // 0x0122 - {0, VAR,NULL, }, // 0x0123 - {0, 21, NULL, }, // 0x0124 - {0, 8, NULL, }, // 0x0125 - {0, 8, NULL, }, // 0x0126 - {0, 8, NULL, }, // 0x0127 - {0, 8, NULL, }, // 0x0128 - {0, 8, NULL, }, // 0x0129 - {0, 2, NULL, }, // 0x012a - {0, 2, NULL, }, // 0x012b - {0, 3, NULL, }, // 0x012c - {0, 4, NULL, }, // 0x012d - {0, 2, NULL, }, // 0x012e - {0, VAR,NULL, }, // 0x012f - {0, 6, NULL, }, // 0x0130 - {0, 86, NULL, }, // 0x0131 - {0, 6, NULL, }, // 0x0132 - {0, VAR,NULL, }, // 0x0133 - {0, VAR,NULL, }, // 0x0134 - {0, 7, NULL, }, // 0x0135 - {0, VAR,NULL, }, // 0x0136 - {0, 6, NULL, }, // 0x0137 - {0, 3, NULL, }, // 0x0138 - {0, 16, NULL, }, // 0x0139 - {0, 4, NULL, }, // 0x013a - {0, 4, NULL, }, // 0x013b - {0, 4, NULL, }, // 0x013c - {0, 6, NULL, }, // 0x013d - {0, 24, NULL, }, // 0x013e - {0, 26, NULL, }, // 0x013f - {0, 22, NULL, }, // 0x0140 - {0, 14, NULL, }, // 0x0141 - {0, 6, NULL, }, // 0x0142 + {0, 13, nullptr, }, // 0x0119 + {0, 15, nullptr, }, // 0x011a + {0, 20, nullptr, }, // 0x011b + {0, 68, nullptr, }, // 0x011c + {0, 2, nullptr, }, // 0x011d + {0, 3, nullptr, }, // 0x011e + {0, 16, nullptr, }, // 0x011f + {0, 6, nullptr, }, // 0x0120 + {0, 14, nullptr, }, // 0x0121 + {0, VAR,nullptr, }, // 0x0122 + {0, VAR,nullptr, }, // 0x0123 + {0, 21, nullptr, }, // 0x0124 + {0, 8, nullptr, }, // 0x0125 + {0, 8, nullptr, }, // 0x0126 + {0, 8, nullptr, }, // 0x0127 + {0, 8, nullptr, }, // 0x0128 + {0, 8, nullptr, }, // 0x0129 + {0, 2, nullptr, }, // 0x012a + {0, 2, nullptr, }, // 0x012b + {0, 3, nullptr, }, // 0x012c + {0, 4, nullptr, }, // 0x012d + {0, 2, nullptr, }, // 0x012e + {0, VAR,nullptr, }, // 0x012f + {0, 6, nullptr, }, // 0x0130 + {0, 86, nullptr, }, // 0x0131 + {0, 6, nullptr, }, // 0x0132 + {0, VAR,nullptr, }, // 0x0133 + {0, VAR,nullptr, }, // 0x0134 + {0, 7, nullptr, }, // 0x0135 + {0, VAR,nullptr, }, // 0x0136 + {0, 6, nullptr, }, // 0x0137 + {0, 3, nullptr, }, // 0x0138 + {0, 16, nullptr, }, // 0x0139 + {0, 4, nullptr, }, // 0x013a + {0, 4, nullptr, }, // 0x013b + {0, 4, nullptr, }, // 0x013c + {0, 6, nullptr, }, // 0x013d + {0, 24, nullptr, }, // 0x013e + {0, 26, nullptr, }, // 0x013f + {0, 22, nullptr, }, // 0x0140 + {0, 14, nullptr, }, // 0x0141 + {0, 6, nullptr, }, // 0x0142 {300, 10, clif_parse_NpcAmountInput, }, // 0x0143 - {0, 23, NULL, }, // 0x0144 - {0, 19, NULL, }, // 0x0145 + {0, 23, nullptr, }, // 0x0144 + {0, 19, nullptr, }, // 0x0145 {300, 6, clif_parse_NpcCloseClicked, }, // 0x0146 - {0, 39, NULL, }, // 0x0147 - {0, 8, NULL, }, // 0x0148 - {0, 9, NULL, }, // 0x0149 - {0, 6, NULL, }, // 0x014a - {0, 27, NULL, }, // 0x014b - {0, VAR,NULL, }, // 0x014c - {0, 2, NULL, }, // 0x014d - {0, 6, NULL, }, // 0x014e - {0, 6, NULL, }, // 0x014f - {0, 110,NULL, }, // 0x0150 - {0, 6, NULL, }, // 0x0151 - {0, VAR,NULL, }, // 0x0152 - {0, VAR,NULL, }, // 0x0153 - {0, VAR,NULL, }, // 0x0154 - {0, VAR,NULL, }, // 0x0155 - {0, VAR,NULL, }, // 0x0156 - {0, 6, NULL, }, // 0x0157 - {0, VAR,NULL, }, // 0x0158 - {0, 54, NULL, }, // 0x0159 - {0, 66, NULL, }, // 0x015a - {0, 54, NULL, }, // 0x015b - {0, 90, NULL, }, // 0x015c - {0, 42, NULL, }, // 0x015d - {0, 6, NULL, }, // 0x015e - {0, 42, NULL, }, // 0x015f - {0, VAR,NULL, }, // 0x0160 - {0, VAR,NULL, }, // 0x0161 - {0, VAR,NULL, }, // 0x0162 - {0, VAR,NULL, }, // 0x0163 - {0, VAR,NULL, }, // 0x0164 - {0, 30, NULL, }, // 0x0165 - {0, VAR,NULL, }, // 0x0166 - {0, 3, NULL, }, // 0x0167 - {0, 14, NULL, }, // 0x0168 - {0, 3, NULL, }, // 0x0169 - {0, 30, NULL, }, // 0x016a - {0, 10, NULL, }, // 0x016b - {0, 43, NULL, }, // 0x016c - {0, 14, NULL, }, // 0x016d - {0, 186,NULL, }, // 0x016e - {0, 182,NULL, }, // 0x016f - {0, 14, NULL, }, // 0x0170 - {0, 30, NULL, }, // 0x0171 - {0, 10, NULL, }, // 0x0172 - {0, 3, NULL, }, // 0x0173 - {0, VAR,NULL, }, // 0x0174 - {0, 6, NULL, }, // 0x0175 - {0, 106,NULL, }, // 0x0176 - {0, VAR,NULL, }, // 0x0177 - {0, 4, NULL, }, // 0x0178 - {0, 5, NULL, }, // 0x0179 - {0, 4, NULL, }, // 0x017a - {0, VAR,NULL, }, // 0x017b - {0, 6, NULL, }, // 0x017c - {0, 7, NULL, }, // 0x017d - {0, VAR,NULL, }, // 0x017e - {0, VAR,NULL, }, // 0x017f - {0, 6, NULL, }, // 0x0180 - {0, 3, NULL, }, // 0x0181 - {0, 106,NULL, }, // 0x0182 - {0, 10, NULL, }, // 0x0183 - {0, 10, NULL, }, // 0x0184 - {0, 34, NULL, }, // 0x0185 - {0, 0, NULL, }, // 0x0186 - {0, 6, NULL, }, // 0x0187 - {0, 8, NULL, }, // 0x0188 - {0, 4, NULL, }, // 0x0189 + {0, 39, nullptr, }, // 0x0147 + {0, 8, nullptr, }, // 0x0148 + {0, 9, nullptr, }, // 0x0149 + {0, 6, nullptr, }, // 0x014a + {0, 27, nullptr, }, // 0x014b + {0, VAR,nullptr, }, // 0x014c + {0, 2, nullptr, }, // 0x014d + {0, 6, nullptr, }, // 0x014e + {0, 6, nullptr, }, // 0x014f + {0, 110,nullptr, }, // 0x0150 + {0, 6, nullptr, }, // 0x0151 + {0, VAR,nullptr, }, // 0x0152 + {0, VAR,nullptr, }, // 0x0153 + {0, VAR,nullptr, }, // 0x0154 + {0, VAR,nullptr, }, // 0x0155 + {0, VAR,nullptr, }, // 0x0156 + {0, 6, nullptr, }, // 0x0157 + {0, VAR,nullptr, }, // 0x0158 + {0, 54, nullptr, }, // 0x0159 + {0, 66, nullptr, }, // 0x015a + {0, 54, nullptr, }, // 0x015b + {0, 90, nullptr, }, // 0x015c + {0, 42, nullptr, }, // 0x015d + {0, 6, nullptr, }, // 0x015e + {0, 42, nullptr, }, // 0x015f + {0, VAR,nullptr, }, // 0x0160 + {0, VAR,nullptr, }, // 0x0161 + {0, VAR,nullptr, }, // 0x0162 + {0, VAR,nullptr, }, // 0x0163 + {0, VAR,nullptr, }, // 0x0164 + {0, 30, nullptr, }, // 0x0165 + {0, VAR,nullptr, }, // 0x0166 + {0, 3, nullptr, }, // 0x0167 + {0, 14, nullptr, }, // 0x0168 + {0, 3, nullptr, }, // 0x0169 + {0, 30, nullptr, }, // 0x016a + {0, 10, nullptr, }, // 0x016b + {0, 43, nullptr, }, // 0x016c + {0, 14, nullptr, }, // 0x016d + {0, 186,nullptr, }, // 0x016e + {0, 182,nullptr, }, // 0x016f + {0, 14, nullptr, }, // 0x0170 + {0, 30, nullptr, }, // 0x0171 + {0, 10, nullptr, }, // 0x0172 + {0, 3, nullptr, }, // 0x0173 + {0, VAR,nullptr, }, // 0x0174 + {0, 6, nullptr, }, // 0x0175 + {0, 106,nullptr, }, // 0x0176 + {0, VAR,nullptr, }, // 0x0177 + {0, 4, nullptr, }, // 0x0178 + {0, 5, nullptr, }, // 0x0179 + {0, 4, nullptr, }, // 0x017a + {0, VAR,nullptr, }, // 0x017b + {0, 6, nullptr, }, // 0x017c + {0, 7, nullptr, }, // 0x017d + {0, VAR,nullptr, }, // 0x017e + {0, VAR,nullptr, }, // 0x017f + {0, 6, nullptr, }, // 0x0180 + {0, 3, nullptr, }, // 0x0181 + {0, 106,nullptr, }, // 0x0182 + {0, 10, nullptr, }, // 0x0183 + {0, 10, nullptr, }, // 0x0184 + {0, 34, nullptr, }, // 0x0185 + {0, 0, nullptr, }, // 0x0186 + {0, 6, nullptr, }, // 0x0187 + {0, 8, nullptr, }, // 0x0188 + {0, 4, nullptr, }, // 0x0189 {0, 4, clif_parse_QuitGame, }, // 0x018a - {0, 4, NULL, }, // 0x018b - {0, 29, NULL, }, // 0x018c - {0, VAR,NULL, }, // 0x018d - {0, 10, NULL, }, // 0x018e - {0, 6, NULL, }, // 0x018f - {0, 90, NULL, }, // 0x0190 - {0, 86, NULL, }, // 0x0191 - {0, 24, NULL, }, // 0x0192 - {0, 6, NULL, }, // 0x0193 - {0, 30, NULL, }, // 0x0194 - {0, 102,NULL, }, // 0x0195 - {0, 9, NULL, }, // 0x0196 - {0, 4, NULL, }, // 0x0197 - {0, 8, NULL, }, // 0x0198 - {0, 4, NULL, }, // 0x0199 - {0, 14, NULL, }, // 0x019a - {0, 10, NULL, }, // 0x019b - {0, VAR,NULL, }, // 0x019c - {300, 6, NULL, }, // 0x019d - {0, 2, NULL, }, // 0x019e - {0, 6, NULL, }, // 0x019f - {0, 3, NULL, }, // 0x01a0 - {0, 3, NULL, }, // 0x01a1 - {0, 35, NULL, }, // 0x01a2 - {0, 5, NULL, }, // 0x01a3 - {0, 11, NULL, }, // 0x01a4 - {0, 26, NULL, }, // 0x01a5 - {0, VAR,NULL, }, // 0x01a6 - {0, 4, NULL, }, // 0x01a7 - {0, 4, NULL, }, // 0x01a8 - {0, 6, NULL, }, // 0x01a9 - {0, 10, NULL, }, // 0x01aa - {0, 12, NULL, }, // 0x01ab - {0, 6, NULL, }, // 0x01ac - {0, VAR,NULL, }, // 0x01ad - {0, 4, NULL, }, // 0x01ae - {0, 4, NULL, }, // 0x01af - {0, 11, NULL, }, // 0x01b0 - {0, 7, NULL, }, // 0x01b1 - {0, VAR,NULL, }, // 0x01b2 - {0, 67, NULL, }, // 0x01b3 - {0, 12, NULL, }, // 0x01b4 - {0, 18, NULL, }, // 0x01b5 - {0, 114,NULL, }, // 0x01b6 - {0, 6, NULL, }, // 0x01b7 - {0, 3, NULL, }, // 0x01b8 - {0, 6, NULL, }, // 0x01b9 - {0, 26, NULL, }, // 0x01ba - {0, 26, NULL, }, // 0x01bb - {0, 26, NULL, }, // 0x01bc - {0, 26, NULL, }, // 0x01bd - {0, 2, NULL, }, // 0x01be - {0, 3, NULL, }, // 0x01bf - {0, 2, NULL, }, // 0x01c0 - {0, 14, NULL, }, // 0x01c1 - {0, 10, NULL, }, // 0x01c2 - {0, VAR,NULL, }, // 0x01c3 - {0, 22, NULL, }, // 0x01c4 - {0, 22, NULL, }, // 0x01c5 - {0, 4, NULL, }, // 0x01c6 - {0, 2, NULL, }, // 0x01c7 - {0, 13, NULL, }, // 0x01c8 - {0, 97, NULL, }, // 0x01c9 - {0, 0, NULL, }, // 0x01ca - {0, 9, NULL, }, // 0x01cb - {0, 9, NULL, }, // 0x01cc - {0, 30, NULL, }, // 0x01cd - {0, 6, NULL, }, // 0x01ce - {0, 28, NULL, }, // 0x01cf - {0, 8, NULL, }, // 0x01d0 - {0, 14, NULL, }, // 0x01d1 - {0, 10, NULL, }, // 0x01d2 - {0, 35, NULL, }, // 0x01d3 - {0, 6, NULL, }, // 0x01d4 + {0, 4, nullptr, }, // 0x018b + {0, 29, nullptr, }, // 0x018c + {0, VAR,nullptr, }, // 0x018d + {0, 10, nullptr, }, // 0x018e + {0, 6, nullptr, }, // 0x018f + {0, 90, nullptr, }, // 0x0190 + {0, 86, nullptr, }, // 0x0191 + {0, 24, nullptr, }, // 0x0192 + {0, 6, nullptr, }, // 0x0193 + {0, 30, nullptr, }, // 0x0194 + {0, 102,nullptr, }, // 0x0195 + {0, 9, nullptr, }, // 0x0196 + {0, 4, nullptr, }, // 0x0197 + {0, 8, nullptr, }, // 0x0198 + {0, 4, nullptr, }, // 0x0199 + {0, 14, nullptr, }, // 0x019a + {0, 10, nullptr, }, // 0x019b + {0, VAR,nullptr, }, // 0x019c + {300, 6, nullptr, }, // 0x019d + {0, 2, nullptr, }, // 0x019e + {0, 6, nullptr, }, // 0x019f + {0, 3, nullptr, }, // 0x01a0 + {0, 3, nullptr, }, // 0x01a1 + {0, 35, nullptr, }, // 0x01a2 + {0, 5, nullptr, }, // 0x01a3 + {0, 11, nullptr, }, // 0x01a4 + {0, 26, nullptr, }, // 0x01a5 + {0, VAR,nullptr, }, // 0x01a6 + {0, 4, nullptr, }, // 0x01a7 + {0, 4, nullptr, }, // 0x01a8 + {0, 6, nullptr, }, // 0x01a9 + {0, 10, nullptr, }, // 0x01aa + {0, 12, nullptr, }, // 0x01ab + {0, 6, nullptr, }, // 0x01ac + {0, VAR,nullptr, }, // 0x01ad + {0, 4, nullptr, }, // 0x01ae + {0, 4, nullptr, }, // 0x01af + {0, 11, nullptr, }, // 0x01b0 + {0, 7, nullptr, }, // 0x01b1 + {0, VAR,nullptr, }, // 0x01b2 + {0, 67, nullptr, }, // 0x01b3 + {0, 12, nullptr, }, // 0x01b4 + {0, 18, nullptr, }, // 0x01b5 + {0, 114,nullptr, }, // 0x01b6 + {0, 6, nullptr, }, // 0x01b7 + {0, 3, nullptr, }, // 0x01b8 + {0, 6, nullptr, }, // 0x01b9 + {0, 26, nullptr, }, // 0x01ba + {0, 26, nullptr, }, // 0x01bb + {0, 26, nullptr, }, // 0x01bc + {0, 26, nullptr, }, // 0x01bd + {0, 2, nullptr, }, // 0x01be + {0, 3, nullptr, }, // 0x01bf + {0, 2, nullptr, }, // 0x01c0 + {0, 14, nullptr, }, // 0x01c1 + {0, 10, nullptr, }, // 0x01c2 + {0, VAR,nullptr, }, // 0x01c3 + {0, 22, nullptr, }, // 0x01c4 + {0, 22, nullptr, }, // 0x01c5 + {0, 4, nullptr, }, // 0x01c6 + {0, 2, nullptr, }, // 0x01c7 + {0, 13, nullptr, }, // 0x01c8 + {0, 97, nullptr, }, // 0x01c9 + {0, 0, nullptr, }, // 0x01ca + {0, 9, nullptr, }, // 0x01cb + {0, 9, nullptr, }, // 0x01cc + {0, 30, nullptr, }, // 0x01cd + {0, 6, nullptr, }, // 0x01ce + {0, 28, nullptr, }, // 0x01cf + {0, 8, nullptr, }, // 0x01d0 + {0, 14, nullptr, }, // 0x01d1 + {0, 10, nullptr, }, // 0x01d2 + {0, 35, nullptr, }, // 0x01d3 + {0, 6, nullptr, }, // 0x01d4 {300, VAR,clif_parse_NpcStringInput, }, // 0x01d5 - set to -1 - {0, 4, NULL, }, // 0x01d6 - {0, 11, NULL, }, // 0x01d7 - {0, 54, NULL, }, // 0x01d8 - {0, 53, NULL, }, // 0x01d9 - {0, 60, NULL, }, // 0x01da - {0, 2, NULL, }, // 0x01db - {0, VAR,NULL, }, // 0x01dc - {0, 47, NULL, }, // 0x01dd - {0, 33, NULL, }, // 0x01de - {0, 6, NULL, }, // 0x01df - {0, 30, NULL, }, // 0x01e0 - {0, 8, NULL, }, // 0x01e1 - {0, 34, NULL, }, // 0x01e2 - {0, 14, NULL, }, // 0x01e3 - {0, 2, NULL, }, // 0x01e4 - {0, 6, NULL, }, // 0x01e5 - {0, 26, NULL, }, // 0x01e6 - {0, 2, NULL, }, // 0x01e7 - {0, 28, NULL, }, // 0x01e8 - {0, 81, NULL, }, // 0x01e9 - {0, 6, NULL, }, // 0x01ea - {0, 10, NULL, }, // 0x01eb - {0, 26, NULL, }, // 0x01ec - {0, 2, NULL, }, // 0x01ed - {0, VAR,NULL, }, // 0x01ee - {0, VAR,NULL, }, // 0x01ef - {0, VAR,NULL, }, // 0x01f0 - {0, VAR,NULL, }, // 0x01f1 - {0, 20, NULL, }, // 0x01f2 - {0, 10, NULL, }, // 0x01f3 - {0, 32, NULL, }, // 0x01f4 - {0, 9, NULL, }, // 0x01f5 - {0, 34, NULL, }, // 0x01f6 - {0, 14, NULL, }, // 0x01f7 - {0, 2, NULL, }, // 0x01f8 - {0, 6, NULL, }, // 0x01f9 - {0, 48, NULL, }, // 0x01fa - {0, 56, NULL, }, // 0x01fb - {0, VAR,NULL, }, // 0x01fc - {0, 4, NULL, }, // 0x01fd - {0, 5, NULL, }, // 0x01fe - {0, 10, NULL, }, // 0x01ff - {0, 26, NULL, }, // 0x0200 - {0, VAR,NULL, }, // 0x0201 - {0, 26, NULL, }, // 0x0202 - {0, 10, NULL, }, // 0x0203 - {0, 18, NULL, }, // 0x0204 - {0, 26, NULL, }, // 0x0205 - {0, 11, NULL, }, // 0x0206 - {0, 34, NULL, }, // 0x0207 - {0, 14, NULL, }, // 0x0208 - {0, 36, NULL, }, // 0x0209 - {0, 10, NULL, }, // 0x020a - {0, 19, NULL, }, // 0x020b - {0, 10, NULL, }, // 0x020c - {0, VAR,NULL, }, // 0x020d - {0, 24, NULL, }, // 0x020e - {0, 0, NULL, }, // 0x020f - {0, 0, NULL, }, // 0x0210 - {0, 0, NULL, }, // 0x0211 - {0, 0, NULL, }, // 0x0212 - {0, 0, NULL, }, // 0x0213 - {0, 0, NULL, }, // 0x0214 - {0, 0, NULL, }, // 0x0215 - {0, 0, NULL, }, // 0x0216 - {0, 0, NULL, }, // 0x0217 - {0, 0, NULL, }, // 0x0218 - {0, 0, NULL, }, // 0x0219 - {0, 0, NULL, }, // 0x021a - {0, 0, NULL, }, // 0x021b - {0, 0, NULL, }, // 0x021c - {0, 0, NULL, }, // 0x021d - {0, 0, NULL, }, // 0x021e - {0, 0, NULL, }, // 0x021f + {0, 4, nullptr, }, // 0x01d6 + {0, 11, nullptr, }, // 0x01d7 + {0, 54, nullptr, }, // 0x01d8 + {0, 53, nullptr, }, // 0x01d9 + {0, 60, nullptr, }, // 0x01da + {0, 2, nullptr, }, // 0x01db + {0, VAR,nullptr, }, // 0x01dc + {0, 47, nullptr, }, // 0x01dd + {0, 33, nullptr, }, // 0x01de + {0, 6, nullptr, }, // 0x01df + {0, 30, nullptr, }, // 0x01e0 + {0, 8, nullptr, }, // 0x01e1 + {0, 34, nullptr, }, // 0x01e2 + {0, 14, nullptr, }, // 0x01e3 + {0, 2, nullptr, }, // 0x01e4 + {0, 6, nullptr, }, // 0x01e5 + {0, 26, nullptr, }, // 0x01e6 + {0, 2, nullptr, }, // 0x01e7 + {0, 28, nullptr, }, // 0x01e8 + {0, 81, nullptr, }, // 0x01e9 + {0, 6, nullptr, }, // 0x01ea + {0, 10, nullptr, }, // 0x01eb + {0, 26, nullptr, }, // 0x01ec + {0, 2, nullptr, }, // 0x01ed + {0, VAR,nullptr, }, // 0x01ee + {0, VAR,nullptr, }, // 0x01ef + {0, VAR,nullptr, }, // 0x01f0 + {0, VAR,nullptr, }, // 0x01f1 + {0, 20, nullptr, }, // 0x01f2 + {0, 10, nullptr, }, // 0x01f3 + {0, 32, nullptr, }, // 0x01f4 + {0, 9, nullptr, }, // 0x01f5 + {0, 34, nullptr, }, // 0x01f6 + {0, 14, nullptr, }, // 0x01f7 + {0, 2, nullptr, }, // 0x01f8 + {0, 6, nullptr, }, // 0x01f9 + {0, 48, nullptr, }, // 0x01fa + {0, 56, nullptr, }, // 0x01fb + {0, VAR,nullptr, }, // 0x01fc + {0, 4, nullptr, }, // 0x01fd + {0, 5, nullptr, }, // 0x01fe + {0, 10, nullptr, }, // 0x01ff + {0, 26, nullptr, }, // 0x0200 + {0, VAR,nullptr, }, // 0x0201 + {0, 26, nullptr, }, // 0x0202 + {0, 10, nullptr, }, // 0x0203 + {0, 18, nullptr, }, // 0x0204 + {0, 26, nullptr, }, // 0x0205 + {0, 11, nullptr, }, // 0x0206 + {0, 34, nullptr, }, // 0x0207 + {0, 14, nullptr, }, // 0x0208 + {0, 36, nullptr, }, // 0x0209 + {0, 10, nullptr, }, // 0x020a + {0, 19, nullptr, }, // 0x020b + {0, 10, nullptr, }, // 0x020c + {0, VAR,nullptr, }, // 0x020d + {0, 24, nullptr, }, // 0x020e + {0, 0, nullptr, }, // 0x020f + {0, 0, nullptr, }, // 0x0210 + {0, 0, nullptr, }, // 0x0211 + {0, 0, nullptr, }, // 0x0212 + {0, 0, nullptr, }, // 0x0213 + {0, 0, nullptr, }, // 0x0214 + {0, 0, nullptr, }, // 0x0215 + {0, 0, nullptr, }, // 0x0216 + {0, 0, nullptr, }, // 0x0217 + {0, 0, nullptr, }, // 0x0218 + {0, 0, nullptr, }, // 0x0219 + {0, 0, nullptr, }, // 0x021a + {0, 0, nullptr, }, // 0x021b + {0, 0, nullptr, }, // 0x021c + {0, 0, nullptr, }, // 0x021d + {0, 0, nullptr, }, // 0x021e + {0, 0, nullptr, }, // 0x021f }; // Checks for packet flooding static -int clif_check_packet_flood(Session *s, int cmd) +uint16_t clif_check_packet_flood(Session *s, int cmd) { + uint16_t len = clif_parse_func_table[cmd].len_unused; + if (len == VAR) + { + Little16 netlen; + if (!packet_fetch(s, 2, reinterpret_cast<Byte *>(&netlen), 2)) + { + return 0; + } + if (!network_to_native(&len, netlen)) + { + s->set_eof(); + return 0; + } + } + if (packet_avail(s) < len) + return 0; + dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); tick_t tick = gettick(); @@ -5182,30 +5401,28 @@ int clif_check_packet_flood(Session *s, int cmd) // Default rate is 100ms interval_t rate = clif_parse_func_table[cmd].rate; if (rate == interval_t::zero()) - rate = std::chrono::milliseconds(100); + rate = 100_ms; // ActionRequest - attacks are allowed a faster rate than sit/stand if (cmd == 0x89) { - int action_type = RFIFOB(s, 6); - if (action_type == 0x00 || action_type == 0x07) - rate = std::chrono::milliseconds(20); + DamageType damage_type; + Byte action_type; + if (!packet_fetch(s, 6, &action_type, 1)) + return 0; + if (!network_to_native(&damage_type, action_type)) + { + s->set_eof(); + return 0; + } + if (damage_type == DamageType::NORMAL || damage_type == DamageType::CONTINUOUS) + rate = 20_ms; else - rate = std::chrono::seconds(1); + rate = 1_s; } -// Restore this code when mana1.0 is released -#if 0 - // ChangeDir - only apply limit if not walking - if (cmd == 0x9b) - { - // .29 clients spam this packet when walking into a blocked tile - if (RFIFOB(fd, 4) == sd->dir || sd->walktimer != -1) - return 0; - - rate = 500; - } -#endif + // Restore this code when mana1.0 is released + // nope, nuh-uh // They are flooding if (tick < sd->flood_rates[cmd] + rate) @@ -5223,16 +5440,16 @@ int clif_check_packet_flood(Session *s, int cmd) if (sd->packet_flood_in >= battle_config.packet_spam_flood) { - PRINTF("packet flood detected from %s [0x%x]\n", sd->status_key.name, cmd); + PRINTF("packet flood detected from %s [0x%x]\n"_fmt, sd->status_key.name, cmd); if (battle_config.packet_spam_kick) { s->set_eof(); - return 1; + return len; } sd->packet_flood_in = 0; } - return 1; + return len; } sd->flood_rates[cmd] = tick; @@ -5240,9 +5457,9 @@ int clif_check_packet_flood(Session *s, int cmd) } inline -void WARN_MALFORMED_MSG(dumb_ptr<map_session_data> sd, const char *msg) +void WARN_MALFORMED_MSG(dumb_ptr<map_session_data> sd, ZString msg) { - PRINTF("clif_validate_chat(): %s (ID %d) sent a malformed message: %s.\n", + PRINTF("clif_validate_chat(): %s (ID %d) sent a malformed message: %s.\n"_fmt, sd->status_key.name, sd->status_key.account_id, msg); } /** @@ -5256,7 +5473,7 @@ void WARN_MALFORMED_MSG(dumb_ptr<map_session_data> sd, const char *msg) * @return a dynamically allocated copy of the message, or empty string upon failure */ static -AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) +AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type, XString buf) { nullpo_retr(AString(), sd); /* @@ -5267,54 +5484,8 @@ AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) return AString(); Session *s = sd->sess; - size_t msg_len = RFIFOW(s, 2) - 4; size_t name_len = sd->status_key.name.to__actual().size(); - /* - * At least one character is required in all instances. - * Notes for length checks: - * - * For all types, header (2) + length (2) is considered empty. - * For type 1, the message must be longer than the maximum name length (24) - * to be valid. - * For type 2, the message must be longer than the sender's name length - * plus the length of the separator (" : "). - */ - size_t min_len = - (type == ChatType::Whisper) ? 24 - : (type == ChatType::Global) ? name_len + 3 - : 0; - - /* The player just sent the header (2) and length (2) words. */ - if (!msg_len) - { - WARN_MALFORMED_MSG(sd, "no message sent"); - return AString(); - } - - /* The client sent (or claims to have sent) an empty message. */ - if (msg_len == min_len) - { - WARN_MALFORMED_MSG(sd, "empty message"); - return AString(); - } - - /* The protocol specifies that the target must be 24 bytes long. */ - if (type == ChatType::Whisper && msg_len < min_len) - { - /* Disallow malformed messages. */ - clif_setwaitclose(s); - WARN_MALFORMED_MSG(sd, "illegal target name"); - return AString(); - } - - size_t pstart = 4; - size_t buf_len = msg_len; - if (type == ChatType::Whisper) - { - pstart += 24; - buf_len -= 24; - } - AString pbuf = RFIFO_STRING(s, pstart, buf_len); + XString pbuf = buf; /* * The client attempted to exceed the maximum message length. @@ -5323,20 +5494,21 @@ AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) * is truncated. But the previous behavior was to drop the message, so * we'll do that, too. */ - if (buf_len >= battle_config.chat_maxline) + // TODO this cuts global chat short by (name_length + 3) + if (buf.size() >= battle_config.chat_maxline) { - WARN_MALFORMED_MSG(sd, "exceeded maximum message length"); + WARN_MALFORMED_MSG(sd, "exceeded maximum message length"_s); return AString(); } if (type == ChatType::Global) { XString p = pbuf; - if (!(p.startswith(sd->status_key.name.to__actual()) && p.xslice_t(name_len).startswith(" : "))) + if (!(p.startswith(sd->status_key.name.to__actual()) && p.xslice_t(name_len).startswith(" : "_s))) { /* Disallow malformed/spoofed messages. */ clif_setwaitclose(s); - WARN_MALFORMED_MSG(sd, "spoofed name/invalid format"); + WARN_MALFORMED_MSG(sd, "spoofed name/invalid format"_s); return AString(); } /* Step beyond the separator. */ @@ -5354,19 +5526,39 @@ AString clif_validate_chat(dumb_ptr<map_session_data> sd, ChatType type) static void clif_parse(Session *s) { - int packet_len = 0, cmd = 0; + // old code: + // no while loop (can hang if more than one packet) + // handles 0x7530 and 0x7532 specially, also 0x0072 + // checks packet length table + // checks rate limiter + // dispatches to actual function, unchecked + // interstitial code: + // introduces while loop + // checks rate limiter + // dispatches to actual function + // if incomplete, unchecks rate limiter + // if error, close socket + // future code: + // hoists while loop + // treats all packets as variable-length, except a hard-coded list + // reads packet of that length unconditionally into a buffer + // does rate-limit check (hoisted?) + // dispatches to actual function + // if error, close socket + dumb_ptr<map_session_data> sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s->session_data.get())); if (!sd || (sd && !sd->state.auth)) { - if (RFIFOREST(s) < 2) - { // too small a packet disconnect - s->set_eof(); - } - if (RFIFOW(s, 0) != 0x72 && RFIFOW(s, 0) != 0x7530) + uint16_t packet_id; + if (!packet_peek_id(s, &packet_id)) + return; + + if (packet_id != 0x0072 && packet_id != 0x7530) { // first packet must be auth or finger s->set_eof(); + return; } } @@ -5375,100 +5567,89 @@ void clif_parse(Session *s) s->set_eof(); return; } - - if (RFIFOREST(s) < 2) - return; // Too small (no packet number) - - cmd = RFIFOW(s, 0); - - // 管理用パケット処理 - if (cmd >= 30000) + if (sd && sd->state.auth == 1 && sd->state.waitingdisconnect == 1) { - switch (cmd) - { - case 0x7530: // Athena情報所得 - WFIFOW(s, 0) = 0x7531; - WFIFO_STRUCT(s, 2, CURRENT_MAP_SERVER_VERSION); - WFIFOSET(s, 10); - RFIFOSKIP(s, 2); - break; - case 0x7532: // 接続の切断 - s->set_eof(); - break; - } + packet_discard(s, packet_avail(s)); return; } - else if (cmd >= 0x200) - return; - // パケット長を計算 - packet_len = clif_parse_func_table[cmd].len; - if (packet_len == VAR) + uint16_t packet_id; + RecvResult rv = RecvResult::Complete; + while (rv == RecvResult::Complete && packet_peek_id(s, &packet_id)) { - if (RFIFOREST(s) < 4) + switch (packet_id) { - return; // Runt packet (variable length without a length sent) + case 0x7530: + { + Packet_Fixed<0x7530> fixed; + rv = recv_fpacket<0x7530, 2>(s, fixed); + if (rv != RecvResult::Complete) + break; + + Packet_Fixed<0x7531> fixed_31; + fixed_31.version = CURRENT_MAP_SERVER_VERSION; + send_fpacket<0x7531, 10>(s, fixed_31); + break; + } + case 0x7532: + { + Packet_Fixed<0x7532> fixed; + rv = recv_fpacket<0x7532, 2>(s, fixed); + if (rv != RecvResult::Complete) + break; + + s->set_eof(); + break; + } } - packet_len = RFIFOW(s, 2); - if (packet_len < 4 || packet_len > 32768) + if (packet_id < 0x0220) { - s->set_eof(); - return; // Runt packet (variable out of bounds) + if (uint16_t len = clif_check_packet_flood(s, packet_id)) + { + // Packet flood: skip packet + packet_discard(s, len); + rv = RecvResult::Complete; + } + else + { + clif_func func = clif_parse_func_table[packet_id].func; + if (!func) + goto unknown_packet; + rv = func(s, sd); + } } + else + goto unknown_packet; } - if (RFIFOREST(s) < packet_len) - { - return; // Runt packet (sent legnth is too small) - } - - if (sd && sd->state.auth == 1 && sd->state.waitingdisconnect == 1) - { // 切断待ちの場合パケットを処理しない - - } - else if (clif_parse_func_table[cmd].func) - { - if (clif_check_packet_flood(s, cmd)) - { - // Flood triggered. Skip packet. - RFIFOSKIP(sd->sess, packet_len); - return; - } + if (rv == RecvResult::Error) + s->set_eof(); + return; - clif_parse_func_table[cmd].func(s, sd); - } - else +unknown_packet: { - // 不明なパケット if (battle_config.error_log) { if (s) - PRINTF("\nclif_parse: session #%d, packet 0x%x, lenght %d\n", - s, cmd, packet_len); -#ifdef DUMP_UNKNOWN_PACKET + PRINTF("\nclif_parse: session #%d, packet 0x%x, lenght %zu\n"_fmt, + s, packet_id, packet_avail(s)); { - int i; - ZString packet_txt = "save/packet.txt"; - PRINTF("---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F"); - for (i = 0; i < packet_len; i++) - { - if ((i & 15) == 0) - PRINTF("\n%04X ", i); - PRINTF("%02X ", RFIFOB(s, i)); - } + ZString packet_txt = "save/packet.txt"_s; if (sd && sd->state.auth) { - PRINTF("\nAccount ID %d, character ID %d, player name %s.\n", + PRINTF("Unknown packet: Account ID %d, character ID %d, player name %s.\n"_fmt, sd->status_key.account_id, sd->status_key.char_id, sd->status_key.name); } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified) - PRINTF("\nAccount ID %d.\n", sd->bl_id); + PRINTF("Unkonwn packet (unauthenticated): Account ID %d.\n"_fmt, sd->bl_id); + else + PRINTF("Unknown packet (unknown)\n"_fmt); io::AppendFile fp(packet_txt); if (!fp.is_open()) { - PRINTF("clif.c: cant write [%s] !!! data is lost !!!\n", + PRINTF("clif.c: cant write [%s] !!! data is lost !!!\n"_fmt, packet_txt); return; } @@ -5479,34 +5660,29 @@ void clif_parse(Session *s) if (sd && sd->state.auth) { FPRINTF(fp, - "%s\nPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n", + "%s\nPlayer with account ID %d (character ID %d, player name %s) sent wrong packet:\n"_fmt, now, sd->status_key.account_id, sd->status_key.char_id, sd->status_key.name); } else if (sd) // not authentified! (refused by char-server or disconnect before to be authentified) FPRINTF(fp, - "%s\nPlayer with account ID %d sent wrong packet:\n", + "%s\nUnauthenticated player with account ID %d sent wrong packet:\n"_fmt, now, sd->bl_id); + else + FPRINTF(fp, + "%s\nUnknown connection sent wrong packet:\n"_fmt, + now); - FPRINTF(fp, - "\t---- 00-01-02-03-04-05-06-07-08-09-0A-0B-0C-0D-0E-0F"); - for (i = 0; i < packet_len; i++) - { - if ((i & 15) == 0) - FPRINTF(fp, "\n\t%04X ", i); - FPRINTF(fp, "%02X ", RFIFOB(s, i)); - } - FPRINTF(fp, "\n\n"); + packet_dump(fp, s); } } -#endif } } - RFIFOSKIP(s, packet_len); } void do_init_clif(void) { - make_listen_port(map_port, SessionParsers{func_parse: clif_parse, func_delete: clif_delete}); + make_listen_port(map_port, SessionParsers{.func_parse= clif_parse, .func_delete= clif_delete}); } +} // namespace tmwa |