summaryrefslogblamecommitdiff
path: root/src/map/intif.cpp
blob: 379bb1d699e6564357485da8949a647b75790a22 (plain) (tree)
1
                    



















                                                                           
 

                               
                                 

                                 
                                 
 

                             

                            
                          
 

                                 

                              
                     
                          

                    
                      



                      
 

                        
 

              

             
                                                                   
                           
 
                                         
                                 
 


                      
                                                            


                                                                                  
                                                                                 
 
                    
 


                      



                                                            
 
                              
                                                        
                                           


                         
      
                                          
 


                      



                                                                                                                           
 
                              
                                                                    


                                                                    
                                                                                   
 


                      



                                                            
 
                              
                                                                                          
                                              

 
                              
                                                        
 
                    


                      
                                                          
 



                                                                             
     

                                                             
     
                                                                  
 
 
                              
                                                            
 
                    
 


                      


                                                      

 
                        
                                                
 


                      


                                                    
 
 
                        
                                               
 


                      



                                                   

 
                           
                                                                      
 
                    
 


                      






                                                     
 
 
                           
                                              
 


                      


                                                    
 
 
                           
                                                                  
 


                      
                                  
                                                 
                      
     






                                                         
     
 
 
                           
                                                                                        
 


                      





                                                     
 
 











                                                                                 
                           
                                                              
 


                      



                                                     
 
 
                           
                                                                     
 


                      
                      
     






                                                         
     
 
 
                           
                                                                             
 


                      



                                                            
 
 
                                       
                                                                                     
 


                      




                                                     

 



                                                                   
      
                                                                                    

                         
                                  
 

                                       
 
                              
     
                                                                        
                                

                     

                                                         
                                                   

                                                                        
         
                                                        
             
                                                      
                                                                                                                                                      



             
                                                                                                                                              
             


                                          
      
                                                                    
 
                                  
 

                                           
                              
                                                                                                      
                                                                

                            
                      
                                     
 
             


                                                                   
      
                                                                                      

                                                                                

                                             
                                             
                               
     
                                     
                
                     
                                                                                                                               
                                                                    
         
                                                       

                                                         
     

 
                              
      
                                                                                                                        
 
                                                                                 
                      
                 


                                                           
     

                                                          
     
                                      
 
             

 
                        
      
                                                                             
 
                                  
 
                                                         
                      

                                    
                                                                      
                                        

                 
                                                          


                                                                         
                                                                                                            
                                                                       




                                                                                                                       
                                                                                                                             
                                                                       


                 
                               

                                                                  

                             
                               


                                       

             

 
                              
      
                                                                          

                               


                                                                       

 
                           
      
                                                                           
 
                              
                                             



                                            
                                                    
 
 
                     
      
                                                                                                                         
 
                 

                                    

                                                                  
               

     

                                     
                                 
                        
 
 
                           
      
                                                                               
 
                              


                                                                          
 
 
                                 
      
                                                                                 
 

                                                                    
 
 



























                                                                                                          
                           
      
                                                                                
 


                                            
                              
                                                           

                                                    
 
 
                           
      
                                                                          
 
                                 
 
 
                           
      
                                                                        
 




                                            
                                                              
 
 
                              
      
                                                                                       
 
                                                            

 
                                                                   


                                                                                          
                                                      
 


                      

                    
         




                                                              
                                            
                  
         
                    







                                                              
                  
         
                    






                                                    
                  
         
                    







                                                              
                  
         
                    







                                                              
                  
         
                    






                                                  
                  
         
                    






                                                   
                  
         
                    






                                                    
                  
         
                    








                                                                                                      
                  
         
                    






                                                    
                  
         
                    






                                                     
                  
         
                    






                                                    
                  
         
                    






                                                    
                  
         
                    






                                                   
                  
         
                    







                                                              
                  
         









                                                     









                                                    
                
                                     
     
              
 
                  
                   
#include "intif.hpp"
//    intif.cpp - Network interface to the internal server.
//
//    Copyright © ????-2004 Athena Dev Teams
//    Copyright © 2004-2011 The Mana World Development Team
//    Copyright © 2011-2014 Ben Longbons <b.r.longbons@gmail.com>
//
//    This file is part of The Mana World (Athena server)
//
//    This program is free software: you can redistribute it and/or modify
//    it under the terms of the GNU General Public License as published by
//    the Free Software Foundation, either version 3 of the License, or
//    (at your option) any later version.
//
//    This program is distributed in the hope that it will be useful,
//    but WITHOUT ANY WARRANTY; without even the implied warranty of
//    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
//    GNU General Public License for more details.
//
//    You should have received a copy of the GNU General Public License
//    along with this program.  If not, see <http://www.gnu.org/licenses/>.

#include "../compat/nullpo.hpp"

#include "../strings/astring.hpp"
#include "../strings/zstring.hpp"
#include "../strings/xstring.hpp"
#include "../strings/literal.hpp"

#include "../io/cxxstdio.hpp"

#include "../net/socket.hpp"

#include "../high/mmo.hpp"

#include "../proto2/char-map.hpp"

#include "../wire/packets.hpp"

#include "battle.hpp"
#include "battle_conf.hpp"
#include "chrif.hpp"
#include "clif.hpp"
#include "globals.hpp"
#include "map.hpp"
#include "party.hpp"
#include "pc.hpp"
#include "storage.hpp"

#include "../poison.hpp"


namespace tmwa
{
namespace map
{
//-----------------------------------------------------------------
// inter serverへの送信

// Message for all GMs on all map servers
void intif_GMmessage(XString mes)
{
    if (!char_session)
        return;

    send_packet_repeatonly<0x3000, 4, 1>(char_session, mes);
}

// The transmission of Wisp/Page to inter-server (player not found on this server)
void intif_wis_message(dumb_ptr<map_session_data> sd, CharName nick, ZString mes)
{
    nullpo_retv(sd);

    if (!char_session)
        return;

    Packet_Head<0x3001> head_01;
    head_01.from_char_name = sd->status_key.name;
    head_01.to_char_name = nick;
    send_vpacket<0x3001, 52, 1>(char_session, head_01, mes);

    if (battle_config.etc_log)
        PRINTF("intif_wis_message from %s to %s)\n"_fmt,
                sd->status_key.name, nick);
}

// The reply of Wisp/page
static
void intif_wis_replay(CharId id, int flag)
{
    if (!char_session)
        return;

    Packet_Fixed<0x3002> fixed_02;
    fixed_02.char_id = id;
    fixed_02.flag = flag;    // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
    send_fpacket<0x3002, 7>(char_session, fixed_02);

    if (battle_config.etc_log)
        PRINTF("intif_wis_replay: id: %d, flag:%d\n"_fmt, id, flag);
}

// The transmission of GM only Wisp/Page from server to inter-server
void intif_wis_message_to_gm(CharName Wisp_name, GmLevel min_gm_level, ZString mes)
{
    if (!char_session)
        return;

    Packet_Head<0x3003> head_03;
    head_03.char_name = Wisp_name;
    head_03.min_gm_level = min_gm_level;
    send_vpacket<0x3003, 30, 1>(char_session, head_03, mes);

    if (battle_config.etc_log)
        PRINTF("intif_wis_message_to_gm: from: '%s', min level: %d, message: '%s'.\n"_fmt,
                Wisp_name, min_gm_level, mes);
}

// アカウント変数送信
void intif_saveaccountreg(dumb_ptr<map_session_data> sd)
{
    nullpo_retv(sd);
    if (!char_session)
        return;

    assert (sd->status.account_reg_num < ACCOUNT_REG_NUM);

    Packet_Head<0x3004> head_04;
    head_04.account_id = block_to_account(sd->bl_id);
    std::vector<Packet_Repeat<0x3004>> repeat_04(sd->status.account_reg_num);
    for (size_t j = 0; j < sd->status.account_reg_num; j++)
    {
        repeat_04[j].name = sd->status.account_reg[j].str;
        repeat_04[j].value = sd->status.account_reg[j].value;
    }
    send_vpacket<0x3004, 8, 36>(char_session, head_04, repeat_04);
}

// アカウント変数要求
void intif_request_accountreg(dumb_ptr<map_session_data> sd)
{
    nullpo_retv(sd);

    if (!char_session)
        return;

    Packet_Fixed<0x3005> fixed_05;
    fixed_05.account_id = block_to_account(sd->bl_id);
    send_fpacket<0x3005, 6>(char_session, fixed_05);
}

// 倉庫データ要求
void intif_request_storage(AccountId account_id)
{
    if (!char_session)
        return;

    Packet_Fixed<0x3010> fixed_10;
    fixed_10.account_id = account_id;
    send_fpacket<0x3010, 6>(char_session, fixed_10);
}

// 倉庫データ送信
void intif_send_storage(Borrowed<Storage> stor)
{
    if (!char_session)
        return;

    Packet_Payload<0x3011> payload_11;
    payload_11.account_id = stor->account_id;
    payload_11.storage = *stor;
    send_ppacket<0x3011>(char_session, payload_11);
}

// パーティ作成要求
void intif_create_party(dumb_ptr<map_session_data> sd, PartyName name)
{
    nullpo_retv(sd);

    if (!char_session)
        return;

    Packet_Fixed<0x3020> fixed_20;
    fixed_20.account_id = sd->status_key.account_id;
    fixed_20.party_name = name;
    fixed_20.char_name = sd->status_key.name;
    fixed_20.map_name = sd->bl_m->name_;
    fixed_20.level = sd->status.base_level;
    send_fpacket<0x3020, 72>(char_session, fixed_20);
}

// パーティ情報要求
void intif_request_partyinfo(PartyId party_id)
{
    if (!char_session)
        return;

    Packet_Fixed<0x3021> fixed_21;
    fixed_21.party_id = party_id;
    send_fpacket<0x3021, 6>(char_session, fixed_21);
}

// パーティ追加要求
void intif_party_addmember(PartyId party_id, AccountId account_id)
{
    if (!char_session)
        return;

    dumb_ptr<map_session_data> sd;
    sd = map_id2sd(account_to_block(account_id));
    if (sd != nullptr)
    {
        Packet_Fixed<0x3022> fixed_22;
        fixed_22.party_id = party_id;
        fixed_22.account_id = account_id;
        fixed_22.char_name = sd->status_key.name;
        fixed_22.map_name = sd->bl_m->name_;
        fixed_22.level = sd->status.base_level;
        send_fpacket<0x3022, 52>(char_session, fixed_22);
    }
}

// パーティ設定変更
void intif_party_changeoption(PartyId party_id, AccountId account_id, int exp, int item)
{
    if (!char_session)
        return;

    Packet_Fixed<0x3023> fixed_23;
    fixed_23.party_id = party_id;
    fixed_23.account_id = account_id;
    fixed_23.exp = exp;
    fixed_23.item = item;
    send_fpacket<0x3023, 14>(char_session, fixed_23);
}

void intif_party_changeleader(PartyId party_id, AccountId account_id, int leader)
{
    if (!char_session)
        return;

    Packet_Fixed<0x3026> fixed_26;
    fixed_26.party_id = party_id;
    fixed_26.account_id = account_id;
    fixed_26.leader = leader;
    send_fpacket<0x3026, 11>(char_session, fixed_26);
}

// パーティ脱退要求
void intif_party_leave(PartyId party_id, AccountId account_id)
{
    if (!char_session)
        return;

    Packet_Fixed<0x3024> fixed_24;
    fixed_24.party_id = party_id;
    fixed_24.account_id = account_id;
    send_fpacket<0x3024, 10>(char_session, fixed_24);
}

// パーティ移動要求
void intif_party_changemap(dumb_ptr<map_session_data> sd, int online)
{
    if (!char_session)
        return;

    if (sd != nullptr)
    {
        Packet_Fixed<0x3025> fixed_25;
        fixed_25.party_id = sd->status.party_id;
        fixed_25.account_id = sd->status_key.account_id;
        fixed_25.map_name = sd->bl_m->name_;
        fixed_25.online = online;
        fixed_25.level = sd->status.base_level;
        send_fpacket<0x3025, 29>(char_session, fixed_25);
    }
}

// パーティ会話送信
void intif_party_message(PartyId party_id, AccountId account_id, XString mes)
{
    if (!char_session)
        return;

    Packet_Head<0x3027> head_27;
    head_27.party_id = party_id;
    head_27.account_id = account_id;
    send_vpacket<0x3027, 12, 1>(char_session, head_27, mes);
}

// パーティ競合チェック要求
void intif_party_checkconflict(PartyId party_id, AccountId account_id, CharName nick)
{
    if (!char_session)
        return;

    Packet_Fixed<0x3028> fixed_28;
    fixed_28.party_id = party_id;
    fixed_28.account_id = account_id;
    fixed_28.char_name = nick;
    send_fpacket<0x3028, 34>(char_session, fixed_28);
}

//-----------------------------------------------------------------
// Packets receive from inter server

// Wisp/Page reception
static
int intif_parse_WisMessage(Session *, const Packet_Head<0x3801>& head, AString& buf)
{
    // rewritten by [Yor]
    dumb_ptr<map_session_data> sd;

    CharName from = head.src_char_name;
    CharName to = head.dst_char_name;

    if (battle_config.etc_log)
    {
        PRINTF("intif_parse_wismessage: id: %d, from: %s, to: %s\n"_fmt,
                head.whisper_id,
                from,
                to);
    }
    sd = map_nick2sd(to); // Searching destination player
    if (sd != nullptr && sd->status_key.name == to)
    {
        // exactly same name (inter-server have checked the name before)
        {
            // if source player not found in ignore list
            {
                clif_wis_message(sd->sess, from, buf);
                intif_wis_replay(head.whisper_id, 0);   // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
            }
        }
    }
    else
        intif_wis_replay(head.whisper_id, 1);   // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
    return 0;
}

// Wisp/page transmission result reception
static
int intif_parse_WisEnd(Session *, const Packet_Fixed<0x3802>& fixed)
{
    dumb_ptr<map_session_data> sd;

    CharName name = fixed.sender_char_name;
    uint8_t flag = fixed.flag;
    if (battle_config.etc_log)
        // flag: 0: success to send wisper, 1: target character is not loged in?, 2: ignored by target
        PRINTF("intif_parse_wisend: player: %s, flag: %d\n"_fmt,
                name, flag);
    sd = map_nick2sd(name);
    if (sd != nullptr)
        clif_wis_end(sd->sess, flag);

    return 0;
}

// Received wisp message from map-server via char-server for ALL gm
static
void mapif_parse_WisToGM(Session *, const Packet_Head<0x3803>& head, AString& message)
{
    // 0x3003/0x3803 <packet_len>.w <wispname>.24B <min_gm_level>.w <message>.?B
    GmLevel min_gm_level = head.min_gm_level;
    CharName Wisp_name = head.char_name;
    // information is sended to all online GM
    for (io::FD i : iter_fds())
    {
        Session *s2 = get_session(i);
        if (!s2)
            continue;
        dumb_ptr<map_session_data> pl_sd = dumb_ptr<map_session_data>(static_cast<map_session_data *>(s2->session_data.get()));
        if (pl_sd && pl_sd->state.auth && !pl_sd->state.connect_new)
        {
            if (pc_isGM(pl_sd).satisfies(min_gm_level))
                clif_wis_message(s2, Wisp_name, message);
        }
    }
}

// アカウント変数通知
static
int intif_parse_AccountReg(Session *, const Packet_Head<0x3804>& head, const std::vector<Packet_Repeat<0x3804>>& repeat)
{
    dumb_ptr<map_session_data> sd = map_id2sd(account_to_block(head.account_id));
    if (sd == nullptr)
        return 1;

    size_t jlim = std::min(ACCOUNT_REG_NUM, repeat.size());
    for (size_t j = 0; j < jlim; j++)
    {
        sd->status.account_reg[j].str = repeat[j].name;
        sd->status.account_reg[j].value = repeat[j].value;
    }
    sd->status.account_reg_num = jlim;

    return 0;
}

// 倉庫データ受信
static
int intif_parse_LoadStorage(Session *, const Packet_Payload<0x3810>& payload)
{
    dumb_ptr<map_session_data> sd;

    sd = map_id2sd(account_to_block(payload.account_id));
    if (sd == nullptr)
    {
        if (battle_config.error_log)
            PRINTF("intif_parse_LoadStorage: user not found %d\n"_fmt,
                    payload.account_id);
        return 1;
    }
    P<Storage> stor = account2storage(payload.account_id);
    if (stor->storage_status == 1)
    {                           // Already open.. lets ignore this update
        if (battle_config.error_log)
            PRINTF("intif_parse_LoadStorage: storage received for a client already open (User %d:%d)\n"_fmt,
                    sd->status_key.account_id, sd->status_key.char_id);
        return 1;
    }
    if (stor->dirty)
    {                           // Already have storage, and it has been modified and not saved yet! Exploit! [Skotlex]
        if (battle_config.error_log)
            PRINTF("intif_parse_LoadStorage: received storage for an already modified non-saved storage! (User %d:%d)\n"_fmt,
                    sd->status_key.account_id, sd->status_key.char_id);
        return 1;
    }

    if (battle_config.save_log)
        PRINTF("intif_openstorage: %d\n"_fmt, payload.account_id);
    *stor = payload.storage;
    stor->dirty = 0;
    stor->storage_status = 1;
    sd->state.storage_open = 1;
    clif_storageitemlist(sd, stor);
    clif_storageequiplist(sd, stor);
    clif_updatestorageamount(sd, stor);

    return 0;
}

// 倉庫データ送信成功
static
void intif_parse_SaveStorage(Session *, const Packet_Fixed<0x3811>& fixed)
{
    if (battle_config.save_log)
        PRINTF("intif_savestorage: done %d %d\n"_fmt, fixed.account_id,
                fixed.unknown);
    storage_storage_saved(fixed.account_id);
}

// パーティ作成可否
static
void intif_parse_PartyCreated(Session *, const Packet_Fixed<0x3820>& fixed)
{
    if (battle_config.etc_log)
        PRINTF("intif: party created\n"_fmt);
    AccountId account_id = fixed.account_id;
    int fail = fixed.error;
    PartyId party_id = fixed.party_id;
    PartyName name = fixed.party_name;
    party_created(account_id, fail, party_id, name);
}

// パーティ情報
static
void intif_parse_PartyInfo(Session *, const Packet_Head<0x3821>& head, bool has_opt, const Packet_Option<0x3821>& option)
{
    if (!has_opt)
    {
        if (battle_config.error_log)
            PRINTF("intif: party noinfo %d\n"_fmt, head.party_id);
        party_recv_noinfo(head.party_id);
        return;
    }

    PartyId pi = head.party_id;
    PartyMost pm = option.party_most;
    PartyPair pp{pi, borrow(pm)};
    party_recv_info(pp);
}

// パーティ追加通知
static
void intif_parse_PartyMemberAdded(Session *, const Packet_Fixed<0x3822>& fixed)
{
    if (battle_config.etc_log)
        PRINTF("intif: party member added %d %d %d\n"_fmt, fixed.party_id,
                fixed.account_id, fixed.flag);
    party_member_added(fixed.party_id, fixed.account_id, fixed.flag);
}

// パーティ設定変更通知
static
void intif_parse_PartyOptionChanged(Session *, const Packet_Fixed<0x3823>& fixed)
{
    party_optionchanged(fixed.party_id, fixed.account_id, fixed.exp,
            fixed.item, fixed.flag);
}

static
void intif_parse_PartyLeaderChanged(Session *, const Packet_Fixed<0x3828>& fixed)
{
    int i;
    PartyPair p = TRY_UNWRAP(party_search(fixed.party_id), return);

    for (i = 0; i < MAX_PARTY; i++)
    {
        PartyMember *m = &p->member[i];

        if (m->account_id == fixed.account_id)
        {
            dumb_ptr<map_session_data> sd = map_id2sd(wrap<BlockId>(unwrap<AccountId>(fixed.account_id)));
            m->leader = (fixed.leader > 0 ? 1 : 0);

            if (sd != nullptr)
            {
                AString msg = STRPRINTF("You are %s a leader of %s."_fmt,
                    fixed.leader > 0 ? "now"_s : "no longer"_s, p->name);
                clif_displaymessage(sd->sess, msg);
            }
            break;
        }
    }

    clif_party_info(p, nullptr);
}

// パーティ脱退通知
static
void intif_parse_PartyMemberLeaved(Session *, const Packet_Fixed<0x3824>& fixed)
{
    PartyId party_id = fixed.party_id;
    AccountId account_id = fixed.account_id;
    CharName name = fixed.char_name;
    if (battle_config.etc_log)
        PRINTF("intif: party member leaved %d %d %s\n"_fmt,
                party_id, account_id, name);
    party_member_leaved(party_id, account_id, name);
}

// パーティ解散通知
static
void intif_parse_PartyBroken(Session *, const Packet_Fixed<0x3826>& fixed)
{
    party_broken(fixed.party_id);
}

// パーティ移動通知
static
void intif_parse_PartyMove(Session *, const Packet_Fixed<0x3825>& fixed)
{
    PartyId party_id = fixed.party_id;
    AccountId account_id = fixed.account_id;
    MapName map = fixed.map_name;
    uint8_t online = fixed.online;
    uint16_t lv = fixed.level;
    party_recv_movemap(party_id, account_id, map, online, lv);
}

// パーティメッセージ
static
void intif_parse_PartyMessage(Session *, const Packet_Head<0x3827>& head, AString& buf)
{
    party_recv_message(head.party_id, head.account_id, buf);
}

//-----------------------------------------------------------------
// inter serverからの通信
// エラーがあれば0(false)を返すこと
// パケットが処理できれば1,パケット長が足りなければ2を返すこと
RecvResult intif_parse(Session *s, uint16_t packet_id)
{
    RecvResult rv;

    switch (packet_id)
    {
        case 0x3800:
        {
            AString mes;
            rv = recv_packet_repeatonly<0x3800, 4, 1>(s, mes);
            if (rv != RecvResult::Complete)
                return rv;

            clif_GMmessage(nullptr, mes, 0);
            break;
        }
        case 0x3801:
        {
            Packet_Head<0x3801> head;
            AString repeat;
            rv = recv_vpacket<0x3801, 56, 1>(s, head, repeat);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_WisMessage(s, head, repeat);
            break;
        }
        case 0x3802:
        {
            Packet_Fixed<0x3802> fixed;
            rv = recv_fpacket<0x3802, 27>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_WisEnd(s, fixed);
            break;
        }
        case 0x3803:
        {
            Packet_Head<0x3803> head;
            AString repeat;
            rv = recv_vpacket<0x3803, 30, 1>(s, head, repeat);
            if (rv != RecvResult::Complete)
                return rv;

            mapif_parse_WisToGM(s, head, repeat);
            break;
        }
        case 0x3804:
        {
            Packet_Head<0x3804> head;
            std::vector<Packet_Repeat<0x3804>> repeat;
            rv = recv_vpacket<0x3804, 8, 36>(s, head, repeat);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_AccountReg(s, head, repeat);
            break;
        }
        case 0x3810:
        {
            Packet_Payload<0x3810> payload;
            rv = recv_ppacket<0x3810>(s, payload);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_LoadStorage(s, payload);
            break;
        }
        case 0x3811:
        {
            Packet_Fixed<0x3811> fixed;
            rv = recv_fpacket<0x3811, 7>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_SaveStorage(s, fixed);
            break;
        }
        case 0x3820:
        {
            Packet_Fixed<0x3820> fixed;
            rv = recv_fpacket<0x3820, 35>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyCreated(s, fixed);
            break;
        }
        case 0x3821:
        {
            Packet_Head<0x3821> head;
            bool has_opt;
            Packet_Option<0x3821> option;
            rv = recv_opacket<0x3821, 8, sizeof(NetPacket_Option<0x3821>)>(s, head, &has_opt, option);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyInfo(s, head, has_opt, option);
            break;
        }
        case 0x3822:
        {
            Packet_Fixed<0x3822> fixed;
            rv = recv_fpacket<0x3822, 11>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyMemberAdded(s, fixed);
            break;
        }
        case 0x3823:
        {
            Packet_Fixed<0x3823> fixed;
            rv = recv_fpacket<0x3823, 15>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyOptionChanged(s, fixed);
            break;
        }
        case 0x3824:
        {
            Packet_Fixed<0x3824> fixed;
            rv = recv_fpacket<0x3824, 34>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyMemberLeaved(s, fixed);
            break;
        }
        case 0x3825:
        {
            Packet_Fixed<0x3825> fixed;
            rv = recv_fpacket<0x3825, 29>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyMove(s, fixed);
            break;
        }
        case 0x3826:
        {
            Packet_Fixed<0x3826> fixed;
            rv = recv_fpacket<0x3826, 7>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyBroken(s, fixed);
            break;
        }
        case 0x3827:
        {
            Packet_Head<0x3827> head;
            AString repeat;
            rv = recv_vpacket<0x3827, 12, 1>(s, head, repeat);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyMessage(s, head, repeat);
            break;
        }
        case 0x3828:
        {
            Packet_Fixed<0x3828> fixed;
            rv = recv_fpacket<0x3828, 11>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            intif_parse_PartyLeaderChanged(s, fixed);
            break;
        }
        case 0x3829:
        {
            Packet_Fixed<0x3829> fixed;
            rv = recv_fpacket<0x3829, 22>(s, fixed);
            if (rv != RecvResult::Complete)
                return rv;

            chrif_parse_preauth(s, fixed);
            break;
        }
        default:
            return RecvResult::Error;
    }
    return rv;
}
} // namespace map
} // namespace tmwa