Compare commits
9 Commits
Author | SHA1 | Date | |
---|---|---|---|
f2106763c1 | |||
5da5cb0314 | |||
6d7f66569a | |||
3e8963b20b | |||
2cf5b06da8 | |||
68c01fc930 | |||
3bc1c4871b | |||
3d732e9a8a | |||
35f226af5c |
1
assets/ui/maladresse.svg
Normal file
1
assets/ui/maladresse.svg
Normal file
@@ -0,0 +1 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" style="height: 256px; width: 256px;"><g class="" transform="translate(0,0)" style=""><path d="M221.313 16a23.682 23.695 0 0 0-23.688 23.688v106.406a23.682 23.695 0 0 0 2.156 9.72 23.682 23.695 0 0 0 3.157 13.81l41.75 71.626-79 55.438 6.094-48.625a23.682 23.695 0 0 0-8.186-20.97l-66.28-81.937a23.682 23.695 0 0 0-33.314-3.5l-9.188 7.438a23.682 23.695 0 0 0-3.53 33.344l59.78 73.906-11.25 89.937a23.682 23.695 0 0 0 12.47 23.876l37.468 53.47a23.695 23.682 1.57 0 0 2.344 2.812 23.682 23.695 0 0 0 13.594 20.062L262 491.53a23.682 23.695 0 0 0 9.97 2.22 23.682 23.695 0 0 0 23.53-2.063l87.156-60.937a23.682 23.695 0 0 0 5.844-33l-6.78-9.688a23.682 23.695 0 0 0-32.97-5.875l-72.406 50.657-59.063-27.625 120.595-84.626a23.695 23.682 1.57 0 0 5.53-5.5 23.682 23.695 0 0 0 14.626-13.594l37.22-91.53 87.813-44.845a23.694 23.682 1.18 0 0 10.312-31.875L488 122.687a23.694 23.682 1.18 0 0-31.875-10.343l-94.688 48.375a23.694 23.682 1.18 0 0-9.843 9.436 23.682 23.695 0 0 0-8.344 10.47l-27.375 67.31-5.22-7.436a23.682 23.695 0 0 0-3-8.844l-50.81-87.094V39.688A23.682 23.695 0 0 0 233.154 16h-11.843zM77.75 376A59.994 60 0 0 0 16 436a59.994 60 0 1 0 120 0 59.994 60 0 0 0-58.25-60z" fill="#fff" fill-opacity="1"></path></g></svg>
|
After Width: | Height: | Size: 1.2 KiB |
12
changelog.md
12
changelog.md
@@ -1,5 +1,17 @@
|
||||
# 13.0
|
||||
|
||||
## 13.0.12 - La méditation d'Illysis
|
||||
|
||||
- les signes draconiques éphémères de 1 round sont supprimés à la descente des TMRs
|
||||
- Générateur de description
|
||||
- correction des termes pour les couleurs des yeux/cheveux
|
||||
- ajout de boutons pour forcer le sexe masculin/féminin
|
||||
- Nouvelle fenêtre de jets de dés
|
||||
- les méditations proposent un bouton pour monter dans les TMRs
|
||||
- fenêtre de lancer de sorts
|
||||
- Correction: les compétences de jeux ne remplacent plus les compétences en dehors des jets de jeu
|
||||
- gestion des maladresses d'attaque et défense
|
||||
|
||||
## 13.0.11 - Le gambit d'Illysis
|
||||
|
||||
- Nouvelle fenêtre de jets de dés
|
||||
|
@@ -924,6 +924,12 @@ select,
|
||||
.system-foundryvtt-reve-de-dragon a:hover {
|
||||
text-shadow: 1px 0px 0px #ff6600;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .tabs .item.active img,
|
||||
.system-foundryvtt-reve-de-dragon .blessures-list li ul li:first-child:hover img,
|
||||
.system-foundryvtt-reve-de-dragon i.moral-radio-checkmark-off:hover img,
|
||||
.system-foundryvtt-reve-de-dragon a:hover img {
|
||||
filter: drop-shadow(1px 0px 0px #ff6600);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .rollable:hover,
|
||||
.system-foundryvtt-reve-de-dragon .rollable:focus {
|
||||
color: #000;
|
||||
@@ -1448,12 +1454,27 @@ select,
|
||||
.system-foundryvtt-reve-de-dragon .competence-list .item-controls.hidden-controls {
|
||||
display: none !important;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular),
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls {
|
||||
vertical-align: super;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls img,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls img {
|
||||
display: inline;
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
margin: 0 0.1rem;
|
||||
border: none;
|
||||
filter: invert(0.8);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls i:is(.fas, .fa, .fa-solid, .fa-regular),
|
||||
.system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) {
|
||||
font-size: 0.8em;
|
||||
color: var(--color-controls-light);
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular):hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls img:hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls img:hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-actions-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover,
|
||||
.system-foundryvtt-reve-de-dragon .item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
@@ -1596,6 +1617,9 @@ select,
|
||||
color: var(--color-text-dark-primary);
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon form.app-personnage-aleatoire h2 {
|
||||
min-width: 30rem;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .app-calendar-astrologie div.theme-astral {
|
||||
width: 14rem;
|
||||
margin: 0.4rem;
|
||||
@@ -2737,11 +2761,9 @@ select,
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-button:hover {
|
||||
background: var(--background-custom-button-hover);
|
||||
background-color: red;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-button-pushed:hover {
|
||||
background: var(--background-custom-button-hover);
|
||||
background-color: red;
|
||||
}
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-button:active,
|
||||
.system-foundryvtt-reve-de-dragon .chat-card-button-pushed:active {
|
||||
|
@@ -200,6 +200,9 @@
|
||||
i.moral-radio-checkmark-off:hover,
|
||||
a:hover {
|
||||
text-shadow: 1px 0px 0px #ff6600;
|
||||
img {
|
||||
filter: drop-shadow(1px 0px 0px #ff6600);
|
||||
}
|
||||
}
|
||||
|
||||
.rollable:hover, .rollable:focus {
|
||||
@@ -754,16 +757,31 @@
|
||||
.competence-list .item-controls.hidden-controls {
|
||||
display: none !important;
|
||||
}
|
||||
.item-actions-controls,
|
||||
.item-controls {
|
||||
vertical-align: super;
|
||||
// a {
|
||||
// }
|
||||
|
||||
.item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular),
|
||||
.item-controls i:is(.fas, .fa, .fa-solid, .fa-regular) {
|
||||
img {
|
||||
display: inline;
|
||||
max-width: 1rem;
|
||||
max-height: 1rem;
|
||||
margin: 0 0.1rem;
|
||||
border: none;
|
||||
filter: invert(0.8);
|
||||
}
|
||||
|
||||
i:is(.fas, .fa, .fa-solid, .fa-regular) {
|
||||
font-size: 0.8em;
|
||||
color: var(--color-controls-light);
|
||||
}
|
||||
.item-actions-controls a.actionItem i:is(.fas, .fa, .fa-solid, .fa-regular):hover,
|
||||
.item-controls i:is(.fas, .far, .fa-solid, .fa-regular):hover {
|
||||
|
||||
img:hover,
|
||||
i:is(.fas, .far, .fa-solid, .fa-regular):hover {
|
||||
opacity: 0.6;
|
||||
}
|
||||
}
|
||||
|
||||
.rdd-roll-dialog .description-sort {
|
||||
max-width: 550px;
|
||||
@@ -910,6 +928,11 @@
|
||||
color: var(--color-text-dark-primary);
|
||||
border-radius: 0.2rem;
|
||||
}
|
||||
form.app-personnage-aleatoire {
|
||||
h2 {
|
||||
min-width: 30rem,
|
||||
}
|
||||
}
|
||||
.app-calendar-astrologie{
|
||||
div.theme-astral{
|
||||
width: 14rem;
|
||||
@@ -1998,12 +2021,10 @@
|
||||
|
||||
.chat-card-button:hover {
|
||||
background: var(--background-custom-button-hover);
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.chat-card-button-pushed:hover {
|
||||
background: var(--background-custom-button-hover);
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
.chat-card-button:active, .chat-card-button-pushed:active {
|
||||
|
@@ -47,11 +47,12 @@ import { RdDRollResult } from "./rdd-roll-result.js";
|
||||
import { RdDInitiative } from "./initiative.mjs";
|
||||
import RollDialog from "./roll/roll-dialog.mjs";
|
||||
import { OptionsAvancees, ROLL_DIALOG_V2, ROLL_DIALOG_V2_TEST } from "./settings/options-avancees.js";
|
||||
import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION } from "./roll/roll-constants.mjs";
|
||||
import { ROLL_TYPE_JEU, ROLL_TYPE_MEDITATION, ROLL_TYPE_SORT } from "./roll/roll-constants.mjs";
|
||||
import { PART_TACHE } from "./roll/roll-part-tache.mjs";
|
||||
import { PART_COMP } from "./roll/roll-part-comp.mjs";
|
||||
import { PART_OEUVRE } from "./roll/roll-part-oeuvre.mjs";
|
||||
import { PART_CUISINE } from "./roll/roll-part-cuisine.mjs";
|
||||
import { PART_SORT } from "./roll/roll-part-sort.mjs";
|
||||
|
||||
export const MAINS_DIRECTRICES = ['Droitier', 'Gaucher', 'Ambidextre']
|
||||
|
||||
@@ -741,12 +742,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async sortMisEnReserve(sort, draconic, coord, ptreve) {
|
||||
await this.createEmbeddedDocuments("Item", [{
|
||||
type: ITEM_TYPES.sortreserve,
|
||||
name: sort.name,
|
||||
img: sort.img,
|
||||
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
|
||||
}],
|
||||
await this.createEmbeddedDocuments("Item", [RdDItemSort.prepareSortEnReserve(sort, draconic, ptreve, coord)],
|
||||
{ renderSheet: false });
|
||||
this.tmrApp.updateTokens();
|
||||
}
|
||||
@@ -1712,15 +1708,18 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
ui.notifications.error("Une queue ou un souffle vous empèche de lancer de sort!")
|
||||
return
|
||||
}
|
||||
if (OptionsAvancees.isUsing(ROLL_DIALOG_V2)) {
|
||||
return await this.rollUnSortV2();
|
||||
}
|
||||
// Duplication car les pts de reve sont modifiés dans le sort!
|
||||
let sorts = foundry.utils.duplicate(this.itemTypes[ITEM_TYPES.sort].filter(it => RdDItemSort.isSortOnCoord(it, coord)))
|
||||
if (sorts.length == 0) {
|
||||
ui.notifications.info(`Aucun sort disponible en ${TMRUtility.getTMR(coord).label} !`);
|
||||
return;
|
||||
return
|
||||
}
|
||||
|
||||
const draconicList = this.computeDraconicAndSortIndex(sorts);
|
||||
const reve = foundry.utils.duplicate(this.system.carac.reve);
|
||||
const draconicList = this.computeDraconicAndSortIndex(sorts)
|
||||
const reve = foundry.utils.duplicate(this.system.carac.reve)
|
||||
|
||||
const dialog = await this.openRollDialog({
|
||||
name: 'lancer-un-sort',
|
||||
@@ -1743,6 +1742,27 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
this.tmrApp?.setTMRPendingAction(dialog);
|
||||
}
|
||||
|
||||
async rollUnSortV2() {
|
||||
const rollData = {
|
||||
ids: { actorId: this.id },
|
||||
type: { allowed: [ROLL_TYPE_SORT], current: ROLL_TYPE_SORT }
|
||||
};
|
||||
const dialog = await RollDialog.create(rollData, {
|
||||
callbacks: [roll => {
|
||||
this.tmrApp?.restoreTMRAfterAction();
|
||||
if (roll.closeTMR) {
|
||||
this.tmrApp?.close();
|
||||
this.tmrApp = undefined;
|
||||
}
|
||||
} ],
|
||||
onRollDone: RollDialog.onRollDoneClose,
|
||||
onClose: () => {
|
||||
this.tmrApp?.restoreTMRAfterAction();
|
||||
}
|
||||
});
|
||||
this.tmrApp?.setTMRPendingAction(dialog);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
isMauvaiseRencontre() { // Gestion queue/souffle 'Mauvaise Rencontre en Perpective'
|
||||
let addMsg = "";
|
||||
@@ -1814,11 +1834,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
else {
|
||||
console.log('lancement de sort', rollData.selectedSort)
|
||||
const precedents = rollData.selectedSort.system.lancements ?? []
|
||||
const lancements = [...precedents, {
|
||||
timestamp: game.system.rdd.calendrier.getTimestamp(),
|
||||
reve: rollData.selectedSort.system.ptreve_reel
|
||||
}]
|
||||
const lancements = RdDItemSort.prepareSortAddLancement(rollData.selectedSort, rollData.selectedSort.system.ptreve_reel)
|
||||
await this.updateEmbeddedDocuments('Item',
|
||||
[{ _id: rollData.selectedSort._id, 'system.lancements': lancements }]
|
||||
)
|
||||
@@ -2109,7 +2125,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
/* -------------------------------------------- */
|
||||
_getSignesDraconiques(coord) {
|
||||
const type = TMRUtility.getTMRType(coord);
|
||||
return this.itemTypes["signedraconique"].filter(it => it.system.typesTMR.includes(type));
|
||||
return this.itemTypes[ITEM_TYPES.signedraconique].filter(it => it.system.typesTMR.includes(type));
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
@@ -2121,18 +2137,19 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
async rollLireSigneDraconique(coord) {
|
||||
if (!this.isHautRevant()) {
|
||||
ui.notifications.info("Seul un haut rêvant peut lire un signe draconique!");
|
||||
return;
|
||||
return
|
||||
}
|
||||
let signes = this._getSignesDraconiques(coord);
|
||||
let signes = this._getSignesDraconiques(coord)
|
||||
if (signes.length == 0) {
|
||||
ui.notifications.info(`Aucun signe draconiques en ${coord} !`);
|
||||
return;
|
||||
ui.notifications.info(`Aucun signe draconiques en ${coord} !`)
|
||||
return
|
||||
}
|
||||
|
||||
let draconicList = this.getDraconics()
|
||||
.map(draconic => {
|
||||
let draconicLecture = foundry.utils.duplicate(draconic);
|
||||
draconicLecture.system.defaut_carac = "intellect";
|
||||
return draconicLecture;
|
||||
let draconicLecture = foundry.utils.duplicate(draconic)
|
||||
draconicLecture.system.defaut_carac = "intellect"
|
||||
return draconicLecture
|
||||
});
|
||||
|
||||
const intellect = this.system.carac.intellect;
|
||||
@@ -2406,7 +2423,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
if (this.tmrApp) {
|
||||
ui.notifications.warn("Vous êtes déja dans les TMR....")
|
||||
this.tmrApp.forceTMRDisplay()
|
||||
return
|
||||
return false
|
||||
}
|
||||
if (mode != 'visu' && this.isDemiReve()) {
|
||||
ui.notifications.warn("Le personnage est déjà dans les Terres Médianes, elles s'affichent en visualisation")
|
||||
@@ -2414,6 +2431,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
}
|
||||
if (mode == 'visu') {
|
||||
await this._doDisplayTMR(mode)
|
||||
return false
|
||||
}
|
||||
else {
|
||||
const rencontre = this.getRencontreTMREnAttente();
|
||||
@@ -2426,6 +2444,7 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
buttonLabel: 'Monter dans les TMR',
|
||||
onAction: async () => await this._doDisplayTMR(mode)
|
||||
})
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2463,6 +2482,29 @@ export class RdDActor extends RdDBaseActorSang {
|
||||
await this.tmrApp.onDeplacement()
|
||||
}
|
||||
|
||||
async quitterTMR(message, viewOnly, cumulFatigue) {
|
||||
if (this.tmrApp) {
|
||||
this.tmrApp = undefined
|
||||
const appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue");
|
||||
await this.santeIncDec(
|
||||
appliquerFatigue ? "fatigue" : "endurance",
|
||||
(appliquerFatigue ? 1 : -1) * cumulFatigue)
|
||||
if (!viewOnly) {
|
||||
await this.supprimerSignesDraconiques(it => it.system.ephemere && it.system.duree == '1 round', { render: false })
|
||||
await this.setEffect(STATUSES.StatusDemiReve, false)
|
||||
ChatUtility.tellToUserAndGM(message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async supprimerSignesDraconiques(filter = it => true, options = { render: true }) {
|
||||
const signes = this.itemTypes[ITEM_TYPES.signedraconique].filter(filter)
|
||||
if (signes.length > 0) {
|
||||
this.deleteEmbeddedDocuments("Item", signes.map(item => item.id), options)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async rollSoins(blesse, blessureId) {
|
||||
const blessure = blesse.blessuresASoigner().find(it => it.id == blessureId);
|
||||
|
@@ -246,10 +246,10 @@ export class RdDBaseActorReve extends RdDBaseActor {
|
||||
if (this.isEffectAllowed(statusId)) {
|
||||
const effect = this.getEffectByStatus(statusId);
|
||||
if (!status && effect) {
|
||||
await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id]);
|
||||
await this.deleteEmbeddedDocuments('ActiveEffect', [effect.id], { render: true})
|
||||
}
|
||||
if (status && !effect) {
|
||||
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)]);
|
||||
await this.createEmbeddedDocuments("ActiveEffect", [StatusEffects.prepareActiveEffect(statusId)], { render: true})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -116,6 +116,7 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
blessure: blessure
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async santeIncDec(name, inc, isCritique = false) {
|
||||
if (name == 'fatigue' && !ReglesOptionnelles.isUsing("appliquer-fatigue")) {
|
||||
@@ -179,6 +180,26 @@ export class RdDBaseActorSang extends RdDBaseActorReve {
|
||||
return Math.max(0, Math.min(maxEndVie, maxEndGraves, maxEndCritiques));
|
||||
}
|
||||
|
||||
async onCreateItem(item, options, id) {
|
||||
switch (item.type) {
|
||||
case ITEM_TYPES.blessure:
|
||||
await this.changeBleedingState()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
async onUpdateItem(item, options, id) {
|
||||
switch (item.type) {
|
||||
case ITEM_TYPES.blessure:
|
||||
await this.changeBleedingState()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
async changeBleedingState() {
|
||||
const bleeding = this.itemTypes[ITEM_TYPES.blessure].find(it => it.isBleeding())
|
||||
await this.setEffect(STATUSES.StatusBleeding, bleeding ? true : false)
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async ajouterBlessure(encaissement, attackerToken = undefined) {
|
||||
|
@@ -248,28 +248,12 @@ export class RdDBaseActor extends Actor {
|
||||
/* -------------------------------------------- */
|
||||
async onPreUpdateItem(item, change, options, id) { }
|
||||
|
||||
async onCreateItem(item, options, id) {
|
||||
switch (item.type) {
|
||||
case ITEM_TYPES.blessure:
|
||||
await this.changeBleedingState()
|
||||
break
|
||||
}
|
||||
}
|
||||
async onCreateItem(item, options, id) { }
|
||||
|
||||
async onUpdateItem(item, options, id) {
|
||||
switch (item.type) {
|
||||
case ITEM_TYPES.blessure:
|
||||
await this.changeBleedingState()
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
async changeBleedingState() {
|
||||
const bleeding = this.itemTypes[ITEM_TYPES.blessure].find(it => it.isBleeding())
|
||||
await this.setEffect(STATUSES.StatusBleeding, bleeding ? true : false)
|
||||
}
|
||||
async onUpdateItem(item, options, id) { }
|
||||
|
||||
async onUpdateActor(update, options, actorId) { }
|
||||
|
||||
async onDeleteItem(item, options, id) {
|
||||
if (item.isInventaire()) {
|
||||
await this._removeItemFromConteneur(item)
|
||||
|
@@ -20,14 +20,15 @@ const PATHS = [
|
||||
const RANDOM_VALUES = {
|
||||
'system.sexe': { 'masculin': 1, 'féminin': 1 },
|
||||
'system.main': { 'droitier': 51, 'gaucher': 15, 'ambidextre': 6 },
|
||||
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains clair': 5, 'blonds': 4, 'blonds très clair': 1, 'roux carotte': 1, 'roux cuivré': 3 },
|
||||
'system.yeux': { 'noirs': 2, 'noisettes': 3, 'bruns vert': 4, 'verts': 3, 'bleus clair': 3, 'bleus gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
|
||||
'system.cheveux': { 'noirs': 2, 'bruns': 5, 'châtains': 3, 'châtain clair': 5, 'blonds': 4, 'blond platine': 1, 'roux carotte': 1, 'roux cuivré': 3, 'chauve': 1 },
|
||||
'system.yeux': { 'noirs': 2, 'noisette': 3, 'brun vert': 4, 'verts': 3, 'bleu clair': 3, 'bleu gris': 2, 'gris': 1, 'mauves': 1, 'indigos': 1 },
|
||||
}
|
||||
|
||||
export class AppPersonnageAleatoire extends FormApplication {
|
||||
static preloadHandlebars() {
|
||||
foundry.applications.handlebars.loadTemplates([
|
||||
'systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs',
|
||||
'systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs',
|
||||
])
|
||||
}
|
||||
|
||||
@@ -49,14 +50,14 @@ export class AppPersonnageAleatoire extends FormApplication {
|
||||
this.current = foundry.utils.duplicate(actor)
|
||||
this.checked = {
|
||||
'name': false,
|
||||
'system.sexe': true,
|
||||
'system.age': true,
|
||||
'system.taille': true,
|
||||
'system.poids': true,
|
||||
'system.main': true,
|
||||
'system.heure': true,
|
||||
'system.cheveux': true,
|
||||
'system.yeux': true
|
||||
'system.sexe': (this.actor.system.sexe ?? '') == '',
|
||||
'system.age': this.actor.system.age == 0,
|
||||
'system.taille': (this.actor.system.taille ?? '') == '',
|
||||
'system.poids': (this.actor.system.poids ?? '') == '',
|
||||
'system.main': (this.actor.system.main ?? '') == '',
|
||||
'system.heure': (this.actor.system.heure ?? '') == '',
|
||||
'system.cheveux': (this.actor.system.cheveux ?? '') == '',
|
||||
'system.yeux': (this.actor.system.yeux ?? '') == '',
|
||||
}
|
||||
}
|
||||
|
||||
@@ -76,6 +77,8 @@ export class AppPersonnageAleatoire extends FormApplication {
|
||||
this.html.find("button.button-apply").click(async event => await this.onApply())
|
||||
this.html.find("input.current-value").change(async event => await this.onChange(event))
|
||||
this.html.find("div.random-field[data-path='system.heure'] select.current-value").change(async event => await this.onChange(event))
|
||||
this.html.find('a[data-action="sexe-masculin"]').click(async event => await this.onSexe('masculin'))
|
||||
this.html.find('a[data-action="sexe-feminin"]').click(async event => await this.onSexe('féminin'))
|
||||
this.html.find("a.random").click(async event => await this.onRandom(event))
|
||||
this.html.find("a.reset").click(async event => await this.onReset(event))
|
||||
this.html.find("a.randomize-selected").click(async event => await this.onRandomizeSelected())
|
||||
@@ -96,6 +99,10 @@ export class AppPersonnageAleatoire extends FormApplication {
|
||||
const fields = this.html.find(selector).parents("div.random-field:first")
|
||||
return fields[0].attributes['data-path'].value
|
||||
}
|
||||
async onSexe(sexe) {
|
||||
this.current['system.sexe'] = sexe
|
||||
this.render()
|
||||
}
|
||||
|
||||
async onChange(event) {
|
||||
const path = this.getPath(event.currentTarget)
|
||||
@@ -180,8 +187,9 @@ export class AppPersonnageAleatoire extends FormApplication {
|
||||
const variation = Math.floor((caracTaille.poidsMax - caracTaille.poidsMin + base / 5) / 2)
|
||||
const total = await RdDDice.rollTotal(`2d${variation} + ${base}`)
|
||||
const cm = total % 100
|
||||
const dm = cm < 10 ? '0' : ''
|
||||
const m = (total - cm) / 100
|
||||
return `${m}m${cm}`
|
||||
return `${m}m${dm}${cm}`
|
||||
}
|
||||
|
||||
|
||||
|
@@ -106,6 +106,25 @@ export class ChatUtility {
|
||||
return await ChatMessage.create(messageData)
|
||||
}
|
||||
|
||||
static tellToUser(message) {
|
||||
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] });
|
||||
}
|
||||
|
||||
static tellToGM(message) {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: message,
|
||||
whisper: ChatUtility.getGMs()
|
||||
});
|
||||
}
|
||||
|
||||
static tellToUserAndGM(message) {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: message,
|
||||
whisper: ChatUtility.getUserAndGMs()
|
||||
})
|
||||
}
|
||||
static getOwners(document) {
|
||||
return document ? game.users.filter(it => document.getUserLevel(it) == CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) : [game.user]
|
||||
}
|
||||
|
@@ -148,10 +148,17 @@ export class RdDItemSort extends Item {
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static incrementBonusCase(actor, sort, coord) {
|
||||
if (TMRUtility.isFleuve(coord)) {
|
||||
coord = FLEUVE_COORD;
|
||||
let bonuscase = RdDItemSort.calculBonuscase(sort, coord)
|
||||
|
||||
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': bonuscase }]);
|
||||
}
|
||||
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase);
|
||||
|
||||
|
||||
static calculBonuscase(sort, coord) {
|
||||
if (TMRUtility.isFleuve(coord)) {
|
||||
coord = FLEUVE_COORD
|
||||
}
|
||||
let list = RdDItemSort.stringToBonuscases(sort.system.bonuscase)
|
||||
const existing = list.find(it => it.case == coord)
|
||||
const bonus = Number(existing?.bonus ?? 0) + 1
|
||||
if (existing) {
|
||||
@@ -160,11 +167,9 @@ export class RdDItemSort extends Item {
|
||||
else {
|
||||
list.push({ case: coord, bonus: 1 })
|
||||
}
|
||||
|
||||
actor.updateEmbeddedDocuments('Item', [{ _id: sort._id, 'system.bonuscase': RdDItemSort.bonuscasesToString(list) }]);
|
||||
return RdDItemSort.bonuscasesToString(list)
|
||||
}
|
||||
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static getCaseBonus(sort, coord) {
|
||||
const search = TMRUtility.isFleuve(coord)
|
||||
@@ -189,4 +194,22 @@ export class RdDItemSort extends Item {
|
||||
.map(it => it.split(':'))
|
||||
.map(it => { return { case: it[0], bonus: it[1] } });
|
||||
}
|
||||
|
||||
static prepareSortEnReserve(sort, draconic, ptreve, coord) {
|
||||
return {
|
||||
type: ITEM_TYPES.sortreserve,
|
||||
name: sort.name,
|
||||
img: sort.img,
|
||||
system: { sortid: sort._id, draconic: (draconic?.name ?? sort.system.draconic), ptreve: ptreve, coord: coord, heurecible: 'Vaisseau' }
|
||||
};
|
||||
}
|
||||
|
||||
static prepareSortAddLancement(sort, reveSort) {
|
||||
const precedents = sort.system.lancements ?? []
|
||||
const lancements = [...precedents, {
|
||||
timestamp: game.system.rdd.calendrier.getTimestamp(),
|
||||
reve: reveSort
|
||||
}]
|
||||
return lancements
|
||||
}
|
||||
}
|
@@ -461,12 +461,7 @@ export class RdDCommands {
|
||||
|
||||
async supprimerSignesDraconiquesEphemeres() {
|
||||
if (game.user.isGM) {
|
||||
game.actors.forEach(actor => {
|
||||
const ephemeres = actor.items.filter(item => item.type = 'signedraconique' && item.system.ephemere);
|
||||
if (ephemeres.length > 0) {
|
||||
actor.deleteEmbeddedDocuments("Item", ephemeres.map(item => item.id));
|
||||
}
|
||||
});
|
||||
game.actors.forEach(actor => actor.supprimerSignesDraconiques(it => it.system.ephemere))
|
||||
}
|
||||
else {
|
||||
ui.notifications.warn("Seul le MJ est autorisé à utiliser la commande /signe");
|
||||
|
@@ -156,6 +156,11 @@ export class RdDResolutionTable {
|
||||
}
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static replaceParticuliereDemiSurprise(chances){
|
||||
foundry.utils.mergeObject(chances, reussites.find(x => x.code == 'part'), { overwrite: true });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
static significativeRequise(chances) {
|
||||
chances.roll = Math.min(chances.part + 1, chances.sign)
|
||||
|
@@ -25,7 +25,7 @@ export class RdDRollDialogEthylisme extends Dialog {
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.bringToTop();
|
||||
this.bringToFront();
|
||||
|
||||
this.html.find(".force-alcool").change((event) => {
|
||||
this.rollData.forceAlcool = Misc.toInt(event.currentTarget.value);
|
||||
|
@@ -22,7 +22,7 @@ export class RdDRollResolutionTable extends Dialog {
|
||||
RdDRollResolutionTable.resolutionTable.render(true);
|
||||
}
|
||||
else{
|
||||
RdDRollResolutionTable.resolutionTable.bringToTop();
|
||||
RdDRollResolutionTable.resolutionTable.bringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ export class RdDRollResolutionTable extends Dialog {
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.bringToTop();
|
||||
this.bringToFront();
|
||||
|
||||
|
||||
this.html.find("[name='diffLibre']").val(Misc.toInt(this.rollData.diffLibre));
|
||||
|
@@ -128,7 +128,7 @@ export class RdDRoll extends Dialog {
|
||||
activateListeners(html) {
|
||||
super.activateListeners(html);
|
||||
this.html = html;
|
||||
this.bringToTop();
|
||||
this.bringToFront();
|
||||
|
||||
console.log('RdDRoll.activateListeners', this.rollData);
|
||||
|
||||
|
@@ -82,7 +82,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
this.subdialog = undefined
|
||||
this.displaySize = undefined
|
||||
if (!this.viewOnly && !game.user.isGM) {
|
||||
this.$tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")");
|
||||
ChatUtility.tellToGM(this.actor.name + " monte dans les terres médianes (" + tmrData.mode + ")");
|
||||
}
|
||||
this.callbacksOnAnimate = [];
|
||||
const displaySize = TMR_DISPLAY_SIZE.clamp(game.settings.get(SYSTEM_RDD, TMR_DISPLAY_SIZE.code) ?? TMR_DISPLAY_SIZE.def);
|
||||
@@ -125,7 +125,11 @@ export class RdDTMRDialog extends Dialog {
|
||||
HtmlUtility.showControlWhen(this.html.find(".appliquerFatigue"), ReglesOptionnelles.isUsing("appliquer-fatigue"));
|
||||
HtmlUtility.showControlWhen(this.html.find(".lire-signe-draconique"), this.actor.isResonanceSigneDraconique(this._getCoordActor()));
|
||||
|
||||
this.html.find('form.tmr-dialog *').click(event => this.subdialog?.bringToTop());
|
||||
this.html.find('form.tmr-dialog *').click(event => {
|
||||
if (this.subdialog?.rendered){
|
||||
this.subdialog?.bringToFront()
|
||||
}
|
||||
})
|
||||
|
||||
// Roll Sort
|
||||
this.html.find('.lancer-sort').click(event => this.lancerUnSort());
|
||||
@@ -169,26 +173,26 @@ export class RdDTMRDialog extends Dialog {
|
||||
|
||||
async forceTMRDisplay() {
|
||||
if (this.rendered) {
|
||||
this.bringToTop()
|
||||
this.bringSubDialogToTop();
|
||||
this.bringToFront()
|
||||
this.bringSubDialogToFront();
|
||||
}
|
||||
}
|
||||
|
||||
bringSubDialogToTop() {
|
||||
if (this.subdialog?.bringToTop && this.subdialog?.element && this.subdialog?.element[0]) {
|
||||
this.subdialog.bringToTop();
|
||||
bringSubDialogToFront() {
|
||||
if (this.subdialog?.bringToFront && this.subdialog?.element && this.subdialog?.element[0]) {
|
||||
this.subdialog.bringToFront();
|
||||
}
|
||||
}
|
||||
|
||||
async restoreTMRAfterAction() {
|
||||
this.subdialog = undefined
|
||||
await this.maximize()
|
||||
this.bringToTop()
|
||||
this.bringToFront()
|
||||
}
|
||||
|
||||
forceTMRContinueAction() {
|
||||
ui.notifications.warn('Vous devez finir votre action avant de continuer dans les TMR');
|
||||
this.bringSubDialogToTop();
|
||||
this.bringSubDialogToFront();
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -343,19 +347,8 @@ export class RdDTMRDialog extends Dialog {
|
||||
this.forceTMRContinueAction()
|
||||
return false
|
||||
}
|
||||
this.descenteTMR = true;
|
||||
if (this.actor.tmrApp) {
|
||||
this.actor.tmrApp = undefined // Cleanup reference
|
||||
const appliquerFatigue = ReglesOptionnelles.isUsing("appliquer-fatigue")
|
||||
await this.actor.santeIncDec(
|
||||
appliquerFatigue ? "fatigue" : "endurance",
|
||||
(appliquerFatigue ? 1 : -1) * this.cumulFatigue)
|
||||
if (!this.viewOnly) {
|
||||
await this.actor.setEffect(STATUSES.StatusDemiReve, false)
|
||||
this.$tellToUserAndGM(message)
|
||||
}
|
||||
|
||||
}
|
||||
this.descenteTMR = true
|
||||
await await this.actor.quitterTMR(message, this.viewOnly, this.cumulFatigue)
|
||||
this.pixiTMR.close();
|
||||
this.pixiTMR = undefined
|
||||
await super.close();
|
||||
@@ -412,7 +405,7 @@ export class RdDTMRDialog extends Dialog {
|
||||
async $ignorerRencontre() {
|
||||
if (this.currentRencontre) {
|
||||
console.log("-> ignorer", this.currentRencontre);
|
||||
this.$tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name);
|
||||
ChatUtility.tellToGM(this.actor.name + " a ignoré: " + this.currentRencontre.name);
|
||||
await this.$deleteRencontreTMRAtPosition()
|
||||
this.updateTokens();
|
||||
this.$updateValuesDisplay();
|
||||
@@ -578,29 +571,6 @@ export class RdDTMRDialog extends Dialog {
|
||||
}, 500);
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
_tellToUser(message) {
|
||||
ChatMessage.create({ content: message, user: game.user.id, whisper: [game.user.id] });
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
$tellToGM(message) {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: message,
|
||||
whisper: ChatUtility.getGMs()
|
||||
});
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
$tellToUserAndGM(message) {
|
||||
ChatMessage.create({
|
||||
user: game.user.id,
|
||||
content: message,
|
||||
whisper: ChatUtility.getUserAndGMs()
|
||||
})
|
||||
}
|
||||
|
||||
/* -------------------------------------------- */
|
||||
async manageRencontre(tmr) {
|
||||
if (this.viewOnly) {
|
||||
@@ -676,14 +646,14 @@ export class RdDTMRDialog extends Dialog {
|
||||
? TMRUtility.getTMRType(tmr.coord) + " ??"
|
||||
: tmr.label + " (" + tmr.coord + ")");
|
||||
|
||||
this.setTMRPendingAction({ bringToTop: () => { } })
|
||||
this.setTMRPendingAction({ bringToFront: () => { } })
|
||||
const myRoll = await RdDDice.rollTotal("1dt", { showDice: SHOW_DICE });
|
||||
this.restoreTMRAfterAction()
|
||||
if (myRoll == 7) {
|
||||
this._tellToUser(myRoll + ": Rencontre en " + coordTMR);
|
||||
ChatUtility.tellToUser(myRoll + ": Rencontre en " + coordTMR);
|
||||
return await game.system.rdd.rencontresTMR.getRencontreAleatoire(tmr, this.actor.isMauvaiseRencontre())
|
||||
} else {
|
||||
this._tellToUser(myRoll + ": Pas de rencontre en " + coordTMR);
|
||||
ChatUtility.tellToUser(myRoll + ": Pas de rencontre en " + coordTMR);
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
@@ -8,6 +8,10 @@ import { RDD_CONFIG, renderTemplate } from "../constants.js"
|
||||
import { EMPOIGNADE } from "../item/arme.js"
|
||||
import { RdDTextEditor } from "../apps/rdd-text-roll-editor.js"
|
||||
import { RollTypeCuisine } from "./roll-type-cuisine.mjs"
|
||||
import { RollTypeMeditation } from "./roll-type-meditation.mjs"
|
||||
import { PART_DEFENSE } from "./roll-part-defense.mjs"
|
||||
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
|
||||
import { RdDRollTables } from "../rdd-rolltables.js"
|
||||
|
||||
export default class ChatRollResult {
|
||||
static init() {
|
||||
@@ -20,6 +24,7 @@ export default class ChatRollResult {
|
||||
foundry.applications.handlebars.loadTemplates({
|
||||
'partial-appel-chance': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-appel-chance.hbs',
|
||||
'partial-attaque-particuliere': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-attaque-particuliere.hbs',
|
||||
'partial-maladresse': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-maladresse.hbs',
|
||||
'partial-encaissement': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-encaissement.hbs',
|
||||
'partial-recul-choc': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-recul-choc.hbs',
|
||||
'partial-info-appel-moral': 'systems/foundryvtt-reve-de-dragon/templates/roll/result/partial-info-appel-moral.hbs',
|
||||
@@ -38,7 +43,7 @@ export default class ChatRollResult {
|
||||
)
|
||||
const save = RollDialog.saveParts(roll, impacts)
|
||||
|
||||
ChatUtility.setMessageData(chatMessage, 'rollData', save)
|
||||
await this.saveChatMessageRoll(chatMessage, save)
|
||||
return chatMessage
|
||||
}
|
||||
|
||||
@@ -48,7 +53,7 @@ export default class ChatRollResult {
|
||||
roll.show.chance = this.isAppelChancePossible(roll)
|
||||
roll.show.encaissement = this.isShowEncaissement(roll)
|
||||
roll.show.recul = this.getRecul(roll)
|
||||
//roll.show.particuliere = roll.show.particuliere ?? []
|
||||
roll.show.maladresse = this.getMaladresse(roll)
|
||||
}
|
||||
|
||||
isAppelChancePossible(roll) {
|
||||
@@ -65,6 +70,23 @@ export default class ChatRollResult {
|
||||
return false
|
||||
}
|
||||
|
||||
getMaladresse(roll) {
|
||||
switch (roll.type.current) {
|
||||
case ROLL_TYPE_DEFENSE:
|
||||
if (roll.rolled.isETotal) {
|
||||
const arme = roll.current[PART_DEFENSE].arme
|
||||
return arme ? 'avec-arme' : 'sans-arme'
|
||||
}
|
||||
break
|
||||
case ROLL_TYPE_ATTAQUE:
|
||||
if (roll.rolled.isETotal || (roll.rolled.isEchec && roll.active.surprise == 'demi')) {
|
||||
const arme = roll.current[PART_ATTAQUE].arme
|
||||
return arme.system.baseInit > 4 ? 'avec-arme' : 'sans-arme'
|
||||
}
|
||||
break
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
getRecul(roll, defender = roll.active.actor, attacker = roll.opponent?.actor) {
|
||||
switch (roll.type.current) {
|
||||
@@ -112,6 +134,9 @@ export default class ChatRollResult {
|
||||
$(html).on("click", '.resister-recul', event => this.onClickRecul(event))
|
||||
$(html).on("click", '.choix-particuliere', event => this.onClickChoixParticuliere(event))
|
||||
$(html).on("click", '.faire-gouter', event => this.onClickFaireGouter(event))
|
||||
$(html).on("click", '.monter-tmr-normale', event => this.onClickMonteeTMR(event, 'normal'))
|
||||
$(html).on("click", '.monter-tmr-rapide', event => this.onClickMonteeTMR(event, 'rapide'))
|
||||
$(html).on("click", '.tirer-maladresse', event => this.onClickTirerMaladresse(event))
|
||||
|
||||
}
|
||||
|
||||
@@ -125,8 +150,16 @@ export default class ChatRollResult {
|
||||
return undefined
|
||||
}
|
||||
|
||||
async saveChatMessageRoll(chatMessage, savedRoll) {
|
||||
await ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
|
||||
}
|
||||
|
||||
loadChatMessageRoll(chatMessage) {
|
||||
return ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||
}
|
||||
|
||||
async updateChatMessage(chatMessage, savedRoll) {
|
||||
ChatUtility.setMessageData(chatMessage, 'rollData', savedRoll)
|
||||
await this.saveChatMessageRoll(chatMessage, savedRoll)
|
||||
const copy = foundry.utils.duplicate(savedRoll)
|
||||
RollDialog.loadRollData(copy)
|
||||
this.prepareDisplay(copy)
|
||||
@@ -136,7 +169,7 @@ export default class ChatRollResult {
|
||||
|
||||
onClickAppelChance(event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
const actor = game.actors.get(savedRoll.ids.actorId)
|
||||
actor.rollAppelChance(
|
||||
() => this.onAppelChanceSuccess(savedRoll, chatMessage),
|
||||
@@ -144,11 +177,13 @@ export default class ChatRollResult {
|
||||
event.preventDefault()
|
||||
}
|
||||
|
||||
onAppelChanceSuccess(savedRoll, chatMessage) {
|
||||
async onAppelChanceSuccess(savedRoll, chatMessage) {
|
||||
const reRoll = foundry.utils.duplicate(savedRoll)
|
||||
console.log('onAppelChanceSuccess savedRoll', savedRoll)
|
||||
reRoll.type.retry = true
|
||||
await this.updateChatMessage(chatMessage, reRoll)
|
||||
const callbacks = [r => ChatUtility.removeChatMessageId(chatMessage.id)]
|
||||
|
||||
// TODO: annuler les effets
|
||||
switch (reRoll.type.current) {
|
||||
case ROLL_TYPE_DEFENSE:
|
||||
@@ -171,7 +206,7 @@ export default class ChatRollResult {
|
||||
|
||||
onClickAppelDestinee(event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
const actor = game.actors.get(savedRoll.ids.actorId)
|
||||
|
||||
actor.appelDestinee(async () => {
|
||||
@@ -184,7 +219,7 @@ export default class ChatRollResult {
|
||||
|
||||
async onClickEncaissement(event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
const attaque = savedRoll.attackerRoll
|
||||
const defender = game.actors.get(savedRoll.ids.actorId)
|
||||
const attacker = game.actors.get(savedRoll.ids.opponentId)
|
||||
@@ -198,7 +233,7 @@ export default class ChatRollResult {
|
||||
|
||||
async onClickRecul(event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
const defender = game.actors.get(savedRoll.ids.actorId)
|
||||
const attacker = game.actors.get(savedRoll.ids.opponentId)
|
||||
savedRoll.done.recul = await defender.encaisserRecul(attacker.getForce(), savedRoll.attackerRoll.dmg.dmgArme)
|
||||
@@ -209,15 +244,38 @@ export default class ChatRollResult {
|
||||
async onClickChoixParticuliere(event) {
|
||||
const choix = event.currentTarget.attributes['data-particuliere'].value
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
savedRoll.particuliere = choix
|
||||
savedRoll.particulieres = [RDD_CONFIG.particuliere[choix]]
|
||||
await this.updateChatMessage(chatMessage, savedRoll)
|
||||
await this.getCombat(savedRoll)?.onAttaqueV2(savedRoll, callbacks)
|
||||
}
|
||||
|
||||
async onClickFaireGouter(event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const savedRoll = ChatUtility.getMessageData(chatMessage, 'rollData')
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
if (!savedRoll.type.retry) {
|
||||
savedRoll.type.retry = true
|
||||
await this.updateChatMessage(chatMessage, savedRoll)
|
||||
}
|
||||
await new RollTypeCuisine().onFaireGouter(savedRoll)
|
||||
}
|
||||
|
||||
async onClickMonteeTMR(event, mode) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
if (await new RollTypeMeditation().onMonteeTMR(savedRoll, mode)) {
|
||||
savedRoll.done.meditation = true
|
||||
await this.updateChatMessage(chatMessage, savedRoll)
|
||||
}
|
||||
}
|
||||
async onClickTirerMaladresse(event) {
|
||||
const chatMessage = ChatUtility.getChatMessage(event)
|
||||
const typeMaladresse = event.currentTarget.attributes['data-maladresse'].value
|
||||
const savedRoll = this.loadChatMessageRoll(chatMessage)
|
||||
await RdDRollTables.getMaladresse({ arme: typeMaladresse == 'avec-arme' })
|
||||
savedRoll.type.maladresse = true
|
||||
savedRoll.type.retry = true
|
||||
await this.updateChatMessage(chatMessage, savedRoll)
|
||||
}
|
||||
}
|
@@ -27,6 +27,7 @@ export class RollDialogAdapter {
|
||||
RollDialogAdapter.setRollDataRolled(rollData, rolled, rollTitle)
|
||||
RollDialogAdapter.adjustRollDataForV1(rollData)
|
||||
RollDialogAdapter.adjustAttaqueParticuliere(rollData)
|
||||
RollDialogAdapter.adjustDemiSurprise(rollData)
|
||||
|
||||
return rolled
|
||||
}
|
||||
@@ -105,6 +106,12 @@ export class RollDialogAdapter {
|
||||
})
|
||||
}
|
||||
|
||||
static adjustDemiSurprise(rollData) {
|
||||
if (rollData.active.surprise == 'demi' && rollData.rolled.isPart) {
|
||||
RdDResolutionTable.replaceParticuliereDemiSurprise(rollData.rolled)
|
||||
}
|
||||
}
|
||||
|
||||
static adjustAttaqueParticuliere(rollData) {
|
||||
if (rollData.type.current != ROLL_TYPE_ATTAQUE || !rollData.rolled.isPart) {
|
||||
return
|
||||
|
@@ -173,6 +173,8 @@ const ROLL_PARTS = [
|
||||
/* -------------------------------------------- */
|
||||
export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2)
|
||||
{
|
||||
static onCloseDoNothing() {
|
||||
}
|
||||
static onRollDoneDoNothing(dialog) {
|
||||
dialog.render()
|
||||
}
|
||||
@@ -181,7 +183,6 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
dialog.close()
|
||||
}
|
||||
|
||||
|
||||
static init() {
|
||||
}
|
||||
|
||||
@@ -236,6 +237,7 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
static async create(rollData, rollOptions = {}) {
|
||||
const rollDialog = new RollDialog(rollData, rollOptions)
|
||||
rollDialog.render(true)
|
||||
return rollDialog
|
||||
}
|
||||
|
||||
static get PARTS() {
|
||||
@@ -322,7 +324,8 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
...(rollOptions.callbacks ?? [])
|
||||
],
|
||||
customChatMessage: rollOptions.customChatMessage,
|
||||
onRollDone: rollOptions.onRollDone ?? RollDialog.onRollDoneDoNothing
|
||||
onRollDone: rollOptions.onRollDone ?? RollDialog.onRollDoneDoNothing,
|
||||
onClose: rollOptions.onClose ?? RollDialog.onCloseDoNothing
|
||||
}
|
||||
this.chatRollResult = new ChatRollResult();
|
||||
this.selectType()
|
||||
@@ -440,20 +443,24 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
return ALL_ROLL_TYPES.find(m => m.code == this.rollData.type.current)
|
||||
}
|
||||
|
||||
async close(options){
|
||||
if (this.rollOptions.onClose){
|
||||
this.rollOptions.onClose()
|
||||
}
|
||||
return await super.close(options)
|
||||
}
|
||||
|
||||
async roll() {
|
||||
|
||||
const roll = RollDialog.saveParts(this.rollData)
|
||||
this.loadRollData(roll)
|
||||
RollDialog.loadRollData(roll)
|
||||
const selectedRollType = this.getSelectedType(roll);
|
||||
selectedRollType.onSelect(roll)
|
||||
roll.current.resultat = this.rollData.current[PART_TRICHER]?.resultat ?? -1
|
||||
roll.choix = {}
|
||||
roll.rolled = await RollDialogAdapter.rollDice(roll, this.rollTitle(roll))
|
||||
|
||||
const impacts = {
|
||||
active: new ActorImpacts(roll.active),
|
||||
opponent: roll.opponent ? new ActorImpacts(roll.opponent) : undefined
|
||||
}
|
||||
const impacts = new ActorImpacts(roll.active)
|
||||
|
||||
roll.result = selectedRollType.getResult(roll, impacts)
|
||||
|
||||
@@ -465,14 +472,13 @@ export default class RollDialog extends HandlebarsApplicationMixin(ApplicationV2
|
||||
|
||||
await Promise.all(callbacks.map(async callback => await callback(roll)))
|
||||
|
||||
await impacts.active?.applyImpacts()
|
||||
await impacts.opponent?.applyImpacts()
|
||||
await impacts.applyImpacts()
|
||||
selectedRollType.onApplyImpacts(roll, impacts)
|
||||
await this.chatRollResult.display(roll, impacts)
|
||||
this.rollOptions.onRollDone(this)
|
||||
}
|
||||
|
||||
loadRollData(roll) {
|
||||
static loadRollData(roll) {
|
||||
RollDialog.$prepareRollData(roll)
|
||||
RollDialog.calculAjustements(roll)
|
||||
roll.v2 = true
|
||||
|
@@ -50,14 +50,6 @@ export class RollPartAttaque extends RollPartSelect {
|
||||
choices(refs) { return refs.attaques }
|
||||
|
||||
static $extractAttaque(attaque, actor) {
|
||||
// const extracted = foundry.utils.mergeObject({
|
||||
// key: `${attaque.action}::${attaque.label}`,
|
||||
// tactique: TACTIQUES[0]
|
||||
// },
|
||||
// attaque
|
||||
// )
|
||||
// return extracted
|
||||
// extracted.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
|
||||
attaque.key = `${attaque.action}::${attaque.label}`
|
||||
attaque.tactique = TACTIQUES[0]
|
||||
attaque.initialDiff = attaque.comp?.system.default_diffLibre ?? 0
|
||||
|
@@ -1,9 +1,6 @@
|
||||
import { ITEM_TYPES } from "../constants.js"
|
||||
import { Grammar } from "../grammar.js"
|
||||
import { ATTAQUE_TYPE, RdDItemArme } from "../item/arme.js"
|
||||
import { RdDBonus } from "../rdd-bonus.js"
|
||||
import { CARACS } from "../rdd-carac.js"
|
||||
import { StatusEffects } from "../settings/status-effects.js"
|
||||
import { DIFF, ROLL_TYPE_DEFENSE } from "./roll-constants.mjs"
|
||||
import { PART_CARAC } from "./roll-part-carac.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
|
@@ -81,8 +81,10 @@ export class RollPartJeu extends RollPartSelect {
|
||||
|
||||
$selectJeu(rollData, key) {
|
||||
this.selectByKey(rollData, key, 0)
|
||||
if (rollData.type.current == ROLL_TYPE_JEU) {
|
||||
RollPartJeu.forceCompJeu(rollData)
|
||||
}
|
||||
}
|
||||
|
||||
static forceCompJeu(rollData) {
|
||||
const jeu = rollData.current[PART_JEU].base ?? rollData.current[PART_JEU].comp
|
||||
|
@@ -22,9 +22,27 @@ export class RollPartSort extends RollPartSelect {
|
||||
isValid(rollData) { return rollData.active.actor.isPersonnage() && rollData.active.actor.isHautRevant() }
|
||||
visible(rollData) { return this.isRollType(rollData, ROLL_TYPE_SORT) }
|
||||
|
||||
restore(rollData) {
|
||||
const saved = this.getSaved(rollData)
|
||||
this.setCurrent(rollData, {
|
||||
key: saved.key,
|
||||
isReserve: saved.isReserve,
|
||||
ptreve: saved.ptreve
|
||||
})
|
||||
}
|
||||
|
||||
store(rollData, targetData) {
|
||||
const current = this.getCurrent(rollData)
|
||||
this.setSaved(targetData, {
|
||||
key: current.key,
|
||||
isReserve: current.isReserve,
|
||||
ptreve: current.ptreve
|
||||
})
|
||||
}
|
||||
|
||||
loadRefs(rollData) {
|
||||
const refs = this.getRefs(rollData)
|
||||
const coord = rollData.active.actor.system.reve.tmrpos.coord
|
||||
const coord = this.getCoord(rollData)
|
||||
const draconics = rollData.active.actor.getDraconics()
|
||||
const sorts = rollData.active.actor.itemTypes[ITEM_TYPES.sort]
|
||||
.map(s => RollPartSort.$extractSort(s, coord, draconics))
|
||||
@@ -33,7 +51,7 @@ export class RollPartSort extends RollPartSelect {
|
||||
{
|
||||
coord: coord,
|
||||
tmr: TMRUtility.getTMR(coord),
|
||||
reve: rollData.active.actor.system.reve.reve.value,
|
||||
reve: this.getReveActuel(rollData),
|
||||
draconics: draconics,
|
||||
all: sorts,
|
||||
sorts: sorts.filter(it => RdDItemSort.isSortOnCoord(it.sort, coord))
|
||||
@@ -41,10 +59,18 @@ export class RollPartSort extends RollPartSelect {
|
||||
{ inplace: true }
|
||||
)
|
||||
if (refs.sorts.length > 0) {
|
||||
this.$selectSort(rollData)
|
||||
this.$selectSort(rollData, this.getSaved(rollData))
|
||||
}
|
||||
}
|
||||
|
||||
getReveActuel(rollData) {
|
||||
return rollData.active.actor.system.reve.reve.value
|
||||
}
|
||||
|
||||
getCoord(rollData) {
|
||||
return rollData.active.actor.system.reve.tmrpos.coord
|
||||
}
|
||||
|
||||
choices(refs) { return refs.sorts }
|
||||
|
||||
static $extractSort(sort, coord, draconics) {
|
||||
@@ -56,11 +82,12 @@ export class RollPartSort extends RollPartSelect {
|
||||
value: isDiffVariable ? -7 : parseInt(sort.system.difficulte),
|
||||
ptreve: isReveVariable ? 1 : sort.system.ptreve,
|
||||
caseTMR: RdDItemSort.getCaseTMR(sort),
|
||||
bonusCase: RdDItemSort.getCaseBonus(sort, coord),
|
||||
isDiffVariable: isDiffVariable,
|
||||
isReveVariable: isReveVariable,
|
||||
isReserve: false,
|
||||
sort: sort,
|
||||
draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name)
|
||||
draconics: RdDItemSort.getDraconicsSort(draconics, sort).map(it => it.name),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,25 +95,27 @@ export class RollPartSort extends RollPartSelect {
|
||||
const current = this.getCurrent(rollData)
|
||||
if (current) {
|
||||
const reserve = current.isReserve ?
|
||||
[{ label: `Mise en réserve en ${current.coord}` }] : []
|
||||
[{ label: `Mise en réserve en ${this.getCoord(rollData)}` }] : []
|
||||
const bonusCase = current.bonusCase ?
|
||||
[{ label: `Bonus case +${current.bonusCase}%` }] : []
|
||||
return [
|
||||
{ label: current.label, diff: current.value },
|
||||
{ label: `r${current.ptreve}` },
|
||||
...bonusCase,
|
||||
{ label: `Rêve ${current.ptreve}` },
|
||||
...reserve
|
||||
]
|
||||
}
|
||||
return []
|
||||
}
|
||||
|
||||
$selectSort(rollData, key) {
|
||||
const previous = this.getCurrent(rollData)
|
||||
const current = this.selectByKey(rollData, key, -7)
|
||||
if (current.key != previous.key) { }
|
||||
current.bonusCase = RdDItemSort.getCaseBonus(current.sort,
|
||||
rollData.active.actor.system.reve.tmrpos.coord)
|
||||
$selectSort(rollData, values) {
|
||||
const current = this.selectByKey(rollData, values.key)
|
||||
if (values.ptreve) {
|
||||
current.ptreve = values.ptreve
|
||||
}
|
||||
if (values.isReserve != undefined) {
|
||||
current.isReserve = values.isReserve
|
||||
}
|
||||
}
|
||||
|
||||
async _onRender(rollDialog, context, options) {
|
||||
@@ -99,7 +128,7 @@ export class RollPartSort extends RollPartSelect {
|
||||
selectSort.addEventListener("change", e => {
|
||||
const selectOptions = e.currentTarget.options
|
||||
const index = selectOptions.selectedIndex
|
||||
this.$selectSort(rollDialog.rollData, selectOptions[index]?.value)
|
||||
this.$selectSort(rollDialog.rollData, { key: selectOptions[index]?.value })
|
||||
rollDialog.render()
|
||||
})
|
||||
|
||||
|
@@ -1,5 +1,4 @@
|
||||
import { DIFF, ROLL_TYPE_ATTAQUE } from "./roll-constants.mjs"
|
||||
import { PART_ATTAQUE } from "./roll-part-attaque.mjs"
|
||||
import { RollType } from "./roll-type.mjs"
|
||||
|
||||
export class RollTypeAttaque extends RollType {
|
||||
|
@@ -32,17 +32,17 @@ export class RollTypeCuisine extends RollType {
|
||||
if (current.fabriquer) {
|
||||
const plat = this.$prepareNourriture(rollData.active.name, current, result)
|
||||
result.messages.push(`${plat.system.quantite} ${plat.name} ont été préparés dans l'équipement`)
|
||||
impacts.active.addCreatedItem(plat)
|
||||
impacts.addCreated('Item', plat)
|
||||
result.plat = { id: plat.id }
|
||||
}
|
||||
if (current.ingredient) {
|
||||
const quantite = Math.min(current.proportions, current.ingredient.system.quantite)
|
||||
if (quantite == current.ingredient.system.quantite) {
|
||||
impacts.active.addDeletedItem(current.ingredient)
|
||||
impacts.addDeleted('Item', current.ingredient)
|
||||
result.messages.push(`Il n'y a plus de ${ingredient.name}`)
|
||||
}
|
||||
else {
|
||||
impacts.active.addItemDelta(current.ingredient, 'system.quantite', -current.proportions)
|
||||
impacts.addDelta('Item', current.ingredient, 'system.quantite', -current.proportions)
|
||||
result.messages.push(`${current.proportions} ${current.ingredient.name} ont été utilisés`)
|
||||
}
|
||||
}
|
||||
@@ -51,7 +51,7 @@ export class RollTypeCuisine extends RollType {
|
||||
onApplyImpacts(roll, impacts) {
|
||||
if (roll.result.plat) {
|
||||
// le plat n'est pas créé immédiatement, il faut donc retrouver l'id
|
||||
roll.result.plat.id = impacts.active.itemCreates.find(it => it.id = roll.result.plat.id)?.createdId
|
||||
roll.result.plat.id = impacts.findCreatedId('Item', roll.result.plat.id)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -1,4 +1,5 @@
|
||||
import { RdDItemSigneDraconique } from "../item/signedraconique.js"
|
||||
import { RollBasicParts } from "./roll-basic-parts.mjs"
|
||||
import { DIFF, ROLL_TYPE_MEDITATION } from "./roll-constants.mjs"
|
||||
import { PART_MEDITATION } from "./roll-part-meditation.mjs"
|
||||
import { RollType } from "./roll-type.mjs"
|
||||
@@ -26,7 +27,7 @@ export class RollTypeMeditation extends RollType {
|
||||
const rolled = rollData.rolled
|
||||
if (meditation && rolled) {
|
||||
if (rolled.isSuccess) {
|
||||
await actor.createEmbeddedDocuments("Item", [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)])
|
||||
await actor.createEmbeddedDocuments('Item', [RdDItemSigneDraconique.prepareSigneDraconiqueMeditation(meditation, rolled)])
|
||||
}
|
||||
if (rolled.isEPart) {
|
||||
await actor.updateEmbeddedDocuments('Item', [{ _id: meditation._id, 'system.malus': meditation.system.malus - 1 }])
|
||||
@@ -34,4 +35,9 @@ export class RollTypeMeditation extends RollType {
|
||||
await actor.santeIncDec("fatigue", 2)
|
||||
}
|
||||
}
|
||||
|
||||
async onMonteeTMR(savedRoll, mode){
|
||||
const actor = RollBasicParts.getTokenActor(savedRoll).actor
|
||||
return actor?.displayTMR(mode)
|
||||
}
|
||||
}
|
@@ -1,4 +1,9 @@
|
||||
import { RdDItemCompetence } from "../item-competence.js"
|
||||
import { RdDItemSort } from "../item-sort.js"
|
||||
import { RdDResolutionTable } from "../rdd-resolution-table.js"
|
||||
import { DIFF, ROLL_TYPE_SORT } from "./roll-constants.mjs"
|
||||
import { PART_COMP } from "./roll-part-comp.mjs"
|
||||
import { PART_SORT } from "./roll-part-sort.mjs"
|
||||
import { RollType } from "./roll-type.mjs"
|
||||
|
||||
export class RollTypeSort extends RollType {
|
||||
@@ -11,4 +16,69 @@ export class RollTypeSort extends RollType {
|
||||
onSelect(rollData) {
|
||||
this.setDiffType(rollData, DIFF.AUCUN)
|
||||
}
|
||||
|
||||
getResult(rollData, impacts) {
|
||||
const rolled = rollData.rolled
|
||||
const actor = rollData.active.actor
|
||||
const coord = actor.system.reve.tmrpos.coord
|
||||
const reveActuel = parseInt(actor.system.reve.reve.value)
|
||||
const draconic = rollData.current[PART_COMP].comp
|
||||
|
||||
const current = rollData.current[PART_SORT]
|
||||
const sort = current.sort
|
||||
const isReserve = current.isReserve
|
||||
const reveSort = current.ptreve
|
||||
const isThanatos = RdDItemCompetence.isThanatos(draconic)
|
||||
|
||||
actor.tmrApp?.restoreTMRAfterAction()
|
||||
|
||||
current.depenseReve = reveSort
|
||||
if (isThanatos) { // Si Thanatos
|
||||
impacts.addActorUpdate("system.reve.reve.thanatosused", true)
|
||||
}
|
||||
|
||||
if (rolled.isSuccess) { // Réussite du sort !
|
||||
if (rolled.isPart) {
|
||||
current.depenseReve = Math.max(Math.floor(current.depenseReve / 2), 1)
|
||||
}
|
||||
if (isReserve) {
|
||||
current.depenseReve++
|
||||
}
|
||||
|
||||
if (reveActuel > current.depenseReve) {
|
||||
// Incrémenter/gére le bonus de case
|
||||
impacts.addUpdate('Item', sort, 'system.bonuscase', RdDItemSort.calculBonuscase(sort, coord))
|
||||
|
||||
if (isReserve) {
|
||||
impacts.addCreated('Item', RdDItemSort.prepareSortEnReserve(sort, draconic, reveSort, coord))
|
||||
}
|
||||
else {
|
||||
rollData.closeTMR = true
|
||||
if (sort.system.isrituel) {
|
||||
impacts.addUpdate('Item', sort, 'system.lancements', RdDItemSort.prepareSortAddLancement(sort, reveSort))
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
current.depenseReve = 0;
|
||||
rollData.show.reveInsuffisant = true
|
||||
foundry.utils.mergeObject(rollData.rolled, RdDResolutionTable.getResultat("echec"), { overwrite: true })
|
||||
}
|
||||
} else {
|
||||
rollData.closeTMR = true
|
||||
if (rolled.isETotal) { // Echec total !
|
||||
current.depenseReve = Math.min(reveActuel, Math.floor(current.depenseReve * 1.5))
|
||||
// TODO: mise en réserve d'un échec total...
|
||||
} else {
|
||||
current.depenseReve = 0
|
||||
}
|
||||
}
|
||||
|
||||
impacts.addActorDelta("system.reve.reve.value", - Math.min(current.depenseReve, reveActuel))
|
||||
|
||||
if (current.depenseReve >= reveActuel) { // 0 points de reve
|
||||
rollData.show.zeroReve = true
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@@ -1,15 +1,25 @@
|
||||
|
||||
const ACTOR_EMBEDDED_DOCTYPES = ['Item', 'ActiveEffect']
|
||||
/**
|
||||
* class designed to store actor modification instructions, to apply them in a single operation, and have the ability to revert these
|
||||
*/
|
||||
export class ActorImpacts {
|
||||
static $newDocumentImpacts(docType) {
|
||||
return { creates: [], deletes: [], updates: [], docType: docType }
|
||||
}
|
||||
static $checkDocType(docType) {
|
||||
if (!ACTOR_EMBEDDED_DOCTYPES.includes(docType)) {
|
||||
throw `Unsupported document type ${docType}`
|
||||
}
|
||||
}
|
||||
|
||||
constructor(actorToken) {
|
||||
this.actorToken = actorToken
|
||||
this.updates = []
|
||||
this.deltas = []
|
||||
this.itemCreates = []
|
||||
this.itemUpdates = []
|
||||
this.itemDeletes = []
|
||||
ACTOR_EMBEDDED_DOCTYPES.forEach(
|
||||
docType => this[docType] = ActorImpacts.$newDocumentImpacts(docType)
|
||||
)
|
||||
}
|
||||
|
||||
addActorUpdate(path, value) {
|
||||
@@ -27,46 +37,55 @@ export class ActorImpacts {
|
||||
}
|
||||
}
|
||||
|
||||
addDeletedItem(item) {
|
||||
this.itemDeletes.push(item)
|
||||
}
|
||||
addCreatedItem(item) {
|
||||
this.itemCreates.push(item)
|
||||
addDeleted(docType, document) {
|
||||
ActorImpacts.$checkDocType(docType)
|
||||
this[docType].deletes.push(document)
|
||||
}
|
||||
|
||||
addItemUpdate(item, path, value) {
|
||||
const existing = this.itemUpdates.find(it => it.id == item.id)
|
||||
addCreated(docType, document) {
|
||||
ActorImpacts.$checkDocType(docType)
|
||||
this[docType].creates.push(document)
|
||||
}
|
||||
|
||||
addUpdate(docType, document, path, value) {
|
||||
ActorImpacts.$checkDocType(docType)
|
||||
const update = [path, value]
|
||||
const existing = this[docType].updates.find(it => it.id == document.id)
|
||||
if (existing) {
|
||||
existing.updates.push(update)
|
||||
}
|
||||
else {
|
||||
this.itemUpdates.push({ id: item.id, updates: [update], deltas: [] })
|
||||
this[docType].updates.push({ id: document.id, updates: [update], deltas: [] })
|
||||
}
|
||||
}
|
||||
|
||||
addItemDelta(item, path, value) {
|
||||
addDelta(document, path, value) {
|
||||
ActorImpacts.$checkDocType(document)
|
||||
const intValue = Number.parseInt(value)
|
||||
if (Number.isInteger(intValue) && intValue != 0) {
|
||||
const delta = [path, intValue]
|
||||
const existing = this.itemUpdates.find(it => it.id == item.id)
|
||||
const existing = this[docType].updates.find(it => it.id == document.id)
|
||||
if (existing) {
|
||||
existing.deltas.push(delta)
|
||||
}
|
||||
else {
|
||||
this.itemUpdates.push({ id: item.id, updates: [], deltas: [delta] })
|
||||
this[docType].updates.push({ id: document.id, updates: [], deltas: [delta] })
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error('Cannot use non integer value {} for delta update', value)
|
||||
console.error('Cannot use non-integer value {} for delta update', value)
|
||||
}
|
||||
}
|
||||
|
||||
reverseImpacts() {
|
||||
const reverse = ActorImpacts.$computeReverts(new ActorImpacts(this.actorToken), this, __ => this.actorToken.actor)
|
||||
reverse.itemCreates = this.itemDeletes.map(it => foundry.utils.duplicate(it))
|
||||
reverse.itemDeletes = this.itemCreates.map(it => { return { id: it.id } })
|
||||
reverse.itemUpdates = this.itemUpdates.map(it => ActorImpacts.$computeReverts({ id: it.id }, it, id => this.$getActorItem(id)))
|
||||
ACTOR_EMBEDDED_DOCTYPES.forEach(
|
||||
docType => {
|
||||
reverse[docType].creates = this[docType].deletes.map(it => foundry.utils.duplicate(it))
|
||||
reverse[docType].deletes = this[docType].creates.map(it => { return { id: it.id } })
|
||||
reverse[docType].updates = this[docType].updates.map(it => ActorImpacts.$computeReverts({ id: it.id }, it, id => this.$getEmbeddedDocument(docType, id)))
|
||||
}
|
||||
)
|
||||
return reverse
|
||||
}
|
||||
|
||||
@@ -77,40 +96,44 @@ export class ActorImpacts {
|
||||
|
||||
async applyImpacts() {
|
||||
const actor = this.actorToken.actor
|
||||
const isItemsDelete = this.itemDeletes.length > 0
|
||||
const isItemsCreate = this.itemCreates.length > 0
|
||||
const isItemsUpdate = this.itemUpdates.length > 0
|
||||
const isActorUpdate = this.updates.length > 0 || this.deltas.length > 0
|
||||
|
||||
if (isItemsDelete) {
|
||||
const deletes = this.itemDeletes.map(it => it.id)
|
||||
await actor.deleteEmbeddedDocuments('Item', deletes, { render: !(isItemsCreate || isItemsUpdate || isActorUpdate) })
|
||||
await Promise.all(ACTOR_EMBEDDED_DOCTYPES.map(async docType => await this.$applyDocumentsImpacts(actor, docType)))
|
||||
const updates = ActorImpacts.$computeUpdates(this, id => actor)
|
||||
await actor.update(updates, { render: true })
|
||||
}
|
||||
|
||||
if (isItemsCreate) {
|
||||
const creates = this.itemCreates
|
||||
const created = await actor.createEmbeddedDocuments('Item', creates, { render: !(isItemsUpdate || isActorUpdate)})
|
||||
|
||||
async $applyDocumentsImpacts(actor, docType) {
|
||||
if (this[docType].deletes.length > 0) {
|
||||
const deletes = this[docType].deletes.map(it => it.id)
|
||||
await actor.deleteEmbeddedDocuments(docType, deletes, { render: false })
|
||||
}
|
||||
|
||||
if (this[docType].creates.length > 0) {
|
||||
const creates = this[docType].creates
|
||||
const created = await actor.createEmbeddedDocuments(docType, creates, { render: false })
|
||||
for (let i = 0; i < creates.length; i++) {
|
||||
creates[i].createdId = created[i].id
|
||||
}
|
||||
}
|
||||
|
||||
if (isItemsUpdate) {
|
||||
const updates = this.itemUpdates.map(u => ActorImpacts.$computeUpdates(u, id => this.$getActorItem(id)))
|
||||
await actor.updateEmbeddedDocuments('Item', updates, { render: !isActorUpdate })
|
||||
}
|
||||
|
||||
if (isActorUpdate) {
|
||||
const updates = ActorImpacts.$computeUpdates(this, id => actor)
|
||||
await actor.update(updates, { render: true })
|
||||
if (this[docType].updates.length > 0) {
|
||||
const updates = this[docType].updates.map(u => ActorImpacts.$computeUpdates(u, id => this.$getEmbeddedDocument(docType, id)))
|
||||
await actor.updateEmbeddedDocuments(docType, updates, { render: false })
|
||||
}
|
||||
}
|
||||
|
||||
$getActorItem(id) {
|
||||
return this.actorToken.actor.items.get(id)
|
||||
findCreatedId(docType, origId){
|
||||
return this[docType].creates.find(it => it.id = origId)?.createdId
|
||||
}
|
||||
|
||||
$getEmbeddedDocument(docType, id) {
|
||||
return this.actorToken.actor.getEmbeddedDocument(docType, id)
|
||||
}
|
||||
|
||||
static $computeUpdates(u, getSource) {
|
||||
if (u.updates.length == 0 && u.deltas.length == 0) {
|
||||
return {}
|
||||
}
|
||||
const source = getSource(u.id)
|
||||
const instruction = { _id: u.id }
|
||||
u.updates.forEach(u => instruction[u[0]] = u[1])
|
||||
@@ -124,5 +147,4 @@ export class ActorImpacts {
|
||||
target.deltas = u.deltas.map(d => [d[0], -d[1]])
|
||||
return target
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -1,12 +1,12 @@
|
||||
<form class="app-personnage-aleatoire">
|
||||
<h2>Génération aléatoire pour {{actor.name}}</h2>
|
||||
<h2>{{actor.name}}</h2>
|
||||
<div class="flex-group-left">
|
||||
{{#if options.isGM}}
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
|
||||
label="Nom" path="name" type="text" value=current.name checked=checked.name
|
||||
}}
|
||||
{{/if}}
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/champ-aleatoire.hbs"
|
||||
{{>"systems/foundryvtt-reve-de-dragon/templates/actor/random/sexe-aleatoire.hbs"
|
||||
label="Sexe" path="system.sexe" type="text"
|
||||
value=current.system.sexe checked=checked.system.sexe
|
||||
}}
|
||||
|
@@ -12,8 +12,8 @@
|
||||
<input class="current-value" name="current.{{path}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/>
|
||||
{{/if}}
|
||||
<div class="item-controls">
|
||||
<input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/>
|
||||
<a class="random" data-action="random" data-tooltip="Aléatoire"><i class="fa-solid fa-dice-d20"></i></a>
|
||||
<a class="reset" data-action="reset" data-tooltip="Reset"><i class="fa-solid fa-eraser"></i></a>
|
||||
<input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/>
|
||||
</div>
|
||||
</div>
|
11
templates/actor/random/sexe-aleatoire.hbs
Normal file
11
templates/actor/random/sexe-aleatoire.hbs
Normal file
@@ -0,0 +1,11 @@
|
||||
<div class="flexrow random-field" data-path="{{path}}">
|
||||
<label for="{{path}}">{{label}}:</label>
|
||||
<input class="current-value" name="current.{{path}}" value="{{value}}" placeholder="{{label}}" type="text" data-dtype="String"/>
|
||||
<div class="item-controls">
|
||||
<input class="check-for-random" type="checkbox" data-tooltip="Sélectionné pour génération automatique" {{#if checked}}checked{{/if}}/>
|
||||
<a data-action="sexe-feminin" data-tooltip="sexe féminin"><i class="fa-solid fa-venus"></i></a>
|
||||
<a data-action="sexe-masculin" data-tooltip="sexe masculin"><i class="fa-solid fa-mars"></i></a>
|
||||
<a class="random" data-action="random" data-tooltip="Aléatoire"><i class="fa-solid fa-dice-d20"></i></a>
|
||||
<a class="reset" data-action="reset" data-tooltip="Reset"><i class="fa-solid fa-eraser"></i></a>
|
||||
</div>
|
||||
</div>
|
@@ -22,15 +22,10 @@
|
||||
{{#if (eq current.dmg.mortalite 'empoignade')}}
|
||||
ou {{active.name}} marquera un point d'empoignade
|
||||
{{else if (eq current.dmg.mortalite 'non-mortel')}}
|
||||
ou encaisser à <span class="rdd-roll-norm">{{plusMoins current.dmg.total}} (non-mortel)</span>
|
||||
ou encaisser à <span class="rdd-roll-norm">{{plusMoins dmg.total}} (non-mortel)</span>
|
||||
{{else}}
|
||||
{{!-- {{~#if (eq current.dmg.mortalite 'mortel')}} --}}
|
||||
ou encaisser à <span class="rdd-roll-echec">{{plusMoins current.dmg.total}}</span>
|
||||
{{!-- {{~#if (eq current.dmg.mortalite 'cauchemar')}} --}}
|
||||
{{!-- {{else}}
|
||||
<span class="rdd-roll-etotal">{{plusMoins dmg.total}}</span> (entités de cauchemar) --}}
|
||||
ou encaisser à <span class="rdd-roll-echec">{{plusMoins dmg.total}}</span>
|
||||
{{/if}}
|
||||
|
||||
</span>
|
||||
{{#if show.recul}}
|
||||
<span class='chat-card-info'>
|
||||
@@ -65,6 +60,7 @@
|
||||
|
||||
<div class="chat-actions">
|
||||
{{> 'partial-attaque-particuliere'}}
|
||||
{{> 'partial-maladresse'}}
|
||||
{{!-- TODO: maladresses --}}
|
||||
</div>
|
||||
|
||||
|
@@ -21,12 +21,12 @@
|
||||
<p>
|
||||
{{active.name}}
|
||||
{{#if rolled.isSuccess}}
|
||||
réussit la recette, pour un plat de qualité {{result.qualite~}}
|
||||
{{#if (lt result.exotisme 0)}}et d'exotisme {{result.exotisme}}{{/if~}}
|
||||
réussit la recette, pour un plat de qualité {{result.qualite}}
|
||||
{{#if (lt result.exotisme 0)}}et d'exotisme {{result.exotisme}}{{/if}}
|
||||
{{else}}
|
||||
fait un piètre cuisinier, et obtient un plat de qualité {{result.qualite~}}
|
||||
{{#if (lt result.exotisme 0)}}à l'exotisme certain ({{result.exotisme}}){{/if~}}
|
||||
{{/if~}}.
|
||||
fait un piètre cuisinier, et obtient un plat de qualité {{result.qualite}}
|
||||
{{#if (lt result.exotisme 0)}}à l'exotisme certain ({{result.exotisme}}){{/if}}
|
||||
{{~/if~}}.
|
||||
{{#if (lt result.exotisme 0)}}
|
||||
<br>Au vu de l'exotisme du plat, les convives devront réussir un jet de @roll[Volonté/Cuisine/{{result.exotisme}}].
|
||||
En cas d'échec, ils peuvent se forcer à faire plaisir à {{active.name}}, mais devront faire un jet de moral Malheureux.
|
||||
|
@@ -44,7 +44,7 @@
|
||||
{{> 'partial-info-appel-moral'}}
|
||||
</div>
|
||||
<div class="chat-actions">
|
||||
{{!-- TODO: maladresses --}}
|
||||
{{> 'partial-maladresse'}}
|
||||
{{> 'partial-recul-choc'}}
|
||||
{{> 'partial-encaissement'}}
|
||||
</div>
|
||||
|
@@ -39,6 +39,19 @@
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="chat-actions">
|
||||
{{#if rolled.isSuccess}}
|
||||
{{#unless done.meditation}}
|
||||
<a class='chat-card-button monter-tmr-normale' data-tooltip="Montée rapide dans les TMR" >
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg"/> Montée normale dans les TMR
|
||||
</a>
|
||||
<a class='chat-card-button monter-tmr-rapide' data-tooltip="Montée rapide dans les TMR" >
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/actions/sort.svg"/> Montée rapide dans les TMR
|
||||
</a>
|
||||
{{/unless}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="chat-buttons">
|
||||
</div>
|
||||
</div>
|
||||
|
@@ -0,0 +1,47 @@
|
||||
<div class="roll-chat">
|
||||
<div class="chat-img">
|
||||
<img src="{{active.img}}" data-tooltip="{{active.name}}" />
|
||||
<img src="{{current.sort.sort.img}}" data-tooltip="{{current.sort.label}}" />
|
||||
</div>
|
||||
|
||||
<div class="chat-header">
|
||||
{{active.name}}
|
||||
{{#if current.sort.isReserve}}met en réserve{{else}}lance{{/if}}
|
||||
le {{#if current.sort.sort.system.isrituel}}rituel{{else}}sort{{/if}}
|
||||
{{current.sort.label}}
|
||||
{{#if (ne current.sort.sort.system.draconic current.comp.comp.name)}}
|
||||
avec la voie de {{current.comp.comp.name}}
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
<div class="chat-resume">
|
||||
{{current.carac.label}} / {{current.comp.label}} à {{current.diff.value}}
|
||||
<br>{{> "systems/foundryvtt-reve-de-dragon/templates/chat-infojet.hbs"}}
|
||||
</div>
|
||||
|
||||
<hr>
|
||||
<div class="chat-details">
|
||||
<p>
|
||||
{{#if rolled.isETotal}}Echec TOTAL
|
||||
{{else if rolled.isEchec}}Echec
|
||||
{{else}}Réussite{{/if}}
|
||||
du {{#if current.sort.sort.system.isrituel}}rituel{{else}}sort{{/if}},
|
||||
{{#if rolled.isSuccess}}
|
||||
le sort est {{#if current.sort.isReserve}}mis en réserve{{else}}lancé{{/if}}
|
||||
avec {{current.sort.ptreve}} point{{~#if (gt current.sort.ptreve 1)}}s{{/if}} de rêve en {{caseTmr-label refs.sort.coord}} ({{refs.sort.coord}}).
|
||||
{{/if}}
|
||||
</p>
|
||||
<p>
|
||||
{{#if (eq current.sort.depenseReve 0)}}Pas de dépense de rêve
|
||||
{{else if (eq current.sort.depenseReve 1)}}1 point de rêve a été dépensé
|
||||
{{else}}{{current.sort.depenseReve}} points de rêve ont été dépensés
|
||||
{{~/if}}.
|
||||
{{#if show.reveInsuffisant}}Pas assez de rêve!{{/if}}
|
||||
</p>
|
||||
|
||||
{{> "systems/foundryvtt-reve-de-dragon/templates/chat-description.hbs" current.sort.sort.system}}
|
||||
</div>
|
||||
|
||||
<div class="chat-buttons">
|
||||
</div>
|
||||
</div>
|
13
templates/roll/result/partial-maladresse.hbs
Normal file
13
templates/roll/result/partial-maladresse.hbs
Normal file
@@ -0,0 +1,13 @@
|
||||
{{#if show.maladresse}}
|
||||
{{#if type.maladresse}}
|
||||
<span class='chat-card-info'>
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/maladresse.svg"/> Maladresse!
|
||||
</span>
|
||||
{{else}}
|
||||
<a class='chat-card-button tirer-maladresse' data-maladresse='{{show.maladresse}}'
|
||||
data-tooltip="Tirer la maladresse">
|
||||
<img src="systems/foundryvtt-reve-de-dragon/assets/ui/maladresse.svg"/> Tirer une maladresse
|
||||
{{#if (eq show.maladresse 'avec-arme')}}armé{{else}}non armé{{/if}}
|
||||
</a>
|
||||
{{/if}}
|
||||
{{/if}}
|
Reference in New Issue
Block a user