update
This commit is contained in:
@@ -11,6 +11,7 @@ defmodule Odinsea.Game.Character do
|
||||
|
||||
alias Odinsea.Database.Schema.Character, as: CharacterDB
|
||||
alias Odinsea.Game.Map, as: GameMap
|
||||
alias Odinsea.Game.{Inventory, InventoryType}
|
||||
alias Odinsea.Net.Packet.Out
|
||||
|
||||
# ============================================================================
|
||||
@@ -231,6 +232,52 @@ defmodule Odinsea.Game.Character do
|
||||
GenServer.stop(via_tuple(character_id), :normal)
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# Inventory API
|
||||
# ============================================================================
|
||||
|
||||
@doc """
|
||||
Gets a specific inventory.
|
||||
"""
|
||||
def get_inventory(character_id, inv_type) do
|
||||
GenServer.call(via_tuple(character_id), {:get_inventory, inv_type})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets an item from a specific inventory slot.
|
||||
"""
|
||||
def get_item(character_id, inv_type, position) do
|
||||
GenServer.call(via_tuple(character_id), {:get_item, inv_type, position})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Moves an item within or between inventories.
|
||||
"""
|
||||
def move_item(character_id, inv_type, src_slot, dst_slot, slot_max \\ 100) do
|
||||
GenServer.call(via_tuple(character_id), {:move_item, inv_type, src_slot, dst_slot, slot_max})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Equips an item (moves from EQUIP inventory to EQUIPPED).
|
||||
"""
|
||||
def equip_item(character_id, src_slot, dst_slot) do
|
||||
GenServer.call(via_tuple(character_id), {:equip_item, src_slot, dst_slot})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Unequips an item (moves from EQUIPPED to EQUIP inventory).
|
||||
"""
|
||||
def unequip_item(character_id, src_slot, dst_slot) do
|
||||
GenServer.call(via_tuple(character_id), {:unequip_item, src_slot, dst_slot})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Drops an item from inventory.
|
||||
"""
|
||||
def drop_item(character_id, inv_type, position, quantity \\ 1) do
|
||||
GenServer.call(via_tuple(character_id), {:drop_item, inv_type, position, quantity})
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# GenServer Callbacks
|
||||
# ============================================================================
|
||||
@@ -286,6 +333,93 @@ defmodule Odinsea.Game.Character do
|
||||
{:reply, result, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:get_inventory, inv_type}, _from, state) do
|
||||
inventory = Map.get(state.inventories, inv_type, Inventory.new(inv_type))
|
||||
{:reply, inventory, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:get_item, inv_type, position}, _from, state) do
|
||||
inventory = Map.get(state.inventories, inv_type, Inventory.new(inv_type))
|
||||
item = Inventory.get_item(inventory, position)
|
||||
{:reply, item, state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:move_item, inv_type, src_slot, dst_slot, slot_max}, _from, state) do
|
||||
inventory = Map.get(state.inventories, inv_type, Inventory.new(inv_type))
|
||||
|
||||
case Inventory.move(inventory, src_slot, dst_slot, slot_max) do
|
||||
{:ok, new_inventory} ->
|
||||
new_inventories = Map.put(state.inventories, inv_type, new_inventory)
|
||||
new_state = %{state | inventories: new_inventories, updated_at: DateTime.utc_now()}
|
||||
{:reply, :ok, new_state}
|
||||
|
||||
{:error, reason} ->
|
||||
{:reply, {:error, reason}, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:equip_item, src_slot, dst_slot}, _from, state) do
|
||||
# Move from EQUIP to EQUIPPED
|
||||
equip_inv = Map.get(state.inventories, :equip, Inventory.new(:equip))
|
||||
equipped_inv = Map.get(state.inventories, :equipped, Inventory.new(:equipped))
|
||||
|
||||
case Inventory.move(equip_inv, src_slot, dst_slot, 1) do
|
||||
{:ok, new_equip_inv} ->
|
||||
new_inventories =
|
||||
state.inventories
|
||||
|> Map.put(:equip, new_equip_inv)
|
||||
|> Map.put(:equipped, equipped_inv)
|
||||
|
||||
# TODO: Recalculate stats based on new equipment
|
||||
new_state = %{state | inventories: new_inventories, updated_at: DateTime.utc_now()}
|
||||
{:reply, :ok, new_state}
|
||||
|
||||
{:error, reason} ->
|
||||
{:reply, {:error, reason}, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:unequip_item, src_slot, dst_slot}, _from, state) do
|
||||
# Move from EQUIPPED to EQUIP
|
||||
equipped_inv = Map.get(state.inventories, :equipped, Inventory.new(:equipped))
|
||||
equip_inv = Map.get(state.inventories, :equip, Inventory.new(:equip))
|
||||
|
||||
case Inventory.move(equipped_inv, src_slot, dst_slot, 1) do
|
||||
{:ok, new_equipped_inv} ->
|
||||
new_inventories =
|
||||
state.inventories
|
||||
|> Map.put(:equipped, new_equipped_inv)
|
||||
|> Map.put(:equip, equip_inv)
|
||||
|
||||
# TODO: Recalculate stats based on removed equipment
|
||||
new_state = %{state | inventories: new_inventories, updated_at: DateTime.utc_now()}
|
||||
{:reply, :ok, new_state}
|
||||
|
||||
{:error, reason} ->
|
||||
{:reply, {:error, reason}, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:drop_item, inv_type, position, quantity}, _from, state) do
|
||||
inventory = Map.get(state.inventories, inv_type, Inventory.new(inv_type))
|
||||
|
||||
case Inventory.drop(inventory, position, quantity) do
|
||||
{:ok, dropped_item, new_inventory} ->
|
||||
new_inventories = Map.put(state.inventories, inv_type, new_inventory)
|
||||
new_state = %{state | inventories: new_inventories, updated_at: DateTime.utc_now()}
|
||||
{:reply, {:ok, dropped_item}, new_state}
|
||||
|
||||
{:error, reason} ->
|
||||
{:reply, {:error, reason}, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:update_position, position}, state) do
|
||||
new_state = %{
|
||||
@@ -361,6 +495,9 @@ defmodule Odinsea.Game.Character do
|
||||
sp_list when is_list(sp_list) -> sp_list
|
||||
end
|
||||
|
||||
# Load inventories from database
|
||||
inventories = load_inventories(db_char.id)
|
||||
|
||||
%State{
|
||||
character_id: db_char.id,
|
||||
account_id: db_char.account_id,
|
||||
@@ -383,7 +520,7 @@ defmodule Odinsea.Game.Character do
|
||||
remaining_ap: db_char.remaining_ap,
|
||||
remaining_sp: remaining_sp,
|
||||
client_pid: client_pid,
|
||||
inventories: %{},
|
||||
inventories: inventories,
|
||||
skills: %{},
|
||||
buffs: [],
|
||||
pets: [],
|
||||
@@ -392,6 +529,30 @@ defmodule Odinsea.Game.Character do
|
||||
}
|
||||
end
|
||||
|
||||
defp load_inventories(character_id) do
|
||||
# Initialize empty inventories for all types
|
||||
base_inventories =
|
||||
InventoryType.all_types()
|
||||
|> Map.new(fn type -> {type, Inventory.new(type)} end)
|
||||
|
||||
# Load items from database
|
||||
case Odinsea.Database.Context.load_character_inventory(character_id) do
|
||||
nil ->
|
||||
base_inventories
|
||||
|
||||
items_by_type ->
|
||||
# Add items to appropriate inventories
|
||||
Enum.reduce(items_by_type, base_inventories, fn {type, items}, acc ->
|
||||
inventory =
|
||||
Enum.reduce(items, Inventory.new(type), fn item, inv ->
|
||||
Inventory.add_from_db(inv, item)
|
||||
end)
|
||||
|
||||
Map.put(acc, type, inventory)
|
||||
end)
|
||||
end
|
||||
end
|
||||
|
||||
defp parse_sp_string(sp_str) do
|
||||
sp_str
|
||||
|> String.split(",")
|
||||
@@ -429,6 +590,12 @@ defmodule Odinsea.Game.Character do
|
||||
remaining_sp: sp_string
|
||||
}
|
||||
|
||||
Odinsea.Database.Context.update_character(state.character_id, attrs)
|
||||
# Save character base data
|
||||
result = Odinsea.Database.Context.update_character(state.character_id, attrs)
|
||||
|
||||
# Save inventories
|
||||
Odinsea.Database.Context.save_character_inventory(state.character_id, state.inventories)
|
||||
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user