defmodule Odinsea.Net.Opcodes do @moduledoc """ Packet opcodes for MapleStory GMS v342. Ported from Java ClientPacket and LoopbackPacket. """ # Define the macro for creating opcodes defmacro defopcode(name, value) do quote do @doc """ Opcode for `#{unquote(name)}`. """ def unquote(name)(), do: unquote(value) end end # ================================================================================================== # Client → Server (Recv Opcodes) # ================================================================================================== # Login/Account def cp_client_hello(), do: 0x01 def cp_check_password(), do: 0x02 def cp_world_info_request(), do: 0x04 def cp_select_world(), do: 0x05 def cp_check_user_limit(), do: 0x06 def cp_check_duplicated_id(), do: 0x0E def cp_create_new_character(), do: 0x12 def cp_create_ultimate(), do: 0x14 def cp_delete_character(), do: 0x15 def cp_select_character(), do: 0x19 def cp_check_spw_request(), do: 0x1A def cp_rsa_key(), do: 0x20 # Connection/Security def cp_alive_ack(), do: 0x16 def cp_exception_log(), do: 0x17 def cp_security_packet(), do: 0x18 def cp_client_dump_log(), do: 0x1D def cp_create_security_handle(), do: 0x1E def cp_hardware_info(), do: 0x21 def cp_set_code_page(), do: 0x22 def cp_window_focus(), do: 0x23 def cp_inject_packet(), do: 0x24 # Migration/Channel def cp_migrate_in(), do: 0x0D def cp_change_channel(), do: 0x25 def cp_enter_cash_shop(), do: 0x26 def cp_enter_mts(), do: 0x27 # PVP def cp_enter_pvp(), do: 0x28 def cp_enter_pvp_party(), do: 0x29 def cp_leave_pvp(), do: 0x2A def cp_pvp_attack(), do: 0x2B def cp_pvp_respawn(), do: 0x2C # Player def cp_move_player(), do: 0x2D def cp_cancel_chair(), do: 0x2F def cp_use_chair(), do: 0x30 def cp_close_range_attack(), do: 0x32 def cp_ranged_attack(), do: 0x33 def cp_magic_attack(), do: 0x34 def cp_passive_energy(), do: 0x35 def cp_take_damage(), do: 0x37 def cp_general_chat(), do: 0x39 def cp_close_chalkboard(), do: 0x3A def cp_face_expression(), do: 0x3B def cp_face_android(), do: 0x3C def cp_use_item_effect(), do: 0x3D def cp_wheel_of_fortune(), do: 0x3E def cp_char_info_request(), do: 0x78 def cp_change_keymap(), do: 0x87 def cp_skill_macro(), do: 0x89 def cp_change_quickslot(), do: 0x8A # Movement def cp_change_map(), do: 0x31 def cp_change_map_special(), do: 0x38 def cp_use_inner_portal(), do: 0x3A def cp_trock_add_map(), do: 0x3B def cp_use_tele_rock(), do: 0x6A # Combat def cp_distribute_ap(), do: 0x68 def cp_auto_assign_ap(), do: 0x69 def cp_distribute_sp(), do: 0x6C def cp_special_move(), do: 0x6D def cp_cancel_buff(), do: 0x6E def cp_skill_effect(), do: 0x6F def cp_heal_over_time(), do: 0x6A def cp_cancel_debuff(), do: 0x70 def cp_give_fame(), do: 0x74 # Items/Inventory def cp_item_sort(), do: 0x4F def cp_item_gather(), do: 0x50 def cp_item_move(), do: 0x51 def cp_move_bag(), do: 0x52 def cp_switch_bag(), do: 0x53 def cp_use_item(), do: 0x55 def cp_cancel_item_effect(), do: 0x56 def cp_use_summon_bag(), do: 0x58 def cp_pet_food(), do: 0x59 def cp_use_mount_food(), do: 0x5A def cp_use_scripted_npc_item(), do: 0x5B def cp_use_recipe(), do: 0x5C def cp_use_cash_item(), do: 0x5D def cp_use_catch_item(), do: 0x5F def cp_use_skill_book(), do: 0x60 def cp_use_owl_minerva(), do: 0x62 def cp_use_return_scroll(), do: 0x64 def cp_use_upgrade_scroll(), do: 0x65 def cp_use_flag_scroll(), do: 0x66 def cp_use_equip_scroll(), do: 0x67 def cp_use_potential_scroll(), do: 0x68 def cp_use_bag(), do: 0x6A def cp_use_magnify_glass(), do: 0x6B def cp_reward_item(), do: 0x8B def cp_item_maker(), do: 0x8C def cp_repair(), do: 0x8E def cp_repair_all(), do: 0x8D def cp_meso_drop(), do: 0x73 def cp_item_pickup(), do: 0x54 # NPC (NOTE: These should match recvops.properties from Java server) def cp_npc_talk(), do: 0x40 def cp_npc_talk_more(), do: 0x42 def cp_npc_shop(), do: 0x43 def cp_storage(), do: 0x44 def cp_use_hired_merchant(), do: 0x45 def cp_merch_item_store(), do: 0x47 def cp_duey_action(), do: 0x48 def cp_quest_action(), do: 0x81 def cp_npc_move(), do: 0x41 def cp_use_scripted_npc_item(), do: 0x59 def cp_repair(), do: 0x89 def cp_repair_all(), do: 0x88 def cp_update_quest(), do: 0x142 def cp_use_item_quest(), do: 0x144 def cp_public_npc(), do: 0x9E # Shop/Merchant def cp_buy_cs_item(), do: 0xB6 def cp_coupon_code(), do: 0xB7 def cp_cs_update(), do: 0xB8 # MTS def cp_touching_mts(), do: 0xB9 def cp_mts_tab(), do: 0xBA # Social def cp_party_operation(), do: 0x91 def cp_deny_party_request(), do: 0x92 def cp_allow_party_invite(), do: 0x93 def cp_expedition_operation(), do: 0x94 def cp_party_search_start(), do: 0x95 def cp_party_search_stop(), do: 0x96 def cp_guild_operation(), do: 0x97 def cp_deny_guild_request(), do: 0x98 def cp_alliance_operation(), do: 0x99 def cp_deny_alliance_request(), do: 0x9A def cp_buddylist_modify(), do: 0x9B def cp_messenger(), do: 0x9C def cp_whisper(), do: 0x9D def cp_party_chat(), do: 0x3F def cp_family_operation(), do: 0x9F def cp_delete_junior(), do: 0xA0 def cp_delete_senior(), do: 0xA1 def cp_use_family(), do: 0xA2 def cp_family_precept(), do: 0xA3 def cp_family_summon(), do: 0xA4 def cp_accept_family(), do: 0xA5 def cp_request_family(), do: 0x9E # Monster def cp_mob_move(), do: 0xA6 def cp_mob_apply_ctrl(), do: 0xA7 def cp_mob_hit_by_mob(), do: 0xA9 def cp_mob_self_destruct(), do: 0xAA def cp_mob_time_bomb_end(), do: 0xAB def cp_mob_area_attack_disease(), do: 0xAC def cp_mob_attack_mob(), do: 0xAD def cp_mob_escort_collision(), do: 0xAE def cp_mob_request_escort_info(), do: 0xAF def cp_mob_skill_delay_end(), do: 0xA8 # NPC/Mob Interaction def cp_damage_reactor(), do: 0xC1 def cp_touch_reactor(), do: 0xC2 def cp_click_reactor(), do: 0xC2 def cp_public_npc(), do: 0x9A # Summons def cp_summon_attack(), do: 0xC6 def cp_move_summon(), do: 0xC4 def cp_damage_summon(), do: 0xC7 def cp_sub_summon(), do: 0xC8 def cp_remove_summon(), do: 0xC9 def cp_move_dragon(), do: 0xCA # Pets def cp_spawn_pet(), do: 0x79 def cp_pet_move(), do: 0xCB def cp_pet_chat(), do: 0xCC def cp_pet_command(), do: 0xCD def cp_pet_drop_pickup_request(), do: 0xCE def cp_pet_auto_pot(), do: 0xCF # Android def cp_move_android(), do: 0x40 # Familiar def cp_use_familiar(), do: 0x61 def cp_spawn_familiar(), do: 0xD0 def cp_rename_familiar(), do: 0xD1 def cp_move_familiar(), do: 0xD2 def cp_attack_familiar(), do: 0xD3 def cp_touch_familiar(), do: 0xD4 # Events/Games def cp_monster_carnival(), do: 0xD5 def cp_player_interaction(), do: 0xC0 def cp_snowball(), do: 0xDA def cp_coconut(), do: 0xDB def cp_left_knock_back(), do: 0xD8 # Anti-Cheat def cp_user_anti_macro_item_use_request(), do: 0x7D def cp_user_anti_macro_skill_use_request(), do: 0x7E def cp_user_anti_macro_question_result(), do: 0x7F # Misc def cp_use_door(), do: 0xBC def cp_use_mech_door(), do: 0xBD def cp_aran_combo(), do: 0x80 def cp_transform_player(), do: 0xBA def cp_note_action(), do: 0xBB def cp_update_quest(), do: 0x85 def cp_use_item_quest(), do: 0x86 def cp_follow_request(), do: 0xBF def cp_follow_reply(), do: 0xC0 def cp_ring_action(), do: 0xC1 def cp_solomon(), do: 0x93 def cp_gach_exp(), do: 0x94 def cp_report(), do: 0xE1 def cp_game_poll(), do: 0xE2 def cp_ship_object(), do: 0xBE def cp_cygnus_summon(), do: 0xBD def cp_reissue_medal(), do: 0x76 def cp_pam_song(), do: 0xE0 # Owl def cp_owl(), do: 0x4B def cp_owl_warp(), do: 0x4C # Profession def cp_profession_info(), do: 0x71 def cp_craft_done(), do: 0x72 def cp_craft_make(), do: 0x73 def cp_craft_effect(), do: 0x74 def cp_start_harvest(), do: 0x75 def cp_stop_harvest(), do: 0x76 def cp_make_extractor(), do: 0x77 def cp_use_bag(), do: 0x6A # Pot System def cp_use_pot(), do: 0xE3 def cp_clear_pot(), do: 0xE4 def cp_feed_pot(), do: 0xE5 def cp_cure_pot(), do: 0xE6 def cp_reward_pot(), do: 0xE7 # ================================================================================================== # Server → Client (Send Opcodes) # ================================================================================================== def lp_check_password_result(), do: 0x00 def lp_guest_id_login_result(), do: 0x01 def lp_account_info_result(), do: 0x02 def lp_check_user_limit_result(), do: 0x03 def lp_set_account_result(), do: 0x04 def lp_confirm_eula_result(), do: 0x05 def lp_check_pin_code_result(), do: 0x06 def lp_update_pin_code_result(), do: 0x07 def lp_view_all_char_result(), do: 0x08 def lp_select_character_by_vac_result(), do: 0x09 def lp_world_information(), do: 0x0A def lp_select_world_result(), do: 0x0B def lp_select_character_result(), do: 0x0C def lp_check_duplicated_id_result(), do: 0x0D def lp_create_new_character_result(), do: 0x0E def lp_delete_character_result(), do: 0x0F def lp_migrate_command(), do: 0x10 def lp_alive_req(), do: 0x11 def lp_latest_connected_world(), do: 0x12 def lp_recommend_world_message(), do: 0x13 def lp_check_spw_result(), do: 0x14 def lp_security_packet(), do: 0x15 def lp_permission_request(), do: 0x16 def lp_exception_log(), do: 0x17 def lp_set_security_event(), do: 0x18 def lp_set_client_key(), do: 0x19 # Character/Map Operations def lp_spawn_player(), do: 184 def lp_remove_player_from_map(), do: 185 def lp_chattext(), do: 186 def lp_move_player(), do: 226 def lp_update_char_look(), do: 241 def lp_whisper(), do: 0x9B def lp_multi_chat(), do: 0x9C def lp_set_physical_office_ip_addr(), do: 0x1A def lp_end_of_scheck(), do: 0x1B # NPC Operations def lp_npc_action(), do: 0x159 def lp_npc_talk(), do: 0x1A3 def lp_open_npc_shop(), do: 0x1A5 def lp_confirm_shop_transaction(), do: 0x1A6 def lp_open_storage(), do: 0x1A9 # ================================================================================================== # Helper Functions # ================================================================================================== @doc """ Looks up an opcode name by its value. """ def find_by_value(value) when is_integer(value) do # This would need to be generated from the opcodes above # For now, return the hex value "0x#{Integer.to_string(value, 16) |> String.upcase() |> String.pad_leading(2, "0")}" end @doc """ Returns all client packet opcodes as a map. """ def client_opcodes do %{ cp_client_hello: 0x01, cp_check_password: 0x02, cp_world_info_request: 0x04, cp_select_world: 0x05, cp_check_user_limit: 0x06, cp_migrate_in: 0x0D, cp_check_duplicated_id: 0x0E, cp_create_new_character: 0x12, cp_create_ultimate: 0x14, cp_delete_character: 0x15, cp_alive_ack: 0x16, cp_exception_log: 0x17, cp_security_packet: 0x18, cp_select_character: 0x19, cp_check_spw_request: 0x1A, cp_client_dump_log: 0x1D, cp_create_security_handle: 0x1E, cp_rsa_key: 0x20, cp_hardware_info: 0x21, cp_set_code_page: 0x22, cp_window_focus: 0x23, cp_inject_packet: 0x24, cp_change_channel: 0x25, cp_enter_cash_shop: 0x26, cp_enter_mts: 0x27, cp_enter_pvp: 0x28, cp_enter_pvp_party: 0x29, cp_leave_pvp: 0x2A, cp_move_player: 0x2D, cp_cancel_chair: 0x2F, cp_use_chair: 0x30, cp_close_range_attack: 0x32, cp_ranged_attack: 0x33, cp_magic_attack: 0x34, cp_passive_energy: 0x35, cp_take_damage: 0x37, cp_general_chat: 0x39, cp_close_chalkboard: 0x3A, cp_face_expression: 0x3B, cp_face_android: 0x3C, cp_use_item_effect: 0x3D, cp_npc_talk: 0x42, cp_npc_move: 0x43, cp_npc_talk_more: 0x44, cp_npc_shop: 0x45, cp_storage: 0x46, cp_use_hired_merchant: 0x47, cp_merch_item_store: 0x49, cp_duey_action: 0x4A, cp_owl: 0x4B, cp_owl_warp: 0x4C, cp_item_sort: 0x4F, cp_item_gather: 0x50, cp_item_move: 0x51, cp_move_bag: 0x52, cp_switch_bag: 0x53, cp_item_pickup: 0x54, cp_use_item: 0x55, cp_cancel_item_effect: 0x56, cp_use_summon_bag: 0x58, cp_pet_food: 0x59, cp_use_mount_food: 0x5A, cp_use_scripted_npc_item: 0x5B, cp_use_recipe: 0x5C, cp_use_cash_item: 0x5D, cp_use_catch_item: 0x5F, cp_use_skill_book: 0x60, cp_use_familiar: 0x61, cp_use_owl_minerva: 0x62, cp_use_tele_rock: 0x6A, cp_use_return_scroll: 0x64, cp_use_upgrade_scroll: 0x65, cp_use_flag_scroll: 0x66, cp_use_equip_scroll: 0x67, cp_use_potential_scroll: 0x68, cp_use_bag: 0x6A, cp_use_magnify_glass: 0x6B, cp_distribute_ap: 0x68, cp_auto_assign_ap: 0x69, cp_heal_over_time: 0x6A, cp_distribute_sp: 0x6C, cp_special_move: 0x6D, cp_cancel_buff: 0x6E, cp_skill_effect: 0x6F, cp_meso_drop: 0x73, cp_give_fame: 0x74, cp_char_info_request: 0x78, cp_spawn_pet: 0x79, cp_cancel_debuff: 0x70, cp_change_map_special: 0x38, cp_use_inner_portal: 0x3A, cp_trock_add_map: 0x3B, cp_user_anti_macro_item_use_request: 0x7D, cp_user_anti_macro_skill_use_request: 0x7E, cp_user_anti_macro_question_result: 0x7F, cp_aran_combo: 0x80, cp_quest_action: 0x83, cp_skill_macro: 0x89, cp_reward_item: 0x8B, cp_item_maker: 0x8C, cp_repair_all: 0x8D, cp_repair: 0x8E, cp_party_operation: 0x91, cp_deny_party_request: 0x92, cp_allow_party_invite: 0x93, cp_expedition_operation: 0x94, cp_party_search_start: 0x95, cp_party_search_stop: 0x96, cp_guild_operation: 0x97, cp_deny_guild_request: 0x98, cp_alliance_operation: 0x99, cp_deny_alliance_request: 0x9A, cp_buddylist_modify: 0x9B, cp_messenger: 0x9C, cp_whisper: 0x9D, cp_request_family: 0x9E, cp_family_operation: 0x9F, cp_delete_junior: 0xA0, cp_delete_senior: 0xA1, cp_use_family: 0xA2, cp_family_precept: 0xA3, cp_family_summon: 0xA4, cp_accept_family: 0xA5, cp_mob_move: 0xA6, cp_mob_apply_ctrl: 0xA7, cp_mob_skill_delay_end: 0xA8, cp_mob_hit_by_mob: 0xA9, cp_mob_self_destruct: 0xAA, cp_mob_time_bomb_end: 0xAB, cp_mob_area_attack_disease: 0xAC, cp_mob_attack_mob: 0xAD, cp_mob_escort_collision: 0xAE, cp_mob_request_escort_info: 0xAF, cp_npc_damage_reactor: 0xC1, cp_touch_reactor: 0xC2, cp_public_npc: 0x9A, cp_buy_cs_item: 0xB6, cp_coupon_code: 0xB7, cp_cs_update: 0xB8, cp_touching_mts: 0xB9, cp_mts_tab: 0xBA, cp_use_door: 0xBC, cp_use_mech_door: 0xBD, cp_cygnus_summon: 0xBE, cp_ship_object: 0xBE, cp_party_chat: 0x3F, cp_player_interaction: 0xC0, cp_follow_request: 0xBF, cp_follow_reply: 0xC0, cp_ring_action: 0xC1, cp_summon_attack: 0xC6, cp_move_summon: 0xC4, cp_damage_summon: 0xC7, cp_sub_summon: 0xC8, cp_remove_summon: 0xC9, cp_move_dragon: 0xCA, cp_move_pet: 0xCB, cp_pet_chat: 0xCC, cp_pet_command: 0xCD, cp_pet_drop_pickup_request: 0xCE, cp_pet_auto_pot: 0xCF, cp_move_familiar: 0xD0, cp_rename_familiar: 0xD1, cp_spawn_familiar: 0xD2, cp_attack_familiar: 0xD3, cp_touch_familiar: 0xD4, cp_monster_carnival: 0xD5, cp_snowball: 0xDA, cp_coconut: 0xDB, cp_left_knock_back: 0xD8, cp_use_pot: 0xE3, cp_clear_pot: 0xE4, cp_feed_pot: 0xE5, cp_cure_pot: 0xE6, cp_reward_pot: 0xE7, cp_report: 0xE1, cp_game_poll: 0xE2, cp_pam_song: 0xE0, cp_move_android: 0x40 } end end