159 lines
4.8 KiB
Elixir
159 lines
4.8 KiB
Elixir
defmodule Odinsea.Channel.Handler.UI do
|
|
@moduledoc """
|
|
Handles user interface interaction packets.
|
|
|
|
Ported from: src/handling/channel/handler/UserInterfaceHandler.java
|
|
|
|
## Main Handlers
|
|
- handle_cygnus_summon/2 - Cygnus/Aran first job advancement
|
|
- handle_game_poll/2 - In-game poll
|
|
- handle_ship_object/2 - Ship/boat object requests
|
|
"""
|
|
|
|
require Logger
|
|
|
|
alias Odinsea.Net.Packet.In
|
|
alias Odinsea.Game.{Character, Map}
|
|
alias Odinsea.Channel.Packets
|
|
|
|
# ============================================================================
|
|
# Job Advancement
|
|
# ============================================================================
|
|
|
|
@doc """
|
|
Handles Cygnus/Aran summon NPC request (CP_CYGNUS_SUMMON / 0xC5).
|
|
|
|
Opens the first job advancement NPC for Cygnus and Aran characters.
|
|
- Job 2000 (Aran) → NPC 1202000
|
|
- Job 1000 (Cygnus Knight) → NPC 1101008
|
|
|
|
Reference: UserInterfaceHandler.CygnusSummon_NPCRequest()
|
|
"""
|
|
def handle_cygnus_summon(_packet, client_pid) do
|
|
case Character.get_state_by_client(client_pid) do
|
|
{:ok, character_id, char_state} ->
|
|
npc_id = case char_state.job do
|
|
2000 -> 1202000 # Aran
|
|
1000 -> 1101008 # Cygnus Knight
|
|
_ -> nil
|
|
end
|
|
|
|
if npc_id do
|
|
# TODO: Start NPC script
|
|
# NPCScriptManager.getInstance().start(c, npc_id)
|
|
Logger.debug("Cygnus/Aran summon NPC: #{npc_id} for character #{character_id}")
|
|
else
|
|
Logger.debug("Invalid job for Cygnus summon: #{char_state.job}, character #{character_id}")
|
|
end
|
|
|
|
:ok
|
|
|
|
{:error, reason} ->
|
|
Logger.warn("Failed to handle Cygnus summon: #{inspect(reason)}")
|
|
end
|
|
end
|
|
|
|
# ============================================================================
|
|
# Game Poll
|
|
# ============================================================================
|
|
|
|
@doc """
|
|
Handles in-game poll (CP_GAME_POLL / 0xD4).
|
|
|
|
Player submits response to server poll/questionnaire.
|
|
|
|
Reference: UserInterfaceHandler.InGame_Poll()
|
|
"""
|
|
def handle_game_poll(packet, client_pid) do
|
|
# tick = In.decode_int(packet)
|
|
selection = In.decode_int(packet)
|
|
|
|
case Character.get_state_by_client(client_pid) do
|
|
{:ok, character_id, char_state} ->
|
|
# TODO: Validate poll is enabled
|
|
# TODO: Validate selection is valid
|
|
# TODO: Record poll response
|
|
# TODO: Send reply packet
|
|
|
|
Logger.debug("Game poll response: #{selection}, character #{character_id}")
|
|
:ok
|
|
|
|
{:error, reason} ->
|
|
Logger.warn("Failed to handle game poll: #{inspect(reason)}")
|
|
end
|
|
end
|
|
|
|
# ============================================================================
|
|
# Ship/Boat Objects
|
|
# ============================================================================
|
|
|
|
@doc """
|
|
Handles ship object request (CP_SHIP_OBJECT / 0x127).
|
|
|
|
Client requests ship/boat status for station maps.
|
|
Used for boats between continents (Ellinia-Orbis, etc.)
|
|
|
|
Packet format varies by map:
|
|
- BB 00 6C 24 05 06 00 - Ellinia
|
|
- BB 00 6E 1C 4E 0E 00 - Leafre
|
|
|
|
Reference: UserInterfaceHandler.ShipObjectRequest()
|
|
"""
|
|
def handle_ship_object(packet, client_pid) do
|
|
# Map ID is encoded in the packet in various ways
|
|
# The full packet structure varies by client version
|
|
|
|
case Character.get_state_by_client(client_pid) do
|
|
{:ok, character_id, char_state} ->
|
|
map_id = char_state.map
|
|
|
|
# Determine ship effect based on map
|
|
effect = get_ship_effect(map_id)
|
|
|
|
# TODO: Check event manager for actual docked status
|
|
# Boats/Trains/Geenie/Flight managers
|
|
|
|
Logger.debug("Ship object request: map #{map_id}, effect #{effect}, character #{character_id}")
|
|
|
|
# TODO: Send boat packet with effect
|
|
# c.sendPacket(MaplePacketCreator.boatPacket(effect))
|
|
|
|
:ok
|
|
|
|
{:error, reason} ->
|
|
Logger.warn("Failed to handle ship object: #{inspect(reason)}")
|
|
end
|
|
end
|
|
|
|
# ============================================================================
|
|
# Helper Functions
|
|
# ============================================================================
|
|
|
|
# Returns the ship effect value for a given map
|
|
# Effect: 1 = Coming, 3 = Going, 1034 = Balrog
|
|
defp get_ship_effect(map_id) do
|
|
case map_id do
|
|
# Ellinia Station >> Orbis
|
|
101000300 -> 3
|
|
# Orbis Station >> Ellinia
|
|
200000111 -> 3
|
|
# Orbis Station >> Ludi
|
|
200000121 -> 3
|
|
# Ludi Station >> Orbis
|
|
220000110 -> 3
|
|
# Orbis Station >> Ariant
|
|
200000151 -> 3
|
|
# Ariant Station >> Orbis
|
|
260000100 -> 3
|
|
# Leafre Station >> Orbis
|
|
240000110 -> 3
|
|
# Orbis Station >> Leafre
|
|
200000131 -> 3
|
|
# During boat rides
|
|
200090010 -> 1 # To Orbis
|
|
200090000 -> 1 # To Ellinia
|
|
_ -> 3 # Default: going
|
|
end
|
|
end
|
|
end
|