Files
odinsea-elixir/lib/odinsea/scripting/behavior.ex
2026-02-14 23:12:33 -07:00

380 lines
11 KiB
Elixir

defmodule Odinsea.Scripting.Behavior do
@moduledoc """
Behavior module defining callbacks for Odinsea game scripts.
This behavior is implemented by script modules that are dynamically
compiled from script files or created manually as Elixir modules.
The scripting system supports the following script types:
- NPC scripts (conversation/dialogue) - uses `cm` (conversation manager)
- Quest scripts - uses `qm` (quest manager)
- Portal scripts - uses `pi` (portal interaction)
- Reactor scripts - uses `rm` (reactor manager)
- Event scripts - uses `em` (event manager)
## Script Globals
When scripts are executed, they have access to these globals:
| Variable | Type | Description |
|----------|------|-------------|
| `cm` | `Odinsea.Scripting.PlayerAPI` | NPC conversation manager |
| `qm` | `Odinsea.Scripting.PlayerAPI` | Quest conversation manager |
| `pi` | `Odinsea.Scripting.PlayerAPI` | Portal interaction |
| `rm` | `Odinsea.Scripting.PlayerAPI` | Reactor actions |
| `em` | `Odinsea.Scripting.EventManager` | Event management |
| `eim` | `Odinsea.Scripting.EventInstance` | Event instance (for events) |
## Script Examples
### NPC Script (Elixir module)
defmodule Odinsea.Scripting.NPC.Script_1002001 do
@behaviour Odinsea.Scripting.Behavior
@impl true
def start(cm) do
Odinsea.Scripting.PlayerAPI.send_ok(cm, "Hello! I'm Cody. Nice to meet you!")
end
@impl true
def action(cm, _mode, _type, _selection) do
Odinsea.Scripting.PlayerAPI.dispose(cm)
end
end
### Portal Script (Elixir module)
defmodule Odinsea.Scripting.Portal.Script_08_xmas_st do
@behaviour Odinsea.Scripting.Behavior
@impl true
def enter(pi) do
# Portal logic here
:ok
end
end
### Event Script (Elixir module)
defmodule Odinsea.Scripting.Event.Boats do
@behaviour Odinsea.Scripting.Behavior
@impl true
def init(em) do
# Initialize event
schedule_new(em)
end
@impl true
def schedule(em, method_name, delay) do
# Handle scheduled callback
end
@impl true
def player_entry(eim, player) do
# Handle player entering event
end
end
"""
# ============================================================================
# NPC/Quest Script Callbacks
# ============================================================================
@doc """
Called when an NPC conversation starts.
## Parameters
- `api` - The conversation manager (`cm` for NPC, `qm` for quest)
"""
@callback start(api :: Odinsea.Scripting.PlayerAPI.t()) :: any()
@doc """
Called when a player responds to an NPC dialogue.
## Parameters
- `api` - The conversation manager
- `mode` - The mode byte (0 = cancel/end, 1 = next/yes)
- `type` - The type byte (usually 0)
- `selection` - The player's selection (for menus)
"""
@callback action(api :: Odinsea.Scripting.PlayerAPI.t(),
mode :: integer(),
type :: integer(),
selection :: integer()) :: any()
# ============================================================================
# Quest Script Callbacks (alternative to action for quest scripts)
# ============================================================================
@doc """
Called when a quest starts (alternative to `action` for quests).
"""
@callback quest_start(api :: Odinsea.Scripting.PlayerAPI.t(),
mode :: integer(),
type :: integer(),
selection :: integer()) :: any()
@doc """
Called when a quest ends/completes (alternative to `action` for quests).
"""
@callback quest_end(api :: Odinsea.Scripting.PlayerAPI.t(),
mode :: integer(),
type :: integer(),
selection :: integer()) :: any()
# ============================================================================
# Portal Script Callbacks
# ============================================================================
@doc """
Called when a player enters a scripted portal.
## Parameters
- `api` - The portal interaction manager
## Returns
- `:ok` - Portal handling successful
- `{:error, reason}` - Portal handling failed
"""
@callback enter(api :: Odinsea.Scripting.PlayerAPI.t()) :: :ok | {:error, term()}
# ============================================================================
# Reactor Script Callbacks
# ============================================================================
@doc """
Called when a reactor is activated/hit.
## Parameters
- `api` - The reactor action manager
"""
@callback act(api :: Odinsea.Scripting.PlayerAPI.t()) :: any()
# ============================================================================
# Event Script Callbacks
# ============================================================================
@doc """
Called when an event is initialized (after ChannelServer loads).
## Parameters
- `em` - The event manager
"""
@callback init(em :: Odinsea.Scripting.EventManager.t()) :: any()
@doc """
Called to set up an event instance.
## Parameters
- `em` - The event manager (or eim for some setups)
- `args` - Variable arguments depending on event type
"""
@callback setup(em :: Odinsea.Scripting.EventManager.t(), args :: term()) :: any()
@doc """
Called when a player enters an event instance.
## Parameters
- `eim` - The event instance manager
- `player` - The player character
"""
@callback player_entry(eim :: Odinsea.Scripting.EventInstance.t(),
player :: Odinsea.Game.Character.t()) :: any()
@doc """
Called when a player changes maps within an event.
## Parameters
- `eim` - The event instance manager
- `player` - The player character
- `map_id` - The new map ID
"""
@callback changed_map(eim :: Odinsea.Scripting.EventInstance.t(),
player :: Odinsea.Game.Character.t(),
map_id :: integer()) :: any()
@doc """
Called when an event times out.
## Parameters
- `eim` - The event instance manager
"""
@callback scheduled_timeout(eim :: Odinsea.Scripting.EventInstance.t()) :: any()
@doc """
Called when all monsters in an event are killed.
## Parameters
- `eim` - The event instance manager
"""
@callback all_monsters_dead(eim :: Odinsea.Scripting.EventInstance.t()) :: any()
@doc """
Called when a player dies in an event.
## Parameters
- `eim` - The event instance manager
- `player` - The player character
"""
@callback player_dead(eim :: Odinsea.Scripting.EventInstance.t(),
player :: Odinsea.Game.Character.t()) :: any()
@doc """
Called when a player is revived in an event.
## Parameters
- `eim` - The event instance manager
- `player` - The player character
## Returns
- `true` - Allow revive
- `false` - Deny revive
"""
@callback player_revive(eim :: Odinsea.Scripting.EventInstance.t(),
player :: Odinsea.Game.Character.t()) :: boolean()
@doc """
Called when a player disconnects from an event.
## Parameters
- `eim` - The event instance manager
- `player` - The player character
## Returns
- `0` - Deregister normally, dispose if no players left
- `x > 0` - Deregister, dispose if less than x players
- `x < 0` - Deregister, dispose if less than |x| players, boot all if leader
"""
@callback player_disconnected(eim :: Odinsea.Scripting.EventInstance.t(),
player :: Odinsea.Game.Character.t()) :: integer()
@doc """
Called when a monster is killed in an event.
## Parameters
- `eim` - The event instance manager
- `mob_id` - The monster ID
## Returns
- Points value for this monster kill
"""
@callback monster_value(eim :: Odinsea.Scripting.EventInstance.t(),
mob_id :: integer()) :: integer()
@doc """
Called when a player leaves the party in an event.
## Parameters
- `eim` - The event instance manager
- `player` - The player character
"""
@callback left_party(eim :: Odinsea.Scripting.EventInstance.t(),
player :: Odinsea.Game.Character.t()) :: any()
@doc """
Called when a party is disbanded in an event.
## Parameters
- `eim` - The event instance manager
"""
@callback disband_party(eim :: Odinsea.Scripting.EventInstance.t()) :: any()
@doc """
Called when a party quest is cleared.
## Parameters
- `eim` - The event instance manager
"""
@callback clear_pq(eim :: Odinsea.Scripting.EventInstance.t()) :: any()
@doc """
Called when a player is removed from an event.
## Parameters
- `eim` - The event instance manager
- `player` - The player character
"""
@callback player_exit(eim :: Odinsea.Scripting.EventInstance.t(),
player :: Odinsea.Game.Character.t()) :: any()
@doc """
Called for scheduled event methods.
## Parameters
- `em` - The event manager
- `method_name` - The name of the method to call
- `delay` - The delay in milliseconds
"""
@callback schedule(em :: Odinsea.Scripting.EventManager.t(),
method_name :: String.t(),
delay :: integer()) :: any()
@doc """
Called when an event's schedule is cancelled.
## Parameters
- `em` - The event manager
"""
@callback cancel_schedule(em :: Odinsea.Scripting.EventManager.t()) :: any()
@doc """
Called when a carnival party is registered.
## Parameters
- `eim` - The event instance manager
- `carnival_party` - The carnival party data
"""
@callback register_carnival_party(eim :: Odinsea.Scripting.EventInstance.t(),
carnival_party :: term()) :: any()
@doc """
Called when a player loads a map in an event.
## Parameters
- `eim` - The event instance manager
- `player` - The player character
"""
@callback on_map_load(eim :: Odinsea.Scripting.EventInstance.t(),
player :: Odinsea.Game.Character.t()) :: any()
# ============================================================================
# Optional Callbacks
# ============================================================================
@optional_callbacks [
# NPC/Quest callbacks
start: 1,
action: 4,
quest_start: 4,
quest_end: 4,
# Portal callbacks
enter: 1,
# Reactor callbacks
act: 1,
# Event callbacks
init: 1,
setup: 2,
player_entry: 2,
changed_map: 3,
scheduled_timeout: 1,
all_monsters_dead: 1,
player_dead: 2,
player_revive: 2,
player_disconnected: 2,
monster_value: 2,
left_party: 2,
disband_party: 1,
clear_pq: 1,
player_exit: 2,
schedule: 3,
cancel_schedule: 1,
register_carnival_party: 2,
on_map_load: 2
]
end