enum PacketFamily : byte { 1 Connection 2 Account 3 Character 4 Login 5 Welcome 6 Walk 7 Face 8 Chair 9 Emote 11 Attack 12 Spell 13 Shop 14 Item 16 StatSkill 17 Global 18 Talk 19 Warp 21 Jukebox 22 Players 23 Avatar 24 Party 25 Refresh 26 NPC 27 PlayerRange 28 NPCRange 29 Range 30 Paperdoll 31 Effect 32 Trade 33 Chest 34 Door 35 Message 36 Bank 37 Locker 38 Barber 39 Guild 40 Music 41 Sit 42 Recover 43 Board 44 Cast 45 Arena 46 Priest 47 Marriage 48 AdminInteract 49 Citizen 50 Quest 51 Book 255 Init } enum PacketAction : byte { 1 Request 2 Accept 3 Reply 4 Remove 5 Agree 6 Create 7 Add 8 Player 9 Take 10 Use 11 Buy 12 Sell 13 Open 14 Close 15 Msg 16 Spec 17 Admin 18 List 20 Tell 21 Report 22 Announce 23 Server 24 Drop 25 Junk 26 Obtain 27 Get 28 Kick 29 Rank 30 Target_Self 31 Target_Other 33 Target_Group 34 Dialog 240 Ping 241 Pong 242 Net3 255 Init } // --- enum AdminLevel : char { 0 Player 1 Spy 2 LightGuide 3 Guardian 4 GameMaster 5 HighGameMaster } enum Direction : char { 0 Down 1 Left 2 Up 3 Right } enum Emote : char { 1 Happy 2 Depressed 3 Sad 4 Angry 5 Confused 6 Surprised 7 Hearts 8 Moon 9 Suicidal 10 Embarrassed 11 Drunk 12 Trade 13 LevelUp 14 Playful } enum QuestPage : char { 1 Progress 2 History } enum Gender : char { 0 Female 1 Male } enum Skin : char { 0 White 1 Tan 2 Yellow 3 Orc 4 Skeleton 5 Panda 6 Fish } "Shows on paperdoll and online player list. Official server/client doesn't support Guide or Guardian icons" enum PaperdollIcon : char { 1 Player 4 GM 5 HGM 6 Party 9 GM_Party 10 HGM_Party } enum AvatarSlot : char { 1 Clothes 2 Hair 3 HairColor } enum TalkReply : short { 1 NotFound } enum SitState : char { 0 Stand 1 Chair 2 Floor } enum SitAction : char { 1 Sit 2 Stand } enum TrainType : char { 1 Stat 2 Skill } enum BookIcon : short { 3 Item 5 Talk 8 Kill 10 Step } enum DialogEntryType : char { 1 Text 2 Link } enum DialogReply : char { 1 OK 2 Link } enum InitReply : byte { 1 Out_Of_Date 2 OK 3 Banned 4 Warp_File_EMF 5 File_EMF 6 File_EIF 7 File_ENF 8 File_ESF 9 Players 10 Map_Mutation 11 Friend_List_Players 12 File_ECF } enum InitBanType : byte { // The logic in the client is "permanent = ban_type >= 2", meaning 0 and 1 are both interpreted // as temporary bans. 0 Temp0 1 Temp 2 Perm } enum FileType : char { 1 Map 2 Item 3 NPC 4 Spell 5 Class } enum GuildReply : short { 1 Busy 2 Not_Approved 3 Already_Member 4 No_Candidates 5 Exists 6 Create_Begin 7 Create_Add_Confirm 8 Create_Add 9 Recruiter_Offline 10 Recruiter_Not_Here 11 Recruiter_Wrong_Guild 12 Not_Recruiter 13 Join_Request 14 Not_Present 15 Account_Low 16 Accepted 17 Not_Found 18 Updated 19 Ranks_Updated 20 Remove_Leader 21 Remove_Not_Member 22 Removed 23 Ranking_Leader 24 Ranking_Not_Member } enum GuildInfoType : short { 1 Description 2 Ranks 3 Bank } enum MapEffect : char { 1 Quake } enum InnUnsubscribeReply : char { 0 Not_Citizen 1 Unsubscribed } enum SkillMasterReply : char { 1 Remove_Items 2 Wrong_Class } enum PartyRequestType : char { 0 Join 1 Invite } enum CharacterReply : short { 1 Exists 2 Full 3 Full3 4 Not_Approved 5 OK 6 Deleted _ SessionId } enum AccountReply : short { 1 Exists 2 Not_Approved 3 Created 5 Change_Failed 6 Changed 7 RequestDenied 8 Reserved8 9 Reserved9 _ SessionId } enum LoginReply : short { 1 Wrong_User 2 Wrong_UserPass 3 OK 4 Banned 5 LoggedIn 6 Busy } enum WarpAnimation : char { 0 None 1 Scroll 2 Admin } enum WarpType : char { 1 Local 2 MapSwitch } enum ItemType : char { 0 Static 2 Money 3 Heal 4 Teleport 5 Spell 6 EXPReward 7 StatReward 8 SkillReward 9 Key 10 Weapon 11 Shield 12 Armor 13 Hat 14 Boots 15 Gloves 16 Accessory 17 Belt 18 Necklace 19 Ring 20 Armlet 21 Bracer 22 Beer 23 EffectPotion 24 HairDye 25 CureCurse } enum PlayerKilledState : char { 1 Alive 2 Dead } // --- struct Paperdoll_BAHWS { short boots short armor short hat short weapon short shield } struct Paperdoll_BAHSW { short boots short armor short hat short shield short weapon } struct Paperdoll_B000A0HSW { short boots short = 0 short = 0 short = 0 short armor short = 0 short hat short shield short weapon } struct Paperdoll_Full { short boots short accessory short gloves short belt short armor short necklace short hat short shield short weapon short ring[2] short armlet[2] short bracer[2] } struct Coords { char x char y } struct BigCoords { short x short y } struct Weight { char current char max } struct Item { short id int amount } struct ReverseItem { int amount short id } "Used for shops, lockers, and various item transfers" struct ShortItem { short id three amount } "Used for craft ingredients" struct VeryShortItem { short id char amount } struct Spell { short id short level } struct CharacterMapInfo { string name short id short map_id struct BigCoords coords Direction direction char class_id raw_string(3) guild_tag char level Gender gender char hairstyle char haircolor Skin skin_id short max_hp short hp short max_tp short tp struct Paperdoll_B000A0HSW paperdoll SitState sit_state char invisible optional WarpAnimation animation break } struct NPCMapInfo { char index short id struct Coords coords Direction direction } struct ItemMapInfo { short uid short id struct Coords coords three amount } struct AvatarChange { short player_id AvatarSlot slot char sound union(slot) { Clothes: clothes { struct Paperdoll_BAHWS paperdoll } Hair: hair { char style char color } HairColor: hair_color { char color } } } struct NearbyInfo { char num_characters break struct CharacterMapInfo characters[num_characters] struct NPCMapInfo npcs[] break struct ItemMapInfo items[] } // --- Init struct OnlinePlayers { string name string title char = 0 PaperdollIcon icon char class_id raw_string(3) guild_tag break } "Initialization request" client_packet(Init, Init) { three challenge char version[3] char protocol prefix_string hdid } "Requests a list of online players. Was used by WatchDog.exe to generate website pages" client_packet(Message, List) { break } "Initialization reply" server_packet(Init, Init) { InitReply reply_code union(reply_code) { Out_Of_Date: out_of_date { char version[3] } OK: ok { byte seq_bytes[2] byte encode_multiple byte decode_multiple short player_id three response } Banned: banned { InitBanType ban_type union(ban_type) { Temp0: ban_temp0 { byte mins_remaining } Temp: ban_temp { byte mins_remaining } } } Warp_File_EMF: warp_file_emf { byte content[] } File_EMF: file_emf { byte content[] } File_EIF: file_eif { char file_id byte content[] } File_ENF: file_enf { char file_id byte content[] } File_ESF: file_esf { char file_id byte content[] } // TODO: represent MESSAGE_LIST response here. It uses the same reply code // 255, 255, 12, 2, 254, 255, 97, 112, 111, 108, 108, 111, 255, 255, 3, 55, 8, 254, 254, 2, 5, 255 // [short:num_characters] {string:name,string:title,char:level,int:experience,Gender:gender,AdminLevel:admin,break} File_ECF: file_ecf { char file_id byte content[] } Map_Mutation: map_mutation { byte content[] } Players: players { short num_online break struct OnlinePlayers list[] } Friend_List_Players: friends { // Should probably be number of friends but what do I know short num_online break // EOSERV is generous enough to send each player name twice string list[] } } } // --- Connection "Confirm initialization data" client_packet(Connection, Accept) { short decode_multiple short encode_multiple short player_id } "Ping reply" client_packet(Connection, Ping) { raw_string k // "k" } "Ping request" server_packet(Connection, Player) { short seq1 char seq2 } // --- Account "Request creating an account" client_packet(Account, Request) { raw_string username } "Confirm creating an account" client_packet(Account, Create) { short session_id break string username string password string fullname string location string email string computer string hdid } "Change password" client_packet(Account, Agree) { string username string oldpassword string newpassword } "Reply to client Account-family packets" server_packet(Account, Reply) { AccountReply reply_code union(reply_code) { Exists: exists { raw_string no } Not_Approved: not_approved { raw_string no } Change_Failed: change_failed { raw_string no } Changed: changed { raw_string ok } Created: created { raw_string go } SessionId: session_id { char sequence_start raw_string ok } } } // --- Character "Character selection screen character info" struct Character_Info { string name int id char level Gender gender char hairstyle char haircolor Skin skin AdminLevel admin struct Paperdoll_BAHSW paperdoll break } "Character selection screen character info" struct Character_List { char num_characters char = 1 break struct Character_Info characters[num_characters] } "Request to create a character" client_packet(Character, Request) { string new // NEW } "Confirm creating a character" client_packet(Character, Create) { short session_id Gender:short gender short hairstyle short haircolor Skin:short skin break string name } "Confirm deleting character from an account" client_packet(Character, Remove) { short session_id int character_id } "Request to delete a character from an account" client_packet(Character, Take) { int character_id } "Reply to client Character-family packets" server_packet(Character, Reply) { CharacterReply reply_code union(reply_code) { Full: full { raw_string no } Full3: full3 { raw_string no } Not_Approved: not_approved { raw_string no } Exists: exists { raw_string no } SessionId: session_id { raw_string ok } OK: ok { struct Character_List character_list } Deleted: deleted { struct Character_List character_list } } } "Reply to client Character_Take" server_packet(Character, Player) { short session_id int character_id } // --- Login "Login request" client_packet(Login, Request) { string username string password } "Login reply" server_packet(Login, Reply) { LoginReply reply_code union(reply_code) { OK: ok { struct Character_List character_list } Wrong_UserPass: wrong_user_pass { raw_string no } Wrong_User: wrong_user { raw_string no } Banned: banned { raw_string no } LoggedIn: logged_in { raw_string no } Busy: busy { raw_string no } } } // --- Welcome struct ServerSettings { short jail_map short rescue_map char rescue_x char rescue_y short spy_and_light_guide_flood_rate short guardian_flood_rate short game_master_flood_rate short high_game_master_flood_rate } enum WelcomeReply : short { 1 SelectCharacter 2 EnterGame 3 ServerBusy 4 LoggedIn } "Selected a character" client_packet(Welcome, Request) { int character_id } "Entering game" client_packet(Welcome, Msg) { three session_id int character_id } "Requesting a file" client_packet(Welcome, Agree) { FileType file_type short session_id union (file_type) { Map: map { short character_id } Item: item { char file_id } NPC: npc { char file_id } Spell: spell { char file_id } Class: class { char file_id } } } "Reply to selecting a character / entering game" server_packet(Welcome, Reply) { WelcomeReply reply_code union(reply_code) { SelectCharacter: select_character { short session_id int character_id short map_id short map_rid[2] three map_filesize short eif_rid[2] short eif_length short enf_rid[2] short enf_length short esf_rid[2] short esf_length short ecf_rid[2] short ecf_length string name string title string guild_name string guild_rank_name char class_id raw_string(3) guild_tag AdminLevel admin char level int experience int usage struct CharacterStats2 stats struct Paperdoll_Full paperdoll char guild_rank struct ServerSettings settings char login_message break } EnterGame: enter_game { break string news[9] struct Weight weight struct Item items[] break struct Spell spells[] break struct NearbyInfo nearby } } } // --- AdminInteract enum AdminMessageType : char { 1 Message 2 Report } struct CharacterStats4 { short hp short max_hp short tp short max_tp struct CharacterBaseStats base struct CharacterSecondaryStats secondary } "Talk to admin" client_packet(AdminInteract, Tell) { raw_string message } "Report character" client_packet(AdminInteract, Report) { string reportee raw_string message } "Incoming admin report" server_packet(AdminInteract, Reply) { AdminMessageType message_type break union(message_type) { Message: message { string player_name string message } Report: report { string player_name string message string reportee_name } } } "Nearby player disappearing (admin hide)" server_packet(AdminInteract, Remove) { short player_id } "Nearby player appearing (admin un-hide)" server_packet(AdminInteract, Agree) { short player_id } "Admin character inventory popup" server_packet(AdminInteract, List) { string name int usage break int gold_bank break struct Item inventory[] break struct ShortItem bank[] } "Admin character info popup" server_packet(AdminInteract, Tell) { string name int usage break break int exp char level short map_id struct BigCoords map_coords struct CharacterStats4 stats short light short dark short fire short water short earth short wind struct Weight weight } // --- Global "Enable whispers" client_packet(Global, Remove) { char = 'n' } "Disable whispers" client_packet(Global, Player) { char = 'y' } "Opened global tab" client_packet(Global, Open) { char = 'y' } "Closed global tab" client_packet(Global, Close) { char = 'n' } // --- Talk struct GlobalBackfillMessage { string player_name string message } "Guild chat message" client_packet(Talk, Request) { raw_string message } "Party chat message" client_packet(Talk, Open) { raw_string message } "Global chat message" client_packet(Talk, Msg) { raw_string message } "Private chat message" client_packet(Talk, Tell) { string name raw_string message } "Public chat message" client_packet(Talk, Report) { raw_string message } "Admin chat message" client_packet(Talk, Admin) { raw_string message } "Admin announcement" client_packet(Talk, Announce) { raw_string message } "Guild chat message" server_packet(Talk, Request) { string player_name string message } "Party chat message" server_packet(Talk, Open) { short player_id string message } "Global chat message" server_packet(Talk, Msg) { string player_name string message } "Private chat message" server_packet(Talk, Tell) { string player_name string message } "Public chat message" server_packet(Talk, Player) { short player_id raw_string message } "Admin chat message" server_packet(Talk, Admin) { string player_name string message } "Admin announcement" server_packet(Talk, Announce) { string player_name string message } "Server message" server_packet(Talk, Server) { raw_string message } "Reply to trying to send a private message" server_packet(Talk, Reply) { TalkReply reply_code raw_string name } "Global chat backfill" server_packet(Talk, List) { struct GlobalBackfillMessage messages[] } "Status bar message" server_packet(Message, Open) { raw_string message } "Large message box" server_packet(Message, Accept) { string messages[4] break } "Temporary mute applied" server_packet(Talk, Spec) { string admin_name } // --- Attack "Attacking" client_packet(Attack, Use) { Direction direction three timestamp } "Nearby player attacking" server_packet(Attack, Player) { short player_id Direction direction } "Nearby player hit by another player" server_packet(Avatar, Reply) { short player_id short victim_id three damage Direction direction char hp_percentage char died } // --- Chair "Sitting on a chair" client_packet(Chair, Request) { SitAction sit_action union(sit_action) { Sit: sit { struct Coords coords } } } "Nearby player sitting on a chair" server_packet(Chair, Player) { short player_id struct Coords coords Direction direction char = 0 } "Your character sitting on a chair" server_packet(Chair, Reply) { short player_id struct Coords coords Direction direction char = 0 } "Your character standing up from a chair" server_packet(Chair, Close) { short player_id struct Coords coords } // --- Sit "Floor sit/stand request" client_packet(Sit, Request) { SitAction sit_action } "Nearby player sitting down" server_packet(Sit, Player) { short player_id struct Coords coords Direction direction char = 0 } "Your character standing up" server_packet(Sit, Close) { short player_id struct Coords coords } "Nearby player standing up" server_packet(Sit, Remove) { short player_id struct Coords coords } "Your character sitting down" server_packet(Sit, Reply) { short player_id struct Coords coords Direction direction char = 0 } // --- Emote "Doing an emote" client_packet(Emote, Report) { Emote emote } "Nearby player doing an emote" server_packet(Emote, Player) { short player_id Emote emote } "Nearby player doing an effect" server_packet(Effect, Player) { short player_id three effect_id } // --- Face "Facing a direction" client_packet(Face, Player) { Direction direction } "Nearby player facing a direction" server_packet(Face, Player) { short player_id Direction direction } // --- Walk struct WalkCommon { Direction direction three timestamp struct Coords coords } "Walking with #nowall" client_packet(Walk, Admin) { struct WalkCommon walk } "Walking through a player" client_packet(Walk, Spec) { struct WalkCommon walk } "Walking" client_packet(Walk, Player) { struct WalkCommon walk } "Nearby player has disappeared from view" server_packet(Avatar, Remove) { short player_id optional WarpAnimation animation } "Player has appeared in nearby view" server_packet(Players, Agree) { struct NearbyInfo nearby } "Nearby player has walked" server_packet(Walk, Player) { short player_id Direction direction struct Coords coords } "Players, NPCs, and Items appearing in nearby view" server_packet(Walk, Reply) { short player_ids[] break char npc_indexes[] break struct ItemMapInfo items[] } "Your character has been frozen" server_packet(Walk, Close) { char = 'S' } "Your character has been unfrozen" server_packet(Walk, Open) { char = 'S' } // --- Bank "Talked to a banker NPC" client_packet(Bank, Open) { short npc_index } "Depositing gold" client_packet(Bank, Add) { int amount } "Withdrawing gold" client_packet(Bank, Take) { int amount } "Open banker NPC interface" server_packet(Bank, Open) { int gold_bank three session_token char locker_upgrades } "Update gold counts after deposit/withdraw" server_packet(Bank, Reply) { int gold_inventory int gold_bank } // --- Locker "Placing an item in a bank locker" client_packet(Locker, Add) { struct Coords locker_coords struct ShortItem deposit_item } "Taking an item from a bank locker" client_packet(Locker, Take) { struct Coords locker_coords short take_item_id } "Opening a bank locker" client_packet(Locker, Open) { struct Coords locker_coords } "Buying a locker space upgrade from a banker NPC" client_packet(Locker, Buy) { char = 1 } "Response to adding an item to a bank locker" server_packet(Locker, Reply) { struct Item deposited_item struct Weight weight struct ShortItem locker_items[] } "Response to taking an item from a bank locker" server_packet(Locker, Get) { struct ShortItem taken_item struct Weight weight struct ShortItem locker_items[] } "Opening a bank locker" server_packet(Locker, Open) { struct Coords locker_coords struct ShortItem locker_items[] } "Response to buying a locker space upgrade from a banker NPC" server_packet(Locker, Buy) { int gold_amount char locker_upgrades } "Reply to trying to add an item to a full locker" server_packet(Locker, Spec) { char locker_max_items } // --- Citizen "Sleeping at an inn" client_packet(Citizen, Request) { short session_id short vendor_id } "Confirm sleeping at an inn" client_packet(Citizen, Accept) { short session_id short vendor_id } "Subscribing to a town" client_packet(Citizen, Reply) { short session_id break short vendor_id break string answer1 string answer2 raw_string answer3 } "Giving up citizenship of a town" client_packet(Citizen, Remove) { short session_id } "Talking to a citizenship NPC" client_packet(Citizen, Open) { short npc_index } "Response to subscribing to a town" server_packet(Citizen, Reply) { char questions_wrong } "Response to giving up citizenship of a town" server_packet(Citizen, Remove) { InnUnsubscribeReply reply_code } "Response from talking to a citizenship NPC" server_packet(Citizen, Open) { three vendor_id char current_home_id short session_id break string question1 string question2 raw_string question3 } "Sleeping at an inn" server_packet(Citizen, Accept) { int gold_amount } "Reply to requesting sleeping at an inn" server_packet(Citizen, Request) { int cost } // --- Shop struct ShopTradeItem { short item_id three buy_price three sell_price char max_buy_amount } struct ShopCraftItem { short item_id struct VeryShortItem ingredients[4] } "Crafting an item from a shop" client_packet(Shop, Create) { short craft_item_id int session_id } "Purchasing an item from a shop" client_packet(Shop, Buy) { struct Item buy_item int session_id } "Selling an item to a shop" client_packet(Shop, Sell) { struct Item sell_item int session_id } "Talking to a shop NPC" client_packet(Shop, Open) { short npc_index } "Response to crafting an item from a shop" server_packet(Shop, Create) { short craft_item_id struct Weight weight struct Item ingredients[4] } "Response to purchasing an item from a shop" server_packet(Shop, Buy) { int gold_amount struct Item bought_item struct Weight weight } "Response to selling an item to a shop" server_packet(Shop, Sell) { struct ReverseItem sold_item int gold_amount struct Weight weight } "Response from talking to a shop NPC" server_packet(Shop, Open) { short session_id string shop_name struct ShopTradeItem trade_items[] break struct ShopCraftItem craft_items[] break } // --- StatSkill struct CharacterBaseStats { short str short intl short wis short agi short con short cha } struct CharacterBaseStats2 { short str short wis short intl short agi short con short cha } struct CharacterSecondaryStats { short mindam short maxdam short accuracy short evade short armor } struct CharacterStats1 { short stat_points short skill_points short hp short max_hp short tp short max_tp short max_sp struct CharacterBaseStats base struct CharacterSecondaryStats secondary } struct CharacterStats2 { short hp short max_hp short tp short max_tp short max_sp short stat_points short skill_points short karma struct CharacterSecondaryStats secondary struct CharacterBaseStats2 base } struct CharacterStats3 { struct CharacterBaseStats base short max_hp short max_tp short max_sp short max_weight struct CharacterSecondaryStats secondary } struct SkillLearn { short id char level_req char class_req int cost short skill_req[4] struct CharacterBaseStats stat_req } "Talking to a skill master NPC" client_packet(StatSkill, Open) { short npc_index } "Learning a skill from a skill master" client_packet(StatSkill, Take) { int session_id short spell_id } "Forgetting a skill at a skill master" client_packet(StatSkill, Remove) { int session_id short spell_id } enum StatId : short { 1 Str 2 Int 3 Wis 4 Agi 5 Con 6 Cha } enum MarriageRequestType : char { 1 MarriageApproval 2 Divorce } enum MarriageReply : short { 1 AlreadyMarried 2 NotMarried 3 Success 4 NotEnoughGold 5 WrongName 6 ServiceBusy 7 DivorceNotification } enum PriestReply : short { 1 NotDressed 2 LowLevel 3 PartnerNotPresent 4 PartnerNotDressed 5 Busy 6 DoYou 7 PartnerAlreadyMarried 8 NoPermission } "Spending a stat point on a stat or skill" client_packet(StatSkill, Add) { TrainType action_type union(action_type) { Stat: stat { StatId stat_id } Skill: skill { short spell_id } } } "Resetting stats at a skill master" client_packet(StatSkill, Junk) { int session_id } "Response from talking to a skill master NPC" server_packet(StatSkill, Open) { short session_id string shop_name struct SkillLearn skills[] } "Response from unsuccessful attempt to learn a skill from a skill master" server_packet(StatSkill, Reply) { SkillMasterReply reply_code union(reply_code) { Remove_Items: remove_items { // TODO: EOSERV doesn't implement - is this really empty? } Wrong_Class: wrong_class { short class_id } } } "Response from learning a skill from a skill master" server_packet(StatSkill, Take) { short spell_id int gold_amount } "Response to forgetting a skill at a skill master" server_packet(StatSkill, Remove) { short spell_id } "Response to spending stat points" server_packet(StatSkill, Player) { short stat_points struct CharacterStats3 stats } "Response to spending skill points" server_packet(StatSkill, Accept) { short skill_points struct Spell spell } "Response to resetting character" server_packet(StatSkill, Junk) { struct CharacterStats1 stats } // --- Item struct ItemCharacterStats { short max_hp short max_tp struct CharacterBaseStats base struct CharacterSecondaryStats secondary } "Using an item" client_packet(Item, Use) { short use_item_id } "Dropping items on the ground" client_packet(Item, Drop) { struct ShortItem drop_item struct Coords coords } "Junking items" client_packet(Item, Junk) { struct Item junk_item } "Taking items from the ground" client_packet(Item, Get) { short take_item_index } "Reply to using an item" server_packet(Item, Reply) { ItemType used_item_type struct Item used_item struct Weight weight union(used_item_type) { Heal: heal { int hp_gain short hp short tp } HairDye: hair_dye { char hair_color } EffectPotion: effect_potion { short effect_id } CureCurse: cure_curse { struct ItemCharacterStats stats } EXPReward: exp_reward { int experience "A value greater than 0 is 'new level' and indicates the player leveled up." char level_up short stat_points short skill_points short max_hp short max_tp short max_sp } } } "Reply to dropping items on the ground" server_packet(Item, Drop) { short item_id three amount_dropped int amount_remaining short item_index struct Coords coords struct Weight weight } "Item appeared on the ground" server_packet(Item, Add) { short item_id short item_index three item_amount struct Coords coords } "Item disappeared from the ground" server_packet(Item, Remove) { short item_index } "Reply to junking items" server_packet(Item, Junk) { struct ShortItem junked_item int junked_item_amount struct Weight weight } "Reply to taking items from the ground" server_packet(Item, Get) { short taken_item_index struct ShortItem taken_item struct Weight weight } "Receive item (from quest)" server_packet(Item, Obtain) { struct ShortItem item char cur_weight } "Lose item (from quest)" server_packet(Item, Kick) { struct Item item char cur_weight } "Reply to using an item that you don't have" server_packet(Item, Agree) { short item_id } "Reply to trying to take a protected item from the ground" server_packet(Item, Spec) { short = 2 } // --- Barber "Talking to barber NPC" client_packet(Barber, Open) { short npc_index } "Purchasing a hair-style" client_packet(Barber, Buy) { char style char color int session_id } "Reply from talking to barber NPC" server_packet(Barber, Open) { int session_id } "Reply from purchasing a hair-style" server_packet(Barber, Agree) { int gold_amount struct AvatarChange change } // --- Board struct BoardPostListing { short post_id break string author string subject } "Removing a post from a town board" client_packet(Board, Remove) { short board_id short post_id } "Posting a new message to a town board" client_packet(Board, Create) { short board_id break string post_subject string post_body } "Reading a post on a town board" client_packet(Board, Take) { short board_id short post_id } "Opening a a town board" client_packet(Board, Open) { short board_id } "Reply to reading a post on a town board" server_packet(Board, Player) { short post_id string post_body } "Reply to opening a town board" server_packet(Board, Open) { char board_id char num_posts struct BoardPostListing posts[num_posts] } // --- Jukebox "Opening the jukebox listing" client_packet(Jukebox, Open) { struct Coords coords } "Requesting a song on a jukebox" client_packet(Jukebox, Msg) { break break short track_id } "Playing a note with the bard skill" client_packet(Jukebox, Use) { char instrument_id char note_id } "Reply to successfully requesting a song" server_packet(Jukebox, Agree) { int gold_amount } "Reply to unsuccessfully requesting a song" server_packet(Jukebox, Reply) { short = 1 } "Reply to opening the jukebox listing" server_packet(Jukebox, Open) { short map_id string jukebox_player } "Someone playing a note with the bard skill nearby" server_packet(Jukebox, Msg) { short player_id Direction direction char instrument_id char note_id } "Play jukebox music" server_packet(Jukebox, Player) { char mfx_id } "Play background music" server_packet(Jukebox, Use) { char mfx_id } // --- Warp "Accept a warp request from the server" client_packet(Warp, Accept) { short map_id short session_id } "Request to download a copy of the map" client_packet(Warp, Take) { short map_id short session_id } "Warp request from server" server_packet(Warp, Request) { WarpType warp_type short map_id union(warp_type) { MapSwitch: map_switch { short map_rid[2] three map_filesize } } short session_id } "Reply after accepting a warp" server_packet(Warp, Agree) { WarpType warp_type union(warp_type) { MapSwitch: map_switch { short map_id WarpAnimation warp_anim } } struct NearbyInfo nearby } // --- Paperdoll struct Paperdoll_Info { string name string home string partner string title string guild string guild_rank short player_id char class_id Gender gender char = 0 } "Request for a player's paperdoll" client_packet(Paperdoll, Request) { short player_id } "Unequipping an item" client_packet(Paperdoll, Remove) { short item_id char sub_loc } "Equipping an item" client_packet(Paperdoll, Add) { short item_id char sub_loc } "Reply to requesting a paperdoll" server_packet(Paperdoll, Reply) { struct Paperdoll_Info info struct Paperdoll_Full paperdoll PaperdollIcon paperdoll_icon } "Reply to unequipping an item" server_packet(Paperdoll, Remove) { struct AvatarChange change short item_id char sub_loc struct ItemCharacterStats stats } "Reply to equipping an item" server_packet(Paperdoll, Agree) { struct AvatarChange change short item_id three item_amount_remaining char sub_loc struct ItemCharacterStats stats } "Failed to equip an item due to being the incorrect class" // There is no visible effect in the client, it simply re-assigns the player's class server_packet(Paperdoll, Ping) { "The player's current class ID -- not the item's required class ID" char class_id } "Nearby player changed clothes" server_packet(Avatar, Agree) { struct AvatarChange change } // --- Book "Request for a player's book" client_packet(Book, Request) { short player_id } "Reply to requesting a book" server_packet(Book, Reply) { struct Paperdoll_Info info PaperdollIcon paperdoll_icon break string quest_name[] } // --- Message "#ping command request" client_packet(Message, Ping) { short = 2 } "#ping command reply" server_packet(Message, Pong) { short = 2 } "Server is rebooting" server_packet(Message, Close) { char = 'r' } // --- Players "#find command request" client_packet(Players, Accept) { raw_string name } "Requesting a list of online players" client_packet(Players, Request) { break } "Requesting a list of online friends" client_packet(Players, List) { break } "Nearby player has logged out" server_packet(Players, Remove) { short player_id } "#find command reply - offline" server_packet(Players, Ping) { raw_string name } "#find command reply - same map" server_packet(Players, Pong) { raw_string name } "#find command reply - different map" server_packet(Players, Net3) { raw_string name } // --- Door "Opening a door" client_packet(Door, Open) { struct Coords coords } "Door nearby opening" server_packet(Door, Open) { struct Coords coords char = 0 } "Reply to trying to open a locked door" server_packet(Door, Close) { char key } // --- Chest "Opening a chest" client_packet(Chest, Open) { struct Coords coords } "Placing an item in to a chest" client_packet(Chest, Add) { struct Coords coords struct ShortItem add_item } "Taking an item from a chest" client_packet(Chest, Take) { struct Coords coords short take_item_id } "Reply to opening a chest" server_packet(Chest, Open) { struct Coords coords struct ShortItem items[] } "Reply to placing an item in to a chest" server_packet(Chest, Reply) { struct Item added_item struct Weight weight struct ShortItem items[] } "Reply to removing an item from a chest" server_packet(Chest, Get) { struct ShortItem taken_item struct Weight weight struct ShortItem items[] } "Chest contents updating" server_packet(Chest, Agree) { struct ShortItem items[] } "Reply to trying to add an item to a full chest" server_packet(Chest, Spec) { byte = 0 } // --- Refresh "Requesting new info about nearby objects" client_packet(Refresh, Request) { break } server_packet(Refresh, Reply) { struct NearbyInfo nearby } // --- Range "Requesting info about nearby players and/or npcs" client_packet(Range, Request) { short player_ids[] break char npc_indexes[] } "Sent when unknown player has walked into view" client_packet(PlayerRange, Request) { short player_ids[] } "Sent when unknown npc has walked into view" client_packet(NPCRange, Request) { char num_npcs break char npc_indexes[] } "MapInfo for characters and/or npcs" server_packet(Range, Reply) { struct NearbyInfo nearby } // --- Party struct PartyMember { short player_id char leader char level char hp_percentage string name } struct PartyExpShare { short player_id int experience "A value greater than 0 is 'new level' and indicates the player leveled up." char level_up } enum PartyReply : char { 0 AlreadyInAnotherParty 1 AlreadyInYourParty 2 PartyIsFull } "Send party invite / join request" client_packet(Party, Request) { PartyRequestType request_type short player_id } "Accept party invite / join request" client_packet(Party, Accept) { PartyRequestType request_type short player_id } "Remove player from a party" client_packet(Party, Remove) { short player_id } "Request updated party info" client_packet(Party, Take) { char num_members } "Received party invite / join request" server_packet(Party, Request) { PartyRequestType request_type short player_id raw_string player_name } "Member list received when party is first joined" server_packet(Party, Create) { struct PartyMember members[] } "New player joined the party" server_packet(Party, Add) { struct PartyMember member } "Player left the party" server_packet(Party, Remove) { short player_id } "Left / disbanded a party" server_packet(Party, Close) { break } "Party member list update" server_packet(Party, List) { struct PartyMember members[] } "Update party member's HP" server_packet(Party, Agree) { short player_id char hp_percentage } "Updated experience and level-ups from party experience" server_packet(Party, Target_Group) { struct PartyExpShare gains[] } "Failed party invite / join request" server_packet(Party, Reply) { PartyReply reply_code union (reply_code) { AlreadyInAnotherParty: already_in_another_party { string player_name } AlreadyInYourParty: already_in_your_party { string player_name } } } // --- Guild struct GuildStaff { char rank break string name } struct GuildMember { char rank break string name string rank_name } "Requested to create a guild" client_packet(Guild, Request) { int session_id break string guild_tag string guild_name } "Accept pending guild creation invite" client_packet(Guild, Accept) { int = 20202 short player_id } "Leave guild" client_packet(Guild, Remove) { int session_id } "Update the guild description or rank list" client_packet(Guild, Agree) { int session_id GuildInfoType info_type union(info_type) { Description: description { raw_string description } Ranks: ranks { string ranks[9] } } } "Final confirm creating a guild" client_packet(Guild, Create) { int session_id break string guild_tag string guild_name string description } "Request to join a guild" client_packet(Guild, Player) { int sesssion_id break string guild_tag string recruiter_name } "Request guild bank / ranks / description" client_packet(Guild, Take) { int session_id GuildInfoType info_type } "Accepted a join request" client_packet(Guild, Use) { short player_id } "Deposit gold in to the guild bank" client_packet(Guild, Buy) { int session_id int gold_amount } "Talking to a guild master NPC" client_packet(Guild, Open) { short npc_index } "Requested member list of a guild" client_packet(Guild, Tell) { int session_id raw_string guild_identity } "Requested general information of a guild" client_packet(Guild, Report) { int session_id raw_string guild_identity } "Disband guild" client_packet(Guild, Junk) { int session_id } "Kick member from guild" client_packet(Guild, Kick) { int session_id raw_string member_name } "Update a member's rank" client_packet(Guild, Rank) { int sesson_id char rank raw_string member_name } "Generic guild reply messages" server_packet(Guild, Reply) { GuildReply reply_code union(reply_code) { Create_Add: create_add { raw_string name } Create_Add_Confirm: create_add_confirm { raw_string name } Join_Request: join_request { short player_id raw_string name } } } "Guild create request" server_packet(Guild, Request) { short player_id raw_string guild_identity } "Guild created" server_packet(Guild, Create) { short leader_id break string guild_tag string guild_name string rank_name int gold_amount } "Get guild description reply" server_packet(Guild, Take) { string description } "Get guild rank list reply" server_packet(Guild, Rank) { string ranks[9] } "Get guild bank reply" server_packet(Guild, Sell) { int gold_amount } "Deposit guild bank reply" server_packet(Guild, Buy) { int gold_amount } "Talk to guild master NPC reply" server_packet(Guild, Open) { three session_id } "Get guild member list reply" server_packet(Guild, Tell) { short num_members break struct GuildMember members[num_members] } "Get guild info reply" server_packet(Guild, Report) { string name string tag string create_date string description string wealth string ranks[9] short num_staff break struct GuildStaff staff[num_staff] } "Joined guild info" server_packet(Guild, Agree) { short recruiter_id break string guild_tag string guild_name string rank_name } "Update guild rank" server_packet(Guild, Accept) { char rank } "Left the guild" // The official server never sends this packet, so the dummy byte is unknown. // This packet is only known as a result of decompiling the official client. server_packet(Guild, Kick) { break } // --- Spell enum SpellTargetType : char { 1 Player 2 NPC } "Begin spell chanting" client_packet(Spell, Request) { short spell_id three timestamp } "Self-targeted spell cast" client_packet(Spell, Target_Self) { Direction direction short spell_id three timestamp } "Targeted spell cast" client_packet(Spell, Target_Other) { SpellTargetType target_type three previous_timestamp short spell_id short victim_id three timestamp } "Group spell cast" client_packet(Spell, Target_Group) { short spell_id three timestamp } "Raise arm to cast a spell (vestigial)" client_packet(Spell, Use) { Direction direction } "Nearby player chanting a spell" server_packet(Spell, Request) { short player_id short spell_id } "Nearby player self-casted a spell" server_packet(Spell, Target_Self) { short player_id short spell_id int spell_heal_hp char hp_percentage // TODO: Represent optionally present data short hp short tp } "Nearby player hit by a damage spell from a player" server_packet(Avatar, Admin) { short caster_id short victim_id char caster_direction three damage char hp_percentage char victim_died short spell_id } "Nearby player raising their arm to cast a spell (vestigial)" server_packet(Spell, Player) { short player_id Direction direction } struct GroupHealTargetPlayer { short player_id char hp_percentage short hp } "Nearby player(s) hit by a group heal spell from a player" server_packet(Spell, Target_Group) { short spell_id short caster_id short caster_tp short spell_heal_hp struct GroupHealTargetPlayer players[] } "Nearby player hit by a heal spell from a player" server_packet(Spell, Target_Other) { short victim_id short caster_id Direction caster_direction short spell_id int spell_heal_hp char hp_percentage short hp } // --- Trade struct TradeItemData { short player1_id struct Item player1_items[] break short player2_id struct Item player2_items[] break } "Requesting a trade with another player" client_packet(Trade, Request) { char unk1 short player_id } "Accepting a trade request" client_packet(Trade, Accept) { char unk1 short player_id } "Remove an item from the trade screen" client_packet(Trade, Remove) { short item_id } "Mark trade as agreed" client_packet(Trade, Agree) { char agree_state } "Add an item to the trade screen" client_packet(Trade, Add) { struct Item add_item } "Cancel the trade" client_packet(Trade, Close) { char unk1 } "Trade request from another player" server_packet(Trade, Request) { char unk1 short player_id raw_string player_name } "Trade window opens" server_packet(Trade, Open) { short player_id string player_name short your_player_id string your_name } "Trade updated (items changed)" server_packet(Trade, Reply) { struct TradeItemData trade_data } "Trade updated (items changed while trade was acceptedd)" server_packet(Trade, Admin) { struct TradeItemData trade_data } "Trade items updated" server_packet(Trade, Use) { struct TradeItemData trade_data } "Own agree state updated" server_packet(Trade, Spec) { char agree_state } "Partner agree state updated" server_packet(Trade, Agree) { short player_id char agree_state } "Partner closed trade window" server_packet(Trade, Close) { short player_id } // --- NPC activity struct LevelUpStats { char level short stat_points short skill_points short max_hp short max_tp short max_sp } // NPC/Cast_Reply/Accept could share data probably "Nearby NPC hit by a player" server_packet(NPC, Reply) { short player_id char player_direction short npc_index three damage short hp_percentage // This is probably something char = 1 } "Nearby NPC hit by a spell from a player" server_packet(Cast, Reply) { short spell_id short player_id char player_direction short npc_index three damage short hp_percentage short caster_tp } "Nearby NPC killed by player" server_packet(NPC, Spec) { short killer_id char killer_direction short npc_index short drop_index short drop_id struct Coords drop_coords int drop_amount three damage int experience } "Reply to request for information about nearby NPCs" server_packet(NPC, Agree) { char num_npcs struct NPCMapInfo npcs[num_npcs] } "Nearby NPC killed by player and you levelled up" server_packet(NPC, Accept) { short killer_id char killer_direction short npc_index short drop_index short drop_id struct Coords drop_coords int drop_amount three damage int experience struct LevelUpStats level_up } "Nearby NPC killed by player spell" server_packet(Cast, Spec) { short spell_id short killer_id char killer_direction short npc_index short drop_index short drop_id struct Coords drop_coords int drop_amount three damage short caster_tp int experience } "Nearby NPC killed by player spell and you levelled up" server_packet(Cast, Accept) { short spell_id short killer_id char killer_direction short npc_index short drop_index short drop_id struct Coords drop_coords int drop_amount three damage short caster_tp int experience struct LevelUpStats level_up } "Killing all boss children" server_packet(NPC, Junk) { short npc_id } "NPC chat message" server_packet(NPC, Dialog) { short npc_index string message } "NPC chat messages" server_packet(Quest, Report) { short npc_id string messages[] } struct NPCUpdatePos { char npc_index struct Coords coords Direction direction } struct NPCUpdateAttack { char npc_index PlayerKilledState killed_state Direction direction short player_id three damage char hp_percentage } struct NPCUpdateChat { char npc_index char message_length raw_string(message_length) message } "Main NPC update message" server_packet(NPC, Player) { struct NPCUpdatePos pos[] break struct NPCUpdateAttack attack[] break struct NPCUpdateChat chat[] break } // --- Quest struct QuestProgressEntry { string name string description short icon short progress short target break } struct DialogQuestEntry { short quest_id string quest_name } struct DialogEntry { DialogEntryType entry_type // Allowing a union here would require a lot of extra implementation work // link_id will just go unused when entry_type != Link short link_id string line } "Talking to a quest NPC" client_packet(Quest, Use) { short npc_index // Quest id is 0 unless manually selected on the dialog short quest_id } "Response to a quest NPC dialog" client_packet(Quest, Accept) { short session_id short dialog_id short quest_id short npc_index DialogReply reply_type union(reply_type) { Link: link { char action } } } "Quest history / progress request" client_packet(Quest, List) { QuestPage page } "Quest selection dialog" server_packet(Quest, Dialog) { char quest_count short vendor_id short quest_id short session_id short dialog_id break struct DialogQuestEntry quest_entries[quest_count] struct DialogEntry entries[] } "Quest history / progress reply" server_packet(Quest, List) { QuestPage page // EOSERV sends total number of quests which seems wrong short num_quests union(page) { Progress: progress { struct QuestProgressEntry quests[] } History: history { string quests[] } } } // This is probably wrong "Nearby player levelled up from quest" server_packet(Item, Accept) { short player_id } // --- Arena "Arena is blocked message" server_packet(Arena, Drop) { char = 'N' } "Arena start message" server_packet(Arena, Use) { char num_players } "Arena kill message" server_packet(Arena, Spec) { short player_id break Direction direction break int num_kills break string killer_name string victim_name } "Arena win message" server_packet(Arena, Accept) { string winner_name int num_kills break string killer_name string victim_name } // --- Marriage "Talking to a law NPC" client_packet(Marriage, Open) { short npc_index } "Requesting marriage approval" client_packet(Marriage, Request) { MarriageRequestType request_type int session_id break raw_string name } "Response from talking to a law NPC" server_packet(Marriage, Open) { three session_id } "Reply to client Marriage-family packets" server_packet(Marriage, Reply) { MarriageReply reply_code union(reply_code) { Success: success { int gold_amount } } } // --- Priest "Accepting a marriage request" client_packet(Priest, Accept) { short session_id } "Talking to a priest NPC" client_packet(Priest, Open) { int npc_index } "Requesting marriage at a priest" client_packet(Priest, Request) { int session_id break string name } "Saying 'I do' at a wedding" client_packet(Priest, Use) { int session_id } "Response from talking to a priest NPC" server_packet(Priest, Open) { int session_id } "Reply to client Priest-family packets" server_packet(Priest, Reply) { PriestReply reply_code } "Wedding request" server_packet(Priest, Request) { short session_id string partner_name } // --- Misc. enum MapDamageType : char { 1 TPDrain 2 Spikes } struct MapDrainDamageOther { short player_id char hp_percentage short damage } "HP/TP update" server_packet(Recover, Player) { short hp short tp short sp } "Stats update" server_packet(Recover, List) { short class_id struct CharacterStats3 stats } "Karma/experience update" server_packet(Recover, Reply) { int experience short karma "A value greater than 0 is 'new level' and indicates the player leveled up." char level_up // Only if level_up != 0 short stat_points short skill_points } "Updated stats when levelling up from party experience" server_packet(Recover, TargetGroup) { short stat_points short skill_points short max_hp short max_tp short max_sp } "Nearby player gained HP" server_packet(Recover, Agree) { short player_id int heal_hp char hp_percentage } "Map effect" server_packet(Effect, Use) { MapEffect effect char param } "Map spike timer" server_packet(Effect, Report) { char = 'S' } "Map spell effect" server_packet(Effect, Agree) { struct Coords coords short effect_id } "Taking spike or tp drain damage" server_packet(Effect, Spec) { MapDamageType map_damage_type union(map_damage_type) { TPDrain: tp_drain { short tp_damage short tp short max_tp } Spikes: spikes { short damage short hp short max_hp } } } "Map drain damage" server_packet(Effect, Target_Other) { short damage short hp short max_hp struct MapDrainDamageOther others[] } "Nearby character taking spike damage" server_packet(Effect, Admin) { short player_id char hp_percentage char died three damage } "Sound effect" server_packet(Music, Player) { char sound_id }