NPCPlugin¶
Manages NPC state, movement, pathfinding, dialog progression, and interactions.
Location¶
- Implementation: src/pedre/plugins/npc/plugin.py
- Base class: src/pedre/plugins/npc/base.py
- Events: src/pedre/plugins/npc/events.py
- Actions: src/pedre/plugins/npc/actions.py
- Conditions: src/pedre/plugins/npc/conditions.py
Configuration¶
The NPCPlugin uses the following settings from pedre.conf.settings:
Movement and Interaction Configuration¶
| Setting | Type | Default | Description |
|---|---|---|---|
NPC_INTERACTION_DISTANCE |
int | 50 | Maximum distance in pixels for player to interact with NPCs |
NPC_WAYPOINT_THRESHOLD |
int | 5 | Distance in pixels to consider an NPC has reached a waypoint |
NPC_MOVEMENT_SPEED |
float | 80.0 | Movement speed in pixels per second |
NPC_INTERACTION_KEY |
string | "SPACE" | Key to interact with NPCs |
These can be overridden in your project's settings.py:
NPC_INTERACTION_DISTANCE = 60
NPC_WAYPOINT_THRESHOLD = 8
NPC_MOVEMENT_SPEED = 100.0
NPC_INTERACTION_KEY = "E"
Public API¶
NPC Registration¶
register_npc¶
register_npc(sprite: arcade.Sprite, name: str) -> None
Register an NPC sprite for management.
Parameters:
sprite- The NPC sprite (typically anAnimatedSpritecreated byload_from_tiled)name- Unique identifier for the NPC
Example:
# Register an NPC sprite (typically called automatically by load_from_tiled)
npc_plugin.register_npc(animated_sprite, "merchant")
Notes:
- NPCs must be registered before they can be interacted with
- Name should be unique within the scene
- Usually called automatically by
load_npcs_from_objects()
Dialog Management¶
get_dialog¶
get_dialog(npc_name: str, dialog_level: int, scene: str = "default") -> tuple[NPCDialogConfig | None, list[Action] | None]
Get dialog for an NPC at a specific conversation level in a scene.
Parameters:
npc_name- The NPC namedialog_level- Current conversation levelscene- Scene name (defaults to "default")
Returns:
- Tuple of
(dialog_config, on_condition_fail_actions): dialog_config: NPCDialogConfig if conditions met, None if no dialog foundon_condition_fail_actions: List of parsedActionobjects if conditions failed, None otherwise
Example:
current_scene = context.scene_plugin.get_current_scene()
dialog_data = npc_plugin.get_dialog("merchant", 0, current_scene)
if dialog_data:
dialog_config, on_fail = dialog_data
if dialog_config:
dialog_plugin.show_dialog("Merchant", dialog_config.text)
Notes:
- Checks dialog conditions using ConditionRegistry
- Falls back to "default" scene if scene-specific dialog not found
- Returns
on_condition_failactions when conditions aren't met
advance_dialog¶
advance_dialog(npc_name: str) -> int
Advance the dialog level for an NPC by 1.
Parameters:
npc_name- The NPC name
Returns:
- The new dialog level
Example:
# After completing a conversation
new_level = npc_plugin.advance_dialog("merchant")
print(f"Merchant now at dialog level {new_level}")
Notes:
- Increments dialog_level by 1
- Dialog level tracks conversation progression
- Used to show different dialog on subsequent interactions
Movement and Pathfinding¶
move_npc_to_position¶
move_npc_to_position(npc_name: str, x: float, y: float) -> None
Start moving an NPC to a target position using A* pathfinding.
Parameters:
npc_name- Name of the NPC to movex- Target x coordinate in pixelsy- Target y coordinate in pixels
Example:
Notes:
- Uses A* pathfinding to avoid obstacles
- Movement is asynchronous (doesn't block)
- Publishes
NPCMovementCompleteEventwhen destination reached - Automatically excludes other moving NPCs from pathfinding
update¶
update(delta_time: float) -> None
Update NPC movements and animations.
Parameters:
delta_time- Time since last update in seconds
Example:
Notes:
- Called automatically by PluginLoader each frame
- Updates NPC positions along paths
- Updates
AnimatedSpriteanimations - Publishes movement/animation complete events
Interaction¶
get_nearby_npc¶
get_nearby_npc(player_sprite: arcade.Sprite) -> tuple[arcade.Sprite, str, int] | None
Find the nearest NPC within interaction distance.
Parameters:
player_sprite- The player sprite
Returns:
- Tuple of
(sprite, name, dialog_level)orNone
Example:
player_sprite = context.player_plugin.get_player_sprite()
nearby = npc_plugin.get_nearby_npc(player_sprite)
if nearby:
sprite, name, dialog_level = nearby
print(f"Near {name} at level {dialog_level}")
Notes:
- Uses
NPC_INTERACTION_DISTANCEsetting - Returns closest NPC within range
- Skips NPCs that are currently moving
- Skips invisible NPCs
interact_with_npc¶
interact_with_npc(name: str) -> bool
Trigger interaction with a specific NPC.
Parameters:
name- Name of the NPC to interact with
Returns:
Trueif interaction started (dialog shown)
Example:
Notes:
- Retrieves NPC's current dialog
- Checks dialog conditions
- Shows dialog via DialogPlugin
- Marks NPC as interacted in current scene
mark_npc_as_interacted¶
mark_npc_as_interacted(npc_name: str, scene_name: str | None = None) -> None
Mark an NPC as interacted with in a specific scene.
Parameters:
npc_name- Name of the NPCscene_name- Scene name (defaults to current scene if not provided)
Example:
# Mark NPC as interacted in current scene
npc_plugin.mark_npc_as_interacted("merchant")
# Mark NPC as interacted in specific scene
npc_plugin.mark_npc_as_interacted("guard", "castle")
Notes:
- Interaction tracking is per-scene
- Used by
npc_interactedcondition check - Called automatically during normal interactions
has_npc_been_interacted_with¶
has_npc_been_interacted_with(npc_name: str, scene_name: str | None = None) -> bool
Check if an NPC has been interacted with in a specific scene.
Parameters:
npc_name- Name of the NPC to checkscene_name- Scene name (defaults to current scene if not provided)
Returns:
Trueif the NPC has been interacted with in the specified scene
Example:
if npc_plugin.has_npc_been_interacted_with("merchant"):
print("Player has talked to merchant before")
Notes:
- Check is scene-specific
- Returns False for NPCs never interacted with
- Used by
npc_interactedcondition
Visibility Management¶
show_npcs¶
show_npcs(npc_names: list[str]) -> None
Make hidden NPCs visible and add them to collision.
Parameters:
npc_names- List of NPC names to reveal
Example:
Notes:
- Makes sprite.visible = True
- Starts appear animation for
AnimatedSpriteNPCs - Adds NPC to wall collision list
- Used by
start_appear_animationaction
State Queries¶
get_npc_by_name¶
get_npc_by_name(name: str) -> NPCState | None
Get NPC state by name.
Parameters:
name- The NPC name
Returns:
- NPCState or None if not found
Example:
npc = npc_plugin.get_npc_by_name("merchant")
if npc:
print(f"Merchant at ({npc.sprite.center_x}, {npc.sprite.center_y})")
print(f"Dialog level: {npc.dialog_level}")
print(f"Moving: {npc.is_moving}")
get_npcs¶
get_npcs() -> dict[str, NPCState]
Get all registered NPCs.
Returns:
- Dictionary mapping NPC names to NPCState instances
Example:
for name, npc in npc_plugin.get_npcs().items():
print(f"{name}: level {npc.dialog_level}, moving={npc.is_moving}")
has_moving_npcs¶
has_moving_npcs() -> bool
Check if any NPCs are currently moving.
Returns:
Trueif at least one NPC is currently moving
Example:
Notes:
- Useful for blocking pausing during cutscenes
- Checks is_moving flag for all NPCs
Save/Load Support¶
get_save_state¶
get_save_state() -> dict[str, Any]
Return serializable state for saving.
Returns:
- Dictionary containing NPC states and interaction history
Example:
save_data = {
"player_position": (x, y),
"npc": npc_plugin.get_save_state(),
# ... other save data
}
Notes:
- Saves positions, visibility, dialog levels, animation flags
- Saves per-scene interaction history
restore_save_state¶
restore_save_state(state: dict[str, Any]) -> None
Phase 1: No metadata to restore for NPCs (sprites don't exist yet).
Parameters:
state- Dictionary containing saved NPC state
apply_entity_state¶
apply_entity_state(state: dict[str, Any]) -> None
Phase 2: Apply saved NPC state after sprites exist.
Parameters:
state- Dictionary containing saved NPC state
Example:
Notes:
- Restores positions, visibility, dialog levels
- Restores animation flags for
AnimatedSpriteNPCs - Restores per-scene interaction history
Scene Caching¶
cache_scene_state¶
cache_scene_state(scene_name: str) -> dict[str, Any]
Return state to cache during scene transitions.
Parameters:
scene_name- Name of the scene being cached
Returns:
- Dictionary containing NPC entity state for the scene
Notes:
- Only caches NPC entity state (positions, visibility, dialog levels)
- Interaction history is global and saved separately
restore_scene_state¶
restore_scene_state(scene_name: str, state: dict[str, Any]) -> None
Restore cached state when returning to a scene.
Parameters:
scene_name- Name of the scene being restoredstate- Previously cached state
Plugin Lifecycle¶
setup¶
setup(context: GameContext) -> None
Initialize the NPC plugin with game context.
Parameters:
context- Game context providing access to other plugins
Notes:
- Called automatically by PluginLoader
- Stores reference to game context
cleanup¶
cleanup() -> None
Clean up NPC resources when the scene unloads.
Notes:
- Clears all registered NPCs
- Clears dialog cache
- Called automatically by PluginLoader
reset¶
reset() -> None
Reset NPC plugin for new game.
Notes:
- Clears NPCs, dialogs, and interaction history
- Called when starting a new game
on_key_press¶
on_key_press(symbol: int, modifiers: int) -> bool
Handle key presses for NPC interaction.
Parameters:
symbol- Arcade key constantmodifiers- Modifier key bitfield
Returns:
Trueif input was consumed
Notes:
- Called automatically by PluginLoader
- Checks for NPC_INTERACTION_KEY press
- Finds nearby NPC and triggers interaction
load_from_tiled¶
load_from_tiled(tile_map: arcade.TileMap, arcade_scene: arcade.Scene) -> None
Load NPCs from Tiled map object layer.
Parameters:
tile_map- The loaded Tiled maparcade_scene- The arcade Scene to add NPCs to
Notes:
- Called automatically by PluginLoader
- Looks for "NPCs" object layer
- Resolves each NPC's sprite via the content registry (
npcsandspritessub-registries) - Each Tiled object only needs a
nameproperty; sprite configuration comes from the content registry
NPC Data Structures¶
NPCState¶
Runtime state tracking for a single NPC.
Attributes:
sprite: arcade.Sprite- The NPC's spritename: str- Unique identifierdialog_level: int- Current conversation level (default: 0)path: deque[tuple[float, float]]- Pathfinding waypointsis_moving: bool- Whether NPC is currently movingappear_event_emitted: bool- Tracks if appear event publisheddisappear_event_emitted: bool- Tracks if disappear event published
Example:
npc = npc_plugin.get_npc_by_name("merchant")
print(f"Dialog level: {npc.dialog_level}")
print(f"Position: ({npc.sprite.center_x}, {npc.sprite.center_y})")
print(f"Moving: {npc.is_moving}, Path length: {len(npc.path)}")
NPCDialogConfig¶
Configuration for NPC dialog at a specific conversation level.
Attributes:
text: list[str]- Dialog text pages to displayname: str | None- Optional display name for speakerconditions: list[Condition] | None- Optional parsed conditions to checkon_condition_fail: list[Action] | None- Parsed actions to execute if conditions fail
Conditions and actions are parsed from JSON at load time via ConditionRegistry and ActionRegistry. You define them as JSON in dialog files; they are stored as parsed objects at runtime.
Dialog Plugin¶
Dialog JSON Format¶
Dialog files live in the dialogs/ subdirectory of your content directory, one file per scene. The scene name is the filename stem (e.g. village.json → scene "village").
Each file is a flat object with keys in the form "{npc_name}/{level}":
{
"npc_name/0": {
"name": "Display Name",
"text": ["First conversation page", "Second page"],
"conditions": [
{"name": "inventory_accessed", "equals": true}
],
"on_condition_fail": [
{"name": "dialog", "speaker": "NPC", "text": ["Not ready yet!"]}
]
},
"npc_name/1": {
"name": "Display Name",
"text": ["Different dialog after progression"]
}
}
Fields:
name(optional) - Display name shown in dialog boxtext(required) - Array of dialog pagesconditions(optional) - Array of condition checkson_condition_fail(optional) - Array of actions if conditions fail
See Dialogs Content Reference for the full schema and file layout.
Scene-Aware Dialogs¶
Dialogs are organized by scene, allowing NPCs to have different conversations depending on location. Each scene corresponds to a {scene}.json file in the dialogs/ content directory.
# Get dialog for current scene
current_scene = context.scene_plugin.get_current_scene()
dialog_data = npc_plugin.get_dialog("merchant", 0, current_scene)
If no scene-specific dialog exists, the plugin falls back to "default" scene.
Dialog Conditions¶
Dialog can be conditional based on game state:
{
"merchant/1": {
"name": "Merchant",
"text": ["You checked your inventory!"],
"conditions": [
{"name": "inventory_accessed", "equals": true}
],
"on_condition_fail": [
{"name": "dialog", "speaker": "Merchant", "text": ["Please check your inventory first!"]}
]
}
}
When conditions fail:
- Returns None for dialog_config
- Returns on_condition_fail actions
- Scripts can execute fallback actions
NPC Sprites and Content Registry¶
NPC sprites are defined via the content registry rather than inline Tiled properties. The plugin looks up each NPC by name in the npcs sub-registry, resolves its associated sprite from the sprites sub-registry, and creates an AnimatedSprite from that definition.
Tiled Map Integration¶
NPCs are placed in Tiled maps using object layers:
- Create an "NPCs" object layer
- Add point objects where NPCs should spawn
- Set the
nameproperty on each object matching an entry in your NPC content registry
Required Tiled Object Properties:
name(string) - NPC identifier (lowercased), must match an entry in thenpcscontent registry
All other configuration (sprite sheet, tile size, scale, animation rows/frames, initially_hidden) comes from the NPC and sprite definitions in the content registry (npcs.json / sprites.json).
Example Tiled Object:
Example NPC content registry entry (npcs.json):
{
"merchant": {
"sprite_id": "merchant_sprite",
"scale": 2.0,
"tile_size": 32,
"initially_hidden": false
}
}
See the NPCs Content Reference and Sprites Content Reference for full details on defining NPC and sprite entries.
Events¶
NPCInteractedEvent¶
Published when player interacts with an NPC.
Attributes:
npc_name: str- Name of the NPC that was interacted withdialog_level: int- Current conversation level
Script Trigger Example:
{
"trigger": {
"event": "npc_interacted",
"npc": "merchant"
},
"actions": [
{"name": "play_sfx", "file": "npc_interact.wav"}
]
}
Notes:
- Fires before dialog is shown
- The
npcfilter is optional (omit to trigger for any NPC)
NPCMovementCompleteEvent¶
Published when an NPC completes movement to target.
Attributes:
npc_name: str- Name of the NPC that completed movement
Script Trigger Example:
{
"trigger": {
"event": "npc_movement_complete",
"npc": "guard"
},
"actions": [
{"name": "dialog", "speaker": "Guard", "text": ["I've arrived!"]}
]
}
Notes:
- Fires when NPC reaches final waypoint
- Path is empty and is_moving is False
- The
npcfilter is optional
NPCAppearCompleteEvent¶
Published when an NPC completes appear animation.
Attributes:
npc_name: str- Name of the NPC that appeared
Script Trigger Example:
{
"trigger": {
"event": "npc_appear_complete",
"npc": "spirit"
},
"actions": [
{"name": "play_sfx", "file": "materialize.wav"},
{"name": "dialog", "speaker": "Spirit", "text": ["I have been summoned!"]}
]
}
Notes:
- Only
AnimatedSpriteNPCs have appear animations - Used internally by WaitForNPCsAppearAction
- The
npcfilter is optional (omit to trigger for any NPC) - Useful for triggering dialog or effects after dramatic entrances
NPCDisappearCompleteEvent¶
Published when an NPC completes disappear animation.
Attributes:
npc_name: str- Name of the NPC that disappeared
Script Trigger Example:
{
"trigger": {
"event": "npc_disappear_complete",
"npc": "ghost"
},
"actions": [
{"name": "play_sfx", "file": "vanish.wav"}
]
}
Notes:
- Only
AnimatedSpriteNPCs have disappear animations - NPC automatically hidden after animation
- The
npcfilter is optional
Actions¶
MoveNPCAction¶
Move one or more NPCs to a waypoint using pathfinding.
Type: move_npc
Parameters:
npcs: list[str]- List of NPC names to movewaypoint: str- Name of waypoint to move to
Example:
Notes:
- Initiates movement immediately
- Doesn't wait for arrival (use
wait_for_movementfor that) - Uses A* pathfinding to avoid obstacles
- Publishes
NPCMovementCompleteEventwhen done
StartAppearAnimationAction¶
Start the appear animation for one or more NPCs.
Type: start_appear_animation
Parameters:
npcs: list[str]- List of NPC names to reveal
Example:
Notes:
- Makes sprite.visible = True
- Starts appear animation for
AnimatedSpriteNPCs - Adds to collision wall list
- Publishes
NPCAppearCompleteEventwhen animation done
AdvanceDialogAction¶
Advance an NPC's dialog level by 1.
Type: advance_dialog
Parameters:
npc: str- Name of the NPC
Example:
Notes:
- Increments dialog_level by 1
- Used to progress conversations
- New level immediately available for next interaction
SetDialogLevelAction¶
Set an NPC's dialog level to a specific value.
Type: set_dialog_level
Parameters:
npc: str- Name of the NPCdialog_level: int- The dialog level to set
Example:
Notes:
- Sets exact dialog level (doesn't increment)
- Useful for jumping to specific conversation states
- Can reset dialog by setting to 0
SetCurrentNPCAction¶
Set the current NPC tracking for dialog event attribution.
Type: set_current_npc
Parameters:
npc: str- Name of the NPC
Example:
Notes:
- Necessary for scripted dialogs (not from direct interaction)
- Ensures DialogClosedEvent has proper NPC attribution
- Should be used before showing scripted dialog
WaitForNPCMovementAction¶
Wait for NPC to complete movement.
Type: wait_for_movement
Parameters:
npc: str- Name of the NPC to wait for
Example:
[
{"name": "move_npc", "npcs": ["guard"], "waypoint": "gate"},
{"name": "wait_for_movement", "npc": "guard"},
{"name": "dialog", "speaker": "Guard", "text": ["I'm here!"]}
]
Notes:
- Pauses script until NPC stops moving
- Checks path is empty and is_moving is False
- Commonly used after move_npc
WaitForNPCsAppearAction¶
Wait for multiple NPCs to complete appear animations.
Type: wait_npcs_appear
Parameters:
npcs: list[str]- List of NPC names to wait for
Example:
[
{"name": "start_appear_animation", "npcs": ["spirit", "guardian"]},
{"name": "wait_npcs_appear", "npcs": ["spirit", "guardian"]},
{"name": "dialog", "speaker": "Spirit", "text": ["We have arrived!"]}
]
Notes:
- Only
AnimatedSpriteNPCs have appear animations - Waits for all NPCs in list
- Regular sprites complete immediately
WaitForNPCsDisappearAction¶
Wait for multiple NPCs to complete disappear animations.
Type: wait_for_npcs_disappear
Parameters:
npcs: list[str]- List of NPC names to wait for
Example:
[
{"name": "start_disappear_animation", "npcs": ["ghost"]},
{"name": "wait_for_npcs_disappear", "npcs": ["ghost"]},
{"name": "change_scene", "target_map": "next_area.tmx"}
]
Notes:
- Only
AnimatedSpriteNPCs have disappear animations - Waits for all NPCs in list
- Regular sprites complete immediately
StartDisappearAnimationAction¶
Start the disappear animation for one or more NPCs.
Type: start_disappear_animation
Parameters:
npcs: list[str]- List of NPC names to make disappear
Example:
Notes:
- Only
AnimatedSpriteNPCs have disappear animations - Waits for animations to complete before finishing
- Removes NPCs from wall collision list when done
- Publishes
NPCDisappearCompleteEventfor each NPC
Conditions¶
npc_interacted¶
Check if an NPC has been interacted with in a specific scene.
Parameters:
check:"npc_interacted"npc: Name of the NPC to checkscene: Optional scene name (defaults to current scene)equals: Expected value (default: true)
Example:
{
"trigger": {
"event": "portal_entered",
"portal": "exit"
},
"conditions": [
{
"name": "npc_interacted",
"npc": "guard"
}
]
}
Check if NOT interacted:
Use Cases:
- Gating progression behind conversations
- Quest prerequisites
- Conditional scene transitions
npc_dialog_level¶
Check an NPC's dialog level.
Parameters:
check:"npc_dialog_level"npc: Name of the NPCequals: Exact level to match
Example:
{
"trigger": {
"event": "npc_interacted",
"npc": "merchant"
},
"conditions": [
{
"name": "npc_dialog_level",
"npc": "merchant",
"equals": 2
}
]
}
Use Cases:
- Branching conversations
- Quest progression tracking
- Conditional NPC responses
Usage Examples¶
Basic NPC Interaction¶
# Check for nearby NPC
player_sprite = context.player_plugin.get_player_sprite()
nearby = npc_plugin.get_nearby_npc(player_sprite)
if nearby:
sprite, name, dialog_level = nearby
print(f"Near {name} at dialog level {dialog_level}")
Moving an NPC¶
{
"move_merchant": {
"scene": "village",
"trigger": {
"event": "object_interacted",
"object_name": "bell"
},
"actions": [
{"name": "move_npc", "npcs": ["merchant"], "waypoint": "market"},
{"name": "wait_for_movement", "npc": "merchant"},
{"name": "dialog", "speaker": "Merchant", "text": ["You called?"]}
]
}
}
Revealing Hidden NPCs¶
{
"summon_spirits": {
"scene": "forest",
"trigger": {
"event": "object_interacted",
"object_name": "ritual_circle"
},
"actions": [
{"name": "play_sfx", "file": "magic.wav"},
{"name": "start_appear_animation", "npcs": ["spirit_1", "spirit_2", "spirit_3"]},
{"name": "wait_npcs_appear", "npcs": ["spirit_1", "spirit_2", "spirit_3"]},
{"name": "dialog", "speaker": "Spirit", "text": ["You have summoned us!"]}
]
}
}
Progressive Conversations¶
{
"merchant_chat_1": {
"scene": "village",
"trigger": {
"event": "npc_interacted",
"npc": "merchant",
"dialog_level": 0
},
"actions": [
{"name": "dialog", "speaker": "Merchant", "text": ["Hello! Check your inventory."]},
{"name": "wait_for_dialog_close"},
{"name": "advance_dialog", "npc": "merchant"}
]
},
"merchant_chat_2": {
"scene": "village",
"trigger": {
"event": "npc_interacted",
"npc": "merchant",
"dialog_level": 1
},
"conditions": [
{"name": "inventory_accessed", "equals": true}
],
"actions": [
{"name": "dialog", "speaker": "Merchant", "text": ["Great! You found the inventory!"]},
{"name": "wait_for_dialog_close"},
{"name": "advance_dialog", "npc": "merchant"}
]
}
}
Coordinated NPC Movement¶
{
"guards_assemble": {
"scene": "castle",
"trigger": {
"event": "object_interacted",
"object_name": "alarm_bell"
},
"actions": [
{"name": "move_npc", "npcs": ["guard_1"], "waypoint": "gate"},
{"name": "move_npc", "npcs": ["guard_2"], "waypoint": "gate"},
{"name": "move_npc", "npcs": ["guard_3"], "waypoint": "gate"},
{"name": "wait_for_movement", "npc": "guard_1"},
{"name": "wait_for_movement", "npc": "guard_2"},
{"name": "wait_for_movement", "npc": "guard_3"},
{"name": "dialog", "speaker": "Captain", "text": ["All guards assembled!"]}
]
}
}
NPC Disappearing¶
{
"ghost_vanish": {
"scene": "haunted_house",
"trigger": {
"event": "dialog_closed",
"npc": "ghost"
},
"actions": [
{"name": "start_disappear_animation", "npcs": ["ghost"]},
{"name": "wait_for_npcs_disappear", "npcs": ["ghost"]},
{"name": "play_sfx", "file": "vanish.wav"},
{"name": "dialog", "speaker": "Narrator", "text": ["The ghost has vanished..."]}
]
}
}
Custom NPC Implementation¶
If you need to replace the NPC plugin with a custom implementation, you can extend the NPCBasePlugin abstract base class.
NPCBasePlugin¶
Location: src/pedre/plugins/npc/base.py
The NPCBasePlugin class defines the minimum interface that any NPC plugin must implement.
Required Methods¶
Your custom NPC plugin must implement these abstract methods:
from pedre.plugins.npc.base import NPCBasePlugin, NPCState
class CustomNPCPlugin(NPCBasePlugin):
"""Custom NPC implementation."""
name = "npc"
dependencies = ["pathfinding"]
def get_npcs(self) -> dict[str, NPCState]:
"""Get all NPCs."""
...
def load_scene_dialogs(self, scene_name: str) -> dict[str, Any]:
"""Load dialogs for a specific scene."""
...
def get_npc_by_name(self, name: str) -> NPCState | None:
"""Get NPC state by name."""
...
def move_npc_to_position(self, npc_name: str, x: float, y: float) -> None:
"""Start moving an NPC to a target position in pixel coordinates."""
...
def has_npc_been_interacted_with(npc_name: str, scene_name: str | None = None) -> bool:
"""Check if an NPC has been interacted with."""
...
def advance_dialog(self, npc_name: str) -> int:
"""Advance the dialog level for an NPC."""
...
def show_npcs(self, npc_names: list[str]) -> None:
"""Make hidden NPCs visible and add them to collision."""
...
Registration¶
Register your custom NPC plugin using the @PluginRegistry.register decorator:
from pedre.plugins.registry import PluginRegistry
from pedre.plugins.npc.base import NPCBasePlugin
@PluginRegistry.register
class CustomNPCPlugin(NPCBasePlugin):
name = "npc"
dependencies = ["pathfinding"]
# ... implement all abstract methods ...
Notes on Custom Implementation¶
- Your custom plugin inherits from
BasePlugin(viaNPCBasePlugin), so you must implement the standard plugin lifecycle methods:setup(),cleanup(), andreset() - The
roleattribute is set to"npc_plugin"in the base class - Your implementation can use any dialog storage or movement plugin
- Register your custom NPC plugin in your project's
INSTALLED_PLUGINSsetting before the default"pedre.plugins.npc"to replace it
Example Custom Implementation:
# In myproject/plugins/custom_npc.py
from pedre.plugins.registry import PluginRegistry
from pedre.plugins.npc.base import NPCBasePlugin
@PluginRegistry.register
class DatabaseNPCPlugin(NPCBasePlugin):
"""NPC plugin that stores state in a database."""
name = "npc"
dependencies = ["pathfinding"]
def __init__(self):
self.db = Database()
# ... rest of initialization ...
def get_npc_by_name(self, name: str) -> NPCState | None:
# Query database for NPC
return self.db.query("SELECT * FROM npcs WHERE name = ?", name)
# ... implement other abstract methods ...
# In myproject/settings.py
INSTALLED_PLUGINS = [
"myproject.plugins.custom_npc", # Load custom NPC first
"pedre.plugins.camera",
"pedre.plugins.audio",
# ... rest of plugins (omit "pedre.plugins.npc") ...
]
See Also¶
- DialogPlugin - Conversation plugin
- ScriptPlugin - Event-driven scripting
- PathfindingPlugin - A* pathfinding plugin
- Configuration Guide
- Scripting Actions
- Scripting Conditions
- Scripting Events