kimi gone wild
This commit is contained in:
200
lib/odinsea/game/drop.ex
Normal file
200
lib/odinsea/game/drop.ex
Normal file
@@ -0,0 +1,200 @@
|
||||
defmodule Odinsea.Game.Drop do
|
||||
@moduledoc """
|
||||
Represents a drop item on a map.
|
||||
Ported from Java server.maps.MapleMapItem
|
||||
|
||||
Drops can be:
|
||||
- Item drops (equipment, use, setup, etc items)
|
||||
- Meso drops (gold/money)
|
||||
|
||||
Drop ownership determines who can loot:
|
||||
- Type 0: Timeout for non-owner only
|
||||
- Type 1: Timeout for non-owner's party
|
||||
- Type 2: Free-for-all (FFA)
|
||||
- Type 3: Explosive/FFA (instant FFA)
|
||||
"""
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
oid: integer(),
|
||||
item_id: integer(),
|
||||
quantity: integer(),
|
||||
meso: integer(),
|
||||
owner_id: integer(),
|
||||
drop_type: integer(),
|
||||
position: %{x: integer(), y: integer()},
|
||||
source_position: %{x: integer(), y: integer()} | nil,
|
||||
quest_id: integer(),
|
||||
player_drop: boolean(),
|
||||
individual_reward: boolean(),
|
||||
picked_up: boolean(),
|
||||
created_at: integer(),
|
||||
expire_time: integer() | nil,
|
||||
public_time: integer() | nil,
|
||||
dropper_oid: integer() | nil
|
||||
}
|
||||
|
||||
defstruct [
|
||||
:oid,
|
||||
:item_id,
|
||||
:quantity,
|
||||
:meso,
|
||||
:owner_id,
|
||||
:drop_type,
|
||||
:position,
|
||||
:source_position,
|
||||
:quest_id,
|
||||
:player_drop,
|
||||
:individual_reward,
|
||||
:picked_up,
|
||||
:created_at,
|
||||
:expire_time,
|
||||
:public_time,
|
||||
:dropper_oid
|
||||
]
|
||||
|
||||
# Default drop expiration times (milliseconds)
|
||||
@default_expire_time 120_000 # 2 minutes
|
||||
@default_public_time 60_000 # 1 minute until FFA
|
||||
|
||||
@doc """
|
||||
Creates a new item drop.
|
||||
"""
|
||||
def new_item_drop(oid, item_id, quantity, owner_id, position, opts \\ []) do
|
||||
drop_type = Keyword.get(opts, :drop_type, 0)
|
||||
quest_id = Keyword.get(opts, :quest_id, -1)
|
||||
individual_reward = Keyword.get(opts, :individual_reward, false)
|
||||
dropper_oid = Keyword.get(opts, :dropper_oid, nil)
|
||||
source_position = Keyword.get(opts, :source_position, nil)
|
||||
now = System.system_time(:millisecond)
|
||||
|
||||
%__MODULE__{
|
||||
oid: oid,
|
||||
item_id: item_id,
|
||||
quantity: quantity,
|
||||
meso: 0,
|
||||
owner_id: owner_id,
|
||||
drop_type: drop_type,
|
||||
position: position,
|
||||
source_position: source_position,
|
||||
quest_id: quest_id,
|
||||
player_drop: false,
|
||||
individual_reward: individual_reward,
|
||||
picked_up: false,
|
||||
created_at: now,
|
||||
expire_time: now + @default_expire_time,
|
||||
public_time: if(drop_type < 2, do: now + @default_public_time, else: 0),
|
||||
dropper_oid: dropper_oid
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Creates a new meso drop.
|
||||
"""
|
||||
def new_meso_drop(oid, amount, owner_id, position, opts \\ []) do
|
||||
drop_type = Keyword.get(opts, :drop_type, 0)
|
||||
individual_reward = Keyword.get(opts, :individual_reward, false)
|
||||
dropper_oid = Keyword.get(opts, :dropper_oid, nil)
|
||||
source_position = Keyword.get(opts, :source_position, nil)
|
||||
now = System.system_time(:millisecond)
|
||||
|
||||
%__MODULE__{
|
||||
oid: oid,
|
||||
item_id: 0,
|
||||
quantity: 0,
|
||||
meso: amount,
|
||||
owner_id: owner_id,
|
||||
drop_type: drop_type,
|
||||
position: position,
|
||||
source_position: source_position,
|
||||
quest_id: -1,
|
||||
player_drop: false,
|
||||
individual_reward: individual_reward,
|
||||
picked_up: false,
|
||||
created_at: now,
|
||||
expire_time: now + @default_expire_time,
|
||||
public_time: if(drop_type < 2, do: now + @default_public_time, else: 0),
|
||||
dropper_oid: dropper_oid
|
||||
}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Marks the drop as picked up.
|
||||
"""
|
||||
def mark_picked_up(%__MODULE__{} = drop) do
|
||||
%{drop | picked_up: true}
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if the drop should expire based on current time.
|
||||
"""
|
||||
def should_expire?(%__MODULE__{} = drop, now) do
|
||||
not drop.picked_up and drop.expire_time != nil and drop.expire_time < now
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if the drop has become public (FFA) based on current time.
|
||||
"""
|
||||
def is_public_time?(%__MODULE__{} = drop, now) do
|
||||
not drop.picked_up and drop.public_time != nil and drop.public_time < now
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if a drop is visible to a specific character.
|
||||
Considers quest requirements and individual rewards.
|
||||
"""
|
||||
def visible_to?(%__MODULE__{} = drop, character_id, _quest_status) do
|
||||
# Individual rewards only visible to owner
|
||||
if drop.individual_reward do
|
||||
drop.owner_id == character_id
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if this is a meso drop.
|
||||
"""
|
||||
def meso?(%__MODULE__{} = drop) do
|
||||
drop.meso > 0
|
||||
end
|
||||
|
||||
@doc """
|
||||
Gets the display ID (item_id for items, meso amount for meso).
|
||||
"""
|
||||
def display_id(%__MODULE__{} = drop) do
|
||||
if drop.meso > 0 do
|
||||
drop.meso
|
||||
else
|
||||
drop.item_id
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Checks if a character can loot this drop.
|
||||
"""
|
||||
def can_loot?(%__MODULE__{} = drop, character_id, now) do
|
||||
# If already picked up, can't loot
|
||||
if drop.picked_up do
|
||||
false
|
||||
else
|
||||
# Check ownership rules based on drop type
|
||||
case drop.drop_type do
|
||||
0 ->
|
||||
# Timeout for non-owner only
|
||||
drop.owner_id == character_id or is_public_time?(drop, now)
|
||||
1 ->
|
||||
# Timeout for non-owner's party (simplified - treat as FFA after timeout)
|
||||
drop.owner_id == character_id or is_public_time?(drop, now)
|
||||
2 ->
|
||||
# FFA
|
||||
true
|
||||
3 ->
|
||||
# Explosive/FFA (instant FFA)
|
||||
true
|
||||
_ ->
|
||||
# Default to owner-only
|
||||
drop.owner_id == character_id
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
Reference in New Issue
Block a user