- extract the 5e stat-block markup into enemy/_statblock.html.twig (sb.block(enemy) macro); the enemy detail page now uses it too - each tracker combatant gets a "stat block" toggle that expands the block in place (Bootstrap collapse), so you don't have to leave the encounter to check AC / attacks - open blocks are remembered in localStorage and re-opened after each damage/heal reload, and the caret rotates when expanded Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
67 lines
2.7 KiB
Twig
67 lines
2.7 KiB
Twig
{#
|
|
# Shared 5e stat-block rendering. Used on the enemy detail page and, folded
|
|
# up, inside each tracker combatant.
|
|
# {% import 'enemy/_statblock.html.twig' as sb %}
|
|
# {{ sb.block(enemy) }}
|
|
#}
|
|
|
|
{% macro mod(n) %}{{ n >= 0 ? '+' ~ n : n }}{% endmacro %}
|
|
|
|
{% macro _stat(label, score, m) %}
|
|
<div class="col text-center">
|
|
<div class="text-uppercase small text-body-secondary">{{ label }}</div>
|
|
<div class="fw-semibold">{{ score }} ({{ m }})</div>
|
|
</div>
|
|
{% endmacro %}
|
|
|
|
{% macro _line(label, value) %}
|
|
{% if value %}
|
|
<div><span class="fw-semibold">{{ label }}.</span> {{ value }}</div>
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
{% macro _section(title, body) %}
|
|
{% if body %}
|
|
<h3 class="h6 border-bottom pb-1 mt-3">{{ title }}</h3>
|
|
<div>{{ body|nl2br }}</div>
|
|
{% endif %}
|
|
{% endmacro %}
|
|
|
|
{% macro block(e) %}
|
|
{% import _self as sb %}
|
|
{{ sb._line('Armor Class', e.armorClass ~ (e.armorClassNote ? ' (' ~ e.armorClassNote ~ ')' : '')) }}
|
|
{{ sb._line('Hit Points', e.hitPoints ~ (e.hitDice ? ' (' ~ e.hitDice ~ ')' : '')) }}
|
|
{{ sb._line('Speed', e.speed) }}
|
|
|
|
<div class="row row-cols-6 my-3 g-1">
|
|
{{ sb._stat('Str', e.strength, sb.mod(e.abilityModifier(e.strength))) }}
|
|
{{ sb._stat('Dex', e.dexterity, sb.mod(e.abilityModifier(e.dexterity))) }}
|
|
{{ sb._stat('Con', e.constitution, sb.mod(e.abilityModifier(e.constitution))) }}
|
|
{{ sb._stat('Int', e.intelligence, sb.mod(e.abilityModifier(e.intelligence))) }}
|
|
{{ sb._stat('Wis', e.wisdom, sb.mod(e.abilityModifier(e.wisdom))) }}
|
|
{{ sb._stat('Cha', e.charisma, sb.mod(e.abilityModifier(e.charisma))) }}
|
|
</div>
|
|
|
|
{{ sb._line('Saving Throws', e.savingThrows) }}
|
|
{{ sb._line('Skills', e.skills) }}
|
|
{{ sb._line('Damage Vulnerabilities', e.damageVulnerabilities) }}
|
|
{{ sb._line('Damage Resistances', e.damageResistances) }}
|
|
{{ sb._line('Damage Immunities', e.damageImmunities) }}
|
|
{{ sb._line('Condition Immunities', e.conditionImmunities) }}
|
|
{{ sb._line('Senses', e.senses) }}
|
|
{{ sb._line('Languages', e.languages ?? '—') }}
|
|
{{ sb._line('Challenge', e.challengeRating ? e.challengeRating ~ (e.experiencePoints ? ' (' ~ e.experiencePoints ~ ' XP)' : '') : null) }}
|
|
{{ sb._line('Proficiency Bonus', e.proficiencyBonus ? sb.mod(e.proficiencyBonus) : null) }}
|
|
|
|
{{ sb._section('Traits', e.traits) }}
|
|
{{ sb._section('Actions', e.actions) }}
|
|
{{ sb._section('Bonus Actions', e.bonusActions) }}
|
|
{{ sb._section('Reactions', e.reactions) }}
|
|
{{ sb._section('Legendary Actions', e.legendaryActions) }}
|
|
{{ sb._section('Description', e.description) }}
|
|
|
|
{% if e.source %}
|
|
<p class="text-body-secondary small mt-3 mb-0">Source: {{ e.source }}</p>
|
|
{% endif %}
|
|
{% endmacro %}
|