This commit is contained in:
ra
2026-02-14 19:36:59 -07:00
parent f5b8aeb39d
commit bbd205ecbe
19 changed files with 5191 additions and 554 deletions

183
lib/odinsea/game/storage.ex Normal file
View File

@@ -0,0 +1,183 @@
defmodule Odinsea.Game.Storage do
@moduledoc """
Manages personal storage (bank) for characters.
Ported from src/server/MapleStorage.java
TODO: Full implementation requires:
- Database persistence
- Inventory system integration
- Item serialization
- Slot management
- Meso storage
"""
use GenServer
require Logger
@default_slots 4
@max_slots 48
@storage_fee 100
defstruct [
:character_id,
:account_id,
:slots,
:meso,
items: %{}
]
# Client API
def start_link(opts) do
GenServer.start_link(__MODULE__, opts)
end
@doc """
Load storage for a character.
"""
def load_storage(account_id) do
# TODO: Load from database
{:ok, %__MODULE__{account_id: account_id, slots: @default_slots, meso: 0, items: %{}}}
end
@doc """
Send storage to client.
"""
def send_storage(client_pid, storage) do
# TODO: Send OPEN_STORAGE packet
Logger.debug("Sending storage to client #{inspect(client_pid)} (STUB)")
:ok
end
@doc """
Take out an item from storage.
"""
def take_out_item(storage, slot) do
# TODO: Full implementation:
# 1. Validate slot
# 2. Get item from storage
# 3. Check inventory space
# 4. Remove from storage
# 5. Add to inventory
# 6. Send update packet
Logger.debug("Storage take out: slot=#{slot} (STUB)")
{:ok, storage}
end
@doc """
Store an item in storage.
"""
def store_item(storage, item, slot) do
# TODO: Full implementation:
# 1. Check storage is not full
# 2. Validate item (not pet, not trade-restricted)
# 3. Charge storage fee (100 mesos)
# 4. Remove karma flags if applicable
# 5. Remove from inventory
# 6. Add to storage
# 7. Send update packet
Logger.debug("Storage store: item=#{inspect(item)}, slot=#{slot} (STUB)")
{:ok, storage}
end
@doc """
Arrange/sort storage items.
"""
def arrange(storage) do
# TODO: Sort items by type/ID
Logger.debug("Storage arrange (STUB)")
{:ok, storage}
end
@doc """
Deposit or withdraw mesos.
"""
def transfer_meso(storage, amount) do
# TODO: Full implementation:
# 1. Validate amount (positive = withdraw, negative = deposit)
# 2. Check character has mesos (if depositing)
# 3. Check storage has mesos (if withdrawing)
# 4. Handle overflow protection
# 5. Transfer mesos
# 6. Send update packet
Logger.debug("Storage meso transfer: #{amount} (STUB)")
{:ok, storage}
end
@doc """
Close storage.
"""
def close(storage) do
# TODO: Save to database
Logger.debug("Storage close (STUB)")
:ok
end
@doc """
Check if storage is full.
"""
def full?(storage) do
map_size(storage.items) >= storage.slots
end
@doc """
Get next available slot.
"""
def next_slot(storage) do
Enum.find(1..storage.slots, fn slot -> !Map.has_key?(storage.items, slot) end)
end
@doc """
Find item by ID in storage.
"""
def find_by_id(storage, item_id) do
Enum.find(storage.items, fn {_slot, item} -> item.item_id == item_id end)
end
# GenServer callbacks
@impl true
def init(opts) do
account_id = Keyword.fetch!(opts, :account_id)
state = %__MODULE__{
account_id: account_id,
slots: @default_slots,
meso: 0,
items: %{}
}
{:ok, state}
end
@impl true
def handle_call({:add_item, slot, item}, _from, state) do
if slot <= state.slots and !Map.has_key?(state.items, slot) do
new_items = Map.put(state.items, slot, item)
{:reply, :ok, %{state | items: new_items}}
else
{:reply, {:error, :invalid_slot}, state}
end
end
@impl true
def handle_call({:remove_item, slot}, _from, state) do
case Map.pop(state.items, slot) do
{nil, _} -> {:reply, {:error, :no_item}, state}
{item, new_items} -> {:reply, {:ok, item}, %{state | items: new_items}}
end
end
@impl true
def handle_call({:set_meso, meso}, _from, state) do
{:reply, :ok, %{state | meso: meso}}
end
@impl true
def handle_call(:get_meso, _from, state) do
{:reply, state.meso, state}
end
end