Initiative rework, with some broken css
This commit is contained in:
10
CHANGELOG.md
10
CHANGELOG.md
@@ -1,5 +1,15 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 1.0.1 - Initiative first !
|
||||||
|
- Added initiative system :
|
||||||
|
- Now use the score rule (the real one if you prefer)
|
||||||
|
- Added global modifiers for Characters, Adversary and Minons in the combat tracker : Confrontation types, Prepared
|
||||||
|
- Added sheet modifiers for Characters and Adversary: Prepared
|
||||||
|
- Initiative buttons in character sheet now display the DicePicker and do the initiative roll
|
||||||
|
- Spanish real translation by Alejabar (thanks !)
|
||||||
|
- Added a GM Dialog Tool for setting global difficulty (TN) value / hidden (with DicePicker live refresh)
|
||||||
|
- Compendium now display Ring and Rank if any in list view
|
||||||
|
|
||||||
## 1.0.0 - First public release
|
## 1.0.0 - First public release
|
||||||
- Removed the 0ds if no skill point
|
- Removed the 0ds if no skill point
|
||||||
- Added initiative roll (only tactics for the moment)
|
- Added initiative roll (only tactics for the moment)
|
||||||
|
|||||||
@@ -283,7 +283,11 @@
|
|||||||
"intrigue": "Intrigue",
|
"intrigue": "Intrigue",
|
||||||
"duel": "Duel",
|
"duel": "Duel",
|
||||||
"skirmish": "Skirmish",
|
"skirmish": "Skirmish",
|
||||||
"mass_battle": "Mass Battle"
|
"mass_battle": "Mass Battle",
|
||||||
|
"prepared_true": "Prepared",
|
||||||
|
"prepared_false": "Surprised",
|
||||||
|
"prepared_null": "Defined in the character sheet (default)",
|
||||||
|
"already_set": "Your initiative has already been drawn"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"advancements": {
|
"advancements": {
|
||||||
@@ -299,11 +303,10 @@
|
|||||||
"curriculum": "In curriculum",
|
"curriculum": "In curriculum",
|
||||||
"curriculum_validate": "Complete this rank"
|
"curriculum_validate": "Complete this rank"
|
||||||
},
|
},
|
||||||
"npc": {
|
"character_types": {
|
||||||
"types": {
|
"character": "Player Character",
|
||||||
"adversary": "Adversary",
|
"adversary": "Adversary",
|
||||||
"minion": "Minion"
|
"minion": "Minion"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"twenty_questions": {
|
"twenty_questions": {
|
||||||
"title": "Twenty questions",
|
"title": "Twenty questions",
|
||||||
|
|||||||
@@ -283,7 +283,11 @@
|
|||||||
"intrigue": "Intriga",
|
"intrigue": "Intriga",
|
||||||
"duel": "Duelo",
|
"duel": "Duelo",
|
||||||
"skirmish": "Escaramuza",
|
"skirmish": "Escaramuza",
|
||||||
"mass_battle": "Batalla a gran escala"
|
"mass_battle": "Batalla a gran escala",
|
||||||
|
"prepared_true": "Prepared",
|
||||||
|
"prepared_false": "Surprised",
|
||||||
|
"prepared_null": "Defined in the character sheet (default)",
|
||||||
|
"already_set": "Your initiative has already been drawn"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"advancements": {
|
"advancements": {
|
||||||
@@ -299,11 +303,10 @@
|
|||||||
"curriculum": "En programa de estudio",
|
"curriculum": "En programa de estudio",
|
||||||
"curriculum_validate": "Completar este rango"
|
"curriculum_validate": "Completar este rango"
|
||||||
},
|
},
|
||||||
"npc": {
|
"character_types": {
|
||||||
"types": {
|
"character": "Personaje jugador",
|
||||||
"adversary": "Adversario",
|
"adversary": "Adversario",
|
||||||
"minion": "Esbirro"
|
"minion": "Esbirro"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"twenty_questions": {
|
"twenty_questions": {
|
||||||
"title": "Veinte preguntas",
|
"title": "Veinte preguntas",
|
||||||
|
|||||||
@@ -283,7 +283,11 @@
|
|||||||
"intrigue": "Intrigue",
|
"intrigue": "Intrigue",
|
||||||
"duel": "Duel",
|
"duel": "Duel",
|
||||||
"skirmish": "Escarmouche",
|
"skirmish": "Escarmouche",
|
||||||
"mass_battle": "Bataille rangée"
|
"mass_battle": "Bataille rangée",
|
||||||
|
"prepared_true": "Prêt(e)",
|
||||||
|
"prepared_false": "Surpris(e)",
|
||||||
|
"prepared_null": "Défini par la fiche de personnage (défaut)",
|
||||||
|
"already_set": "Votre initiative a déjà été tirée"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"advancements": {
|
"advancements": {
|
||||||
@@ -299,11 +303,10 @@
|
|||||||
"curriculum": "Inclus dans le cursus",
|
"curriculum": "Inclus dans le cursus",
|
||||||
"curriculum_validate": "Valider la progression"
|
"curriculum_validate": "Valider la progression"
|
||||||
},
|
},
|
||||||
"npc": {
|
"character_types": {
|
||||||
"types": {
|
"character": "Personnage Joueur",
|
||||||
"adversary": "Antagoniste",
|
"adversary": "Antagoniste",
|
||||||
"minion": "Sous-fifre"
|
"minion": "Sous-fifre"
|
||||||
}
|
|
||||||
},
|
},
|
||||||
"twenty_questions": {
|
"twenty_questions": {
|
||||||
"title": "Le jeu des Vingt questions",
|
"title": "Le jeu des Vingt questions",
|
||||||
|
|||||||
@@ -96,6 +96,12 @@ export class ActorL5r5e extends Actor {
|
|||||||
if (data.void_points.value > data.void_points.max) {
|
if (data.void_points.value > data.void_points.max) {
|
||||||
data.void_points.value = data.void_points.max;
|
data.void_points.value = data.void_points.max;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// *** Migration stuff ***
|
||||||
|
// TODO remove in patch 1.1+
|
||||||
|
if (data.prepared === undefined) {
|
||||||
|
data.prepared = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -175,6 +175,7 @@ export class BaseSheetL5r5e extends ActorSheet {
|
|||||||
new game.l5r5e.DicePickerDialog({
|
new game.l5r5e.DicePickerDialog({
|
||||||
skillId: li.data("skill") || null,
|
skillId: li.data("skill") || null,
|
||||||
skillCatId: li.data("skillcat") || null,
|
skillCatId: li.data("skillcat") || null,
|
||||||
|
isInitiativeRoll: li.data("initiative") || false,
|
||||||
actor: this.actor,
|
actor: this.actor,
|
||||||
}).render(true);
|
}).render(true);
|
||||||
});
|
});
|
||||||
@@ -186,6 +187,16 @@ export class BaseSheetL5r5e extends ActorSheet {
|
|||||||
event.target.select();
|
event.target.select();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Prepared (Initiative)
|
||||||
|
html.find(".prepared-control").on("click", (event) => {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
const preparedId = $(event.currentTarget).data("id");
|
||||||
|
if (["adversary", "character"].includes(preparedId)) {
|
||||||
|
this._switchPrepared();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// *** Items : add, edit, delete ***
|
// *** Items : add, edit, delete ***
|
||||||
html.find(".item-add").on("click", (event) => {
|
html.find(".item-add").on("click", (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
@@ -204,6 +215,20 @@ export class BaseSheetL5r5e extends ActorSheet {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Switch the state "prepared" (initiative)
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
_switchPrepared() {
|
||||||
|
this.actor.data.data.prepared = !this.actor.data.data.prepared;
|
||||||
|
this.actor.update({
|
||||||
|
data: {
|
||||||
|
prepared: this.actor.data.data.prepared,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
this.render(false);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a generic item with sub type
|
* Add a generic item with sub type
|
||||||
* @private
|
* @private
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ export class NpcSheetL5r5e extends BaseSheetL5r5e {
|
|||||||
|
|
||||||
sheetData.data.types = NpcSheetL5r5e.types.map((e) => ({
|
sheetData.data.types = NpcSheetL5r5e.types.map((e) => ({
|
||||||
id: e,
|
id: e,
|
||||||
label: game.i18n.localize("l5r5e.npc.types." + e),
|
label: game.i18n.localize("l5r5e.character_types." + e),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
return sheetData;
|
return sheetData;
|
||||||
|
|||||||
@@ -22,57 +22,90 @@ export class CombatL5r5e extends Combat {
|
|||||||
ids = [ids];
|
ids = [ids];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make combatants array
|
// Get global modifiers
|
||||||
const combatants = [];
|
const cfg = {
|
||||||
ids.forEach((combatantId) => {
|
difficulty: game.settings.get("l5r5e", "initiative.difficulty.value"),
|
||||||
const combatant = game.combat.combatants.find((c) => c._id === combatantId);
|
difficultyHidden: game.settings.get("l5r5e", "initiative.difficulty.hidden"),
|
||||||
if (combatant && combatant.actor) {
|
prepared: {
|
||||||
combatants.push(combatant);
|
character: game.settings.get("l5r5e", "initiative.prepared.character"),
|
||||||
}
|
adversary: game.settings.get("l5r5e", "initiative.prepared.adversary"),
|
||||||
});
|
minion: game.settings.get("l5r5e", "initiative.prepared.minion"),
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
// Get modifiers
|
// SkillId from DicePicker or global
|
||||||
const difficulty = game.settings.get("l5r5e", "initiative.difficulty.value");
|
const skillId = messageOptions.skillId
|
||||||
const difficultyHidden = game.settings.get("l5r5e", "initiative.difficulty.hidden");
|
? messageOptions.skillId
|
||||||
const skillId = CONFIG.l5r5e.initiativeSkills[game.settings.get("l5r5e", "initiative.encounter")];
|
: CONFIG.l5r5e.initiativeSkills[game.settings.get("l5r5e", "initiative.encounter")];
|
||||||
const skillCat = CONFIG.l5r5e.skills.get(skillId);
|
const skillCat = CONFIG.l5r5e.skills.get(skillId);
|
||||||
|
|
||||||
// Get score for each combatant
|
// Get score for each combatant
|
||||||
const updatedCombatants = [];
|
const updatedCombatants = [];
|
||||||
combatants.forEach((combatant) => {
|
ids.forEach((combatantId) => {
|
||||||
|
const combatant = game.combat.combatants.find((c) => c._id === combatantId);
|
||||||
|
if (!combatant || !combatant.actor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// shortcut to data
|
||||||
const data = combatant.actor.data.data;
|
const data = combatant.actor.data.data;
|
||||||
|
|
||||||
// A character’s initiative value is based on their state of preparedness when the conflict began.
|
// A character’s initiative value is based on their state of preparedness when the conflict began.
|
||||||
// If the character was ready for the conflict, their base initiative value is their focus attribute.
|
// If the character was ready for the conflict, their base initiative value is their focus attribute.
|
||||||
// If the character was unprepared (such as when surprised), their base initiative value is their vigilance attribute.
|
// If the character was unprepared (such as when surprised), their base initiative value is their vigilance attribute.
|
||||||
const isPrepared = true; // TODO in actor ? (pc and npc)
|
let initiative = 0;
|
||||||
let initiative = isPrepared ? data.focus : data.vigilance;
|
|
||||||
|
|
||||||
|
if (combatant.actor.data.type === "npc" && combatant.actor.data.data.type === "minion") {
|
||||||
|
// Minion NPCs can generate initiative value without a check, using their focus or vigilance attribute
|
||||||
|
initiative = cfg.prepared.minion ? data.focus : data.vigilance;
|
||||||
|
} else {
|
||||||
// PC and Adversary
|
// PC and Adversary
|
||||||
// (minion NPCs can generate initiative value without a check, using their focus or vigilance attribute)
|
const isPc = combatant.actor.data.type === "character";
|
||||||
if (combatant.actor.data.type !== "npc" || combatant.actor.data.data.type === "minion") {
|
|
||||||
const formula = [`${data.rings[data.stance]}dr`];
|
// prepared is a boolean or if null we get the info in the actor sheet
|
||||||
const skillValue =
|
let isPrepared = isPc ? cfg.prepared.character : cfg.prepared.adversary;
|
||||||
combatant.actor.data.type === "npc" ? data.skills[skillCat] : data.skills[skillCat][skillId];
|
if (isPrepared === "null") {
|
||||||
|
isPrepared = data.prepared;
|
||||||
|
}
|
||||||
|
initiative = isPrepared ? data.focus : data.vigilance;
|
||||||
|
|
||||||
|
// Roll formula
|
||||||
|
if (!formula) {
|
||||||
|
const createFormula = [`${data.rings[data.stance]}dr`];
|
||||||
|
const skillValue = isPc ? data.skills[skillCat][skillId] : data.skills[skillCat];
|
||||||
if (skillValue > 0) {
|
if (skillValue > 0) {
|
||||||
formula.push(`${skillValue}ds`);
|
createFormula.push(`${skillValue}ds`);
|
||||||
|
}
|
||||||
|
formula = createFormula.join("+");
|
||||||
}
|
}
|
||||||
|
|
||||||
const roll = new game.l5r5e.RollL5r5e(formula.join("+"));
|
const roll = new game.l5r5e.RollL5r5e(formula);
|
||||||
|
|
||||||
roll.actor = combatant.actor;
|
roll.actor = combatant.actor;
|
||||||
roll.l5r5e.stance = data.stance;
|
roll.l5r5e.stance = data.stance;
|
||||||
roll.l5r5e.skillId = skillId;
|
roll.l5r5e.skillId = skillId;
|
||||||
roll.l5r5e.summary.difficulty = difficulty;
|
roll.l5r5e.skillCatId = skillCat;
|
||||||
roll.l5r5e.summary.difficultyHidden = difficultyHidden;
|
roll.l5r5e.summary.difficulty =
|
||||||
|
messageOptions.difficulty !== undefined ? messageOptions.difficulty : cfg.difficulty;
|
||||||
|
roll.l5r5e.summary.difficultyHidden =
|
||||||
|
messageOptions.difficultyHidden !== undefined
|
||||||
|
? messageOptions.difficultyHidden
|
||||||
|
: cfg.difficultyHidden;
|
||||||
|
roll.l5r5e.summary.voidPointUsed = !!messageOptions.useVoidPoint;
|
||||||
|
|
||||||
roll.roll();
|
roll.roll();
|
||||||
roll.toMessage({ flavor: game.i18n.localize("l5r5e.chatdices.initiative_roll") });
|
roll.toMessage({
|
||||||
|
flavor:
|
||||||
|
game.i18n.localize("l5r5e.chatdices.initiative_roll") +
|
||||||
|
" (" +
|
||||||
|
game.i18n.localize(`l5r5e.conflict.initiative.prepared_${isPrepared}`) +
|
||||||
|
")",
|
||||||
|
});
|
||||||
|
|
||||||
// if the character succeeded on their Initiative check, they add 1 to their base initiative value,
|
// if the character succeeded on their Initiative check, they add 1 to their base initiative value,
|
||||||
// plus an additional amount equal to their bonus successes.
|
// plus an additional amount equal to their bonus successes.
|
||||||
if (roll.l5r5e.summary.success >= difficulty) {
|
if (roll.l5r5e.summary.success >= roll.l5r5e.summary.difficulty) {
|
||||||
initiative = initiative + 1 + Math.max(roll.l5r5e.summary.success - difficulty, 0);
|
initiative =
|
||||||
|
initiative + 1 + Math.max(roll.l5r5e.summary.success - roll.l5r5e.summary.difficulty, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
export class DicePickerDialog extends FormApplication {
|
export class DicePickerDialog extends FormApplication {
|
||||||
/**
|
/**
|
||||||
* Current Actor
|
* Current Actor
|
||||||
|
* @type {Actor}
|
||||||
|
* @private
|
||||||
*/
|
*/
|
||||||
_actor = null;
|
_actor = null;
|
||||||
|
|
||||||
@@ -29,6 +31,7 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
add_void_point: true,
|
add_void_point: true,
|
||||||
},
|
},
|
||||||
useVoidPoint: false,
|
useVoidPoint: false,
|
||||||
|
isInitiativeRoll: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -84,8 +87,9 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
* skillCatId string (artisan)
|
* skillCatId string (artisan)
|
||||||
* difficulty number (0-9)
|
* difficulty number (0-9)
|
||||||
* difficultyHidden boolean
|
* difficultyHidden boolean
|
||||||
|
* isInitiativeRoll boolean
|
||||||
*
|
*
|
||||||
* @param options actor, actorId, ringId, actorName, skillId, skillCatId, difficulty, difficultyHidden
|
* @param options actor, actorId, ringId, actorName, skillId, skillCatId, difficulty, difficultyHidden, isInitiativeRoll
|
||||||
*/
|
*/
|
||||||
constructor(options = {}) {
|
constructor(options = {}) {
|
||||||
super({}, options);
|
super({}, options);
|
||||||
@@ -104,33 +108,38 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Ring
|
// Ring
|
||||||
if (options?.ringId) {
|
if (options.ringId) {
|
||||||
this.ringId = options.ringId;
|
this.ringId = options.ringId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skill / SkillCategory
|
// Skill / SkillCategory
|
||||||
if (options?.skillId) {
|
if (options.skillId) {
|
||||||
this.skillId = options.skillId;
|
this.skillId = options.skillId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// SkillCategory skillCatId
|
// SkillCategory skillCatId
|
||||||
if (options?.skillCatId) {
|
if (options.skillCatId) {
|
||||||
this.skillCatId = options.skillCatId;
|
this.skillCatId = options.skillCatId;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Difficulty
|
// Difficulty
|
||||||
if (options?.difficulty) {
|
if (options.difficulty) {
|
||||||
this.difficulty = options.difficulty;
|
this.difficulty = options.difficulty;
|
||||||
} else {
|
} else {
|
||||||
this.difficulty = game.settings.get("l5r5e", "initiative.difficulty.value");
|
this.difficulty = game.settings.get("l5r5e", "initiative.difficulty.value");
|
||||||
}
|
}
|
||||||
|
|
||||||
// difficultyHidden
|
// DifficultyHidden
|
||||||
if (options?.difficultyHidden) {
|
if (options.difficultyHidden) {
|
||||||
this.difficultyHidden = options.difficultyHidden;
|
this.difficultyHidden = options.difficultyHidden;
|
||||||
} else {
|
} else {
|
||||||
this.difficultyHidden = game.settings.get("l5r5e", "initiative.difficulty.hidden");
|
this.difficultyHidden = game.settings.get("l5r5e", "initiative.difficulty.hidden");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// InitiativeRoll
|
||||||
|
if (options.isInitiativeRoll) {
|
||||||
|
this.object.isInitiativeRoll = !!options.isInitiativeRoll;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -355,12 +364,13 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
let formula = [];
|
// If initiative roll, check if player already have
|
||||||
if (this.object.ring.value > 0) {
|
if (this.object.isInitiativeRoll) {
|
||||||
formula.push(`${this.object.ring.value}dr`);
|
const combatant = game.combat.combatants.find((c) => c.actor._id === this._actor._id && c.initiative > 0);
|
||||||
|
if (combatant) {
|
||||||
|
ui.notifications.error(game.i18n.localize("l5r5e.conflict.initiative.already_set"));
|
||||||
|
return this.close();
|
||||||
}
|
}
|
||||||
if (this.object.skill.value > 0) {
|
|
||||||
formula.push(`${this.object.skill.value}ds`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update Actor
|
// Update Actor
|
||||||
@@ -381,12 +391,36 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update actor
|
// Update actor
|
||||||
this._actor.update({
|
await this._actor.update({
|
||||||
data: diffObject(this._actor.data.data, actorData),
|
data: diffObject(this._actor.data.data, actorData),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// Let's roll !
|
// Build the formula
|
||||||
|
let formula = [];
|
||||||
|
if (this.object.ring.value > 0) {
|
||||||
|
formula.push(`${this.object.ring.value}dr`);
|
||||||
|
}
|
||||||
|
if (this.object.skill.value > 0) {
|
||||||
|
formula.push(`${this.object.skill.value}ds`);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.object.isInitiativeRoll) {
|
||||||
|
// Initiative roll
|
||||||
|
this._actor.rollInitiative({
|
||||||
|
initiativeOptions: {
|
||||||
|
formula: formula.join("+"),
|
||||||
|
// updateTurn: true,
|
||||||
|
messageOptions: {
|
||||||
|
skillId: this.object.skill.id,
|
||||||
|
difficulty: this.object.difficulty.value,
|
||||||
|
difficultyHidden: this.object.difficulty.hidden,
|
||||||
|
useVoidPoint: this.object.useVoidPoint,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
// Regular roll, so let's roll !
|
||||||
const roll = await new game.l5r5e.RollL5r5e(formula.join("+"));
|
const roll = await new game.l5r5e.RollL5r5e(formula.join("+"));
|
||||||
|
|
||||||
roll.actor = this._actor;
|
roll.actor = this._actor;
|
||||||
@@ -399,6 +433,8 @@ export class DicePickerDialog extends FormApplication {
|
|||||||
|
|
||||||
await roll.roll();
|
await roll.roll();
|
||||||
await roll.toMessage();
|
await roll.toMessage();
|
||||||
|
}
|
||||||
|
|
||||||
return this.close();
|
return this.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -109,7 +109,7 @@ export class GmToolsDialog extends FormApplication {
|
|||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
// right clic - minus 1
|
// right clic - minus 1
|
||||||
this.object.difficulty = Math.max(1, this.object.difficulty - 1);
|
this.object.difficulty = Math.max(0, this.object.difficulty - 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
game.settings.set("l5r5e", "initiative.difficulty.value", this.object.difficulty).then(() => this.submit());
|
game.settings.set("l5r5e", "initiative.difficulty.value", this.object.difficulty).then(() => this.submit());
|
||||||
|
|||||||
@@ -61,63 +61,80 @@ export default class HooksL5r5e {
|
|||||||
* Combat tracker
|
* Combat tracker
|
||||||
*/
|
*/
|
||||||
static async renderCombatTracker(app, html, data) {
|
static async renderCombatTracker(app, html, data) {
|
||||||
// TODO do this in partial
|
// Display Combat bar (only for GMs)
|
||||||
let bar = "";
|
await this._gmCombatBar(app, html, data);
|
||||||
|
|
||||||
// *** Encounter Type ***
|
|
||||||
const encounterIcons = {
|
|
||||||
intrigue: "i_courtier",
|
|
||||||
duel: "fas fa-tint", // fa-tint / fa-blind
|
|
||||||
skirmish: "i_bushi",
|
|
||||||
mass_battle: "fa fa-users",
|
|
||||||
};
|
|
||||||
const encounterType = game.settings.get("l5r5e", "initiative.encounter");
|
|
||||||
Object.entries(CONFIG.l5r5e.initiativeSkills).forEach(([id, skill]) => {
|
|
||||||
bar =
|
|
||||||
bar +
|
|
||||||
`<a class="encounter encounter-control" data-id="${id}">` +
|
|
||||||
`<i class="${encounterIcons[id]}${id === encounterType ? " active" : ""}" title="${game.i18n.localize(
|
|
||||||
"l5r5e.conflict.initiative." + id
|
|
||||||
)}"></i>` +
|
|
||||||
`</a>`;
|
|
||||||
});
|
|
||||||
|
|
||||||
// *** Prepared ***
|
|
||||||
// TODO
|
|
||||||
// const encounterType = game.settings.get("l5r5e", "initiative.prepared");
|
|
||||||
bar =
|
|
||||||
bar +
|
|
||||||
`<a class="encounter prepared-control" data-id="tmp">` +
|
|
||||||
`<i class="fa fa-low-vision" title="npc prepared or not (WIP)"></i>` +
|
|
||||||
`</a>`;
|
|
||||||
|
|
||||||
const elmt = html.find("#l5r5e_encounter");
|
|
||||||
if (elmt.length > 0) {
|
|
||||||
elmt.html(bar);
|
|
||||||
} else {
|
|
||||||
html.find("#combat-round").append(`<nav class="encounters flexrow" id="l5r5e_encounter">${bar}</nav>`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Buttons Listener
|
/**
|
||||||
|
* Display a GM bar for Combat/Initiative
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
static async _gmCombatBar(app, html, data) {
|
||||||
|
// Only for GMs
|
||||||
|
if (!game.user.isGM) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// *** Conf ***
|
||||||
|
const encounterTypeList = Object.keys(CONFIG.l5r5e.initiativeSkills);
|
||||||
|
const prepared = {
|
||||||
|
character: game.settings.get("l5r5e", "initiative.prepared.character"),
|
||||||
|
adversary: game.settings.get("l5r5e", "initiative.prepared.adversary"),
|
||||||
|
minion: game.settings.get("l5r5e", "initiative.prepared.minion"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// *** Template ***
|
||||||
|
const tpl = await renderTemplate(`${CONFIG.l5r5e.paths.templates}gm/combat-tracker-bar.html`, {
|
||||||
|
encounterType: game.settings.get("l5r5e", "initiative.encounter"),
|
||||||
|
encounterTypeList,
|
||||||
|
prepared,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add/replace in bar
|
||||||
|
const elmt = html.find("#l5r5e_gm_combat_tracker_bar");
|
||||||
|
if (elmt.length > 0) {
|
||||||
|
elmt.replaceWith(tpl);
|
||||||
|
} else {
|
||||||
|
html.find("#combat-round").append(tpl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Buttons Listeners
|
||||||
|
// TODO event for multiple GM
|
||||||
html.find(".encounter-control").on("click", (event) => {
|
html.find(".encounter-control").on("click", (event) => {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
event.stopPropagation();
|
event.stopPropagation();
|
||||||
const encounter = $(event.currentTarget).data("id");
|
const encounter = $(event.currentTarget).data("id");
|
||||||
|
if (!encounterTypeList.includes(encounter)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
game.settings
|
game.settings
|
||||||
.set("l5r5e", "initiative.encounter", encounter)
|
.set("l5r5e", "initiative.encounter", encounter)
|
||||||
.then(() => HooksL5r5e.renderCombatTracker(app, html, data));
|
.then(() => HooksL5r5e._gmCombatBar(app, html, data));
|
||||||
});
|
});
|
||||||
|
|
||||||
// html.find(".prepared-control").on("click", (event) => {
|
html.find(".prepared-control").on("click", (event) => {
|
||||||
// event.preventDefault();
|
event.preventDefault();
|
||||||
// event.stopPropagation();
|
event.stopPropagation();
|
||||||
// let prepared = $(event.currentTarget).data('id');
|
let preparedId = $(event.currentTarget).data("id");
|
||||||
// // if same, unset it
|
if (!Object.hasOwnProperty.call(prepared, preparedId)) {
|
||||||
// if (prepared === encounterType) {
|
return;
|
||||||
// prepared = "";
|
}
|
||||||
// }
|
let value = prepared[preparedId];
|
||||||
// game.settings.set("l5r5e", "initiative.prepared", prepared).then(() => HooksL5r5e.renderCombatTracker(app, html, data));
|
switch (value) {
|
||||||
// });
|
case "false":
|
||||||
|
value = "true";
|
||||||
|
break;
|
||||||
|
case "true":
|
||||||
|
value = preparedId === "minion" ? "false" : "null";
|
||||||
|
break;
|
||||||
|
case "null":
|
||||||
|
value = "false";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
game.settings
|
||||||
|
.set("l5r5e", `initiative.prepared.${preparedId}`, value)
|
||||||
|
.then(() => HooksL5r5e._gmCombatBar(app, html, data));
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export const PreloadTemplates = async function () {
|
|||||||
"systems/l5r5e/templates/actors/npc/social.html",
|
"systems/l5r5e/templates/actors/npc/social.html",
|
||||||
"systems/l5r5e/templates/actors/npc/rings.html",
|
"systems/l5r5e/templates/actors/npc/rings.html",
|
||||||
"systems/l5r5e/templates/actors/npc/attributes.html",
|
"systems/l5r5e/templates/actors/npc/attributes.html",
|
||||||
|
"systems/l5r5e/templates/actors/npc/conflict.html",
|
||||||
"systems/l5r5e/templates/actors/npc/skill.html",
|
"systems/l5r5e/templates/actors/npc/skill.html",
|
||||||
"systems/l5r5e/templates/actors/npc/techniques.html",
|
"systems/l5r5e/templates/actors/npc/techniques.html",
|
||||||
// items
|
// items
|
||||||
|
|||||||
@@ -26,11 +26,25 @@ export const RegisterSettings = function () {
|
|||||||
type: String,
|
type: String,
|
||||||
default: "skirmish",
|
default: "skirmish",
|
||||||
});
|
});
|
||||||
game.settings.register("l5r5e", "initiative.prepared", {
|
game.settings.register("l5r5e", "initiative.prepared.character", {
|
||||||
name: "Initiative NPC prepared or not",
|
name: "Initiative PC prepared or not",
|
||||||
scope: "world",
|
scope: "world",
|
||||||
config: false,
|
config: false,
|
||||||
type: Boolean,
|
type: String,
|
||||||
default: true,
|
default: "null",
|
||||||
|
});
|
||||||
|
game.settings.register("l5r5e", "initiative.prepared.adversary", {
|
||||||
|
name: "Initiative NPC adversary are prepared or not",
|
||||||
|
scope: "world",
|
||||||
|
config: false,
|
||||||
|
type: String,
|
||||||
|
default: "null",
|
||||||
|
});
|
||||||
|
game.settings.register("l5r5e", "initiative.prepared.minion", {
|
||||||
|
name: "Initiative NPC minion are prepared or not",
|
||||||
|
scope: "world",
|
||||||
|
config: false,
|
||||||
|
type: String,
|
||||||
|
default: "true",
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -264,6 +264,38 @@ sup {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.prepared {
|
||||||
|
&-character {
|
||||||
|
color: $l5r5e-earth;
|
||||||
|
}
|
||||||
|
&-adversary {
|
||||||
|
color: $l5r5e-fire;
|
||||||
|
}
|
||||||
|
&-minion {
|
||||||
|
color: $l5r5e-water;
|
||||||
|
}
|
||||||
|
&-icon {
|
||||||
|
font-weight: 900;
|
||||||
|
font-family: "Font Awesome 5 Free";
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
display: inline-block;
|
||||||
|
font-style: normal;
|
||||||
|
font-variant: normal;
|
||||||
|
text-rendering: auto;
|
||||||
|
line-height: 1;
|
||||||
|
&-true:before {
|
||||||
|
content: "\f06e";
|
||||||
|
}
|
||||||
|
&-false:before {
|
||||||
|
content: "\f070";
|
||||||
|
}
|
||||||
|
&-null:before {
|
||||||
|
content: "\f2a8";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fix for "search anywhere" draggable icon
|
// Fix for "search anywhere" draggable icon
|
||||||
.window-draggable-handle {
|
.window-draggable-handle {
|
||||||
z-index: 2;
|
z-index: 2;
|
||||||
|
|||||||
@@ -24,25 +24,6 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.initiative {
|
|
||||||
&-wrapper {
|
|
||||||
display: block;
|
|
||||||
flex: 100%;
|
|
||||||
text-align: center;
|
|
||||||
}
|
|
||||||
button {
|
|
||||||
width: 22%;
|
|
||||||
margin: 0 0.25rem 0.25rem;
|
|
||||||
padding: 0 0.5rem;
|
|
||||||
color: #5a6e5a;
|
|
||||||
background: rgba(255, 255, 255, 0.5);
|
|
||||||
border: 1px solid #5a6e5a;
|
|
||||||
border-radius: 1rem;
|
|
||||||
}
|
|
||||||
button:focus {
|
|
||||||
box-shadow: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fieldset {
|
fieldset {
|
||||||
&.advancement {
|
&.advancement {
|
||||||
display: block;
|
display: block;
|
||||||
@@ -592,6 +573,25 @@
|
|||||||
}
|
}
|
||||||
&.actor,
|
&.actor,
|
||||||
&.npc {
|
&.npc {
|
||||||
|
.initiative {
|
||||||
|
&-wrapper {
|
||||||
|
display: block;
|
||||||
|
flex: 100%;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
width: 22%;
|
||||||
|
margin: 0 0.25rem 0.25rem;
|
||||||
|
padding: 0 0.5rem;
|
||||||
|
color: #5a6e5a;
|
||||||
|
background: rgba(255, 255, 255, 0.5);
|
||||||
|
border: 1px solid #5a6e5a;
|
||||||
|
border-radius: 1rem;
|
||||||
|
}
|
||||||
|
button:focus {
|
||||||
|
box-shadow: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
.limited {
|
.limited {
|
||||||
h1 {
|
h1 {
|
||||||
margin: 0.5rem 0;
|
margin: 0.5rem 0;
|
||||||
|
|||||||
@@ -568,7 +568,6 @@ button {
|
|||||||
h3 {
|
h3 {
|
||||||
font-size: 0.85rem;
|
font-size: 0.85rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.encounter {
|
.encounter {
|
||||||
i {
|
i {
|
||||||
font-size: 23px;
|
font-size: 23px;
|
||||||
@@ -576,7 +575,35 @@ button {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.active {
|
.active {
|
||||||
box-shadow: 0 1px 5px $l5r5e-red;
|
color: $l5r5e-maho;
|
||||||
|
}
|
||||||
|
|
||||||
|
&-icon {
|
||||||
|
font-weight: 900;
|
||||||
|
font-family: "Font Awesome 5 Free";
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
display: inline-block;
|
||||||
|
font-style: normal;
|
||||||
|
font-variant: normal;
|
||||||
|
text-rendering: auto;
|
||||||
|
line-height: 1;
|
||||||
|
|
||||||
|
&-intrigue:before {
|
||||||
|
content: "\f21b";
|
||||||
|
}
|
||||||
|
|
||||||
|
&-duel:before {
|
||||||
|
content: "\f506";
|
||||||
|
}
|
||||||
|
|
||||||
|
&-skirmish:before {
|
||||||
|
content: "\f505";
|
||||||
|
}
|
||||||
|
|
||||||
|
&-mass_battle:before {
|
||||||
|
content: "\f447";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,8 +5,27 @@
|
|||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"minimumCoreVersion": "0.7.9",
|
"minimumCoreVersion": "0.7.9",
|
||||||
"compatibleCoreVersion": "0.7.9",
|
"compatibleCoreVersion": "0.7.9",
|
||||||
|
"manifestPlusVersion": "1.0.0",
|
||||||
"socket": true,
|
"socket": true,
|
||||||
"author": "Team L5R",
|
"author": "Team L5R",
|
||||||
|
"authors": [
|
||||||
|
{
|
||||||
|
"name": "Vlyan",
|
||||||
|
"discord": "Vlyan#6771"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Mandar"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Carter"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Hrunh"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Sasmira"
|
||||||
|
}
|
||||||
|
],
|
||||||
"background": "L5R-Header.webp",
|
"background": "L5R-Header.webp",
|
||||||
"scripts": [],
|
"scripts": [],
|
||||||
"esmodules": ["./scripts/main-l5r5e.js"],
|
"esmodules": ["./scripts/main-l5r5e.js"],
|
||||||
|
|||||||
@@ -85,7 +85,8 @@
|
|||||||
"max": 1,
|
"max": 1,
|
||||||
"value": 0
|
"value": 0
|
||||||
},
|
},
|
||||||
"stance": "void"
|
"stance": "void",
|
||||||
|
"prepared": true
|
||||||
},
|
},
|
||||||
"advancement": {
|
"advancement": {
|
||||||
"xp_total": 0,
|
"xp_total": 0,
|
||||||
|
|||||||
@@ -1,9 +1,14 @@
|
|||||||
<fieldset class="initiative initiative-wrapper">
|
<fieldset class="initiative initiative-wrapper">
|
||||||
<legend class="section-header">{{ localize 'l5r5e.conflict.initiative.title' }}</legend>
|
<legend class="section-header">
|
||||||
<button class="initiative dice-picker" data-skill="sentiment">{{ localize 'l5r5e.conflict.initiative.intrigue'}}</button>
|
{{ localize 'l5r5e.conflict.initiative.title' }}
|
||||||
<button class="initiative dice-picker" data-skill="meditation">{{ localize 'l5r5e.conflict.initiative.duel'}}</button>
|
<a class="encounter prepared-control" data-id="{{entity.type}}">
|
||||||
<button class="initiative dice-picker" data-skill="tactics">{{ localize 'l5r5e.conflict.initiative.skirmish'}}</button>
|
<i class="fa fas prepared-icon prepared-icon-{{data.prepared}} prepared-{{entity.type}}" title="{{localize (localize 'l5r5e.conflict.initiative.prepared_{value}' value=data.prepared)}}"></i>
|
||||||
<button class="initiative dice-picker" data-skill="command">{{ localize 'l5r5e.conflict.initiative.mass_battle'}}</button>
|
</a>
|
||||||
|
</legend>
|
||||||
|
<button class="initiative dice-picker" data-initiative="true" data-skill="sentiment">{{ localize 'l5r5e.conflict.initiative.intrigue'}}</button>
|
||||||
|
<button class="initiative dice-picker" data-initiative="true" data-skill="meditation">{{ localize 'l5r5e.conflict.initiative.duel'}}</button>
|
||||||
|
<button class="initiative dice-picker" data-initiative="true" data-skill="tactics">{{ localize 'l5r5e.conflict.initiative.skirmish'}}</button>
|
||||||
|
<button class="initiative dice-picker" data-initiative="true" data-skill="command">{{ localize 'l5r5e.conflict.initiative.mass_battle'}}</button>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
<fieldset class="stances-content flexrow">
|
<fieldset class="stances-content flexrow">
|
||||||
<legend class="section-header">{{ localize 'l5r5e.conflict.stance' }}</legend>
|
<legend class="section-header">{{ localize 'l5r5e.conflict.stance' }}</legend>
|
||||||
|
|||||||
@@ -20,7 +20,12 @@
|
|||||||
</header>
|
</header>
|
||||||
{{!-- Sheet Body --}}
|
{{!-- Sheet Body --}}
|
||||||
<section class="sheet-body">
|
<section class="sheet-body">
|
||||||
|
<article>
|
||||||
{{> 'systems/l5r5e/templates/actors/npc/skill.html' }}
|
{{> 'systems/l5r5e/templates/actors/npc/skill.html' }}
|
||||||
|
{{#ifCond data.type '==' 'adversary'}}
|
||||||
|
{{> 'systems/l5r5e/templates/actors/npc/conflict.html' }}
|
||||||
|
{{/ifCond}}
|
||||||
|
</article>
|
||||||
<article>
|
<article>
|
||||||
{{> 'systems/l5r5e/templates/actors/npc/narrative.html' }}
|
{{> 'systems/l5r5e/templates/actors/npc/narrative.html' }}
|
||||||
</article>
|
</article>
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
|
<fieldset class="initiative initiative-wrapper">
|
||||||
|
<legend class="section-header">
|
||||||
|
{{ localize 'l5r5e.conflict.initiative.title' }}
|
||||||
|
<a class="encounter prepared-control" data-id="{{data.type}}">
|
||||||
|
<i class="fa fas prepared-icon prepared-icon-{{data.prepared}} prepared-{{data.type}}" title="{{localize (localize 'l5r5e.conflict.initiative.prepared_{value}' value=data.prepared)}}"></i>
|
||||||
|
</a>
|
||||||
|
</legend>
|
||||||
|
<button class="initiative dice-picker" data-initiative="true" data-skill="sentiment">{{ localize 'l5r5e.conflict.initiative.intrigue'}}</button>
|
||||||
|
<button class="initiative dice-picker" data-initiative="true" data-skill="meditation">{{ localize 'l5r5e.conflict.initiative.duel'}}</button>
|
||||||
|
<button class="initiative dice-picker" data-initiative="true" data-skill="tactics">{{ localize 'l5r5e.conflict.initiative.skirmish'}}</button>
|
||||||
|
<button class="initiative dice-picker" data-initiative="true" data-skill="command">{{ localize 'l5r5e.conflict.initiative.mass_battle'}}</button>
|
||||||
|
</fieldset>
|
||||||
<fieldset class="stances-content flexrow">
|
<fieldset class="stances-content flexrow">
|
||||||
<legend class="section-header">{{ localize 'l5r5e.conflict.stance' }}</legend>
|
<legend class="section-header">{{ localize 'l5r5e.conflict.stance' }}</legend>
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
17
system/templates/gm/combat-tracker-bar.html
Normal file
17
system/templates/gm/combat-tracker-bar.html
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
<nav class="encounters flexrow" id="l5r5e_gm_combat_tracker_bar">
|
||||||
|
<div class="encounter">
|
||||||
|
{{#each encounterTypeList}}
|
||||||
|
<a class="encounter encounter-control" data-id="{{this}}">
|
||||||
|
<i class="fa fas encounter-icon-{{this}}{{#ifCond this '==' ../encounterType}} active{{/ifCond}}" title="{{localize (localize 'l5r5e.conflict.initiative.{id}' id=this)}}"></i>
|
||||||
|
</a>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="prepared">
|
||||||
|
{{#each prepared as |prepared charType|}}
|
||||||
|
<a class="encounter prepared-control" data-id="{{charType}}">
|
||||||
|
<i class="fa fas prepared-icon-{{prepared}} prepared-{{charType}}" title="{{localize (localize 'l5r5e.conflict.initiative.prepared_{value}' value=prepared)}} ({{localize (localize 'l5r5e.character_types.{type}' type=charType)}})"></i>
|
||||||
|
</a>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
Reference in New Issue
Block a user