Entities

The entities module provides the base classes for all game characters, NPCs, and enemies, along with the stats and AI systems.

Entity Base Classes

Base entity system for characters, NPCs, and enemies.

This module provides the base Entity class that all game entities inherit from.

class barebones_rpg.entities.entity.Entity(*, id=<factory>, name, description='', stats=<factory>, inventory_slots=20, inventory=None, equipment=None, equipped_items=<factory>, faction='neutral', can_act=True, position=(0, 0), ai=None, metadata=<factory>)[source]

Bases: BaseModel

Base class for all entities in the game (characters, NPCs, enemies).

Entities have stats, can participate in combat, and can be extended with custom behavior.

Example

>>> hero = Entity(name="Hero", stats=Stats(hp=100, atk=15))
>>> goblin = Entity(name="Goblin", stats=Stats(hp=30, atk=5))
>>> hero.stats.hp -= 10  # Take damage
>>> print(hero.is_alive())
True
id: str
name: str
description: str
stats: Stats
inventory_slots: int
inventory: Optional[Any]
equipment: Optional[Any]
equipped_items: Dict[str, str]
faction: str
can_act: bool
position: Tuple[int, int]
ai: Optional[AIInterface]
metadata: Dict[str, Any]
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

__init__(**data)[source]

Create a new model by parsing and validating input data from keyword arguments.

Raises [ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.

self is explicitly positional-only to allow self as a field name.

property stats_manager: StatsManager

Get the stats manager for this entity.

is_alive()[source]

Check if entity is alive.

Return type:

bool

is_dead()[source]

Check if entity is dead.

Return type:

bool

take_damage(amount, source=None, damage_type='physical')[source]

Take damage from an attack.

Parameters:
  • amount (int) – Base damage amount

  • source (Optional[Entity]) – Entity that caused the damage

  • damage_type (str) – Type of damage (physical, magic, or custom)

Return type:

int

Returns:

Actual damage taken after defense and resistance calculations

Note

Damage calculation: final = max(0, starting - defense - (resistance * starting)) - Defense provides flat reduction - Resistance provides percentage reduction (-1.0 to 1.0) - Positive resistance reduces damage (0.5 = 50% reduction) - Negative resistance increases damage (-0.5 = 50% extra damage, i.e., weakness) - Both defense and resistance can be applied simultaneously

heal(amount)[source]

Heal the entity.

Parameters:

amount (int) – Amount to heal

Return type:

int

Returns:

Actual amount healed

restore_mana(amount)[source]

Restore mana/MP.

Parameters:

amount (int) – Amount to restore

Return type:

int

Returns:

Actual amount restored

can_perform_action()[source]

Check if entity can perform an action.

Return type:

bool

Returns:

True if entity can act

init_inventory(max_slots=None)[source]

Initialize inventory for this entity.

Parameters:

max_slots (Optional[int]) – Maximum inventory slots (uses inventory_slots if None)

Return type:

Any

Returns:

The created Inventory instance

init_equipment()[source]

Initialize equipment for this entity.

Return type:

Any

Returns:

The created Equipment instance

register_action(action_name, callback)[source]

Register a custom action for this entity.

This allows extending entities with custom behavior.

Parameters:
  • action_name (str) – Name of the action

  • callback – Function to call when action is performed

Return type:

None

perform_action(action_name, **kwargs)[source]

Perform a custom action.

Parameters:
  • action_name (str) – Name of the action

  • **kwargs – Arguments to pass to the action

Return type:

Any

Returns:

Result of the action

to_dict()[source]

Convert entity to dictionary for saving.

Return type:

Dict[str, Any]

Returns:

Dictionary representation of entity

classmethod from_dict(data)[source]

Create entity from dictionary.

Parameters:

data (Dict[str, Any]) – Dictionary representation

Return type:

Entity

Returns:

Entity instance

class barebones_rpg.entities.entity.Character(*, id=<factory>, name, description='', stats=<factory>, inventory_slots=20, inventory=None, equipment=None, equipped_items=<factory>, faction='player', can_act=True, position=(0, 0), ai=None, metadata=<factory>, character_class='warrior', title='')[source]

Bases: Entity

Player character class.

Extends Entity with character-specific features like experience and leveling.

faction: str
character_class: str
title: str
gain_exp(amount, events=None)[source]

Gain experience points.

Parameters:
Return type:

bool

Returns:

True if leveled up

level_up(stat_points_per_level=3)[source]

Level up the character.

Parameters:

stat_points_per_level (int) – Number of stat points to award (default: 3)

Return type:

None

This can be overridden to customize stat growth. The default implementation gives unallocated stat points that can be spent on any stat. Games can override this to auto-allocate, use different point values, or restrict what stats can be increased.

allocate_stat_point(stat_name, amount=1)[source]

Allocate stat points to increase a stat.

This method is fully generic - it can increase any stat (primary attributes or derived substats). Games can override this to add restrictions.

Parameters:
  • stat_name (str) – Name of the stat to increase

  • amount (int) – Number of points to spend (default: 1)

Return type:

bool

Returns:

True if allocation was successful, False if not enough points

Example

>>> character.allocate_stat_point("strength", 2)  # Increase STR by 2
>>> character.allocate_stat_point("training_speed", 1)  # Train speed substat
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class barebones_rpg.entities.entity.NPC(*, id=<factory>, name, description='', stats=<factory>, inventory_slots=20, inventory=None, equipment=None, equipped_items=<factory>, faction='neutral', can_act=True, position=(0, 0), ai=None, metadata=<factory>, dialog_tree_id=None, quest_ids=<factory>, is_merchant=False, merchant_inventory=<factory>)[source]

Bases: Entity

Non-player character class.

NPCs can have dialog, quests, and custom behavior.

faction: str
dialog_tree_id: Optional[str]
quest_ids: List[str]
is_merchant: bool
merchant_inventory: List[str]
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class barebones_rpg.entities.entity.Enemy(*, id=<factory>, name, description='', stats=<factory>, inventory_slots=20, inventory=None, equipment=None, equipped_items=<factory>, faction='enemy', can_act=True, position=(0, 0), ai=None, metadata=<factory>, ai_type='aggressive', exp_reward=10, gold_reward=5, loot_table=<factory>, aggro_range=5)[source]

Bases: Entity

Enemy character class.

Enemies have AI behavior and drop items/exp when defeated.

The loot_table supports both string references (looked up in LootRegistry) and direct Item objects for procedural generation:

Example

>>> from barebones_rpg.items import create_material
>>>
>>> # Using string references (requires LootRegistry setup)
>>> goblin = Enemy(
...     name="Goblin",
...     loot_table=[
...         {"item": "Goblin Bone", "chance": 0.3},
...         {"item": "Health Potion", "chance": 0.1}
...     ]
... )
>>>
>>> # Using direct Item objects (code-first)
>>> goblin = Enemy(
...     name="Goblin",
...     loot_table=[
...         {"item": create_material("Bone", value=5), "chance": 0.3}
...     ]
... )
faction: str
ai_type: str
exp_reward: int
gold_reward: int
loot_table: List[Dict[str, Any]]
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

aggro_range: int

Stats System

Stats system for entities.

This module provides the stats system used by all entities (characters, NPCs, enemies). Stats are flexible and can be extended for different game types.

class barebones_rpg.entities.stats.Stats(**data)[source]

Bases: BaseModel

Base stats for an entity using attribute-based system.

Primary Attributes (core stats that determine derived values): - STR (Strength): Physical damage, melee power - CON (Constitution): HP, physical defense - INT (Intelligence): Magic damage, MP, magic defense - DEX (Dexterity): Speed, accuracy, evasion, critical chance - CHA (Charisma): Dialog, persuasion, prices

Derived Substats are calculated from attributes + training bonuses.

Example

>>> stats = Stats(strength=15, constitution=12, intelligence=10)
>>> stats.hp -= 20
>>> print(stats.hp)
100
>>> stats.allocate_stat_points("strength", 2)  # Direct allocation
>>> print(stats.strength)
17
strength: int
constitution: int
intelligence: int
dexterity: int
charisma: int
hp: int
mp: int
base_max_hp: int
base_max_mp: int
base_physical_defense: int
base_magic_defense: int
base_speed: int
base_accuracy: int
base_evasion: int
base_critical: int
training_physical_defense: int
training_magic_defense: int
training_speed: int
training_accuracy: int
training_evasion: int
training_critical: int
hp_per_con: int
mp_per_int: int
defense_per_con: float
magic_def_per_int: float
speed_per_dex: float
accuracy_per_dex: float
evasion_per_dex: float
critical_per_dex: float
level: int
exp: int
exp_to_next: int
stat_points: int
custom: Dict[str, Any]
resistances: Dict[str, float]
model_config: ClassVar[ConfigDict] = {'extra': 'allow'}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

model_post_init(_Stats__context)[source]

Initialize max HP/MP after creation if not explicitly set.

get_max_hp()[source]

Calculate effective max HP.

Return type:

int

get_max_mp()[source]

Calculate effective max MP.

Return type:

int

get_physical_defense()[source]

Calculate effective physical defense.

Return type:

int

get_magic_defense()[source]

Calculate effective magic defense.

Return type:

int

get_speed()[source]

Calculate effective speed.

Return type:

int

get_accuracy()[source]

Calculate effective accuracy.

Return type:

int

get_evasion()[source]

Calculate effective evasion.

Return type:

int

get_critical()[source]

Calculate effective critical chance.

Return type:

int

property max_hp: int

Max HP property for backward compatibility.

property max_mp: int

Max MP property for backward compatibility.

property physical_defense: int

Physical defense property.

property magic_defense: int

Magic defense property.

property speed: int

Speed property.

property accuracy: int

Accuracy property.

property evasion: int

Evasion property.

property critical: int

Critical chance property.

modify(stat_name, amount)[source]

Modify a stat by a given amount.

Parameters:
  • stat_name (str) – Name of the stat to modify

  • amount (int) – Amount to change (positive or negative)

Return type:

None

set_stat(stat_name, value)[source]

Set a stat to a specific value.

Parameters:
  • stat_name (str) – Name of the stat to set

  • value (int) – New value

Return type:

bool

Returns:

True if stat was set successfully

get_stat(stat_name, default=0)[source]

Get a stat value, including derived stats.

Parameters:
  • stat_name (str) – Name of the stat

  • default (int) – Default value if stat doesn’t exist

Return type:

int

Returns:

The stat value

restore_hp(amount)[source]

Restore HP, capped at max_hp.

Parameters:

amount (int) – Amount to restore

Return type:

int

Returns:

Actual amount restored

restore_mp(amount)[source]

Restore MP, capped at max_mp.

Parameters:

amount (int) – Amount to restore

Return type:

int

Returns:

Actual amount restored

take_damage(amount)[source]

Take damage, reducing HP.

Parameters:

amount (int) – Damage amount

Return type:

int

Returns:

Actual damage taken

is_alive()[source]

Check if entity is alive (HP > 0).

Return type:

bool

is_dead()[source]

Check if entity is dead (HP <= 0).

Return type:

bool

get_resistance(damage_type)[source]

Get resistance value for a damage type.

Parameters:

damage_type (str) – Name of the damage type

Returns:

  • Positive values = resistance (0.5 = 50% damage reduction)

  • Negative values = weakness (-0.5 = 50% extra damage)

  • 0.0 = no resistance or weakness

Return type:

Resistance value (-1.0 to 1.0)

set_resistance(damage_type, value)[source]

Set resistance for a damage type.

Parameters:
  • damage_type (str) – Name of the damage type

  • value (float) – Resistance value (-1.0 to 1.0): Positive = resistance, Negative = weakness

Return type:

None

modify_resistance(damage_type, delta)[source]

Modify resistance for a damage type by a delta.

Parameters:
  • damage_type (str) – Name of the damage type

  • delta (float) – Amount to change resistance by (can be positive or negative)

Return type:

None

class barebones_rpg.entities.stats.StatusEffect(**data)[source]

Bases: BaseModel

A status effect that can be applied to an entity.

Examples: poisoned, stunned, buffed, etc.

name: str
duration: int
stat_modifiers: Dict[str, int]
on_turn: Optional[Callable]
metadata: Dict[str, Any]
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

tick()[source]

Process one turn of the status effect.

Return type:

bool

Returns:

True if effect should continue, False if it expired

class barebones_rpg.entities.stats.StatsManager(base_stats)[source]

Bases: object

Manages stats and status effects for an entity.

This provides a layer on top of Stats that handles temporary modifiers, status effects, and stat change events.

__init__(base_stats)[source]

Initialize the stats manager.

Parameters:

base_stats (Stats) – The base stats for the entity

get_effective_stat(stat_name, default=0)[source]

Get the effective value of a stat including all modifiers.

Parameters:
  • stat_name (str) – Name of the stat

  • default (int) – Default value if stat doesn’t exist

Return type:

int

Returns:

The effective stat value

add_status_effect(effect)[source]

Add a status effect.

Parameters:

effect (StatusEffect) – The status effect to add

Return type:

bool

Returns:

True if status effect was added successfully

remove_status_effect(effect_name)[source]

Remove a status effect by name.

Parameters:

effect_name (str) – Name of the effect to remove

Return type:

bool

Returns:

True if effect was found and removed

process_status_effects()[source]

Process all status effects for one turn.

Return type:

None

has_status(effect_name)[source]

Check if entity has a specific status effect.

Parameters:

effect_name (str) – Name of the status effect

Return type:

bool

Returns:

True if entity has the effect

on_stat_change(callback)[source]

Subscribe to stat change events.

Parameters:

callback (Callable) – Function to call when stats change

Return type:

None

AI Interface

AI interface system for entity behavior.

This module provides a flexible interface for implementing custom AI behavior for NPCs and enemies. Users can implement their own AI using any approach: state machines, behavior trees, LLM-based decision making, etc.

class barebones_rpg.entities.ai_interface.AIContext(**data)[source]

Bases: BaseModel

Context information for AI decision making.

Provides common fields and a metadata dict for custom context.

Example

>>> context = AIContext(
...     entity=goblin,
...     nearby_entities=[player, other_goblin],
...     metadata={"location": current_location, "combat": combat_instance}
... )
entity: Any
nearby_entities: List[Any]
metadata: Dict[str, Any]
model_config: ClassVar[ConfigDict] = {'arbitrary_types_allowed': True}

Configuration for the model, should be a dictionary conforming to [ConfigDict][pydantic.config.ConfigDict].

class barebones_rpg.entities.ai_interface.AIInterface[source]

Bases: ABC

Base interface for AI implementations.

Implement decide_action() to create custom AI behavior. Users can implement this for any AI approach: - Simple state machines - Behavior trees - Utility-based AI - LLM-based decision making - Rule-based systems

Example

>>> class AggressiveMeleeAI(AIInterface):
...     def decide_action(self, context: AIContext) -> dict:
...         if context.nearby_entities:
...             target = context.nearby_entities[0]
...             return {"action": "attack", "target": target}
...         return {"action": "wait"}
>>>
>>> goblin = Enemy(name="Goblin", ai=AggressiveMeleeAI())
abstractmethod decide_action(context)[source]

Decide what action to take based on the current context.

Parameters:

context (AIContext) – AIContext with entity state and custom metadata

Return type:

dict

Returns:

Dict with “action” key and action-specific data. Common actions: “attack”, “move”, “use_skill”, “use_item”, “wait”, “flee”

Examples

{“action”: “attack”, “target”: enemy} {“action”: “move”, “position”: (10, 5)} {“action”: “use_skill”, “skill”: “fireball”, “target”: enemy} {“action”: “wait”}

Example

>>> def decide_action(self, context: AIContext) -> dict:
...     entity = context.entity
...     if entity.stats.hp < entity.stats.max_hp * 0.3:
...         return {"action": "flee"}
...     elif context.nearby_entities:
...         target = context.nearby_entities[0]
...         return {"action": "attack", "target": target}
...     return {"action": "wait"}

AI Implementations

AI systems for entities.

This module provides AI behavior for NPCs and enemies, including pathfinding-based movement and decision making using the AIInterface.

class barebones_rpg.entities.ai.SimplePathfindingAI(pathfinder, attack_range=1, max_moves=3)[source]

Bases: AIInterface

Simple pathfinding-based AI for enemies.

This AI will: - Move toward a target using pathfinding - Attack if adjacent to target - Spend available action points efficiently

Parameters:
  • pathfinder (TilemapPathfinder) – The pathfinder to use for navigation

  • attack_range (int) – Range at which entity can attack (default: 1)

  • max_moves (int) – Maximum moves per turn (default: 3)

__init__(pathfinder, attack_range=1, max_moves=3)[source]

Initialize the AI.

Parameters:
  • pathfinder (TilemapPathfinder) – The pathfinder to use for navigation

  • attack_range (int) – Range at which entity can attack

  • max_moves (int) – Maximum moves per turn

decide_action(context)[source]

Decide what action to take based on context.

This implementation: 1. Finds nearest enemy in nearby_entities 2. If in attack range, returns attack action 3. If not in range, returns move action toward target 4. If no enemies nearby, returns wait action

Parameters:

context (AIContext) – AI context with entity and surroundings

Return type:

dict

Returns:

Dict with action information

class barebones_rpg.entities.ai.TacticalAI(pathfinder, flee_hp_threshold=0.3, attack_range=1, max_moves=3)[source]

Bases: AIInterface

More advanced tactical AI with behavior modes.

This AI can: - Chase and attack - Flee when low health - Patrol between points - Guard a specific location

Parameters:
  • pathfinder (TilemapPathfinder) – The pathfinder to use for navigation

  • flee_hp_threshold (float) – HP percentage threshold for fleeing (default: 0.3)

  • attack_range (int) – Attack range (default: 1)

  • max_moves (int) – Maximum moves per turn (default: 3)

__init__(pathfinder, flee_hp_threshold=0.3, attack_range=1, max_moves=3)[source]

Initialize the tactical AI.

Parameters:
  • pathfinder (TilemapPathfinder) – The pathfinder to use for navigation

  • flee_hp_threshold (float) – HP percentage threshold for fleeing

  • attack_range (int) – Attack range

  • max_moves (int) – Maximum moves per turn

decide_action(context)[source]

Decide what action to take based on context.

This implementation considers health status: - If HP below threshold, flees from nearest enemy - Otherwise, behaves like SimplePathfindingAI

Parameters:

context (AIContext) – AI context with entity and surroundings

Return type:

dict

Returns:

Dict with action information

should_flee(entity)[source]

Check if entity should flee based on HP.

Parameters:

entity (Entity) – The entity to check

Return type:

bool

Returns:

True if entity should flee

set_behavior(mode, flee_threshold=None)[source]

Set AI behavior mode.

Parameters:
  • mode (str) – Behavior mode (“aggressive”, “defensive”, “patrol”, “guard”)

  • flee_threshold (Optional[float]) – HP threshold for fleeing (0.0-1.0)