port over some more
This commit is contained in:
@@ -94,6 +94,10 @@ defmodule Odinsea.Game.Character do
|
||||
:face,
|
||||
# GM Level (0 = normal player, >0 = GM)
|
||||
:gm,
|
||||
# Guild
|
||||
:guild_id,
|
||||
:guild_rank,
|
||||
:alliance_rank,
|
||||
# Stats
|
||||
:stats,
|
||||
# Position & Map
|
||||
@@ -134,6 +138,9 @@ defmodule Odinsea.Game.Character do
|
||||
hair: non_neg_integer(),
|
||||
face: non_neg_integer(),
|
||||
gm: non_neg_integer(),
|
||||
guild_id: non_neg_integer(),
|
||||
guild_rank: non_neg_integer(),
|
||||
alliance_rank: non_neg_integer(),
|
||||
stats: Stats.t(),
|
||||
map_id: non_neg_integer(),
|
||||
position: Position.t(),
|
||||
@@ -281,6 +288,30 @@ defmodule Odinsea.Game.Character do
|
||||
GenServer.call(via_tuple(character_id), {:drop_item, inv_type, position, quantity})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Adds meso to the character.
|
||||
Returns {:ok, new_meso} on success, {:error, reason} on failure.
|
||||
"""
|
||||
def gain_meso(character_id, amount, show_in_chat \\ false) do
|
||||
GenServer.call(via_tuple(character_id), {:gain_meso, amount, show_in_chat})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if the character has inventory space for an item.
|
||||
Returns {:ok, slot} with the next free slot, or {:error, :inventory_full}.
|
||||
"""
|
||||
def check_inventory_space(character_id, inv_type, quantity \\ 1) do
|
||||
GenServer.call(via_tuple(character_id), {:check_inventory_space, inv_type, quantity})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Adds an item to the character's inventory (from a drop).
|
||||
Returns {:ok, item} on success, {:error, reason} on failure.
|
||||
"""
|
||||
def add_item_from_drop(character_id, item) do
|
||||
GenServer.call(via_tuple(character_id), {:add_item_from_drop, item})
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# GenServer Callbacks
|
||||
# ============================================================================
|
||||
@@ -423,6 +454,45 @@ defmodule Odinsea.Game.Character do
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:gain_meso, amount, show_in_chat}, _from, state) do
|
||||
# Cap meso at 9,999,999,999 (MapleStory max)
|
||||
max_meso = 9_999_999_999
|
||||
new_meso = min(state.meso + amount, max_meso)
|
||||
|
||||
new_state = %{state | meso: new_meso, updated_at: DateTime.utc_now()}
|
||||
|
||||
# TODO: Send meso gain packet to client if show_in_chat is true
|
||||
|
||||
{:reply, {:ok, new_meso}, new_state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:check_inventory_space, inv_type, _quantity}, _from, state) do
|
||||
inventory = Map.get(state.inventories, inv_type, Inventory.new(inv_type))
|
||||
|
||||
case Inventory.get_next_free_slot(inventory) do
|
||||
nil -> {:reply, {:error, :inventory_full}, state}
|
||||
slot -> {:reply, {:ok, slot}, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:add_item_from_drop, item}, _from, state) do
|
||||
inv_type = get_inventory_type_from_item_id(item.item_id)
|
||||
inventory = Map.get(state.inventories, inv_type, Inventory.new(inv_type))
|
||||
|
||||
case Inventory.add_item(inventory, item) do
|
||||
{:ok, new_inventory, assigned_item} ->
|
||||
new_inventories = Map.put(state.inventories, inv_type, new_inventory)
|
||||
new_state = %{state | inventories: new_inventories, updated_at: DateTime.utc_now()}
|
||||
{:reply, {:ok, assigned_item}, new_state}
|
||||
|
||||
{:error, reason} ->
|
||||
{:reply, {:error, reason}, state}
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:update_position, position}, state) do
|
||||
new_state = %{
|
||||
@@ -459,6 +529,19 @@ defmodule Odinsea.Game.Character do
|
||||
{:via, Registry, {Odinsea.CharacterRegistry, character_id}}
|
||||
end
|
||||
|
||||
defp get_inventory_type_from_item_id(item_id) do
|
||||
type_prefix = div(item_id, 1_000_000)
|
||||
|
||||
case type_prefix do
|
||||
1 -> :equip
|
||||
2 -> :use
|
||||
3 -> :setup
|
||||
4 -> :etc
|
||||
5 -> :cash
|
||||
_ -> :etc
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Converts database character to in-game state.
|
||||
"""
|
||||
@@ -517,6 +600,9 @@ defmodule Odinsea.Game.Character do
|
||||
hair: db_char.hair,
|
||||
face: db_char.face,
|
||||
gm: db_char.gm,
|
||||
guild_id: db_char.guild_id || 0,
|
||||
guild_rank: db_char.guild_rank || 0,
|
||||
alliance_rank: db_char.alliance_rank || 0,
|
||||
stats: stats,
|
||||
map_id: db_char.map_id,
|
||||
position: position,
|
||||
@@ -850,4 +936,112 @@ defmodule Odinsea.Game.Character do
|
||||
# TODO: Use actual MapleStory EXP table
|
||||
level * level * level + 100 * level
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# Scripting API Helper Functions
|
||||
# ============================================================================
|
||||
|
||||
@doc """
|
||||
Gets the character's channel ID.
|
||||
"""
|
||||
def get_channel(character_id) do
|
||||
case get_state(character_id) do
|
||||
nil -> {:error, :character_not_found}
|
||||
%State{channel_id: channel_id} -> {:ok, channel_id}
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates the character's meso.
|
||||
"""
|
||||
def update_meso(character_id, new_meso) do
|
||||
GenServer.cast(via_tuple(character_id), {:update_meso, new_meso})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates the character's job.
|
||||
"""
|
||||
def update_job(character_id, new_job) do
|
||||
GenServer.cast(via_tuple(character_id), {:update_job, new_job})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Updates a skill level.
|
||||
"""
|
||||
def update_skill(character_id, skill_id, level, master_level) do
|
||||
GenServer.cast(via_tuple(character_id), {:update_skill, skill_id, level, master_level})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Adds an item to inventory.
|
||||
"""
|
||||
def add_item(character_id, inventory_type, item) do
|
||||
GenServer.call(via_tuple(character_id), {:add_item, inventory_type, item})
|
||||
end
|
||||
|
||||
@doc """
|
||||
Removes items by item ID.
|
||||
"""
|
||||
def remove_item_by_id(character_id, item_id, quantity) do
|
||||
GenServer.call(via_tuple(character_id), {:remove_item_by_id, item_id, quantity})
|
||||
end
|
||||
|
||||
# ============================================================================
|
||||
# GenServer Callbacks - Scripting Operations
|
||||
# ============================================================================
|
||||
|
||||
@impl true
|
||||
def handle_cast({:update_meso, new_meso}, state) do
|
||||
new_state = %{state | meso: new_meso, updated_at: DateTime.utc_now()}
|
||||
{:noreply, new_state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:update_job, new_job}, state) do
|
||||
new_state = %{state | job: new_job, updated_at: DateTime.utc_now()}
|
||||
{:noreply, new_state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_cast({:update_skill, skill_id, level, master_level}, state) do
|
||||
skill_entry = %{
|
||||
level: level,
|
||||
master_level: master_level,
|
||||
expiration: -1
|
||||
}
|
||||
new_skills = Map.put(state.skills, skill_id, skill_entry)
|
||||
new_state = %{state | skills: new_skills, updated_at: DateTime.utc_now()}
|
||||
{:noreply, new_state}
|
||||
end
|
||||
|
||||
@impl true
|
||||
def handle_call({:add_item, inventory_type, item}, _from, state) do
|
||||
inventory = Map.get(state.inventories, inventory_type, Inventory.new(inventory_type))
|
||||
|
||||
case Inventory.add_item(inventory, item) do
|
||||
{:ok, new_inventory} ->
|
||||
new_inventories = Map.put(state.inventories, inventory_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({:remove_item_by_id, item_id, quantity}, _from, state) do
|
||||
inventory_type = Inventory.get_type_by_item_id(item_id)
|
||||
inventory = Map.get(state.inventories, inventory_type, Inventory.new(inventory_type))
|
||||
|
||||
case Inventory.remove_by_id(inventory, item_id, quantity) do
|
||||
{:ok, new_inventory, _removed} ->
|
||||
new_inventories = Map.put(state.inventories, inventory_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
|
||||
end
|
||||
|
||||
Reference in New Issue
Block a user