kimi gone wild

This commit is contained in:
ra
2026-02-14 23:12:33 -07:00
parent bbd205ecbe
commit 0222be36c5
98 changed files with 39726 additions and 309 deletions

View File

@@ -0,0 +1,282 @@
defmodule Odinsea.Channel.Handler.Alliance do
@moduledoc """
Handles Guild Alliance operations.
Ported from: src/handling/channel/handler/AllianceHandler.java
Guild alliances allow multiple guilds to:
- Share a common chat channel
- Display alliance information
- Coordinate activities
## Operations
- 1: Load alliance info
- 2: Leave alliance
- 3: Invite guild to alliance
- 4: Accept alliance invitation
- 6: Expel guild from alliance
- 7: Change alliance leader
- 8: Update alliance titles (ranks)
- 9: Change member guild rank
- 10: Update alliance notice
- 22: Deny alliance invitation
## Main Handlers
- handle_alliance/2 - All alliance operations
- handle_deny_invite/2 - Deny alliance invitation
"""
require Logger
alias Odinsea.Net.Packet.In
alias Odinsea.Game.Character
alias Odinsea.World.Guild
alias Odinsea.Channel.Packets
# ============================================================================
# Alliance Operations
# ============================================================================
@doc """
Handles all alliance operations (CP_ALLIANCE_OPERATION / 0xBA).
Reference: AllianceHandler.HandleAlliance()
"""
def handle_alliance(packet, client_pid, denied \\ false) do
case Character.get_state_by_client(client_pid) do
{:ok, character_id, char_state} ->
guild_id = char_state.guild_id
# Check if in guild
if guild_id <= 0 do
send(client_pid, {:send_packet, Packets.enable_actions()})
:ok
else
# Get guild info
# guild = World.Guild.get_guild(guild_id)
op = In.decode_byte(packet)
# Handle deny separately
if op == 22 do
handle_deny_invite(client_pid, character_id, char_state, guild_id)
else
handle_alliance_op(op, packet, client_pid, character_id, char_state, guild_id)
end
end
{:error, reason} ->
Logger.warn("Failed to handle alliance: #{inspect(reason)}")
end
end
# ============================================================================
# Individual Operations
# ============================================================================
# Operation 1: Load alliance info
defp handle_alliance_op(1, _packet, client_pid, character_id, char_state, guild_id) do
alliance_id = char_state.alliance_id
if alliance_id > 0 do
# TODO: Get alliance info from World.Alliance
# packets = World.Alliance.get_alliance_info(alliance_id, false)
# Enum.each(packets, fn packet -> send(client_pid, {:send_packet, packet}) end)
Logger.debug("Alliance load: alliance #{alliance_id}, character #{character_id}")
end
:ok
end
# Operation 2: Leave alliance / Operation 6: Expel guild
defp handle_alliance_op(op, packet, client_pid, character_id, char_state, guild_id)
when op in [2, 6] do
alliance_id = char_state.alliance_id
guild_rank = char_state.guild_rank
# Get target guild ID
target_guild_id = if op == 6 and byte_size(packet.data) >= 4 do
In.decode_int(packet)
else
guild_id
end
# Permission check: alliance rank <= 2, or own guild
if guild_rank <= 2 or target_guild_id == guild_id do
# TODO: Remove guild from alliance
# World.Alliance.remove_guild_from_alliance(alliance_id, target_guild_id, target_guild_id != guild_id)
Logger.debug("Alliance remove: guild #{target_guild_id} from alliance #{alliance_id}, character #{character_id}")
end
:ok
end
# Operation 3: Invite guild to alliance
defp handle_alliance_op(3, packet, client_pid, character_id, char_state, guild_id) do
alliance_id = char_state.alliance_id
alliance_rank = char_state.alliance_rank
# Get guild leader name to invite
target_leader_name = In.decode_string(packet)
# Only alliance leader (rank 1) can invite
if alliance_rank == 1 do
# TODO: Get target guild leader ID
# target_leader_id = World.Guild.get_guild_leader(target_leader_name)
# TODO: Get target character
# target_char = ChannelServer.get_player_storage().get_character_by_id(target_leader_id)
# TODO: Check if can invite
# if World.Alliance.can_invite(alliance_id) do
# # Send invite
# target_char.client.send_packet(Packets.alliance_invite(alliance_name, character_id))
# World.Guild.set_invited_id(target_char.guild_id, alliance_id)
# end
Logger.debug("Alliance invite: to leader #{target_leader_name}, alliance #{alliance_id}, character #{character_id}")
end
:ok
end
# Operation 4: Accept alliance invitation
defp handle_alliance_op(4, _packet, client_pid, character_id, char_state, guild_id) do
# Get invited alliance ID
# invited_alliance_id = World.Guild.get_invited_id(guild_id)
# if invited_alliance_id > 0 do
# # Add guild to alliance
# success = World.Alliance.add_guild_to_alliance(invited_alliance_id, guild_id)
# if not success do
# # Send error message
# end
#
# # Clear invited ID
# World.Guild.set_invited_id(guild_id, 0)
# end
Logger.debug("Alliance accept: guild #{guild_id}, character #{character_id}")
:ok
end
# Operation 7: Change alliance leader
defp handle_alliance_op(7, packet, client_pid, character_id, char_state, guild_id) do
alliance_id = char_state.alliance_id
alliance_rank = char_state.alliance_rank
# Only alliance leader can change leader
if alliance_rank == 1 do
new_leader_id = In.decode_int(packet)
# TODO: Change alliance leader
# World.Alliance.change_alliance_leader(alliance_id, new_leader_id)
Logger.debug("Alliance leader change: to #{new_leader_id}, alliance #{alliance_id}, character #{character_id}")
end
:ok
end
# Operation 8: Update alliance titles/ranks
defp handle_alliance_op(8, packet, client_pid, character_id, char_state, guild_id) do
alliance_id = char_state.alliance_id
alliance_rank = char_state.alliance_rank
# Only alliance leader can update titles
if alliance_rank == 1 do
# Read 5 rank titles
ranks = Enum.map(1..5, fn _ -> In.decode_string(packet) end)
# TODO: Update alliance ranks
# World.Alliance.update_alliance_ranks(alliance_id, ranks)
Logger.debug("Alliance ranks update: alliance #{alliance_id}, character #{character_id}")
end
:ok
end
# Operation 9: Change member guild rank
defp handle_alliance_op(9, packet, client_pid, character_id, char_state, guild_id) do
alliance_id = char_state.alliance_id
alliance_rank = char_state.alliance_rank
# Alliance rank <= 2 can change ranks
if alliance_rank <= 2 do
target_guild_id = In.decode_int(packet)
new_rank = In.decode_byte(packet)
# TODO: Change guild rank in alliance
# World.Alliance.change_alliance_rank(alliance_id, target_guild_id, new_rank)
Logger.debug("Alliance rank change: guild #{target_guild_id} to rank #{new_rank}, alliance #{alliance_id}, character #{character_id}")
end
:ok
end
# Operation 10: Update alliance notice
defp handle_alliance_op(10, packet, client_pid, character_id, char_state, guild_id) do
alliance_id = char_state.alliance_id
alliance_rank = char_state.alliance_rank
# Alliance rank <= 2 can update notice
if alliance_rank <= 2 do
notice = In.decode_string(packet)
# Check notice length (max 100)
if String.length(notice) <= 100 do
# TODO: Update alliance notice
# World.Alliance.update_alliance_notice(alliance_id, notice)
Logger.debug("Alliance notice update: alliance #{alliance_id}, character #{character_id}")
end
end
:ok
end
# Unknown operation
defp handle_alliance_op(op, _packet, _client_pid, character_id, _char_state, guild_id) do
Logger.warning("Unknown alliance operation #{op} from character #{character_id}, guild #{guild_id}")
:ok
end
# ============================================================================
# Deny Invite Handler
# ============================================================================
@doc """
Handles deny alliance invitation (CP_DENY_ALLIANCE_REQUEST / 0xBB).
Also called when op == 22 in alliance operation.
Reference: AllianceHandler.DenyInvite()
"""
def handle_deny_invite(client_pid, character_id, char_state, guild_id) do
# Get invited alliance ID
# invited_alliance_id = World.Guild.get_invited_id(guild_id)
# if invited_alliance_id > 0 do
# # Get alliance leader
# leader_id = World.Alliance.get_alliance_leader(invited_alliance_id)
#
# if leader_id > 0 do
# # Notify leader of rejection
# leader = ChannelServer.get_player_storage().get_character_by_id(leader_id)
# if leader do
# leader.drop_message(5, "#{guild.name} Guild has rejected the Guild Union invitation.")
# end
# end
#
# # Clear invited ID
# World.Guild.set_invited_id(guild_id, 0)
# end
Logger.debug("Alliance invite denied: guild #{guild_id}, character #{character_id}")
:ok
end
end