fix: Dice So Nice import v14 compat, override Foundry text colors for readability
Release Creation / build (release) Failing after 1m28s
Release Creation / build (release) Failing after 1m28s
- hooks.mjs: replace static dice-so-nice import with dynamic import
using game.modules.get('dice-so-nice').id (path removed in v14)
- hooks.mjs: fix permission condition (|| -> &&), jQuery -> vanilla JS
- less/base.less: override --color-text-* and --button-text-color
for both .themed.theme-dark (AppV2) and body.theme-dark (legacy apps)
- target #settings-config buttons + labels + hints for dark grays
This commit is contained in:
+101
-114
@@ -1,5 +1,4 @@
|
||||
export class TotemPicker extends Application {
|
||||
|
||||
export class TotemPicker extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
|
||||
constructor(linkEl, actor) {
|
||||
super();
|
||||
@@ -7,45 +6,39 @@ export class TotemPicker extends Application {
|
||||
this.actor = actor;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
static get DEFAULT_OPTIONS() {
|
||||
return {
|
||||
id: "TOTEM_PICKER",
|
||||
title: game.i18n.localize("VERMINE.totem_picker"),
|
||||
template: 'systems/vermine2047/templates/applications/choose-totem.hbs',
|
||||
popOut: true,
|
||||
resizable: true,
|
||||
height: "800",
|
||||
width: "800"
|
||||
});
|
||||
position: { width: 800, height: 800 },
|
||||
window: { title: game.i18n.localize("VERMINE.totem_picker"), resizable: true }
|
||||
};
|
||||
}
|
||||
|
||||
getData() {
|
||||
// Send data to the template
|
||||
return {
|
||||
config: CONFIG.VERMINE,
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: 'systems/vermine2047/templates/applications/choose-totem.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
_prepareContext() {
|
||||
return { config: CONFIG.VERMINE };
|
||||
}
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
html.find('.totem').click(event => {
|
||||
const totem = $(event.target).parent('a').data('totem');
|
||||
if (totem != null) {
|
||||
this.actor.update({ 'system.identity.totem': totem });
|
||||
}
|
||||
this.close();
|
||||
html.querySelectorAll('.totem').forEach(el => {
|
||||
el.addEventListener('click', event => {
|
||||
const link = event.target.closest('a');
|
||||
if (!link?.dataset.totem) return;
|
||||
this.actor.update({ 'system.identity.totem': link.dataset.totem });
|
||||
this.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/*async _updateObject(event, formData) {
|
||||
// console.log(formData.exampleInput);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
export class ActorPicker extends Application {
|
||||
|
||||
export class ActorPicker extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
|
||||
constructor(linkEl, actor) {
|
||||
super();
|
||||
@@ -53,152 +46,146 @@ export class ActorPicker extends Application {
|
||||
this.actor = actor;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
static get DEFAULT_OPTIONS() {
|
||||
return {
|
||||
id: "ACTOR_PICKER",
|
||||
title: game.i18n.localize("VERMINE.actor_picker"),
|
||||
template: 'systems/vermine2047/templates/applications/choose-actor.hbs',
|
||||
popOut: true,
|
||||
resizable: true,
|
||||
height: "350",
|
||||
width: "600"
|
||||
});
|
||||
position: { width: 600, height: 350 },
|
||||
window: { title: game.i18n.localize("VERMINE.actor_picker"), resizable: true }
|
||||
};
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: 'systems/vermine2047/templates/applications/choose-actor.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
getData() {
|
||||
// Send data to the template
|
||||
_prepareContext() {
|
||||
const npcs = game.actors.filter(a => a.type == "npc");
|
||||
const characters = game.actors.filter(a => a.type == "character");
|
||||
const all = game.actors.filter(a => a.type == "npc" || a.type == 'character');
|
||||
const type = $(this.linkEl).data('type');
|
||||
const type = this.linkEl.dataset.type;
|
||||
|
||||
let actorsList = [];
|
||||
if (type == 'members') {
|
||||
actorsList = characters;
|
||||
} else if (type == 'relations') {
|
||||
actorsList = npcs;//[...npcs, ...characters];
|
||||
actorsList = npcs;
|
||||
} else {
|
||||
actorsList = all;
|
||||
}
|
||||
return {
|
||||
config: CONFIG.VERMINE,
|
||||
actorsList: actorsList
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
async activateListeners(html) {
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
html.find('.actor').click(async (event) => {
|
||||
const actorId = $(event.target).parent('div').data('actor-id');
|
||||
const type = $(this.linkEl).data('type');
|
||||
|
||||
if (!actorId) return;
|
||||
|
||||
let actorsList = [];
|
||||
html.querySelectorAll('.actor').forEach(el => {
|
||||
el.addEventListener('click', async event => {
|
||||
const div = event.target.closest('div');
|
||||
const actorId = div?.dataset.actorId;
|
||||
const type = this.linkEl.dataset.type;
|
||||
if (!actorId) return;
|
||||
|
||||
if (type == 'members') {
|
||||
actorsList = foundry.utils.duplicate(this.actor.system.members || []);
|
||||
} else if (type == 'encounters') {
|
||||
actorsList = foundry.utils.duplicate(this.actor.system.encounters || []);
|
||||
}
|
||||
|
||||
if (!Array.isArray(actorsList)) {
|
||||
actorsList = [];
|
||||
}
|
||||
let actorsList = [];
|
||||
|
||||
// Add actor if not already present
|
||||
if (!actorsList.includes(actorId)) {
|
||||
actorsList.push(actorId);
|
||||
}
|
||||
if (type == 'members') {
|
||||
actorsList = foundry.utils.duplicate(this.actor.system.members || []);
|
||||
} else if (type == 'encounters') {
|
||||
actorsList = foundry.utils.duplicate(this.actor.system.encounters || []);
|
||||
}
|
||||
|
||||
if (type == 'members') {
|
||||
await this.actor.update({ 'system.members': actorsList });
|
||||
} else if (type == 'encounters') {
|
||||
await this.actor.update({ 'system.encounters': actorsList });
|
||||
}
|
||||
|
||||
this.close();
|
||||
if (!Array.isArray(actorsList)) {
|
||||
actorsList = [];
|
||||
}
|
||||
|
||||
if (!actorsList.includes(actorId)) {
|
||||
actorsList.push(actorId);
|
||||
}
|
||||
|
||||
if (type == 'members') {
|
||||
await this.actor.update({ 'system.members': actorsList });
|
||||
} else if (type == 'encounters') {
|
||||
await this.actor.update({ 'system.encounters': actorsList });
|
||||
}
|
||||
|
||||
this.close();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
export class TraitSelector extends Application {
|
||||
export class TraitSelector extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
|
||||
constructor(targetItem) {
|
||||
super();
|
||||
this.targetItem = targetItem;
|
||||
this.traits = CONFIG.VERMINE.traits
|
||||
this.traits = CONFIG.VERMINE.traits;
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static get defaultOptions() {
|
||||
return foundry.utils.mergeObject(super.defaultOptions, {
|
||||
classes: ["vermine2047", "trait-selector"],
|
||||
title: game.i18n.localize("VERMINE.traits_selector"),
|
||||
template: 'systems/vermine2047/templates/applications/choose-traits.hbs',
|
||||
popOut: true,
|
||||
resizable: true,
|
||||
height: "500",
|
||||
width: "500"
|
||||
});
|
||||
static get DEFAULT_OPTIONS() {
|
||||
return {
|
||||
id: "TRAIT_SELECTOR",
|
||||
position: { width: 500, height: 500 },
|
||||
window: { title: game.i18n.localize("VERMINE.traits_selector"), resizable: true },
|
||||
classes: ["vermine2047", "trait-selector"]
|
||||
};
|
||||
}
|
||||
getData() {
|
||||
|
||||
static PARTS = {
|
||||
main: {
|
||||
template: 'systems/vermine2047/templates/applications/choose-traits.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
_prepareContext() {
|
||||
return {
|
||||
traits: this.traits,
|
||||
item: this.targetItem
|
||||
}
|
||||
};
|
||||
}
|
||||
async activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.validateTraits(html);
|
||||
html.find('input').change(ev => {
|
||||
this.onChangeInput(ev)
|
||||
})
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this._validateTraits(html);
|
||||
html.querySelectorAll('input').forEach(el => {
|
||||
el.addEventListener('change', ev => this._onChangeInput(ev));
|
||||
});
|
||||
}
|
||||
async validateTraits(html) {
|
||||
let checks = html.find("input.trait-selector");
|
||||
for (let inp of checks) {
|
||||
|
||||
async _validateTraits(html) {
|
||||
const checks = html.querySelectorAll("input.trait-selector");
|
||||
for (const inp of checks) {
|
||||
if (this.targetItem.system.traits[inp.dataset.trait]) {
|
||||
if (inp.type == "checkbox") {
|
||||
inp.checked = true
|
||||
inp.checked = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
await this.render(true)
|
||||
await this.render(true);
|
||||
}
|
||||
|
||||
async onChangeInput(ev) {
|
||||
let el = ev.currentTarget;
|
||||
|
||||
let traitKey = el.dataset.trait; // Récupère la clé du trait à partir de l'attribut data-trait
|
||||
let traitValue = parseInt(el.value) || null
|
||||
let traits = this.targetItem.system.traits || {}; // Récupère les traits actuels, ou un objet vide si aucun trait n'est défini
|
||||
|
||||
|
||||
console.log(traitKey, traitValue, traits)
|
||||
async _onChangeInput(ev) {
|
||||
const el = ev.currentTarget;
|
||||
const traitKey = el.dataset.trait;
|
||||
const traitValue = parseInt(el.value) || null;
|
||||
const traits = this.targetItem.system.traits || {};
|
||||
|
||||
if (el.classList.contains('trait-selector')) {
|
||||
if (!traits[traitKey]) {
|
||||
// Si la case est cochée, ajoute le trait
|
||||
await this.targetItem.update({ [`system.traits.${traitKey}`]: this.traits[traitKey] });
|
||||
} else {
|
||||
// Si la case est décochée, retire le trait
|
||||
await this.targetItem.update({ [`system.traits.${traitKey}`]: null });
|
||||
}
|
||||
}
|
||||
if (traitValue) {
|
||||
console.log(el.value)
|
||||
// Logique pour les valeurs des traits si nécessaire
|
||||
el.closest("label").querySelector('.trait-selector').checked = true;
|
||||
} else {
|
||||
el.closest("label").querySelector('.trait-selector').checked = false;
|
||||
}
|
||||
this.render(true)
|
||||
this.render(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+43
-40
@@ -26,46 +26,6 @@ VERMINE.DifficultyLevels = {
|
||||
3: { "label": "DIFFICULTY_LEVELS.hard", "difficulty": 7 },
|
||||
4: { "label": "DIFFICULTY_LEVELS.very_hard", "difficulty": 9 },
|
||||
5: { "label": "DIFFICULTY_LEVELS.impossible", "difficulty": 10 }
|
||||
},
|
||||
|
||||
VERMINE.ThreatLevels = {
|
||||
1: { "label": "THREAT_LEVELS.minor", "attack": 3, "vigor": 1, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 },
|
||||
2: { "label": "THREAT_LEVELS.serious", "attack": 4, "vigor": 2, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 },
|
||||
3: { "label": "THREAT_LEVELS.major", "attack": 5, "vigor": 3, "minorWound": 2, "majorWound": 1, "deadlyWound": 1 },
|
||||
4: { "label": "THREAT_LEVELS.deadly", "attack": 6, "vigor": 4, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 },
|
||||
}
|
||||
|
||||
VERMINE.ExperienceLevels = {
|
||||
1: { "label": "SKILL_LEVELS.beginner", "action": 3, "specialties": 4, "rerolls": 0, "contact": "7" },
|
||||
2: { "label": "SKILL_LEVELS.proficient", "action": 3, "specialties": 5, "rerolls": 0, "contact": "5 ou 7" },
|
||||
3: { "label": "SKILL_LEVELS.expert", "action": 4, "specialties": 6, "rerolls": 1, "contact": "5,7 ou 9" },
|
||||
4: { "label": "SKILL_LEVELS.master", "action": 4, "specialties": 6, "rerolls": 2, "contact": "3,5,7 ou 9" },
|
||||
}
|
||||
|
||||
VERMINE.RoleLevels = {
|
||||
1: { "label": "ROLE_LEVELS.minor", "reaction": 3, "reaction_bonus": 0, "pools": 0, "gear": 9, "gear_hindrance": 0, "protection": 1 },
|
||||
2: { "label": "ROLE_LEVELS.secondary", "reaction": 3, "reaction_bonus": 1, "pools": 1, "gear": 9, "gear_hindrance": 1, "protection": 2 },
|
||||
3: { "label": "ROLE_LEVELS.important", "reaction": 3, "reaction_bonus": 2, "pools": 2, "gear": 9, "gear_hindrance": 2, "protection": 3 },
|
||||
4: { "label": "ROLE_LEVELS.major", "reaction": 4, "reaction_bonus": 2, "pools": 4, "gear": 10, "gear_hindrance": 2, "protection": 3 },
|
||||
}
|
||||
|
||||
VERMINE.PatternLevels = {
|
||||
1: { "label": "PATTERN_LEVELS.insect", "attack": 2, "damage": 0, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 },
|
||||
2: { "label": "PATTERN_LEVELS.rat", "attack": 3, "damage": 1, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 },
|
||||
3: { "label": "PATTERN_LEVELS.dog", "attack": 4, "damage": 3, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 },
|
||||
4: { "label": "PATTERN_LEVELS.bear", "attack": 6, "damage": 6, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 },
|
||||
}
|
||||
|
||||
VERMINE.SizeLevels = {
|
||||
1: { "attack": 2, "vigor": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 },
|
||||
2: { "attack": 3, "vigor": 2, "minorWound": 0, "majorWound": 1, "deadlyWound": 1 },
|
||||
3: { "attack": 4, "vigor": 3, "minorWound": 1, "majorWound": 1, "deadlyWound": 1 }
|
||||
}
|
||||
|
||||
VERMINE.PackLevels = {
|
||||
1: { "attack": 1, "damage": 1, "minorWound": 0, "majorWound": 0, "deadlyWound": 1 },
|
||||
2: { "attack": 2, "damage": 2, "minorWound": 2, "majorWound": 2, "deadlyWound": 2 },
|
||||
3: { "attack": 5, "damage": 5, "minorWound": 3, "majorWound": 3, "deadlyWound": 3 }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -251,6 +211,49 @@ VERMINE.skillCategories = {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Skills mapping: each skill belongs to a category.
|
||||
* Used by templates to render skill-select dropdowns.
|
||||
*/
|
||||
VERMINE.skills = {
|
||||
// man
|
||||
arts: { category: "man" },
|
||||
civilization: { category: "man" },
|
||||
psychology: { category: "man" },
|
||||
rumors: { category: "man" },
|
||||
healing: { category: "man" },
|
||||
// animal
|
||||
animalism: { category: "animal" },
|
||||
dissection: { category: "animal" },
|
||||
wildlife: { category: "animal" },
|
||||
repulsion: { category: "animal" },
|
||||
tracks: { category: "animal" },
|
||||
// tool
|
||||
crafting: { category: "tool" },
|
||||
diy: { category: "tool" },
|
||||
mecanical: { category: "tool" },
|
||||
piloting: { category: "tool" },
|
||||
technology: { category: "tool" },
|
||||
// weapon
|
||||
firearms: { category: "weapon" },
|
||||
archery: { category: "weapon" },
|
||||
armory: { category: "weapon" },
|
||||
throwing: { category: "weapon" },
|
||||
melee: { category: "weapon" },
|
||||
// survival
|
||||
alertness: { category: "survival" },
|
||||
atletics: { category: "survival" },
|
||||
food: { category: "survival" },
|
||||
stealth: { category: "survival" },
|
||||
close: { category: "survival" },
|
||||
// world
|
||||
environment: { category: "world" },
|
||||
flora: { category: "world" },
|
||||
road: { category: "world" },
|
||||
toxics: { category: "world" },
|
||||
ruins: { category: "world" }
|
||||
}
|
||||
|
||||
VERMINE.sexes = { "male": "SEXES.male", "female": "SEXES.female" };
|
||||
|
||||
VERMINE.totems = {
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
import { VermineUtils } from "./roll.mjs";
|
||||
export class CombatResultDialog extends Dialog {
|
||||
|
||||
constructor(dialogData, options) {
|
||||
/*let options = { classes: ["combat", "result"], ...options };
|
||||
let conf = {
|
||||
title: "Résultat de la confrontation",
|
||||
content: dialogData.content
|
||||
};
|
||||
super(conf, options);
|
||||
this.dialogData = dialogData;*/
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
activateListeners(html) {
|
||||
/*super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.setEphemere(this.dialogData.signe.system.ephemere);
|
||||
html.find(".signe-aleatoire").click(event => this.setSigneAleatoire());
|
||||
html.find("[name='signe.system.ephemere']").change((event) => this.setEphemere(event.currentTarget.checked));
|
||||
html.find(".signe-xp-sort").change((event) => this.onValeurXpSort(event));
|
||||
html.find("input.select-actor").change((event) => this.onSelectActor(event));
|
||||
html.find("input.select-tmr").change((event) => this.onSelectTmr(event));*/
|
||||
}
|
||||
|
||||
|
||||
async onSelectActor(event) {
|
||||
/*const actorId = this.html.find(event.currentTarget)?.data("actor-id");
|
||||
const actor = this.dialogData.actors.find(it => it.id == actorId);
|
||||
if (actor) {
|
||||
actor.selected = event.currentTarget.checked;
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -139,7 +139,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(foundry.appli
|
||||
|
||||
getHandicapSelect() {
|
||||
const sel = this.#getHandicap();
|
||||
return parseInt(sel?.value, 10) || 1;
|
||||
return Math.max(0, (parseInt(sel?.value, 10) || 1) - 1);
|
||||
}
|
||||
|
||||
getSkillCategory() {
|
||||
|
||||
@@ -43,19 +43,19 @@ export async function initUserDice(dice3d, user) {
|
||||
export function darkenColor(color, percent) {
|
||||
const num = parseInt(color.replace('#', ''), 16);
|
||||
const amt = Math.round(2.55 * percent);
|
||||
const R = (num >> 16) + amt;
|
||||
const G = ((num >> 8) & 0x00FF) + amt;
|
||||
const B = (num & 0x0000FF) + amt;
|
||||
return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
|
||||
const R = (num >> 16) - amt;
|
||||
const G = ((num >> 8) & 0x00FF) - amt;
|
||||
const B = (num & 0x0000FF) - amt;
|
||||
return '#' + (0x1000000 + (R < 0 ? 0 : R > 255 ? 255 : R) * 0x10000 + (G < 0 ? 0 : G > 255 ? 255 : G) * 0x100 + (B < 0 ? 0 : B > 255 ? 255 : B)).toString(16).slice(1);
|
||||
}
|
||||
|
||||
export function lightenColor(color, percent) {
|
||||
const num = parseInt(color.replace('#', ''), 16);
|
||||
const amt = Math.round(2.55 * percent);
|
||||
const R = (num >> 16) - amt;
|
||||
const G = ((num >> 8) & 0x00FF) - amt;
|
||||
const B = (num & 0x0000FF) - amt;
|
||||
return '#' + (0x1000000 + (R < 0 ? 0 : R > 255 ? 255 : R) * 0x10000 + (G < 0 ? 0 : G > 255 ? 255 : G) * 0x100 + (B < 0 ? 0 : B > 255 ? 255 : B)).toString(16).slice(1);
|
||||
const R = (num >> 16) + amt;
|
||||
const G = ((num >> 8) & 0x00FF) + amt;
|
||||
const B = (num & 0x0000FF) + amt;
|
||||
return '#' + (0x1000000 + (R < 255 ? R < 1 ? 0 : R : 255) * 0x10000 + (G < 255 ? G < 1 ? 0 : G : 255) * 0x100 + (B < 255 ? B < 1 ? 0 : B : 255)).toString(16).slice(1);
|
||||
}
|
||||
export function oppositeColor(color) {
|
||||
const num = parseInt(color.replace('#', ''), 16);
|
||||
|
||||
+20
-221
@@ -1,5 +1,4 @@
|
||||
import { VERMINE } from "./config.mjs";
|
||||
import { getActorSkillScore, updateActorSkillScore } from "./functions.mjs";
|
||||
|
||||
|
||||
/**
|
||||
* Handles combat-related dice rolls for Vermine2047.
|
||||
@@ -28,7 +27,8 @@ export class VermineFight {
|
||||
*/
|
||||
async performTest(enemyAchievement, enemyConservation, skillKey, skill, params, actor) {
|
||||
// Use d10 as per Vermine2047 official rules
|
||||
const dicePool = (params.spleen != undefined || params.purpose != undefined) ? '5' : '4';
|
||||
const basePool = Math.max(skill, 1)
|
||||
const dicePool = (params.spleen != undefined || params.purpose != undefined) ? String(basePool + 1) : String(basePool)
|
||||
const difficulty = params.difficulty || 7; // Default difficulty
|
||||
const r = new Roll(dicePool + `d10`);
|
||||
let diceString = '';
|
||||
@@ -167,218 +167,25 @@ export class VermineFight {
|
||||
// data injected to char data
|
||||
static previousValues = {
|
||||
dicePool: 4,
|
||||
skills: VERMINE.skillsList,
|
||||
cskills: VERMINE.cskills,
|
||||
skills: [],
|
||||
cskills: [],
|
||||
cephalic: false,
|
||||
achievementReroll: VERMINE.achievementReroll,
|
||||
conservationReroll: VERMINE.conservationReroll
|
||||
achievementReroll: 0,
|
||||
conservationReroll: 0
|
||||
};
|
||||
|
||||
static rollerTemplate = 'systems/vermine2047/templates/fight.html';
|
||||
static CombatResultTemplate = 'systems/vermine2047/templates/fight-result.html';
|
||||
|
||||
static async chatMessageHandler(message, html, data) {
|
||||
// console.log("accès au fin du fin", message._id);
|
||||
|
||||
// sélection du dé actif
|
||||
html.on("click", '.confrontation .die.d10', event => {
|
||||
const diceResult = parseInt($(event.target).html(), 10);
|
||||
html.find('.confrontation .die.d10').removeClass('active');
|
||||
$(event.target).addClass('active');
|
||||
});
|
||||
|
||||
// sélection des dés d'accomplissement (achievement = successes)
|
||||
html.on("click", '.confrontation .add-to-achievement', event => {
|
||||
const diceResult = parseInt(html.find('.confrontation .die.d10.active').html(), 10);
|
||||
html.find('.confrontation .die.d10.active').removeClass('min').addClass('max');
|
||||
});
|
||||
|
||||
// sélection des dés de conservation
|
||||
html.on("click", '.confrontation .add-to-conservation', event => {
|
||||
const diceResult = parseInt(html.find('.confrontation .die.d10.active').html(), 10);
|
||||
html.find('.confrontation .die.d10.active').removeClass('max').addClass('min');
|
||||
});
|
||||
|
||||
// reset de la sélection des pools
|
||||
html.on("click", '.confrontation .reset', event => {
|
||||
html.find('.confrontation .die.d10')
|
||||
.removeClass('max')
|
||||
.removeClass('min');
|
||||
});
|
||||
|
||||
// résolution de la confrontation
|
||||
// Note: With d10 system, we count successes (dice >= difficulty) instead of summing
|
||||
html.on("click", '.confrontation .resolve', async event => {
|
||||
let achievementDice = 0;
|
||||
let conservationDice = 0;
|
||||
let achievementBasis = 0;
|
||||
let conservationBasis = 0;
|
||||
const difficulty = 7; // Default difficulty for legacy compatibility
|
||||
|
||||
// Count successes (dice >= difficulty) for achievement
|
||||
html.find('.confrontation .die.d10.max').each(function (index) {
|
||||
const value = parseInt($(this).html(), 10);
|
||||
if (value >= difficulty) {
|
||||
achievementDice++;
|
||||
}
|
||||
});
|
||||
|
||||
// Count successes (dice >= difficulty) for conservation
|
||||
html.find('.confrontation .die.d10.min').each(function (index) {
|
||||
const value = parseInt($(this).html(), 10);
|
||||
if (value >= difficulty) {
|
||||
conservationDice++;
|
||||
}
|
||||
});
|
||||
|
||||
// saisie des résultats
|
||||
achievementBasis = html.find('td.achievement-result').data('achievement-basis');
|
||||
html.find('td.achievement-result').data('achievement-value', achievementDice);
|
||||
html.find('td.achievement-result').html(achievementBasis + achievementDice);
|
||||
|
||||
conservationBasis = html.find('td.conservation-result').data('conservation-basis');
|
||||
html.find('td.conservation-result').data('conservation-value', conservationDice);
|
||||
html.find('td.conservation-result').html(conservationBasis + conservationDice);
|
||||
|
||||
// calcul des marges (now based on successes, not sum)
|
||||
const achievementMargin = achievementBasis + achievementDice - parseInt(html.find('td.adv-achievement-result').html(), 10);
|
||||
const conservationMargin = conservationBasis + conservationDice - parseInt(html.find('td.adv-conservation-result').html(), 10);
|
||||
html.find('td.achievement-margin').html(achievementMargin);
|
||||
html.find('td.conservation-margin').html(conservationMargin);
|
||||
|
||||
});
|
||||
|
||||
|
||||
// fin de la résolution de la confrontation
|
||||
|
||||
|
||||
}
|
||||
|
||||
static async chatListeners(html) {
|
||||
// supprime le masquage des résultats du dé
|
||||
html.off("click", ".dice-roll");
|
||||
}
|
||||
|
||||
/**
|
||||
* main class function
|
||||
* @returns
|
||||
*/
|
||||
static async ui(externalData = {}) {
|
||||
let actor = {};
|
||||
|
||||
// get the actor
|
||||
try {
|
||||
actor = game.user.character;
|
||||
} catch (e) {
|
||||
throw ("Aucun personnage défini !");
|
||||
}
|
||||
|
||||
if (actor == null && externalData.speakerId != undefined && externalData.speakerId != null) {
|
||||
// on récupère le speakerId, et de là l'objet actor
|
||||
actor = game.actors.get(externalData.speakerId);
|
||||
VermineFight.previousValues['speakerName'] = actor.name;
|
||||
VermineFight.previousValues['speakerImg'] = actor.img;
|
||||
} else {
|
||||
VermineFight.previousValues['speakerName'] = "Anonyme";
|
||||
}
|
||||
|
||||
// get the data
|
||||
let charData = (externalData) => {
|
||||
let o = Object.assign({ _template: VermineFight.rollerTemplate }, { ...VermineFight.previousValues, ...externalData });
|
||||
return o;
|
||||
};
|
||||
let data = charData(externalData);
|
||||
console.log(data);
|
||||
|
||||
// render template
|
||||
let html = await foundry.applications.handlebars.renderTemplate(data._template, data);
|
||||
|
||||
let ui = new Dialog({
|
||||
title: game.i18n.localize("VERMINE.FightTool"),
|
||||
content: html,
|
||||
buttons: {
|
||||
roll: {
|
||||
label: game.i18n.localize('VERMINE.Roll4Fight'),
|
||||
callback: (html) => {
|
||||
let form = html.find('#dice-pool-form');
|
||||
if (!form[0].checkValidity()) {
|
||||
throw "Invalid Data";
|
||||
}
|
||||
let enemyAchievement, enemyConservation, skillKey, skill = 5, enemySkill, params = {};
|
||||
form.serializeArray().forEach(e => {
|
||||
switch (e.name) {
|
||||
case "skill":
|
||||
case "cephalic":
|
||||
if (e.value !== '') {
|
||||
skillKey = e.value;
|
||||
}
|
||||
break;
|
||||
case "skill-score":
|
||||
skill = +e.value;
|
||||
break;
|
||||
case "specialization":
|
||||
params.specialization = true;
|
||||
break;
|
||||
case "usure":
|
||||
params.usure = +e.value;
|
||||
break;
|
||||
case "trait":
|
||||
params.trait = +e.value;
|
||||
break;
|
||||
case "purpose":
|
||||
params.purpose = true;
|
||||
break;
|
||||
case "spleen":
|
||||
params.spleen = true;
|
||||
break;
|
||||
case "adv-skill":
|
||||
enemySkill = +e.value;
|
||||
break;
|
||||
case "achievement":
|
||||
enemyAchievement = +e.value;
|
||||
break;
|
||||
case "conservation":
|
||||
enemyConservation = +e.value;
|
||||
break;
|
||||
}
|
||||
});
|
||||
// prise en compte de l'usure sur la feuille de perso
|
||||
if (params.usure != undefined) {
|
||||
const newSpentScore = getActorSkillScore(actor, skillKey, 'spent') + params.usure;
|
||||
console.log(newSpentScore);
|
||||
updateActorSkillScore(actor, skillKey, 'spent', newSpentScore);
|
||||
}
|
||||
|
||||
return VermineFight.get().performTest(enemyAchievement + enemySkill, enemyConservation + enemySkill, skillKey, skill, params, actor);
|
||||
}
|
||||
},
|
||||
cancel: {
|
||||
label: game.i18n.localize('Close'),
|
||||
callback: () => { }
|
||||
}
|
||||
},
|
||||
render: function (h) {
|
||||
h.on("change", 'select[name="skill"]', event => {
|
||||
const skillLabel = $(event.target).val();
|
||||
const currentSkillScore = getActorSkillScore(actor, skillLabel) - getActorSkillScore(actor, skillLabel, 'spent');
|
||||
if (parseInt(currentSkillScore, 10) >= 0) {
|
||||
h.find('input#skillScore').val(currentSkillScore);
|
||||
}
|
||||
});
|
||||
}
|
||||
}, { width: 601, height: 'fit-content' });
|
||||
ui.render(true);
|
||||
return ui;
|
||||
}
|
||||
}
|
||||
|
||||
export class VermineCombat extends Combat {
|
||||
_encounterCheck() {
|
||||
console.log('encounter combat object', this);
|
||||
// encounter check
|
||||
}
|
||||
|
||||
async rollInitiative(ids, formula = undefined, messageOptions = {}) {
|
||||
console.log(`${game.system.title} | Combat.rollInitiative()`, ids, formula, messageOptions);
|
||||
// roll initiative
|
||||
return super.rollInitiative(ids, formula, messageOptions)
|
||||
|
||||
}
|
||||
@@ -421,13 +228,6 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb
|
||||
return "systems/vermine2047/templates/combat-tracker.hbs";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
get template() {
|
||||
return "systems/vermine2047/templates/combat-tracker.hbs";
|
||||
}
|
||||
|
||||
async getData(options) {
|
||||
const context = await super.getData(options);
|
||||
|
||||
@@ -441,7 +241,9 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb
|
||||
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
html.find("[data-attitude]").click(this._setStatut.bind(this));
|
||||
html.querySelectorAll("[data-attitude]").forEach(el => {
|
||||
el.addEventListener("click", this._setStatut.bind(this));
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -465,23 +267,20 @@ export class VermineCombatTracker extends foundry.applications.sidebar.tabs.Comb
|
||||
}
|
||||
|
||||
let actor = await game.actors.get(combatant.actorId)
|
||||
console.log(actor, combatant)
|
||||
// combatant attitude set
|
||||
}
|
||||
}
|
||||
|
||||
export class VermineCombatant extends Combatant {
|
||||
constructor(data, context) {
|
||||
super(data, context);
|
||||
this.setDefaultAttitude();
|
||||
|
||||
}
|
||||
setDefaultAttitude() {
|
||||
this.attitude = this.token.flags.world?.attitude || "active"
|
||||
super(data, context)
|
||||
if (this.token) {
|
||||
this.attitude = this.token.flags.world?.attitude || "active"
|
||||
} else {
|
||||
this.attitude = "active"
|
||||
}
|
||||
}
|
||||
_getInitiativeFormula() {
|
||||
|
||||
return String(CONFIG.Combat.initiative.formula || game.system.initiative);
|
||||
return String(CONFIG.Combat.initiative.formula || game.system.initiative)
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+28
-30
@@ -1,47 +1,45 @@
|
||||
import { VERMINE } from './config.mjs'
|
||||
|
||||
/**
|
||||
* renvoie le score d'une compétence d'un actor existant
|
||||
* @param {VermineActor}
|
||||
* @return {number||null} Data for rendering or null
|
||||
* Returns the score of a skill for an actor.
|
||||
* Skills are stored as a flat object in actor.system.skills: { [key]: { value, spent, label, category } }
|
||||
* @param {VermineActor} actor
|
||||
* @param {string} skillLabel - The localized label of the skill to find
|
||||
* @param {"value"|"spent"} [property="value"] - Which property to return
|
||||
* @returns {number|null} The skill score or null if not found
|
||||
*/
|
||||
export function getActorSkillScore(actor, skillLabel, property = "value") {
|
||||
let returnedValue = null;
|
||||
const skills = actor.system?.skills;
|
||||
if (!skills) return null;
|
||||
|
||||
for(let i in actor.system.skills){
|
||||
for(let j in actor.system.skills[i].data){
|
||||
if (actor.system.skills[i].data[j].label == skillLabel){
|
||||
returnedValue = actor.system.skills[i].data[j][property];
|
||||
}
|
||||
for (const key of Object.keys(skills)) {
|
||||
if (skills[key].label === skillLabel) {
|
||||
return skills[key][property] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
return returnedValue;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* met à jour le score d'une compétence d'un actor existant
|
||||
* @param {VermineActor}
|
||||
* @return {boolean} bool
|
||||
* Updates the score of a skill for an actor.
|
||||
* @param {VermineActor} selectedActor
|
||||
* @param {string} skillLabel - The localized label of the skill to update
|
||||
* @param {"value"|"spent"} [property="value"] - Which property to update
|
||||
* @param {number} updatedValue - The new value
|
||||
* @returns {boolean} Whether the update was successful
|
||||
*/
|
||||
export function updateActorSkillScore(selectedActor, skillLabel, property = "value", updatedValue) {
|
||||
try {
|
||||
let updated = false;
|
||||
// on recherche le label parmi les compétences
|
||||
for (let st in selectedActor.system.skills){
|
||||
for (let s in selectedActor.system.skills[st].data){
|
||||
if (selectedActor.system.skills[st].data[s].label == skillLabel){
|
||||
selectedActor.system.skills[st].data[s][property] = updatedValue; // printing the new value
|
||||
const systemSkillKey = `system.skills.${st}.data.${s}.${property}`;
|
||||
selectedActor.update({[systemSkillKey]:updatedValue }); // updating actor's data
|
||||
updated = true;
|
||||
}
|
||||
const skills = selectedActor.system?.skills;
|
||||
if (!skills) return false;
|
||||
|
||||
for (const key of Object.keys(skills)) {
|
||||
if (skills[key].label === skillLabel) {
|
||||
skills[key][property] = updatedValue;
|
||||
selectedActor.update({ [`system.skills.${key}.${property}`]: updatedValue });
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return updated;
|
||||
} catch(e){
|
||||
return false;
|
||||
} catch (e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -124,7 +124,7 @@ export const registerHandlebarsHelpers = function () {
|
||||
Handlebars.registerHelper('threatLevel', function (property, level, options) {
|
||||
if (level < 1 || level > 4)
|
||||
return "";
|
||||
let levelData = CONFIG.VERMINE.ThreatLevels[level];
|
||||
let levelData = CONFIG.VERMINE.npcThreatLevels[level];
|
||||
if (property == 'label') {
|
||||
return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : "";
|
||||
} else {
|
||||
@@ -136,7 +136,7 @@ export const registerHandlebarsHelpers = function () {
|
||||
Handlebars.registerHelper('experienceLevel', function (property, level, options) {
|
||||
if (level < 1 || level > 4)
|
||||
return "";
|
||||
let levelData = CONFIG.VERMINE.ExperienceLevels[level];
|
||||
let levelData = CONFIG.VERMINE.npcExperienceLevels[level];
|
||||
if (property == 'label') {
|
||||
return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : "";
|
||||
} else {
|
||||
@@ -148,7 +148,7 @@ export const registerHandlebarsHelpers = function () {
|
||||
Handlebars.registerHelper('roleLevel', function (property, level, options) {
|
||||
if (level < 1 || level > 4)
|
||||
return "";
|
||||
let levelData = CONFIG.VERMINE.RoleLevels[level];
|
||||
let levelData = CONFIG.VERMINE.npcRoleLevels[level];
|
||||
if (property == 'label') {
|
||||
return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : "";
|
||||
} else {
|
||||
@@ -160,7 +160,7 @@ export const registerHandlebarsHelpers = function () {
|
||||
Handlebars.registerHelper('patternLevel', function (property, level, options) {
|
||||
if (level < 1 || level > 4)
|
||||
return "";
|
||||
let levelData = CONFIG.VERMINE.PatternLevels[level];
|
||||
let levelData = CONFIG.VERMINE.creaturePatternLevels[level];
|
||||
if (property == 'label') {
|
||||
return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : "";
|
||||
} else {
|
||||
@@ -172,7 +172,7 @@ export const registerHandlebarsHelpers = function () {
|
||||
Handlebars.registerHelper('sizeLevel', function (property, level, options) {
|
||||
if (level < 1 || level > 4)
|
||||
return "";
|
||||
let levelData = CONFIG.VERMINE.SizeLevels[level];
|
||||
let levelData = CONFIG.VERMINE.creatureSizeLevels[level];
|
||||
if (property == 'label') {
|
||||
return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : "";
|
||||
} else {
|
||||
@@ -184,7 +184,7 @@ export const registerHandlebarsHelpers = function () {
|
||||
Handlebars.registerHelper('packLevel', function (property, level, options) {
|
||||
if (level < 0 || level > 3)
|
||||
return "";
|
||||
let levelData = CONFIG.VERMINE.PackLevels[level];
|
||||
let levelData = CONFIG.VERMINE.creaturePackLevels[level];
|
||||
if (property == 'label') {
|
||||
return (levelData !== undefined) ? game.i18n.localize(levelData[property]) : "";
|
||||
} else {
|
||||
|
||||
+15
-9
@@ -1,6 +1,5 @@
|
||||
import RollDialog from "./dialogs/rollDialog.mjs";
|
||||
import { initUserDice } from "./dice3d.mjs";
|
||||
import { DiceSystem } from '../../../../modules/dice-so-nice/api.js';
|
||||
import { VermineUtils } from "./roll.mjs";
|
||||
import { registerTours } from "./tour.mjs";
|
||||
|
||||
@@ -10,6 +9,9 @@ export const registerHooks = function () {
|
||||
*/
|
||||
CONFIG.debug.hooks = false;
|
||||
Hooks.once('diceSoNiceReady', async (dice3d) => {
|
||||
const dsnModule = game.modules.get('dice-so-nice');
|
||||
if (!dsnModule?.active) return;
|
||||
const { DiceSystem } = await import(`/modules/${dsnModule.id}/api.js`);
|
||||
const vermineSystem = new DiceSystem('Vermine2047', 'Vermine 2047', "preferred", 'totem')
|
||||
dice3d.addSystem(vermineSystem);
|
||||
|
||||
@@ -43,7 +45,7 @@ export const registerHooks = function () {
|
||||
if (rerollTitle) {
|
||||
rerollTitle.addEventListener("click", () => { html.querySelector(".reroll").classList.toggle('visible') })
|
||||
}
|
||||
if (message.author?._id != game.user._id || !game.user.isGM) {
|
||||
if (message.author?._id !== game.user._id && !game.user.isGM) {
|
||||
// désactiver les inputs pour les joueurs non-auteurs du message
|
||||
html.querySelectorAll("input").forEach(inp => inp.disabled = true);
|
||||
//cacher le boutton reroll
|
||||
@@ -61,17 +63,21 @@ export const registerHooks = function () {
|
||||
}
|
||||
})
|
||||
Hooks.once("ready", async () => {
|
||||
console.info("Vermine 2047 | System Initialized.");
|
||||
// System initialized
|
||||
//await registerTours();
|
||||
|
||||
});
|
||||
|
||||
// changement de la pause
|
||||
Hooks.on("renderPause", async function () {
|
||||
if ($("#pause").attr("class") !== "paused") return;
|
||||
$(".paused img").attr("src", 'systems/vermine2047/assets/images/ui/vermine_pause.webp');
|
||||
$(".paused img").css({ "opacity": 1 });
|
||||
$("#pause.paused figcaption").text("Communauté endormie...");
|
||||
const pauseEl = document.getElementById("pause");
|
||||
if (!pauseEl || pauseEl.className !== "paused") return;
|
||||
pauseEl.querySelectorAll("img").forEach(img => {
|
||||
img.src = 'systems/vermine2047/assets/images/ui/vermine_pause.webp';
|
||||
img.style.opacity = 1;
|
||||
});
|
||||
const caption = pauseEl.querySelector("figcaption");
|
||||
if (caption) caption.textContent = "Communauté endormie...";
|
||||
});
|
||||
|
||||
/**
|
||||
@@ -107,7 +113,7 @@ export const registerHooks = function () {
|
||||
/* -------------------------------------------- */
|
||||
|
||||
Hooks.on("preCreateActor", function (actor) {
|
||||
console.log('pre create actor', actor.img);
|
||||
// pre create actor
|
||||
if (actor.img == "icons/svg/mystery-man.svg") {
|
||||
actor.updateSource({ "img": `systems/vermine2047/assets/icons/actors/${actor.type}.webp` });
|
||||
}
|
||||
@@ -138,7 +144,7 @@ export const registerHooks = function () {
|
||||
if (game.user.isGM) {
|
||||
let combatant = (game.combat.combatant) ? game.combat.combatant.actor : "";
|
||||
|
||||
console.log('update combat', game.combat);
|
||||
// update combat
|
||||
|
||||
/*if (combatant.type == "marker" && combatant.system.settings.general.isCounter == true) {
|
||||
let step = (!combatant.system.settings.general.counting) ? -1 : combatant.system.settings.general.counting;
|
||||
|
||||
+52
-54
@@ -28,7 +28,8 @@ export class VermineUtils {
|
||||
skillCategory = null,
|
||||
keepTotem = null,
|
||||
skillLevel = null,
|
||||
hasSpecialty = false
|
||||
hasSpecialty = false,
|
||||
handicap = 0
|
||||
}) {
|
||||
// Validate inputs
|
||||
if (!actor) {
|
||||
@@ -100,10 +101,13 @@ export class VermineUtils {
|
||||
NoD++; // Cancel the decrement for adapted
|
||||
} else if (keepTotem === 'adapted' && totems.human) {
|
||||
modFormula = `(1D10cs>=${adjustedDifficulty}[adapted_${safeUserName}]*2)`;
|
||||
NoD++; // Cancel the decrement for human
|
||||
NoD++; // Cancel the decrement for human
|
||||
}
|
||||
}
|
||||
|
||||
// Apply handicap (wounds/maluses reduce dice pool)
|
||||
NoD = Math.max(1, NoD - handicap)
|
||||
|
||||
// Build base formula
|
||||
const baseFormula = `${NoD}d10cs>=${adjustedDifficulty}[regular_${safeUserName}]`;
|
||||
|
||||
@@ -364,67 +368,61 @@ export class VermineUtils {
|
||||
* @param {HTMLElement} html - The HTML element containing chat events.
|
||||
*/
|
||||
static async chatListenners(html) {
|
||||
// Ensure html is a jQuery object
|
||||
const $html = $(html);
|
||||
|
||||
// Get reroll count
|
||||
const rerollCountElement = $html.find('#allowed_reroll')[0];
|
||||
const rerollCountElement = html.querySelector('#allowed_reroll');
|
||||
const rerollCount = rerollCountElement?.innerText;
|
||||
|
||||
|
||||
// Enable/disable rerolls based on count
|
||||
if (!rerollCount || parseInt(rerollCount, 10) < 1) {
|
||||
// Disable rerolls for all dice
|
||||
$html.find('.die').each(function() {
|
||||
this.classList.remove("rerollable");
|
||||
});
|
||||
} else {
|
||||
// Enable rerolls for all dice
|
||||
$html.find('.die').each(function() {
|
||||
this.classList.add("rerollable");
|
||||
});
|
||||
}
|
||||
const dieClass = !rerollCount || parseInt(rerollCount, 10) < 1 ? 'remove' : 'add';
|
||||
html.querySelectorAll('.die').forEach(el => el.classList[dieClass]("rerollable"));
|
||||
|
||||
// Add click event for rerollable dice
|
||||
$html.find('.rerollable').click(async (ev) => {
|
||||
ev.preventDefault();
|
||||
const msgId = ev.currentTarget.closest("li.message")?.dataset?.messageId;
|
||||
if (msgId) {
|
||||
const message = await game.messages.get(msgId);
|
||||
await VermineUtils.onReroll(message, ev);
|
||||
}
|
||||
html.querySelectorAll('.rerollable').forEach(el => {
|
||||
el.addEventListener('click', async (ev) => {
|
||||
ev.preventDefault();
|
||||
const msgId = ev.currentTarget.closest("li.message")?.dataset?.messageId;
|
||||
if (msgId) {
|
||||
const message = await game.messages.get(msgId);
|
||||
await VermineUtils.onReroll(message, ev);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// Update granted reroll label
|
||||
$html.find("#effort-reroll").change(ev => {
|
||||
const label = $html.find("#granted-reroll")[0];
|
||||
if (label) {
|
||||
label.innerText = ev.currentTarget.value;
|
||||
}
|
||||
});
|
||||
const effortReroll = html.querySelector("#effort-reroll");
|
||||
if (effortReroll) {
|
||||
effortReroll.addEventListener('change', ev => {
|
||||
const label = html.querySelector("#granted-reroll");
|
||||
if (label) {
|
||||
label.innerText = ev.currentTarget.value;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add click event for granting rerolls
|
||||
$html.find("button.grant-reroll").click(async (ev) => {
|
||||
const grantedRerollElement = $html.find('#granted-reroll')[0];
|
||||
const allowedRerollElement = $html.find("#allowed_reroll")[0];
|
||||
|
||||
if (grantedRerollElement && allowedRerollElement) {
|
||||
allowedRerollElement.innerText = grantedRerollElement.innerText;
|
||||
}
|
||||
|
||||
const mesEl = ev.currentTarget.closest('[data-message-id]');
|
||||
const messageId = mesEl?.dataset?.messageId;
|
||||
|
||||
if (messageId) {
|
||||
// Hide reroll grant area
|
||||
ev.currentTarget.closest('.reroll-from-effort').style.display = "none";
|
||||
|
||||
const rollMessage = ev.currentTarget.closest(".vermine-roll-message");
|
||||
if (rollMessage) {
|
||||
const content = rollMessage.outerHTML;
|
||||
const message = await game.messages.get(messageId);
|
||||
await message.update({ content: content });
|
||||
html.querySelectorAll("button.grant-reroll").forEach(el => {
|
||||
el.addEventListener('click', async (ev) => {
|
||||
const grantedRerollElement = html.querySelector('#granted-reroll');
|
||||
const allowedRerollElement = html.querySelector("#allowed_reroll");
|
||||
|
||||
if (grantedRerollElement && allowedRerollElement) {
|
||||
allowedRerollElement.innerText = grantedRerollElement.innerText;
|
||||
}
|
||||
}
|
||||
|
||||
const mesEl = ev.currentTarget.closest('[data-message-id]');
|
||||
const messageId = mesEl?.dataset?.messageId;
|
||||
|
||||
if (messageId) {
|
||||
ev.currentTarget.closest('.reroll-from-effort').style.display = "none";
|
||||
|
||||
const rollMessage = ev.currentTarget.closest(".vermine-roll-message");
|
||||
if (rollMessage) {
|
||||
const content = rollMessage.outerHTML;
|
||||
const message = await game.messages.get(messageId);
|
||||
await message.update({ content: content });
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -448,10 +446,10 @@ export class VermineUtils {
|
||||
blind = true;
|
||||
// Falls through
|
||||
case "gmroll": // GM + rolling player
|
||||
whisper = this.getUsers(user => user.isGM);
|
||||
whisper = game.users?.filter(user => user.isGM) || [];
|
||||
break;
|
||||
case "roll": // Everybody
|
||||
whisper = this.getUsers(user => user.active);
|
||||
whisper = game.users?.filter(user => user.active) || [];
|
||||
break;
|
||||
case "selfroll":
|
||||
whisper = [game.user.id];
|
||||
|
||||
@@ -10,7 +10,7 @@ export const registerSettings = function () {
|
||||
"2": "Cauchemar",
|
||||
"3": "Apocalypse"
|
||||
},
|
||||
default: 'e',
|
||||
default: '1',
|
||||
onChange: value => {
|
||||
let el = document.querySelector('.game-mode');
|
||||
el.id = 'game-mode-' + game.settings.get('vermine2047', 'game-mode')
|
||||
|
||||
@@ -139,13 +139,15 @@ class WelcomeTour extends VermineTour {
|
||||
}
|
||||
export async function registerTours() {
|
||||
game.tours.register("vermine2047", "welcome", new WelcomeTour());
|
||||
$(document).on("click", "#chat-log #vermine-tour-chat-button", (el) => {
|
||||
const tour = game.tours.get("vermine2047.welcome");
|
||||
tour == null ? void 0 : tour.start();
|
||||
document.addEventListener("click", (el) => {
|
||||
if (el.target.closest("#chat-log #vermine-tour-chat-button")) {
|
||||
const tour = game.tours.get("vermine2047.welcome");
|
||||
tour?.start();
|
||||
}
|
||||
});
|
||||
if (game.settings.get("vermine2047", "first-run-tips-shown"))
|
||||
return;
|
||||
console.log("Posting first-start messages...");
|
||||
// Posting first-start messages
|
||||
const gms = ChatMessage.getWhisperRecipients("GM");
|
||||
ChatMessage.implementation;
|
||||
ChatMessage.create({
|
||||
|
||||
Reference in New Issue
Block a user