Combatant
One participant in a combat, and the mutable state that belongs to this fight.
A Combatant is not a creature — it points at one via reference and reads its statistics
from there. What lives on the combatant is what changes during the fight: current hit points
and other ranges in data, active effects and modifiers, and its place in the turn
order via initiative.
That split is what lets six goblins share one monster entry while each tracks its own damage.
The reverse case is a shared combatant — a player character, whose entity is unique — where
the Entity/combatant link means state persists between sessions instead of being deleted
with the combat.
A combatant may also be tied to a map Token, in which case label, name, role and
visibility are kept in sync between the two.
- SeeAlso:
Game,Initiative,Entity,Token
| Property | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | The unique identifier for this combatant. A UUID string automatically generated when the combatant is created. This serves as the primary key in the Realm database. |
label |
string |
No | A short label distinguishing this combatant from identical ones. Assigned by Game/addCombatant(_:) and mirrored onto the map token. Friendly combatants get a bare letter, others a letter and number. Examples: "A" — a friendly combatant; "G1", "G2" — the first and second goblin SeeAlso: CombatantLabel, uniqueName |
name |
string |
No | The display name of the combatant. Copied from the referenced entity or token when the combatant is created, and editable afterwards so a creature can be renamed for this fight only. Examples: "Goblin"; "Thorin Ironforge" |
role |
Role | No | Which side the combatant is on. Drives colouring on the map, experience totals and automatic initiative rolling. A nil value is treated as hostile. SeeAlso: Role, isHostile, isFriendlyOrNeutral |
hidden |
boolean |
No | Whether the combatant is concealed from the players. Hidden combatants are omitted from the player display and the web client’s initiative list. Kept in sync with the map token’s visibility. |
notes |
string |
No | Game-master notes for this combatant. Free-form annotations scoped to this fight — tactics, reminders, what the creature is carrying. |
initiative |
Array<Initiative> | Yes | This combatant’s places in the turn order. Usually one entry, but a combatant can act several times per round, so systems with multiple actions or legendary turns produce more than one. SeeAlso: Initiative, rollInitiative(), activeInitiative |
data |
Object |
No | Per-combat state overriding the referenced entity’s values. Holds whatever changes during the fight — most importantly the ranges configured by the system, such as current and maximum hit points. Values here take precedence over the entity’s own data when the combatant’s view context is built. Usage Examples: "hp.current", "hp.maximum", "hp.temporary" Note: The structure of this data varies by game system.; SeeAlso: configureRangesFromEntity(_:), rangeFor(_:title:) |
attributes |
Object |
Yes | Dynamic attribute storage supporting various data types. A flexible key-value store for attributes and properties that need to be queryable or frequently accessed. Supports multiple data types through RealmAny. |
reference |
string |
No | A soft link to the Entity this combatant represents. Stored as an app URL rather than a Realm relationship, so a combatant survives the entity being unavailable and can be serialized on its own. Resolved through CacheManager by entity and entityId. Examples: "/monster/goblin"; "/character/thorin-ironforge" SeeAlso: referenceURL, entity |
modifiers |
Array<Modifier> | Yes | Adjustments applied directly to this combatant. Applied on top of the combatant’s context when its view context is computed, alongside the modifiers carried by effects. Examples: Equipment bonuses (+2 to AC from armor); Temporary penalties (-2 to attacks) SeeAlso: Modifier, activeModifiers |
effects |
Array<StatusEffect> | Yes | Conditions currently affecting this combatant. Each effect may carry its own modifiers, which are applied together with modifiers. Examples: Conditions: "poisoned", "stunned", "paralyzed"; Buffs: "blessed", "hasted", "invisible" SeeAlso: StatusEffect |
bloodied |
any |
Yes | |
defeated |
any |
Yes | |
player |
any |
Yes | |
image |
any |
Yes | |
entityId |
string |
No | The identifier of the referenced entity, without loading the entity itself. |
entityType |
any |
No | The kind of content this combatant references, derived from reference. Determines which system configuration applies — ranges, defeated conditions, role defaults. |
tokenId |
any |
Yes |
Initiative
Section titled “Initiative”One slot a Combatant occupies in the turn order.
Turn order is modelled as entries rather than a single number on the combatant, because a
combatant can act more than once per round — legendary actions, multiple initiative counts,
or a system that hands out several turns. Each entry carries its own rolled value and,
once Game/sortInitiative() has run, its order within the round.
An entry with no order exists but is not yet in the turn order.
- SeeAlso:
Combatant,Game
| Property | Type | Required | Description |
|---|---|---|---|
id |
string |
Yes | The unique identifier for this initiative entry. A UUID string generated when the entry is created. Embedded objects have no primary key, so this is what Game/initiativeId points at to mark the acting entry. |
name |
string |
No | An optional label for this entry. Distinguishes a combatant’s several entries from one another where the system gives them distinct meanings. Examples: "Legendary Action"; "Lair Action" |
value |
AnyRealmValue | Yes | The rolled or assigned initiative value. Held as AnyRealmValue because systems score initiative differently — a number in most, a drawn card or suit in others. .none means the entry has not been rolled yet and it is excluded from sorting. Examples: .int(17); .string("Ace of Spades") SeeAlso: roll(), Game/rollInitiative(for:) |
order |
integer |
No | This entry’s position in the round, counting from 1. Assigned by Game/sortInitiative(). nil while the entry is not part of the turn order — which is exactly what isActive reports. |

