Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ad4daf0b00 | ||
|
|
c96e8d69d7 | ||
|
|
282fb2794a | ||
|
|
46b9512256 | ||
|
|
8316112741 | ||
|
|
75f39551f8 | ||
|
|
ef76ae1116 |
+2
-1
@@ -34,7 +34,8 @@ module.exports = {
|
|||||||
Dialog: 'readonly',
|
Dialog: 'readonly',
|
||||||
foundry: 'readonly',
|
foundry: 'readonly',
|
||||||
Handlebars: 'readonly',
|
Handlebars: 'readonly',
|
||||||
renderTemplate: 'readonly'
|
renderTemplate: 'readonly',
|
||||||
|
fromUuid: 'readonly'
|
||||||
},
|
},
|
||||||
rules: {
|
rules: {
|
||||||
// Possible Problems
|
// Possible Problems
|
||||||
|
|||||||
@@ -376,6 +376,13 @@
|
|||||||
"evolution_dice": "Evolution dice",
|
"evolution_dice": "Evolution dice",
|
||||||
"open_experience_phase": "Experience phase",
|
"open_experience_phase": "Experience phase",
|
||||||
"open_learning": "Learning",
|
"open_learning": "Learning",
|
||||||
|
"validate_phase": "Validate phase",
|
||||||
|
"validate_phase_done": "Experience phase validated: learning limits reset.",
|
||||||
|
"error_not_editable": "You do not have permission to modify this element.",
|
||||||
|
"vehicle_assign": "Attach vehicle",
|
||||||
|
"vehicle_assign_confirm": "This vehicle already belongs to \"{group}\". Attach it to this group?",
|
||||||
|
"vehicle_assign_failed": "Could not attach this vehicle to the group.",
|
||||||
|
"vehicle_import_failed": "Could not import this vehicle from the compendium.",
|
||||||
"learning_limits": "Learning limits (per phase)",
|
"learning_limits": "Learning limits (per phase)",
|
||||||
"learned_skill": "Skill",
|
"learned_skill": "Skill",
|
||||||
"learned_specialty": "Specialty",
|
"learned_specialty": "Specialty",
|
||||||
|
|||||||
@@ -359,6 +359,13 @@
|
|||||||
"evolution_dice": "Dés d'Évolution",
|
"evolution_dice": "Dés d'Évolution",
|
||||||
"open_experience_phase": "Phase d'Expérience",
|
"open_experience_phase": "Phase d'Expérience",
|
||||||
"open_learning": "Apprentissage",
|
"open_learning": "Apprentissage",
|
||||||
|
"validate_phase": "Valider la phase",
|
||||||
|
"validate_phase_done": "Phase d'Expérience validée : limites d'apprentissage réinitialisées.",
|
||||||
|
"error_not_editable": "Vous n'avez pas la permission de modifier cet élément.",
|
||||||
|
"vehicle_assign": "Attacher le véhicule",
|
||||||
|
"vehicle_assign_confirm": "Ce véhicule appartient déjà à « {group} ». L'attacher à ce Groupe ?",
|
||||||
|
"vehicle_assign_failed": "Impossible d'attacher ce véhicule au Groupe.",
|
||||||
|
"vehicle_import_failed": "Impossible d'importer ce véhicule depuis le compendium.",
|
||||||
"learning_limits": "Limites d'apprentissage (par phase)",
|
"learning_limits": "Limites d'apprentissage (par phase)",
|
||||||
"learned_skill": "Compétence",
|
"learned_skill": "Compétence",
|
||||||
"learned_specialty": "Spécialité",
|
"learned_specialty": "Spécialité",
|
||||||
|
|||||||
@@ -368,6 +368,33 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fiche de Groupe : mêmes dés de Réserve cliquables (AppV2).
|
||||||
|
&.group div.hexa {
|
||||||
|
.hexa-style();
|
||||||
|
.transition();
|
||||||
|
margin: 0.2rem;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&:hover {
|
||||||
|
.hexa-style(rgba(255, 255, 255, 0.425), rgba(0, 0, 0, 0.288));
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
position: absolute;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
opacity: 0;
|
||||||
|
z-index: 1;
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.checked {
|
||||||
|
.hexa-style(rgb(0, 0, 0), rgba(0, 0, 0, 0.288));
|
||||||
|
&:hover { .hexa-style(rgb(43, 43, 43), rgba(0, 0, 0, 0.288)); }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.sheet-header-toggle {
|
.sheet-header-toggle {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
margin-bottom: 0.5rem;
|
margin-bottom: 0.5rem;
|
||||||
|
|||||||
@@ -42,7 +42,8 @@
|
|||||||
font-family: "DistressBlack", sans-serif;
|
font-family: "DistressBlack", sans-serif;
|
||||||
text-transform: uppercase;
|
text-transform: uppercase;
|
||||||
font-size: @font-size-12;
|
font-size: @font-size-12;
|
||||||
color: @color-amber;
|
// Brun foncé lisible sur le fond beige de la fiche (le jaune était illisible).
|
||||||
|
color: @color-chitin-dark;
|
||||||
margin: 8px 0 4px;
|
margin: 8px 0 4px;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
border-bottom: none;
|
border-bottom: none;
|
||||||
|
|||||||
@@ -18,6 +18,29 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Toggle « Chaman » de l'onglet Totem : ne pas étirer sur toute la largeur.
|
||||||
|
.chaman-toggle {
|
||||||
|
width: fit-content;
|
||||||
|
margin: 0.5rem auto;
|
||||||
|
gap: 0.5rem;
|
||||||
|
|
||||||
|
label {
|
||||||
|
font-family: "DistressBlack", sans-serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-size: @font-size-12;
|
||||||
|
color: @theme-color-dark;
|
||||||
|
cursor: pointer;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="checkbox"] {
|
||||||
|
width: 1rem;
|
||||||
|
height: 1rem;
|
||||||
|
margin: 0;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
div.minor-totems {
|
div.minor-totems {
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
|
|||||||
@@ -311,6 +311,11 @@ export default class VermineBaseActorSheet extends HandlebarsApplicationMixin(fo
|
|||||||
static #onClickRadioHexa(event, target) {
|
static #onClickRadioHexa(event, target) {
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
event.stopPropagation()
|
event.stopPropagation()
|
||||||
|
// Évite une erreur de permission pour un utilisateur non éditeur.
|
||||||
|
if (!this.isEditable) {
|
||||||
|
ui.notifications.warn(game.i18n.localize("VERMINE.error_not_editable"))
|
||||||
|
return
|
||||||
|
}
|
||||||
const input = target
|
const input = target
|
||||||
const update = {}
|
const update = {}
|
||||||
let current = this.document
|
let current = this.document
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ export default class VermineCharacterSheetV2 extends VermineBaseActorSheet {
|
|||||||
actions: {
|
actions: {
|
||||||
addSpecialty: VermineCharacterSheetV2.#onAddSpecialty,
|
addSpecialty: VermineCharacterSheetV2.#onAddSpecialty,
|
||||||
openExperiencePhase: VermineCharacterSheetV2.#onOpenExperiencePhase,
|
openExperiencePhase: VermineCharacterSheetV2.#onOpenExperiencePhase,
|
||||||
openLearning: VermineCharacterSheetV2.#onOpenLearning
|
openLearning: VermineCharacterSheetV2.#onOpenLearning,
|
||||||
|
validatePhase: VermineCharacterSheetV2.#onValidatePhase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -125,4 +126,11 @@ export default class VermineCharacterSheetV2 extends VermineBaseActorSheet {
|
|||||||
const dialog = await LearningDialog.create({ actorId: this.document.id })
|
const dialog = await LearningDialog.create({ actorId: this.document.id })
|
||||||
if (dialog) dialog.render(true)
|
if (dialog) dialog.render(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Valide la phase d'Expérience courante et réinitialise les limites. */
|
||||||
|
static async #onValidatePhase() {
|
||||||
|
const { VermineExperience } = await import("../../system/experience.mjs")
|
||||||
|
await VermineExperience.resetPhaseLimits(this.document)
|
||||||
|
ui.notifications.info(game.i18n.localize("VERMINE.validate_phase_done"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet {
|
|||||||
addObjective: VermineGroupSheetV2.#onAddObjective,
|
addObjective: VermineGroupSheetV2.#onAddObjective,
|
||||||
createTotemAbility: VermineGroupSheetV2.#onCreateTotemAbility,
|
createTotemAbility: VermineGroupSheetV2.#onCreateTotemAbility,
|
||||||
openLearning: VermineGroupSheetV2.#onOpenLearning,
|
openLearning: VermineGroupSheetV2.#onOpenLearning,
|
||||||
openExperiencePhase: VermineGroupSheetV2.#onOpenExperiencePhase
|
openExperiencePhase: VermineGroupSheetV2.#onOpenExperiencePhase,
|
||||||
|
validatePhase: VermineGroupSheetV2.#onValidatePhase
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -109,6 +110,50 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet {
|
|||||||
return game.actors.filter(a => a.type === "vehicle" && a.system.ownerId === this.document.id)
|
return game.actors.filter(a => a.type === "vehicle" && a.system.ownerId === this.document.id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dépôt d'un acteur Véhicule sur la fiche : lie le véhicule au Groupe
|
||||||
|
* (system.ownerId) au lieu de le dupliquer, puis affiche la liste.
|
||||||
|
* Gère les dépôts depuis un compendium (copie importée dans le monde)
|
||||||
|
* et demande confirmation si le véhicule appartient déjà à un autre Groupe.
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
async _onDropActor(event, data) {
|
||||||
|
let actor = data instanceof foundry.abstract.Document ? data : await fromUuid(data.uuid)
|
||||||
|
if (actor?.type !== "vehicle") {
|
||||||
|
return super._onDropActor?.(event, data)
|
||||||
|
}
|
||||||
|
// Véhicule issu d'un compendium : importer une copie dans le monde.
|
||||||
|
if (actor.compendium) {
|
||||||
|
try {
|
||||||
|
const copy = await game.actors.importFromCompendium(actor.compendium, actor._id, { renderSheet: false })
|
||||||
|
if (!copy) return
|
||||||
|
actor = copy
|
||||||
|
} catch {
|
||||||
|
ui.notifications.warn(game.i18n.localize("VERMINE.vehicle_import_failed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Véhicule déjà rattaché à un autre Groupe : confirmation avant transfert.
|
||||||
|
const currentOwner = actor.system?.ownerId
|
||||||
|
if (currentOwner && currentOwner !== this.document.id) {
|
||||||
|
const other = game.actors.get(currentOwner)
|
||||||
|
const content = game.i18n.localize("VERMINE.vehicle_assign_confirm").replace("{group}", other?.name ?? currentOwner)
|
||||||
|
const confirmed = await Dialog.confirm({
|
||||||
|
title: game.i18n.localize("VERMINE.vehicle_assign"),
|
||||||
|
content,
|
||||||
|
defaultYes: false
|
||||||
|
})
|
||||||
|
if (!confirmed) return
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await actor.update({ "system.ownerId": this.document.id })
|
||||||
|
} catch {
|
||||||
|
ui.notifications.warn(game.i18n.localize("VERMINE.vehicle_assign_failed"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.render()
|
||||||
|
}
|
||||||
|
|
||||||
// Actions : délégation aux applications AppV1 existantes pour TotemPicker/ActorPicker
|
// Actions : délégation aux applications AppV1 existantes pour TotemPicker/ActorPicker
|
||||||
static async #onChooseTotem(event, target) {
|
static async #onChooseTotem(event, target) {
|
||||||
const { TotemPicker } = await import("../../system/applications.mjs")
|
const { TotemPicker } = await import("../../system/applications.mjs")
|
||||||
@@ -172,4 +217,11 @@ export default class VermineGroupSheetV2 extends VermineBaseActorSheet {
|
|||||||
const dialog = await GroupLearningDialog.create({ actorId: this.document.id })
|
const dialog = await GroupLearningDialog.create({ actorId: this.document.id })
|
||||||
if (dialog) dialog.render(true)
|
if (dialog) dialog.render(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Valide la phase d'Expérience courante du Groupe et réinitialise les limites. */
|
||||||
|
static async #onValidatePhase() {
|
||||||
|
const { VermineExperience } = await import("../../system/experience.mjs")
|
||||||
|
await VermineExperience.resetPhaseLimits(this.document)
|
||||||
|
ui.notifications.info(game.i18n.localize("VERMINE.validate_phase_done"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -182,7 +182,9 @@ export default class LearningDialog extends HandlebarsApplicationMixin(foundry.a
|
|||||||
}
|
}
|
||||||
|
|
||||||
#getSpecialtyName() {
|
#getSpecialtyName() {
|
||||||
return this.#el.querySelector("#specialty-name")?.value?.trim() || game.i18n.localize("ITEMS.new_specialty");
|
// Le dialogue peut avoir été fermé pendant le jet (this.#el null).
|
||||||
|
const el = this.#el?.querySelector("#specialty-name");
|
||||||
|
return el?.value?.trim() || game.i18n.localize("ITEMS.new_specialty");
|
||||||
}
|
}
|
||||||
|
|
||||||
#compute() {
|
#compute() {
|
||||||
|
|||||||
@@ -213,4 +213,24 @@ export class VermineExperience {
|
|||||||
const preferred = actor.system?.skill_categories?.preferred
|
const preferred = actor.system?.skill_categories?.preferred
|
||||||
return Boolean(category && preferred && category === preferred)
|
return Boolean(category && preferred && category === preferred)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Réinitialise les limites d'apprentissage (learned.*) de la phase
|
||||||
|
* courante, pour un personnage ou un Groupe, sans toucher au compteur
|
||||||
|
* de phase (avancé uniquement par le dialogue d'attribution du MJ).
|
||||||
|
* @param {foundry.abstract.Document} actor personnage ou Groupe
|
||||||
|
* @returns {Promise<void>}
|
||||||
|
*/
|
||||||
|
static async resetPhaseLimits(actor) {
|
||||||
|
const ex = actor.system?.experience
|
||||||
|
if (!ex) return
|
||||||
|
const update = {}
|
||||||
|
if (ex.learned && typeof ex.learned === "object") {
|
||||||
|
for (const key of Object.keys(ex.learned)) {
|
||||||
|
if (key === "phase") continue
|
||||||
|
update[`system.experience.learned.${key}`] = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (Object.keys(update).length) await actor.update(update)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -25,6 +25,9 @@
|
|||||||
<button type="button" data-action="openLearning">
|
<button type="button" data-action="openLearning">
|
||||||
<i class="fas fa-graduation-cap"></i> {{ localize 'VERMINE.open_learning' }}
|
<i class="fas fa-graduation-cap"></i> {{ localize 'VERMINE.open_learning' }}
|
||||||
</button>
|
</button>
|
||||||
|
<button type="button" data-action="validatePhase">
|
||||||
|
<i class="fas fa-check"></i> {{ localize 'VERMINE.validate_phase' }}
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<section class="exp-rewards">
|
<section class="exp-rewards">
|
||||||
|
|||||||
@@ -1,6 +1,14 @@
|
|||||||
<div class="tab gear sheet-part {{#if @root.tabs.gear.active}}active{{/if}}" data-group="sheet" data-tab="gear">
|
<div class="tab gear sheet-part {{#if @root.tabs.gear.active}}active{{/if}}" data-group="sheet" data-tab="gear">
|
||||||
<div class="grid grid-2col">
|
<div class="weapons">
|
||||||
<div>
|
<h4>{{localize 'ITEMS.weapons'}}</h4>
|
||||||
|
{{> "systems/vermine2047/templates/actor/parts/actor-weapons.hbs"}}
|
||||||
|
</div>
|
||||||
|
<div class="protections">
|
||||||
|
<h4>{{localize 'ITEMS.defenses'}}</h4>
|
||||||
|
{{> "systems/vermine2047/templates/actor/parts/actor-defenses.hbs"}}
|
||||||
|
</div>
|
||||||
|
<div class="objects">
|
||||||
|
<h4>{{localize 'ITEMS.items'}}</h4>
|
||||||
<ol class="items-list">
|
<ol class="items-list">
|
||||||
<li class="item flexrow items-header">
|
<li class="item flexrow items-header">
|
||||||
<div class="item-name" style="flex:4;">{{ localize 'IDENTITY.name'}}</div>
|
<div class="item-name" style="flex:4;">{{ localize 'IDENTITY.name'}}</div>
|
||||||
@@ -31,15 +39,12 @@
|
|||||||
{{/each}}
|
{{/each}}
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div class="vehicles">
|
||||||
|
<h4>{{localize 'ITEMS.vehicles'}}</h4>
|
||||||
|
{{> "systems/vermine2047/templates/actor/group/group-vehicles.hbs"}}
|
||||||
|
</div>
|
||||||
|
<div class="equipment-notes">
|
||||||
<h4>{{ localize 'IDENTITY.notes'}}</h4>
|
<h4>{{ localize 'IDENTITY.notes'}}</h4>
|
||||||
{{formInput systemFields.equipment.fields.description enriched=enrichedEquipmentNotes value=system.equipment.description name="system.equipment.description" toggled=true}}
|
{{formInput systemFields.equipment.fields.description enriched=enrichedEquipmentNotes value=system.equipment.description name="system.equipment.description" toggled=true}}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
<h4>{{localize 'ITEMS.weapons'}}</h4>
|
|
||||||
{{> "systems/vermine2047/templates/actor/parts/actor-weapons.hbs"}}
|
|
||||||
<h4>{{localize 'ITEMS.defenses'}}</h4>
|
|
||||||
{{> "systems/vermine2047/templates/actor/parts/actor-defenses.hbs"}}
|
|
||||||
<h4>{{localize 'ITEMS.vehicles'}}</h4>
|
|
||||||
{{> "systems/vermine2047/templates/actor/group/group-vehicles.hbs"}}
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -13,6 +13,13 @@
|
|||||||
{{/if}}
|
{{/if}}
|
||||||
<span>/ {{system.reserve.max}}D</span>
|
<span>/ {{system.reserve.max}}D</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="reserve-dice flexrow">
|
||||||
|
{{#repeat system.reserve.max 1 "d"}}
|
||||||
|
<div class="hexa {{#iflteq @d @root.system.reserve.value}}checked{{/iflteq}}">
|
||||||
|
<input type="radio" data-dtype="Number" name="system.reserve.value" value="{{@d}}" data-action="clickRadio" />
|
||||||
|
</div>
|
||||||
|
{{/repeat}}
|
||||||
|
</div>
|
||||||
<div class="morale-control flexrow flex-group-center">
|
<div class="morale-control flexrow flex-group-center">
|
||||||
<label>{{ localize 'VERMINE.morale' }}:</label>
|
<label>{{ localize 'VERMINE.morale' }}:</label>
|
||||||
{{#if isEditMode}}
|
{{#if isEditMode}}
|
||||||
@@ -46,6 +53,7 @@
|
|||||||
<div class="group-experience-actions flexrow flex-group-center">
|
<div class="group-experience-actions flexrow flex-group-center">
|
||||||
<button type="button" data-action="openLearning"><i class="fas fa-graduation-cap"></i> {{ localize 'VERMINE.open_learning' }}</button>
|
<button type="button" data-action="openLearning"><i class="fas fa-graduation-cap"></i> {{ localize 'VERMINE.open_learning' }}</button>
|
||||||
<button type="button" data-action="openExperiencePhase"><i class="fas fa-star"></i> {{ localize 'VERMINE.experience_phase' }}</button>
|
<button type="button" data-action="openExperiencePhase"><i class="fas fa-star"></i> {{ localize 'VERMINE.experience_phase' }}</button>
|
||||||
|
<button type="button" data-action="validatePhase"><i class="fas fa-check"></i> {{ localize 'VERMINE.validate_phase' }}</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user