Files
odinsea-elixir/lib/odinsea/channel/handler/monster_carnival.ex
2026-02-14 23:12:33 -07:00

182 lines
5.6 KiB
Elixir

defmodule Odinsea.Channel.Handler.MonsterCarnival do
@moduledoc """
Handles Monster Carnival (CPQ - Carnival Party Quest) operations.
Ported from: src/handling/channel/handler/MonsterCarnivalHandler.java
CPQ is a PvP-style party quest where two parties compete:
- Summon monsters to send to the opposing team
- Use debuff skills on the opposing team
- Deploy guardians for defense
## Tabs
- 0: Summon monsters
- 1: Use debuff skills
- 2: Summon guardians
## Main Handlers
- handle_monster_carnival/2 - All CPQ operations
"""
require Logger
alias Odinsea.Net.Packet.In
alias Odinsea.Game.Character
alias Odinsea.Channel.Packets
# ============================================================================
# CPQ Operations
# ============================================================================
@doc """
Handles all Monster Carnival operations (CP_MONSTER_CARNIVAL / 0x125).
Tabs:
- 0: Summon monsters (mob list index)
- 1: Use debuff skills (skill list index)
- 2: Summon guardians (guardian index)
Reference: MonsterCarnivalHandler.MonsterCarnival()
"""
def handle_monster_carnival(packet, client_pid) do
case Character.get_state_by_client(client_pid) do
{:ok, character_id, char_state} ->
# Check if in carnival party
if char_state.carnival_party == nil do
Logger.debug("Monster Carnival rejected: character #{character_id} not in carnival party")
send(client_pid, {:send_packet, Packets.enable_actions()})
:ok
else
tab = In.decode_byte(packet)
num = In.decode_int(packet)
handle_carnival_tab(tab, num, client_pid, character_id, char_state)
end
{:error, reason} ->
Logger.warn("Failed to handle monster carnival: #{inspect(reason)}")
end
end
# ============================================================================
# Tab Handlers
# ============================================================================
# Tab 0: Summon monsters
defp handle_carnival_tab(0, num, client_pid, character_id, char_state) do
map_id = char_state.map
team = char_state.carnival_party.team
available_cp = char_state.carnival_party.available_cp
# TODO: Get mob list for map
# mobs = Map.get_mobs_to_spawn(map_id)
# TODO: Validate num is valid index
# TODO: Check available CP >= mob_cost
# If valid:
# - Spawn monster for opposing team
# - Deduct CP
# - Update CP displays
# - Broadcast summon message
Logger.debug("CPQ summon mob: index #{num}, team #{team}, map #{map_id}, character #{character_id}")
# Send enable actions (success or failure)
send(client_pid, {:send_packet, Packets.enable_actions()})
:ok
end
# Tab 1: Use debuff skills
defp handle_carnival_tab(1, num, client_pid, character_id, char_state) do
map_id = char_state.map
team = char_state.carnival_party.team
available_cp = char_state.carnival_party.available_cp
# TODO: Get skill list for map
# skills = Map.get_skill_ids(map_id)
# TODO: Validate num is valid index
# TODO: Get skill from MapleCarnivalFactory
# TODO: Check available CP >= skill.cp_loss
# If valid:
# - Apply debuff to opposing team
# - Deduct CP
# - Update CP displays
# - Broadcast skill usage
Logger.debug("CPQ debuff: index #{num}, team #{team}, map #{map_id}, character #{character_id}")
# Send enable actions (success or failure)
send(client_pid, {:send_packet, Packets.enable_actions()})
:ok
end
# Tab 2: Summon guardians
defp handle_carnival_tab(2, num, client_pid, character_id, char_state) do
map_id = char_state.map
team = char_state.carnival_party.team
available_cp = char_state.carnival_party.available_cp
# TODO: Get guardian skill from MapleCarnivalFactory
# skill = MapleCarnivalFactory.getGuardian(num)
# TODO: Check available CP >= skill.cp_loss
# If valid:
# - Spawn carnival reactor (guardian)
# - Deduct CP
# - Update CP displays
# - Broadcast summon message
Logger.debug("CPQ guardian: index #{num}, team #{team}, map #{map_id}, character #{character_id}")
# Send enable actions (success or failure)
send(client_pid, {:send_packet, Packets.enable_actions()})
:ok
end
# Unknown tab
defp handle_carnival_tab(tab, num, client_pid, character_id, _char_state) do
Logger.warning("Unknown CPQ tab #{tab} (num #{num}) from character #{character_id}")
send(client_pid, {:send_packet, Packets.enable_actions()})
:ok
end
# ============================================================================
# CP Management
# ============================================================================
@doc """
Updates CP display for a player.
party_cp: true = show party CP, false = show personal CP
"""
def update_cp(client_pid, available_cp, total_cp, team, party_cp \\ false) do
# TODO: Build CP update packet
# packet = Packets.cp_update(available_cp, total_cp, team, party_cp)
# send(client_pid, {:send_packet, packet})
:ok
end
@doc """
Broadcasts player summoned message to map.
"""
def broadcast_summon(map_id, player_name, tab, num) do
# TODO: Build summon broadcast packet
# packet = Packets.player_summoned(player_name, tab, num)
# Map.broadcast_packet(map_id, packet, exclude: player_id)
:ok
end
@doc """
Distributes CP to carnival party members.
"""
def distribute_cp(carnival_party, cp_amount) do
# TODO: Add CP to party total
# TODO: Update each member's display
:ok
end
end