fix: Correct critical bugs and complete Creature/Group DataModel implementation

- Fix TypeError: controls.find is not a function in hooks.mjs
- Fix undefined 'npc' variable in applications.mjs
- Fix CONFIG.VERMINE.model undefined by checking game.system.template existence
- Fix TypeError: html.find(...).forEach is not a function in roll.mjs
- Fix Cannot set properties of undefined (setting 'initial') in actor.mjs
- Fix Cannot read properties of undefined (reading 'difficulty') in actor.mjs
- Fix ActiveEffect application phase 'initial' already completed by adding combatStatus to base template
- Fix Missing helper: 'select' in roll-dialog.hbs (removed invalid Handlebars select block)
- Add SIZE_LEVELS labels to creatureSizeLevels config
- Add SIZE_LEVELS translations to fr.json
- Add combatStatus to base actor template
- Convert all .html templates to .hbs for Foundry v14 compatibility
- Update item-sheet.mjs to use .hbs extension
- Update handlebars-manager.mjs to use .hbs for all partials

Complete Vermine2047 Creature and Group sheet implementation:
- Creature: Pattern, Size, Role, Pack with computed values
- Group: Totem, Reserve, Morale, Objectives, Members management
- All templates functional with proper styling

Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
This commit is contained in:
2026-06-04 20:58:22 +02:00
parent f9f07cbc7e
commit 30d6f71fc7
43 changed files with 19225 additions and 609 deletions
+142 -59
View File
@@ -1,88 +1,171 @@
<div class="grid grid-2col">
<div class="grid grid-2col">
{{!-- Group Reserve and Morale --}}
<div class="grid-span-2">
<h4 class="align-center">{{ localize 'VERMINE.reserve' }}</h4>
<div class="reserve-control flexrow flex-group-center">
<label>{{ localize 'VERMINE.pool' }}:</label>
<input type="number" name="system.reserve.value" value="{{system.reserve.value}}"
data-dtype="Number" min="{{system.reserve.min}}" max="{{system.reserve.max}}" />
<span>/ {{system.reserve.max}}D</span>
</div>
<div class="morale-control flexrow flex-group-center">
<label>{{ localize 'VERMINE.morale' }}:</label>
<select name="system.morale.level">
<option value="high" {{#if (eq system.morale.level "high")}}selected{{/if}}>{{ localize 'VERMINE.morale_high' }}</option>
<option value="normal" {{#if (eq system.morale.level "normal")}}selected{{/if}}>{{ localize 'VERMINE.morale_normal' }}</option>
<option value="low" {{#if (eq system.morale.level "low")}}selected{{/if}}>{{ localize 'VERMINE.morale_low' }}</option>
<option value="crisis" {{#if (eq system.morale.level "crisis")}}selected{{/if}}>{{ localize 'VERMINE.morale_crisis' }}</option>
</select>
<input type="number" name="system.morale.value" value="{{system.morale.value}}"
data-dtype="Number" min="{{system.morale.min}}" max="{{system.morale.max}}" />
<span>/ {{system.morale.max}}D</span>
</div>
</div>
{{!-- Group Members --}}
<div>
<h4 class="align-center">
<span>{{ localize 'VERMINE.group_members'}}</span>
<a class="item-control chooseActor" title="Add member"
data-type="members"><i class="fas fa-plus"></i></a>
<span>{{ localize 'VERMINE.group_members' }}</span>
<a class="item-control chooseActor" title="{{ localize 'UI.add' }}"
data-type="members"><i class="fas fa-plus"></i></a>
</h4>
<ol class="actor-list">
{{#each members as |actor id|}}
{{log actor}}
<li class="actor flexrow" data-actor-id="{{actor._id}}">
<div class="actor-name" style="flex:4;">
<a class="item-control">{{actor.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control member-delete" title="Delete Member"><i
class="fas fa-trash"></i></a>
</div>
</li>
{{#each system.members as |memberId|}}
{{#with (lookup ../resolvedMembers memberId) as |member|}}
<li class="actor flexrow" data-actor-id="{{memberId}}">
<div class="actor-name" style="flex:4;">
{{#if member}}
<a class="item-control">{{member.name}}</a>
{{else}}
<a class="item-control" style="color: red;">ID: {{memberId}}</a>
{{/if}}
</div>
<div class="item-controls flexrow">
<a class="item-control member-delete" title="{{ localize 'UI.effect_delete' }}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/with}}
{{/each}}
</ol>
</div>
{{!-- Group Encounters --}}
<div>
<h4 class="align-center">
<span>{{ localize 'VERMINE.encounters'}}</span>
<a class="item-control chooseActor" title="Add member"
data-type="encounters"><i class="fas fa-plus"></i></a>
<span>{{ localize 'VERMINE.encounters' }}</span>
<a class="item-control chooseActor" title="{{ localize 'UI.add' }}"
data-type="encounters"><i class="fas fa-plus"></i></a>
</h4>
<ol class="actor-list">
{{#each encounters as |actor id|}}
<li class="actor flexrow" data-actor-id="{{actor._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control">{{actor.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control encounter-delete" title="Delete Encounter"><i
class="fas fa-trash"></i></a>
</div>
</li>
{{#each system.encounters as |encounterId|}}
{{#with (lookup ../resolvedEncounters encounterId) as |encounter|}}
<li class="actor flexrow" data-actor-id="{{encounterId}}">
<div class="item-name" style="flex:4;">
{{#if encounter}}
<a class="item-control">{{encounter.name}}</a>
{{else}}
<a class="item-control" style="color: red;">ID: {{encounterId}}</a>
{{/if}}
</div>
<div class="item-controls flexrow">
<a class="item-control encounter-delete" title="{{ localize 'UI.effect_delete' }}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/with}}
{{/each}}
</ol>
</div>
<div>
{{!-- Group Objectives --}}
<div class="grid-span-2">
<h4 class="align-center">{{ localize 'VERMINE.objectives' }}</h4>
<div>
<h5>{{ localize 'VERMINE.major_objectives' }}</h5>
<ol class="list-item">
{{#each system.objectives.major as |objective id|}}
<li class="item flexrow" data-index="{{id}}">
<div class="item-name" style="flex:4;">
<input type="text" name="system.objectives.major.{{id}}" value="{{objective}}"
placeholder="Objectif majeur..." />
</div>
<div class="item-controls flexrow">
<a class="item-control objective-delete" title="{{ localize 'UI.effect_delete' }}"
data-type="major" data-index="{{id}}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
<a class="item-control item-create" title="{{ localize 'UI.add' }}"
data-type="major_objective"><i class="fas fa-plus"></i> {{ localize 'ITEMS.new_objective' }}</a>
</div>
<div>
<h5>{{ localize 'VERMINE.minor_objectives' }}</h5>
<ol class="list-item">
{{#each system.objectives.minor as |objective id|}}
<li class="item flexrow" data-index="{{id}}">
<div class="item-name" style="flex:4;">
<input type="text" name="system.objectives.minor.{{id}}" value="{{objective}}"
placeholder="Objectif mineur..." />
</div>
<div class="item-controls flexrow">
<a class="item-control objective-delete" title="{{ localize 'UI.effect_delete' }}"
data-type="minor" data-index="{{id}}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
<a class="item-control item-create" title="{{ localize 'UI.add' }}"
data-type="minor_objective"><i class="fas fa-plus"></i> {{ localize 'ITEMS.new_objective' }}</a>
</div>
</div>
{{!-- Group Abilities --}}
<div class="grid-span-2">
<h4 class="align-center">
<span>{{ localize 'VERMINE.boost'}}</span>
<a class="item-control chooseActor" title="Add encounter"
data-type="npc"><i class="fas fa-plus"></i></a>
<span>{{ localize 'VERMINE.group_abilities' }}</span>
<a class="item-control item-create" title="{{ localize 'ITEMS.new_ability' }}"
data-type="ability"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each abilities as |item id|}}
{{#if (ne item.type 'totem')}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="Edit Item">{{item.name}}</a>
<a class="item-control item-edit" title="{{ localize 'UI.effect_edit' }}">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="Delete Item"><i
class="fas fa-trash"></i></a>
<a class="item-control item-delete" title="{{ localize 'UI.effect_delete' }}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/if}}
{{/each}}
</ol>
</div>
<div>
<h4 class="align-center">
<span>{{ localize 'VERMINE.totem_abilities'}}</span>
<a class="item-control item-create" title="Create item"
data-type="ability"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each totem_abilities as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="Edit Item">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="Delete Item"><i
class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
<div>
<h4 class="align-center">
{{ localize 'VERMINE.pool' }}
</h4>
{{!-- Totem Section --}}
<div class="grid-span-2">
<h4 class="align-center">{{ localize 'IDENTITY.totem' }}</h4>
<div class="flexrow flex-group-center">
<label>{{ localize 'IDENTITY.instincts' }}:</label>
<input type="text" name="system.identity.instincts" value="{{system.identity.instincts}}"
placeholder="Ex: Triompher, relever un défi..." />
</div>
<div class="flexrow flex-group-center">
<label>{{ localize 'IDENTITY.prohibits' }}:</label>
<input type="text" name="system.identity.prohibits" value="{{system.identity.prohibits}}"
placeholder="Ex: Fuir, abandonner..." />
</div>
<div class="flexrow flex-group-center">
{{#if (eq system.identity.totem "")}}
<a name="chooseTotem" class="chooseTotem">{{ localize 'VERMINE.totem_picker' }}</a>
{{else}}
<div class="totem-display flexrow">
<span style="flex: 1;">{{ smarttl "TOTEMS" system.identity.totem }}</span>
<a name="chooseTotem" class="chooseTotem">{{ localize 'UI.effect_edit' }}</a>
</div>
{{/if}}
</div>
</div>
</div>
+13 -26
View File
@@ -8,47 +8,34 @@
<h1 class="char-name flexrow flex-group-left w-full">
<label>{{ localize 'IDENTITY.name' }}</label>
<input name="name" type="text" value="{{actor.name}}"
placeholder="{{localize "VERMINE.GroupNamePlaceholder"}}" />
placeholder="Nom du groupe" />
</h1>
<div class="profile flexrow flex-group-center">
<label>{{ localize 'IDENTITY.profile' }}</label>
<input name="system.identity.profile" type="text"
value="{{system.identity.profile }}" data-dtype="String" />
</div>
<div class="flexrow flex-group-center w-full">
<label for="system.identity.age">{{ localize 'IDENTITY.morale'
}}</label>
<div class="flexrow row">
<input type="number" name="system.identity.age"
value="{{ system.morale.value }}" data-dtype="Number"
max="7" min="1" />
<span id="moraleLevel">({{ system.morale.level }})</span>
</div>
value="{{system.identity.profile}}" data-dtype="String" />
</div>
</section>
<section class="char-level grid-span-5">
<h1 class="char-vermine2047 flexrow flex-group-left w-full">
<label for="system.identity.totem">{{ localize 'IDENTITY.totem'
}}</label>
<label for="system.identity.totem">{{ localize 'IDENTITY.totem' }}</label>
{{#if (eq system.identity.totem "")}}
<a name="chooseTotem" class="chooseTotem">Choisissez&hellip;</a>
{{ else }}
<a name="chooseTotem" class="chooseTotem">{{ smarttl "TOTEMS"
system.identity.totem }}</a>
<a name="chooseTotem" class="chooseTotem">{{ smarttl "TOTEMS" system.identity.totem }}</a>
{{/if}}
</h1>
<div class="level flexrow flex-group-center">
<label>{{ localize 'VERMINE.level' }}</label>
<input name="system.level.value" type="number"
value="{{system.level.value}}" data-dtype="Number" min="{{system.level.min}}" max="{{system.level.max}}" />
<span>/ {{system.level.max}}</span>
</div>
<div class="reputation flexrow flex-group-center">
<label>{{ localize 'VERMINE.reputation' }}</label>
<input name="system.reputation.value" type="number"
value="{{system.reputation.value }}" data-dtype="Number" min="2"
max="10" />
<img src="{{totem}}" alt>
</div>
<div class="experience flexrow flex-group-center">
<label>{{ localize 'VERMINE.level' }}</label>
<input name="system.level.value" type="number"
value="{{system.level.value }}" data-dtype="Number" min="0"
max="3" />
value="{{system.reputation.value}}" data-dtype="Number" min="{{system.reputation.min}}" max="{{system.reputation.max}}" />
<span>/ {{system.reputation.max}}</span>
</div>
</section>
</header>
</header>
+150 -94
View File
@@ -1,96 +1,152 @@
<div class="grid grid-2col">
<div>
<h4>
<span>{{ localize 'ITEMS.abilities'}}</span>
<a class="item-control item-create" title="Create item" data-type="ability"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each abilities as |item id|}}
{{#if (ne item.type 'totem')}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="Edit Item">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/if}}
{{/each}}
</ol>
</div>
<div>
<h4>
<span>{{ localize 'ITEMS.specialties'}}</span>
<a class="item-control item-create" title="Create item" data-type="specialty"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each specialties as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="Edit Item">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
<div>
<h4>
<span>{{ localize 'ITEMS.backgrounds'}}</span>
<a class="item-control item-create" title="Create item" data-type="background"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each backgrounds as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="Edit Item">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
<div>
<h4>
<span>{{ localize 'ITEMS.traumas'}}</span>
<a class="item-control item-create" title="Create item" data-type="trauma"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each traumas as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="Edit Item">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
<div>
<h4>
<span>{{ localize 'ITEMS.evolutions'}}</span>
<a class="item-control item-create" title="Create item" data-type="evolution"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each evolutions as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="Edit Item">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="Delete Item"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
<div class="grid grid-2col">
{{!-- Group Identity --}}
<div>
<h4>{{ localize 'IDENTITY.profile' }}</h4>
<div class="flexrow flex-group-center">
<input type="text" name="system.identity.profile" value="{{system.identity.profile}}"
placeholder="Profil du groupe..." style="flex: 1;" />
</div>
</div>
<div>
<h4>{{ localize 'IDENTITY.origin' }}</h4>
<div class="flexrow flex-group-center">
<input type="text" name="system.identity.origin" value="{{system.identity.origin}}"
placeholder="Origine..." style="flex: 1;" />
</div>
</div>
<div>
<h4>{{ localize 'IDENTITY.theme' }}</h4>
<div class="flexrow flex-group-center">
<input type="text" name="system.identity.theme" value="{{system.identity.theme}}"
placeholder="Concept..." style="flex: 1;" />
</div>
</div>
<div>
<h4>{{ localize 'VERMINE.level' }}</h4>
<div class="flexrow flex-group-center">
<input type="number" name="system.level.value" value="{{system.level.value}}"
data-dtype="Number" min="{{system.level.min}}" max="{{system.level.max}}" />
<span>/ {{system.level.max}}</span>
</div>
</div>
<div>
<h4>{{ localize 'VERMINE.reputation' }}</h4>
<div class="flexrow flex-group-center">
<input type="number" name="system.reputation.value" value="{{system.reputation.value}}"
data-dtype="Number" min="{{system.reputation.min}}" max="{{system.reputation.max}}" />
<span>/ {{system.reputation.max}}</span>
</div>
</div>
{{!-- Group Notes --}}
<div class="grid-span-2">
<h4>{{ localize 'IDENTITY.notes' }}</h4>
{{editor system.identity.notes target="system.identity.notes" button=true owner=owner editable=editable}}
</div>
{{!-- Group Abilities (from items) --}}
<div class="grid-span-2">
<h4>
<span>{{ localize 'VERMINE.abilities' }}</span>
<a class="item-control item-create" title="{{ localize 'ITEMS.new_ability' }}" data-type="ability"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each abilities as |item id|}}
{{#if (ne item.type 'totem')}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="{{ localize 'UI.effect_edit' }}">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="{{ localize 'UI.effect_delete' }}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/if}}
{{/each}}
</ol>
</div>
{{!-- Specialties --}}
<div>
<h4>
<span>{{ localize 'ITEMS.specialties' }}</span>
<a class="item-control item-create" title="{{ localize 'ITEMS.new_specialty' }}" data-type="specialty"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each specialties as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="{{ localize 'UI.effect_edit' }}">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="{{ localize 'UI.effect_delete' }}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
{{!-- Backgrounds --}}
<div>
<h4>
<span>{{ localize 'ITEMS.backgrounds' }}</span>
<a class="item-control item-create" title="{{ localize 'ITEMS.new_background' }}" data-type="background"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each backgrounds as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="{{ localize 'UI.effect_edit' }}">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="{{ localize 'UI.effect_delete' }}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
{{!-- Traumas --}}
<div>
<h4>
<span>{{ localize 'ITEMS.traumas' }}</span>
<a class="item-control item-create" title="{{ localize 'ITEMS.new_trauma' }}" data-type="trauma"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each traumas as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="{{ localize 'UI.effect_edit' }}">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="{{ localize 'UI.effect_delete' }}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
{{!-- Evolutions --}}
<div>
<h4>
<span>{{ localize 'ITEMS.evolutions' }}</span>
<a class="item-control item-create" title="{{ localize 'ITEMS.new_evolution' }}" data-type="evolution"><i class="fas fa-plus"></i></a>
</h4>
<ol class="list-item">
{{#each evolutions as |item id|}}
<li class="item flexrow" data-item-id="{{item._id}}">
<div class="item-name" style="flex:4;">
<a class="item-control item-edit" title="{{ localize 'UI.effect_edit' }}">{{item.name}}</a>
</div>
<div class="item-controls flexrow">
<a class="item-control item-delete" title="{{ localize 'UI.effect_delete' }}"><i class="fas fa-trash"></i></a>
</div>
</li>
{{/each}}
</ol>
</div>
</div>