osrlib.core.creature
The attribute surface a character or a monster instance offers the rules, as protocols.
A rules function in osrlib.core.combat, osrlib.core.spells,
and osrlib.core.effects takes the creature it acts on as one of the three protocols
here, unless what it reads needs a single concrete type, in which case it takes that type and says so in its
own entry. A Character and a
MonsterInstance satisfy the protocols structurally, so you pass
either without a cast, and pyright checks that whatever else you pass has the attributes the function
reads. Nothing here is instantiated. Read a protocol to learn what a function needs from its argument, and
annotate your own code with it when you write a function that takes either kind of creature.
Creature is the base: an id, a name, hit points, conditions, and stat
modifiers. Combatant adds the combat numbers an attack or a saving throw reads.
Caster adds what memorizing and casting read. A function that needs an attribute
only one concrete type has, such as a monster's template or a character's inventory, either takes that
concrete type or reads the attribute with getattr and a default, and its docstring says which.
Typical usage:
from osrlib.core.alignment import Alignment
from osrlib.core.character import CHARACTER_CREATION_STREAM, create_character
from osrlib.core.creature import Combatant, Creature
from osrlib.core.monsters import MONSTER_SPAWN_STREAM, spawn_monster
from osrlib.core.rng import RngStreams
from osrlib.core.ruleset import Ruleset
from osrlib.data import load_monsters
streams = RngStreams(master_seed=7)
hero = create_character(
name="Hild",
class_id="fighter",
alignment=Alignment.LAWFUL,
ruleset=Ruleset(),
stream=streams.get(CHARACTER_CREATION_STREAM),
).character
goblin = spawn_monster(load_monsters().get("goblin"), id="monster-0001", stream=streams.get(MONSTER_SPAWN_STREAM))
def hurt(creature: Creature) -> bool:
return creature.current_hp < creature.max_hp
def can_be_hit(combatant: Combatant) -> bool:
return combatant.armour_class is not None
print(hurt(hero), hurt(goblin), can_be_hit(hero), can_be_hit(goblin))
# False False True True
Caster
A creature that memorizes and casts spells.
memorize_spells, validate_cast,
cast_spell, and disrupt_casting
take this. A Character satisfies it and a
MonsterInstance does not, because monsters in the compiled data never
cast. The class that decides which list and how many slots is not part of the surface: those functions take
the ClassDefinition or the
CasterProfile as a separate argument.
Examples:
from osrlib.core.alignment import Alignment
from osrlib.core.character import CHARACTER_CREATION_STREAM, create_character
from osrlib.core.creature import Caster
from osrlib.core.rng import RngStreams
from osrlib.core.ruleset import Ruleset
stream = RngStreams(master_seed=7).get(CHARACTER_CREATION_STREAM)
zelia = create_character(
name="Zelia",
class_id="magic_user",
alignment=Alignment.NEUTRAL,
ruleset=Ruleset(),
stream=stream,
starting_spell_ids=["sleep"],
).character
print(isinstance(zelia, Caster), zelia.level, zelia.spell_book, zelia.memorized_spells)
# True 1 ('sleep',) ()
level
instance-attribute
level: int
The caster's level, which sets slots, range, and effect size. A scroll is read at the scroll's own level rather than the reader's.
spell_book
instance-attribute
The spell ids an arcane caster owns copies of. Empty for a divine caster.
memorized_spells
instance-attribute
memorized_spells: tuple[MemorizedSpell, ...]
The prepared copies as MemorizedSpell entries, spent as they are cast.
Combatant
A creature with the numbers an attack, an initiative roll, or a saving throw reads.
attack_roll, resolve_attack,
saving_throw, and
participant_modifier take this. Both concrete creature types
satisfy it. Every number is read-only, because each one is derived: a character's from class, level, and
gear, a monster's from its template and its drained hit dice.
Examples:
from osrlib.core.creature import Combatant
from osrlib.core.monsters import MONSTER_SPAWN_STREAM, spawn_monster
from osrlib.core.rng import RngStreams
from osrlib.data import load_monsters
stream = RngStreams(master_seed=3).get(MONSTER_SPAWN_STREAM)
goblin = spawn_monster(load_monsters().get("goblin"), id="monster-0001", stream=stream)
print(isinstance(goblin, Combatant), goblin.thac0, goblin.armour_class)
# True 19 6
armour_class
property
armour_class: int | None
Descending armour class, or None for a creature an attack roll cannot hit.
armour_class_ascending
property
armour_class_ascending: int | None
The ascending form of armour_class, or None on the same terms.
melee_modifier
property
melee_modifier: int
The bonus a melee attack and its damage take, from strength or from an effect.
missile_modifier
property
missile_modifier: int
The bonus a missile attack takes, from dexterity. A monster's is 0.
initiative_modifier
property
initiative_modifier: int
The bonus an individual initiative roll takes. A monster's is 0.
Creature
Bases: Protocol
What every rules function needs from the creature it acts on.
A Character and a MonsterInstance
both satisfy this, and so does anything of your own with these attributes. Functions that read only this
surface, such as has_condition,
apply_healing, and incapacitated,
take it. A function that also reads combat numbers takes Combatant.
The hit points, conditions, and stat modifiers are writable, because the rules change them: damage lowers
current_hp, a spell appends to conditions, an effect attaches a modifier. The id, name, and alignment are
read-only here, because a monster's name comes from its template and a character's id is None until a
session assigns one.
Examples:
from osrlib.core.creature import Creature
from osrlib.core.monsters import MONSTER_SPAWN_STREAM, spawn_monster
from osrlib.core.rng import RngStreams
from osrlib.data import load_monsters
stream = RngStreams(master_seed=3).get(MONSTER_SPAWN_STREAM)
goblin = spawn_monster(load_monsters().get("goblin"), id="monster-0001", stream=stream)
print(isinstance(goblin, Creature), goblin.name, goblin.current_hp == goblin.max_hp)
# True Goblin True
id
property
id: str | None
The entity id a session assigned, or None for a character no session holds yet.
Events name creatures by it.
name
property
name: str
The display name: the one a character was created with, or the one a monster's template gives.
alignment
property
alignment: Alignment | None
The creature's Alignment.
None for a monster whose template lists none.
current_hp
instance-attribute
current_hp: int
Hit points now. The rules lower and raise it in place.
conditions
instance-attribute
conditions: tuple[ActiveCondition, ...]
The active ActiveCondition entries, in the order they were granted.
Read them through has_condition.
stat_modifiers
instance-attribute
stat_modifiers: tuple[ActiveModifier, ...]
The active ActiveModifier entries. Read them through
modifier_total and its siblings.