added select in DP for skill list (wip)
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
- Added the ability to techniques, with a skill set, to open the DicePicker with presets values.
|
- Added the ability to techniques, with a skill set, to open the DicePicker with presets values.
|
||||||
- Some can interact with targets, but do the default difficulty if none.
|
- Some can interact with targets, but do the default difficulty if none.
|
||||||
- Compendiums :
|
- Compendiums :
|
||||||
- Techniques : Added difficulty and skill values.
|
- Techniques : Added difficulty and skill values (not all techniques).
|
||||||
|
|
||||||
## 1.6.0 - QoL & SoftLock
|
## 1.6.0 - QoL & SoftLock
|
||||||
- PC/NPC/Armies sheet:
|
- PC/NPC/Armies sheet:
|
||||||
|
|||||||
@@ -619,28 +619,13 @@ export class BaseCharacterSheetL5r5e extends BaseSheetL5r5e {
|
|||||||
if (!item || item.type !== "technique" || !item.data.data.skill) {
|
if (!item || item.type !== "technique" || !item.data.data.skill) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemData = item.data.data;
|
const itemData = item.data.data;
|
||||||
|
|
||||||
const difficulties = game.l5r5e.DicePickerDialog.parseDifficulty(this.actor, itemData.difficulty);
|
|
||||||
if (!difficulties) {
|
|
||||||
// do not block if no target or not found
|
|
||||||
difficulties.difficulty = null;
|
|
||||||
difficulties.difficultyHidden = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const skills = game.l5r5e.DicePickerDialog.parseSkills(itemData.skill);
|
|
||||||
if (!skills) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
console.log(difficulties, skills); // todo tmp
|
|
||||||
|
|
||||||
new game.l5r5e.DicePickerDialog({
|
new game.l5r5e.DicePickerDialog({
|
||||||
actor: this.actor,
|
actor: this.actor,
|
||||||
ringId: itemData.ring || null,
|
ringId: itemData.ring || null,
|
||||||
...difficulties,
|
difficulty: itemData.difficulty || null,
|
||||||
...skills,
|
skillsList: itemData.skill || null,
|
||||||
}).render(true);
|
}).render(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
value: 0,
|
value: 0,
|
||||||
defaultValue: 0,
|
defaultValue: 0,
|
||||||
cat: "",
|
cat: "",
|
||||||
|
list: [],
|
||||||
name: "",
|
name: "",
|
||||||
assistance: 0,
|
assistance: 0,
|
||||||
},
|
},
|
||||||
@@ -94,6 +95,7 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
* ringId string (fire)
|
* ringId string (fire)
|
||||||
* skillId string (design)
|
* skillId string (design)
|
||||||
* skillCatId string (artisan)
|
* skillCatId string (artisan)
|
||||||
|
* skillsList string[] (artisan,fitness)
|
||||||
* difficulty number (0-9)
|
* difficulty number (0-9)
|
||||||
* difficultyHidden boolean
|
* difficultyHidden boolean
|
||||||
* isInitiativeRoll boolean
|
* isInitiativeRoll boolean
|
||||||
@@ -121,7 +123,12 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
this.ringId = options.ringId;
|
this.ringId = options.ringId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skill / SkillCategory
|
// SkillList
|
||||||
|
if (options.skillsList) {
|
||||||
|
this.skillList = options.skillsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skill
|
||||||
if (options.skillId) {
|
if (options.skillId) {
|
||||||
this.skillId = options.skillId;
|
this.skillId = options.skillId;
|
||||||
}
|
}
|
||||||
@@ -132,9 +139,7 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Difficulty
|
// Difficulty
|
||||||
if (options.difficulty) {
|
if (!options.difficulty || !this.parseDifficulty(options.difficulty)) {
|
||||||
this.difficulty = options.difficulty;
|
|
||||||
} else {
|
|
||||||
this.difficulty = game.settings.get("l5r5e", "initiative-difficulty-value");
|
this.difficulty = game.settings.get("l5r5e", "initiative-difficulty-value");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,8 +157,10 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
* Refresh data (used from socket)
|
* Refresh data (used from socket)
|
||||||
*/
|
*/
|
||||||
async refresh() {
|
async refresh() {
|
||||||
|
if (this._difficultyHiddenIsLock.option) {
|
||||||
this.difficulty = game.settings.get("l5r5e", "initiative-difficulty-value");
|
this.difficulty = game.settings.get("l5r5e", "initiative-difficulty-value");
|
||||||
this.difficultyHidden = false;
|
this.difficultyHidden = false;
|
||||||
|
}
|
||||||
this.render(false);
|
this.render(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -178,6 +185,21 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
this.object.ring.value = this._actor.data.data.rings[this.object.ring.id];
|
this.object.ring.value = this._actor.data.data.rings[this.object.ring.id];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the list of allowed skill to choose.
|
||||||
|
* Coma separated, can be a category names or skill names.
|
||||||
|
* @param {string} skillsList
|
||||||
|
*/
|
||||||
|
set skillList(skillsList) {
|
||||||
|
if (!skillsList) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.object.skill.list = this.parseSkillsList(skillsList);
|
||||||
|
if (this.object.skill.list.length > 0) {
|
||||||
|
this.skillId = this.object.skill.list[0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set and load skill's required data from actor and skillId
|
* Set and load skill's required data from actor and skillId
|
||||||
* @param skillId
|
* @param skillId
|
||||||
@@ -236,6 +258,9 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
* @param difficulty
|
* @param difficulty
|
||||||
*/
|
*/
|
||||||
set difficulty(difficulty) {
|
set difficulty(difficulty) {
|
||||||
|
if (this._difficultyHiddenIsLock.option) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
difficulty = parseInt(difficulty);
|
difficulty = parseInt(difficulty);
|
||||||
if (isNaN(difficulty) || difficulty < 0) {
|
if (isNaN(difficulty) || difficulty < 0) {
|
||||||
difficulty = 2;
|
difficulty = 2;
|
||||||
@@ -266,6 +291,14 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
return `L5R Dice Roller` + (this._actor ? " - " + this._actor.data.name : "");
|
return `L5R Dice Roller` + (this._actor ? " - " + this._actor.data.name : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return true if an actor is loaded and is a Character
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
get actorIsPc() {
|
||||||
|
return !this._actor || this._actor.data?.type === "character";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct and return the data object used to render the HTML template for this form application.
|
* Construct and return the data object used to render the HTML template for this form application.
|
||||||
* @param options
|
* @param options
|
||||||
@@ -277,7 +310,7 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
ringsList: game.l5r5e.HelpersL5r5e.getRingsList(this._actor),
|
ringsList: game.l5r5e.HelpersL5r5e.getRingsList(this._actor),
|
||||||
data: this.object,
|
data: this.object,
|
||||||
actor: this._actor,
|
actor: this._actor,
|
||||||
actorIsPc: !this._actor || this._actor.data?.type === "character",
|
actorIsPc: this.actorIsPc,
|
||||||
canUseVoidPoint:
|
canUseVoidPoint:
|
||||||
this.object.difficulty.addVoidPoint || !this._actor || this._actor.data.data.void_points.value > 0,
|
this.object.difficulty.addVoidPoint || !this._actor || this._actor.data.data.void_points.value > 0,
|
||||||
disableSubmit: this.object.skill.value < 1 && this.object.ring.value < 1,
|
disableSubmit: this.object.skill.value < 1 && this.object.ring.value < 1,
|
||||||
@@ -311,6 +344,14 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
activateListeners(html) {
|
activateListeners(html) {
|
||||||
super.activateListeners(html);
|
super.activateListeners(html);
|
||||||
|
|
||||||
|
// Skill Selection from list
|
||||||
|
html.find("select[name=skill]").on("change", async (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
this.skillId = event.target.value;
|
||||||
|
this.render(false);
|
||||||
|
});
|
||||||
|
|
||||||
// Select Ring
|
// Select Ring
|
||||||
html.find('input[name="approach"]').on("click", async (event) => {
|
html.find('input[name="approach"]').on("click", async (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -561,113 +602,11 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
return game.user.assignHotbarMacro(macro, "auto"); // 1st available
|
return game.user.assignHotbarMacro(macro, "auto"); // 1st available
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the difficulty from technique
|
|
||||||
*
|
|
||||||
* Exemples :
|
|
||||||
* "@T:vigilance"
|
|
||||||
* "@T:vigilance|min"
|
|
||||||
* "@T:vigilance|max"
|
|
||||||
* "@T:vigilance|max(statusRank)"
|
|
||||||
* "@T:intrigueRank"
|
|
||||||
* "@T:martialRank"
|
|
||||||
* "@T:statusRank|max"
|
|
||||||
* "@T:strife.value|max"
|
|
||||||
*
|
|
||||||
* @param {string|number} difficulty
|
|
||||||
* @return {{difficulty: number, difficultyHidden: boolean}|boolean}
|
|
||||||
*/
|
|
||||||
static parseDifficulty(actor, difficulty) {
|
|
||||||
const out = {
|
|
||||||
difficulty: null,
|
|
||||||
difficultyHidden: null,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Macro style
|
|
||||||
if (!Number.isNumeric(difficulty) && difficulty.startsWith("@")) {
|
|
||||||
// 0: "@T:vigilance|max(statusRank)"
|
|
||||||
// 1: "T" // Meaning : S(elf), T(arget)
|
|
||||||
// 2: "vigilance"
|
|
||||||
// 3: "max"
|
|
||||||
// 4: "statusRank"
|
|
||||||
const infos = difficulty.match(/^@([TS]):([^|]+?)(?:\|(min|max)(?:\(([^)]+?)\))?)?$/);
|
|
||||||
|
|
||||||
// Search for reference actor
|
|
||||||
if (!infos || ((infos[1] === "T" || !!infos[3]) && game.user.targets.size < 1)) {
|
|
||||||
// no target set, do manual TN
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Define which actor is needed for the difficulty
|
|
||||||
let targetActor;
|
|
||||||
if (infos[1] === "S") {
|
|
||||||
targetActor = actor;
|
|
||||||
} else {
|
|
||||||
// Between the targets
|
|
||||||
targetActor = DicePickerDialog._getTargetActorFromSelection(
|
|
||||||
infos[4] || infos[2],
|
|
||||||
!infos[3] ? null : infos[3] === "min"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!targetActor) {
|
|
||||||
console.log("L5R5E | Fail to get actor from target selection");
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Check in actor.<prop> or actor.data.data.<prop>
|
|
||||||
difficulty = targetActor[infos[2]] || targetActor.data.data[infos[2]] || null;
|
|
||||||
if (difficulty < 1) {
|
|
||||||
console.log("L5R5E | Fail to parse difficulty from target");
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hide npc stats on target
|
|
||||||
if (infos[1] === "T") {
|
|
||||||
out.difficultyHidden = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fallback
|
|
||||||
out.difficulty = parseInt(difficulty);
|
|
||||||
if (isNaN(out.difficulty) || out.difficulty < 0) {
|
|
||||||
out.difficulty = null;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse Skills from technique
|
|
||||||
* @param {string} skills
|
|
||||||
* @return {{skillId: number, skillCatId: number}|boolean}
|
|
||||||
*/
|
|
||||||
static parseSkills(skills) {
|
|
||||||
// Check category
|
|
||||||
const categories = game.l5r5e.HelpersL5r5e.getCategoriesSkillsList();
|
|
||||||
const categories2 = game.l5r5e.HelpersL5r5e.getSkillsList(true);
|
|
||||||
|
|
||||||
// Expand category (social) to it's skillname (command,courtesy...)
|
|
||||||
// const skillList = [];
|
|
||||||
// skills.split(',').forEach(e => {
|
|
||||||
// if () {
|
|
||||||
// table.push(e);
|
|
||||||
// }
|
|
||||||
// });
|
|
||||||
|
|
||||||
console.log(categories, categories2);
|
|
||||||
|
|
||||||
// Check skill
|
|
||||||
|
|
||||||
return {
|
|
||||||
skillId: skills,
|
|
||||||
// skillCatId,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the actor who have the min/max value for this property
|
* Return the actor who have the min/max value for this property
|
||||||
* @param {string} property Property name (vigilance, strife.value)
|
* @param {string} property Property name (vigilance, strife.value)
|
||||||
* @param {boolean|null} isMin Null: single target, Min/Max: get the actor who have the max value
|
* @param {boolean|null} isMin Null: single target, Min/Max: get the actor who have the max value
|
||||||
* @return {null|*}
|
* @return {ActorL5r5e|null}
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
static _getTargetActorFromSelection(property, isMin = null) {
|
static _getTargetActorFromSelection(property, isMin = null) {
|
||||||
@@ -706,4 +645,103 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
}
|
}
|
||||||
return targetActor;
|
return targetActor;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the difficulty from technique
|
||||||
|
*
|
||||||
|
* Exemples :
|
||||||
|
* "@S:vigilance"
|
||||||
|
* "@T:vigilance"
|
||||||
|
* "@T:vigilance|min"
|
||||||
|
* "@T:vigilance|max"
|
||||||
|
* "@T:vigilance|max(statusRank)"
|
||||||
|
* "@T:intrigueRank"
|
||||||
|
* "@T:martialRank"
|
||||||
|
* "@T:statusRank|max"
|
||||||
|
* "@T:strife.value|max"
|
||||||
|
*
|
||||||
|
* @param {string|number} difficulty
|
||||||
|
* @return {boolean}
|
||||||
|
*/
|
||||||
|
parseDifficulty(difficulty) {
|
||||||
|
// Macro style
|
||||||
|
if (!Number.isNumeric(difficulty) && difficulty.startsWith("@")) {
|
||||||
|
// 0: "@T:vigilance|max(statusRank)"
|
||||||
|
// 1: "T" // Meaning : S(elf), T(arget)
|
||||||
|
// 2: "vigilance"
|
||||||
|
// 3: "max"
|
||||||
|
// 4: "statusRank"
|
||||||
|
const infos = difficulty.match(/^@([TS]):([^|]+?)(?:\|(min|max)(?:\(([^)]+?)\))?)?$/);
|
||||||
|
if (!infos) {
|
||||||
|
console.log("L5R5E | Fail to parse difficulty", difficulty);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Define which actor is needed for the difficulty
|
||||||
|
let targetActor;
|
||||||
|
if (infos[1] === "S") {
|
||||||
|
targetActor = this._actor;
|
||||||
|
} else if (game.user.targets.size > 0) {
|
||||||
|
// Between the targets
|
||||||
|
targetActor = DicePickerDialog._getTargetActorFromSelection(
|
||||||
|
infos[4] || infos[2],
|
||||||
|
!infos[3] ? null : infos[3] === "min"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
// Wrong syntax or no target set, do manual TN
|
||||||
|
if (!targetActor) {
|
||||||
|
console.log("L5R5E | Fail to get actor from target selection");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check in actor.<prop> or actor.data.data.<prop>
|
||||||
|
difficulty = targetActor[infos[2]] || targetActor.data.data[infos[2]] || null;
|
||||||
|
if (difficulty < 1) {
|
||||||
|
console.log("L5R5E | Fail to parse difficulty from target");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Hide npc stats on target
|
||||||
|
if (infos[1] === "T") {
|
||||||
|
this.difficultyHidden = true;
|
||||||
|
this._difficultyHiddenIsLock.option = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// finally
|
||||||
|
difficulty = parseInt(difficulty);
|
||||||
|
if (isNaN(difficulty) || difficulty < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
this.difficulty = difficulty;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse Skills from technique
|
||||||
|
*
|
||||||
|
* Character : expand category (social) to it's skillname (command,courtesy...)
|
||||||
|
* NPC : shrink to category names
|
||||||
|
*
|
||||||
|
* @param {string} skillList
|
||||||
|
* @return {string[]}
|
||||||
|
*/
|
||||||
|
parseSkillsList(skillList) {
|
||||||
|
const categories = game.l5r5e.HelpersL5r5e.getCategoriesSkillsList();
|
||||||
|
const out = new Set();
|
||||||
|
skillList.split(",").forEach((s) => {
|
||||||
|
s = s.trim();
|
||||||
|
|
||||||
|
if (CONFIG.l5r5e.skills.has(s)) {
|
||||||
|
out.add(this.actorIsPc ? s : CONFIG.l5r5e.skills.get(s));
|
||||||
|
} else if (categories.has(s)) {
|
||||||
|
if (this.actorIsPc) {
|
||||||
|
categories.get(s).forEach((e) => out.add(e));
|
||||||
|
} else {
|
||||||
|
out.add(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return [...out];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -93,6 +93,9 @@
|
|||||||
border: none !important;
|
border: none !important;
|
||||||
text-shadow: none !important;
|
text-shadow: none !important;
|
||||||
}
|
}
|
||||||
|
select {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
img {
|
img {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|||||||
@@ -20,9 +20,24 @@
|
|||||||
</td>
|
</td>
|
||||||
<td class="skill">
|
<td class="skill">
|
||||||
{{#if data.skill.name}}
|
{{#if data.skill.name}}
|
||||||
|
{{#if data.skill.list}}
|
||||||
|
{{#if actorIsPc}}
|
||||||
|
<label>{{localizeSkill data.skill.cat 'title'}}</label>
|
||||||
|
{{/if}}
|
||||||
|
<select class="attribute-dtype" name="skill">
|
||||||
|
{{#select data.skill.id}}
|
||||||
|
{{#each data.skill.list as |id|}}
|
||||||
|
<option value="{{id}}">{{localizeSkillId id}}</option>
|
||||||
|
{{/each}}
|
||||||
|
{{/select}}
|
||||||
|
</select>
|
||||||
|
{{else}}
|
||||||
<label>{{localizeSkill data.skill.cat 'title'}}</label>
|
<label>{{localizeSkill data.skill.cat 'title'}}</label>
|
||||||
{{#if actorIsPc}}
|
{{#if actorIsPc}}
|
||||||
|
<div>
|
||||||
<label>{{data.skill.name}}</label>
|
<label>{{data.skill.name}}</label>
|
||||||
|
</div>
|
||||||
|
{{/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
<label id="stance_label">{{localizeSkill data.skill.cat data.ring.id}}</label>
|
<label id="stance_label">{{localizeSkill data.skill.cat data.ring.id}}</label>
|
||||||
<div id="skill_default_value" class="dice-container pointer-choice">
|
<div id="skill_default_value" class="dice-container pointer-choice">
|
||||||
|
|||||||
Reference in New Issue
Block a user