{% extends 'entity/layout.html.twig' %} {% set entityName = character.name %} {% set backRoute = 'characters_index' %} {% set backLabel = 'Personnages' %} {% block stylesheets %} {{ parent() }} {% include 'entity/_element_weakness_styles.html.twig' %} {% endblock %} {% block detail %}
{% if character.appearance %} {{ character.name }} {% else %}
✦
{% endif %}

{{ character.name }}

{% if character.title %}

{{ character.title }}

{% endif %} {% if character.roles %}
{% for roleId in character.roles %} {% set r = roleMap[roleId] ?? null %} {% if r %} {% if r.iconUrl %}{% endif %} {{ r.name }} {% endif %} {% endfor %}
{% endif %}
{% if character.height or character.weight or character.biography %}
{% if character.height or character.weight %}
{% if character.height %} Taille : {{ character.height }} {% endif %} {% if character.weight %} Poids : {{ character.weight }} {% endif %}
{% endif %} {% if character.biography %}

{{ character.biography }}

{% endif %}
{% endif %} {# ── Native passives ── #} {% if passiveSkills is not empty %} {% set iconRoutes = {0: 'icon_csi_forever', 3: 'icon_narval_souls'} %}
Passif{{ passiveSkills|length > 1 ? 's' }}
{% for p in passiveSkills %} {# Icône custom si extraData.icon_id est renseigné et que le jeu a une route icônes ; fallback sur images/passive.png sinon. #} {% set iconId = p.extraData['icon_id'] ?? null %} {% set iconRoute = iconRoutes[p.gameId] ?? null %}
{% if iconId and iconRoute %} {{ p.name }} {% else %} Passif {% endif %}
{{ p.name }} {% if p.description %}

{{ p.description|nl2br }}

{% endif %}
{% endfor %}
{% endif %} {# ── Base stats ── #} {% with {s: character.stats} %} {% if s.pvMax or s.egMax or s.attaque or s.defense or s.arcane or s.sagesse or s.vitesse or s.finesse %}
Stats de base
PV {{ s.pvMax != 0 ? s.pvMax : '—' }}
EG {{ s.egMax != 0 ? s.egMax : '—' }}
ATQ{{ s.attaque != 0 ? s.attaque : '—' }}
DEF{{ s.defense != 0 ? s.defense : '—' }}
ARC{{ s.arcane != 0 ? s.arcane : '—' }}
SAG{{ s.sagesse != 0 ? s.sagesse : '—' }}
VIT{{ s.vitesse != 0 ? s.vitesse : '—' }}
FIN{{ s.finesse != 0 ? s.finesse : '—' }}
{% endif %} {% endwith %} {# ── Attribute values ── #} {% if character.attributeValues %} {% set av = character.attributeValues %}
Valeurs d'attributs (gain par point investi)
PV {{ (av.pvMax ?? 0) != 0 ? '+' ~ av.pvMax : '—' }}
EG {{ (av.egMax ?? 0) != 0 ? '+' ~ av.egMax : '—' }}
ATQ{{ (av.attaque ?? 0) != 0 ? '+' ~ av.attaque : '—' }}
DEF{{ (av.defense ?? 0) != 0 ? '+' ~ av.defense : '—' }}
ARC{{ (av.arcane ?? 0) != 0 ? '+' ~ av.arcane : '—' }}
SAG{{ (av.sagesse ?? 0) != 0 ? '+' ~ av.sagesse : '—' }}
VIT{{ (av.vitesse ?? 0) != 0 ? '+' ~ av.vitesse : '—' }}
FIN{{ (av.finesse ?? 0) != 0 ? '+' ~ av.finesse : '—' }}
{% endif %} {# ── Stat multipliers ── #} {% set mults = [] %} {% if character.multiplierPvMax is not null and character.multiplierPvMax != 1 %}{% set pct = ((character.multiplierPvMax - 1) * 1000)|round / 10 %}{% set mults = mults|merge([{label: 'PV', css: 'pv', pct: pct}]) %}{% endif %} {% if character.multiplierEgMax is not null and character.multiplierEgMax != 1 %}{% set pct = ((character.multiplierEgMax - 1) * 1000)|round / 10 %}{% set mults = mults|merge([{label: 'EG', css: 'eg', pct: pct}]) %}{% endif %} {% if character.multiplierAttaque is not null and character.multiplierAttaque != 1 %}{% set pct = ((character.multiplierAttaque - 1) * 1000)|round / 10 %}{% set mults = mults|merge([{label: 'ATQ', css: 'atq', pct: pct}]) %}{% endif %} {% if character.multiplierDefense is not null and character.multiplierDefense != 1 %}{% set pct = ((character.multiplierDefense - 1) * 1000)|round / 10 %}{% set mults = mults|merge([{label: 'DEF', css: 'def', pct: pct}]) %}{% endif %} {% if character.multiplierArcane is not null and character.multiplierArcane != 1 %}{% set pct = ((character.multiplierArcane - 1) * 1000)|round / 10 %}{% set mults = mults|merge([{label: 'ARC', css: 'arc', pct: pct}]) %}{% endif %} {% if character.multiplierSagesse is not null and character.multiplierSagesse != 1 %}{% set pct = ((character.multiplierSagesse - 1) * 1000)|round / 10 %}{% set mults = mults|merge([{label: 'SAG', css: 'sag', pct: pct}]) %}{% endif %} {% if character.multiplierVitesse is not null and character.multiplierVitesse != 1 %}{% set pct = ((character.multiplierVitesse - 1) * 1000)|round / 10 %}{% set mults = mults|merge([{label: 'VIT', css: 'vit', pct: pct}]) %}{% endif %} {% if character.multiplierFinesse is not null and character.multiplierFinesse != 1 %}{% set pct = ((character.multiplierFinesse - 1) * 1000)|round / 10 %}{% set mults = mults|merge([{label: 'FIN', css: 'fin', pct: pct}]) %}{% endif %} {% if mults is not empty %}
Multiplicateurs de stats
{% for m in mults %}
{{ m.label }} {{ m.pct > 0 ? '+' }}{{ m.pct }}%
{% endfor %}
{% endif %} {# ── Combat stats ── #} {% set hasCombat = character.accuracy is not null or character.evasion is not null or character.criticalRate is not null or character.criticalEvasion is not null or character.magicEvasion is not null or character.physicalCounter is not null or character.magicalCounter is not null or character.regenPv is not null or character.regenEg is not null or character.regenPower is not null or character.priority is not null or character.bonusHit is not null or character.threat is not null or character.defenseRate is not null or character.regenRate is not null or character.healingRate is not null or character.egCost is not null or character.powerGains is not null or character.physicalTaken is not null or character.magicalTaken is not null or character.xpGain is not null %} {% if hasCombat %}
Statistiques de combat
{% if character.accuracy is not null %}Précision :{{ character.accuracy }}%{% endif %} {% if character.evasion is not null %}Esquive :{{ character.evasion }}%{% endif %} {% if character.criticalRate is not null %}Critique :{{ character.criticalRate }}%{% endif %} {% if character.criticalEvasion is not null %}Anti-critique :{{ character.criticalEvasion }}%{% endif %} {% if character.magicEvasion is not null %}Esquive magique :{{ character.magicEvasion }}%{% endif %} {% if character.physicalCounter is not null %}Contre physique :{{ character.physicalCounter }}%{% endif %} {% if character.magicalCounter is not null %}Contre magique :{{ character.magicalCounter }}%{% endif %} {% if character.regenPv is not null %}Rég. PV :{{ character.regenPv > 0 ? '+' }}{{ character.regenPv }}%{% endif %} {% if character.regenEg is not null %}Rég. EG :{{ character.regenEg > 0 ? '+' }}{{ character.regenEg }}%{% endif %} {% if character.regenPower is not null %}Rég. {{ ('resource.tp.' ~ character.gameId)|trans({}, 'game') }} :{{ character.regenPower > 0 ? '+' }}{{ character.regenPower }}%{% endif %} {% if character.priority is not null %}Priorité :{{ character.priority }}{% endif %} {% if character.bonusHit is not null %}Bonus coup :{{ character.bonusHit }}{% endif %} {% if character.threat is not null %}Menace :×{{ character.threat }}{% endif %} {% if character.defenseRate is not null %}Taux défense :{{ character.defenseRate }}{% endif %} {% if character.regenRate is not null %}Taux rég. :{{ character.regenRate }}{% endif %} {% if character.healingRate is not null %}Taux soin :×{{ character.healingRate }}{% endif %} {% if character.egCost is not null %}Coût EG :×{{ character.egCost }}{% endif %} {% if character.powerGains is not null %}Gains {{ ('resource.tp.' ~ character.gameId)|trans({}, 'game') }} :×{{ character.powerGains }}{% endif %} {% if character.physicalTaken is not null %}Dég. phys. reçus :×{{ character.physicalTaken }}{% endif %} {% if character.magicalTaken is not null %}Dég. mag. reçus :×{{ character.magicalTaken }}{% endif %} {% if character.xpGain is not null %}Gain XP :×{{ character.xpGain }}{% endif %}
{% endif %} {# ── Boolean flags ── #} {% set flags = [] %} {% if character.bodyguard %}{% set flags = flags|merge(['Garde du corps']) %}{% endif %} {% if character.keepsPower %}{% set flags = flags|merge(['Conserve ' ~ ('resource.tp.' ~ character.gameId)|trans({}, 'game')]) %}{% endif %} {% if character.halfEncounters %}{% set flags = flags|merge(['Rencontres ÷2']) %}{% endif %} {% if character.noEncounters %}{% set flags = flags|merge(['Aucune rencontre']) %}{% endif %} {% if character.noSurprises %}{% set flags = flags|merge(['Pas de surprise']) %}{% endif %} {% if character.morePreventives %}{% set flags = flags|merge(['Plus de préventives']) %}{% endif %} {% if character.doubleMoney %}{% set flags = flags|merge(['Argent ×2']) %}{% endif %} {% if character.betterLoot %}{% set flags = flags|merge(['Meilleur butin']) %}{% endif %} {% if character.noSkills %}{% set flags = flags|merge(['Compétences désactivées']) %}{% endif %} {% if flags is not empty %}
Aptitudes passives
{% for flag in flags %} {{ flag }} {% endfor %}
{% endif %} {# ── Elemental types (not CSI Forever) ── #} {% if character.gameId != 0 and character.elementalTypes %}
Types élémentaux
{% for elementId in character.elementalTypes %} {% set e = elementMap[elementId] ?? null %} {% if e and e.iconUrl %}{% endif %} {{ e.name ?? '?' }} {% endfor %}
{% endif %} {# ── Weaknesses & Resistances (computed from elementalTypes × element_relation) ── #} {% if character.gameId != 0 and (weaknesses|length + resistances|length) > 0 %}
Résistances et faiblesses
{% if weaknesses|length > 0 %}
Faiblesses
    {% for atkId, mult in weaknesses %} {% set e = elementMap[atkId] ?? null %}
  • {% if e and e.iconUrl %} {% elseif e and e.color %} {% endif %} {{ e.name ?? '?' }} × {{ mult }}
  • {% endfor %}
{% endif %} {% if resistances|length > 0 %}
Résistances
    {% for atkId, mult in resistances %} {% set e = elementMap[atkId] ?? null %}
  • {% if e and e.iconUrl %} {% elseif e and e.color %} {% endif %} {{ e.name ?? '?' }} × {{ mult == 0 ? '0 (immunité)' : mult }}
  • {% endfor %}
{% endif %}
{% endif %} {# ── Elemental resistances ── #} {% if character.elementalResistance %}
Résistances élémentales
{% for entry in character.elementalResistance %} {% set res = ((entry.multiplier - 1) * 100)|round %} {{ elementMap[entry.element_id].name ?? '?' }} : {{ res > 0 ? '+' }}{{ res }}% {% endfor %}
{% endif %} {# ── Status immunities ── #} {% if character.statusImmunity %}
Immunités aux statuts
{% for statusId in character.statusImmunity %} {{ statusMap[statusId] ?? '?' }} {% endfor %}
{% endif %} {# ── Usable weapons ── #} {% if character.usableWeapons %}
Armes utilisables
{% for wtId in character.usableWeapons %} {{ weaponTypeMap[wtId] ?? '?' }} {% endfor %}
{% endif %} {# ── Usable armors ── #} {% if character.usableArmors %}
Armures utilisables
{% for atId in character.usableArmors %} {{ armorTypeMap[atId] ?? '?' }} {% endfor %}
{% endif %} {% if character.grantsSkills %}
Compétences accordées
{% for id in character.grantsSkills %} {{ skillMap[id] ?? '?' }} {% endfor %}
{% endif %} {# ── Spells learned on level-up ── #} {% if character.learnSpells %}
Sorts appris
{% for entry in character.learnSpells %} {% endfor %}
Niv.Sort
{{ entry.level }} {{ skillMap[entry.skillId] ?? '?' }}
{% endif %} {# ── Apprentissage par Atouts (Narval Souls) ── #} {% if character.learnByAtoutsSpells %}
Apprentissage par Atouts
{% for skillId in character.learnByAtoutsSpells %} {% endfor %}
Sort
{{ skillMap[skillId] ?? '?' }}
{% endif %}
{% endblock %}