Compare commits

..

7 Commits

Author SHA1 Message Date
9d654246c2 Merge pull request '12.0.7 - La propriété d'Astrobazzarh' (#709) from VincentVk/foundryvtt-reve-de-dragon:v11 into v11
Reviewed-on: #709
2024-09-01 20:21:04 +02:00
111fac2b2d Amélioration dialogue voyage
- le changement de terrain change l'affichage de compétences
- le total de fatigue est affiché (ajustement + base)
2024-09-01 20:13:09 +02:00
3e99265125 Version 12.0.7 - La propriété d'Astrobazzarh
- correction des opérations faites à la création d'un Item:
  - la durée des queues/rencontres/souffles
  - les effets draconiques d'un souffle/queue
  - mise à jour des points de tâche des blessures lors des soins
- pas d'expérience sur les particulières quand aucun MJ n'est connecté
- Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
  d'une entité incarnée permet d'accorder le personnage
- Les messages pour résister aux possessions/conjuration sont envoyées
  au défenseur
- Les messages pour résister aux empoignades sont envoyées au défenseur
2024-08-31 00:59:26 +02:00
28878b74fc Fix: demandes au défenseur
Les demandes de résistance pour les possessions sont envoyées au
défenseur

Les demlandes de défense contre une empoignade dont envoyées au
 défenseur
2024-08-31 00:58:58 +02:00
ba8276ef37 Possibilité d'accorder un personnage
Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
d'une entité incarnée permet d'accorder le personnage
2024-08-31 00:21:24 +02:00
b9e8c24461 Pas d'expérience si le MJ n'est pas connecté
Pour éviter les jets de dés abusifs quand le MJ n'est pas là,
les réussites particulières ne rapportent plus d'expérience
lorsque le MJ n'est pas connecté
2024-08-30 23:56:20 +02:00
8754ea9f5f Fix hook sur creation
Correction des Hooks qui font des calculs à la création d'un item.

- document instanceof Document est false pour un Actor
- le tri des users ne marche pas sur foundry 12
- mise à jour des blessures lors des soins

Correction de la détermination du MJ connecté permettant de nouveau:
- jets de dés quand aucun MJ n'est connecté
- affichage de l'horloge
2024-08-30 23:54:06 +02:00
14 changed files with 113 additions and 77 deletions

View File

@ -1,4 +1,17 @@
# 12.0 # 12.0
## 12.0.7 - La propriété d'Astrobazzarh
- correction des opérations faites à la création d'un Item:
- la durée des queues/rencontres/souffles
- les effets draconiques d'un souffle/queue
- mise à jour des points de tâche des blessures lors des soins
- pas d'expérience sur les particulières quand aucun MJ n'est connecté
- Le drag&drop d'un acteur depuis la liste des acteurs sur la fiche
d'une entité incarnée permet d'accorder le personnage
- Les messages pour résister aux possessions/conjuration sont envoyées
au défenseur
- Les messages pour résister aux empoignades sont envoyées au défenseur
- la commande /voyage affiche maintenant le total de fatigue pour chaque voyageur
- la commande /voyage affiche maintenant les compétences liées au terrain
## 12.0.6 - Le bazar d'Astrobazzarh ## 12.0.6 - Le bazar d'Astrobazzarh
- Corrections de l'inventaire en bazar: - Corrections de l'inventaire en bazar:

View File

@ -1548,6 +1548,9 @@ export class RdDActor extends RdDBaseActorSang {
/* -------------------------------------------- */ /* -------------------------------------------- */
async appliquerAjoutExperience(rollData, hideChatMessage = 'show') { async appliquerAjoutExperience(rollData, hideChatMessage = 'show') {
if (!Misc.firstConnectedGM()){
return
}
hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM) hideChatMessage = hideChatMessage == 'hide' || (Misc.isRollModeHiddenToPlayer() && !game.user.isGM)
let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, rollData.jetResistance); let xpData = await this._appliquerExperience(rollData.rolled, rollData.selectedCarac.label, rollData.competence, rollData.jetResistance);
if (xpData.length) { if (xpData.length) {

View File

@ -508,8 +508,8 @@ export class RdDBaseActorReve extends RdDBaseActor {
isEntiteAccordee(attacker) { return true } isEntiteAccordee(attacker) { return true }
async setEntiteReveAccordee(attacker) { async setEntiteReveAccordee(actor) {
ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entite de cauchemer/rêve"); ui.notifications.error("Impossible de s'accorder à " + this.name + ": ce n'est pas une entité incarnée");
} }
} }

View File

@ -33,27 +33,4 @@ export class RdDCreature extends RdDBaseActorSang {
} }
} }
isEntiteAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = this.system.sante.resonnance
return (resonnance.actors.find(it => it == attacker.id))
}
return true
}
/* -------------------------------------------- */
async setEntiteReveAccordee(attacker) {
if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = foundry.utils.duplicate(this.system.sante.resonnance);
if (resonnance.actors.find(it => it == attacker.id)) {
// déjà accordé
return;
}
await this.update({ "system.sante.resonnance": [...resonnance, attacker.id] });
}
else {
super.setEntiteReveAccordee(attacker)
}
}
} }

View File

@ -54,6 +54,12 @@ export class RdDActorEntiteSheet extends RdDBaseActorReveSheet {
}); });
} }
async _onDropActor(event, dragData) {
const dropActor = fromUuidSync(dragData.uuid)
await this.actor.setEntiteReveAccordee(dropActor)
super._onDropActor(event, dragData)
}
async deleteSubActeur(actorId) { async deleteSubActeur(actorId) {
let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId); let newResonances = this.actor.system.sante.resonnance.actors.filter(id => id != actorId);
await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false }); await this.actor.update({ 'system.sante.resonnance.actors': newResonances }, { renderSheet: false });

View File

@ -67,7 +67,7 @@ export class RdDEntite extends RdDBaseActorReve {
if (this.isNonIncarnee()) { if (this.isNonIncarnee()) {
return return
} }
await RdDEncaisser.encaisser(this) await RdDEncaisser.encaisser(this)
} }
isEffectAllowed(effectId) { isEffectAllowed(effectId) {
@ -91,20 +91,16 @@ export class RdDEntite extends RdDBaseActorReve {
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
async setEntiteReveAccordee(attacker) { async setEntiteReveAccordee(actor) {
if (this.isEntite([ENTITE_INCARNE])) { if (this.isEntite([ENTITE_INCARNE])) {
let resonnance = foundry.utils.duplicate(this.system.sante.resonnance); if (this.system.sante.resonnance.actors.find(it => it == actor.id)) {
if (resonnance.actors.find(it => it == attacker.id)) {
// déjà accordé // déjà accordé
return; return
} }
resonnance.actors.push(attacker.id); await this.update({ "system.sante.resonnance.actors": [...this.system.sante.resonnance.actors, actor.id] })
await this.update({ "system.sante.resonnance": resonnance });
} }
else { else {
super.setEntiteReveAccordee(attacker) super.setEntiteReveAccordee(actor)
} }
} }
} }

View File

@ -166,11 +166,12 @@ export class Misc {
} }
static firstConnectedGM() { static firstConnectedGM() {
if (game.users?.activeGM) { if (foundry.utils.isNewerVersion(game.release.version, '12.0')) {
return game.users.activeGM return game.users.activeGM
} }
return game.users.sort(Misc.ascending(u => u.id)).find(u => u.isGM && u.active); return game.users.find(u => u.isGM && u.active);
} }
static connectedGMs() { static connectedGMs() {
return game.users.filter(u => u.isGM && u.active); return game.users.filter(u => u.isGM && u.active);
} }
@ -188,16 +189,20 @@ export class Misc {
* and there is no connected GM * and there is no connected GM
*/ */
static documentIfResponsible(document) { static documentIfResponsible(document) {
if (document instanceof Document) { if (foundry.utils.isNewerVersion(game.release.version, '12.0')) {
if (Misc.isUniqueConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document))) { if (game.users.activeGM || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document)))
{
return document return document
} }
} }
else if (Misc.isUniqueConnectedGM() || (Misc.connectedGMs().length == 0 && Misc.isOwnerPlayer(document))) {
return document
}
return undefined return undefined
} }
static isOwnerPlayer(actor) { static isOwnerPlayer(document) {
return actor.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER) return document.testUserPermission && document.testUserPermission(game.user, CONST.DOCUMENT_OWNERSHIP_LEVELS.OWNER)
} }
static isOwnerPlayerOrUniqueConnectedGM(actor) { static isOwnerPlayerOrUniqueConnectedGM(actor) {

View File

@ -248,7 +248,7 @@ export class RdDEmpoignade {
if (rollData.rolled.isPart) { if (rollData.rolled.isPart) {
rollData.particuliere = "finesse"; rollData.particuliere = "finesse";
} }
let msg = await RdDResolutionTable.displayRollData(rollData, attacker, 'chat-empoignade-resultat.html'); let msg = await RdDResolutionTable.displayRollData(rollData, defender, 'chat-empoignade-resultat.html');
RdDEmpoignade.$storeRollEmpoignade(msg, rollData); RdDEmpoignade.$storeRollEmpoignade(msg, rollData);
} }

View File

@ -131,7 +131,7 @@ export class RdDPossession {
} }
const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid) const possession = (rollData.isECNIDefender ? rollData.attacker : rollData.defender).getPossession(rollData.possession.system.possessionid)
RdDPossession.storePossessionAttaque(possession, rollData) RdDPossession.storePossessionAttaque(possession, rollData)
await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html'); await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.html');
} }
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -171,7 +171,7 @@ export class RdDPossession {
rollData.possession = possession rollData.possession = possession
RdDPossession.$updateEtatPossession(rollData.possession) RdDPossession.$updateEtatPossession(rollData.possession)
await RdDResolutionTable.displayRollData(rollData, rollData.defender, 'chat-resultat-possession.html') await RdDResolutionTable.displayRollData(rollData, rollData.attacker, 'chat-resultat-possession.html')
if (rollData.possession.isPosseder || rollData.possession.isConjurer) { if (rollData.possession.isPosseder || rollData.possession.isConjurer) {
// conjuration // conjuration
victime.deleteEmbeddedDocuments("Item", [rollData.possession._id]) victime.deleteEmbeddedDocuments("Item", [rollData.possession._id])

View File

@ -97,7 +97,7 @@ export class RdDResolutionTable {
} }
static actorChatName(actor) { static actorChatName(actor) {
return actor?.userName ?? game.user.name; return actor?.name ?? game.user.name;
} }
/* -------------------------------------------- */ /* -------------------------------------------- */

View File

@ -1,6 +1,7 @@
import { TYPES } from "../item.js" import { TYPES } from "../item.js"
import { RdDItemCompetence } from "../item-competence.js" import { RdDItemCompetence } from "../item-competence.js"
import { ChatUtility } from "../chat-utility.js" import { ChatUtility } from "../chat-utility.js"
import { Misc } from "../misc.js"
const CODES_COMPETENCES_VOYAGE = ['Extérieur', 'Forêt', 'Montagne', 'Marais', 'Glace', 'Equitation'] const CODES_COMPETENCES_VOYAGE = ['Extérieur', 'Forêt', 'Montagne', 'Marais', 'Glace', 'Equitation']
const TABLEAU_FATIGUE_MARCHE = [ const TABLEAU_FATIGUE_MARCHE = [
@ -36,7 +37,7 @@ export class DialogFatigueVoyage extends Dialog {
const parameters = { const parameters = {
tableauFatigueMarche: TABLEAU_FATIGUE_MARCHE, tableauFatigueMarche: TABLEAU_FATIGUE_MARCHE,
playerActors: game.actors.filter(actor => actor.isPersonnageJoueur()) playerActors: game.actors.filter(actor => actor.isPersonnageJoueur())
.map(actor => DialogFatigueVoyage.prepareActor(actor)), .map(actor => DialogFatigueVoyage.prepareActorParameters(actor)),
nombreHeures: 1, nombreHeures: 1,
} }
DialogFatigueVoyage.setModeDeplacement(parameters, undefined, undefined) DialogFatigueVoyage.setModeDeplacement(parameters, undefined, undefined)
@ -53,21 +54,37 @@ export class DialogFatigueVoyage extends Dialog {
parameters.typeTerrain = ligneFatigueMarche parameters.typeTerrain = ligneFatigueMarche
parameters.vitesseDeplacement = rythme.vitesse parameters.vitesseDeplacement = rythme.vitesse
parameters.fatigueHoraire = rythme.fatigue parameters.fatigueHoraire = rythme.fatigue
parameters.playerActors.forEach(voyageur =>
DialogFatigueVoyage.selectSurvie(voyageur, parameters.typeTerrain.code)
)
} }
static prepareActor(actor) { static prepareActorParameters(actor) {
const competencesVoyage = {} const actorParameters = {
CODES_COMPETENCES_VOYAGE.forEach(codeSurvie => id: actor.id,
competencesVoyage[codeSurvie] = RdDItemCompetence.findCompetence(actor.itemTypes[TYPES.competence], codeSurvie, { onMessage: () => { } })
)
return {
actor: actor, actor: actor,
selected: true, selected: true,
ajustementFatigue: 0, ajustementFatigue: 0,
competencesVoyage: competencesVoyage survies: {}
} }
const competencesVoyage = {}
CODES_COMPETENCES_VOYAGE.forEach(codeSurvie => {
competencesVoyage[codeSurvie] = RdDItemCompetence.findCompetence(actor.itemTypes[TYPES.competence], codeSurvie, { onMessage: () => { } })
})
TABLEAU_FATIGUE_MARCHE.forEach(terrain => {
actorParameters.survies[terrain.code] = Misc.join(
terrain.survies.map(survie => {
const niveau = competencesVoyage[survie]?.system.niveau
return `${survie}: ${niveau}`
}),
', ')
})
return actorParameters
} }
static selectSurvie(actorParameters, code) {
actorParameters.survieCourante = actorParameters.survies[code]
}
constructor(html, parameters) { constructor(html, parameters) {
const options = { const options = {
@ -97,6 +114,7 @@ export class DialogFatigueVoyage extends Dialog {
this.html.find('select[name="code-terrain"]').change(event => this.changeParameters()) this.html.find('select[name="code-terrain"]').change(event => this.changeParameters())
this.html.find('select[name="vitesse-deplacement"]').change(event => this.changeParameters()) this.html.find('select[name="vitesse-deplacement"]').change(event => this.changeParameters())
this.html.find('input[name="nombre-heures"]').change(event => this.changeParameters()) this.html.find('input[name="nombre-heures"]').change(event => this.changeParameters())
this.html.find('.list-item input[name="ajustement-fatigue"]').change(event => this.changeParameters())
this.html.find('button[name="appliquer-fatigue"]').click(event => this.appliquerFatigue()) this.html.find('button[name="appliquer-fatigue"]').click(event => this.appliquerFatigue())
} }
@ -118,6 +136,10 @@ export class DialogFatigueVoyage extends Dialog {
selectVitesseDeplacement.append(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs', rythme)) selectVitesseDeplacement.append(await renderTemplate('systems/foundryvtt-reve-de-dragon/templates/voyage/option-vitesse-fatigue.hbs', rythme))
}) })
selectVitesseDeplacement.val(this.parameters.vitesseDeplacement).change() selectVitesseDeplacement.val(this.parameters.vitesseDeplacement).change()
Promise.all(this.getActorRows()
.map(async row => row.find('label.voyage-liste-survies').text(this.$extractActorParameters(row).survieCourante)
))
} }
} }
@ -132,16 +154,24 @@ export class DialogFatigueVoyage extends Dialog {
} }
async setFatigue() { async setFatigue() {
this.html.find('input[name="base-fatigue"]').val(this.parameters.nombreHeures * this.parameters.fatigueHoraire) const baseFatigue = this.parameters.nombreHeures * this.parameters.fatigueHoraire
this.html.find('input[name="base-fatigue"]').val(baseFatigue)
this.updateActorTotalFatigue(baseFatigue)
}
async updateActorTotalFatigue(baseFatigue) {
Promise.all(this.getActorRows()
.map(async row => {
const actor = this.$extractActorParameters(row)
row.find('input[name="total-fatigue"]').val(actor.ajustement + baseFatigue)
}))
} }
async appliquerFatigue() { async appliquerFatigue() {
const fatigueBase = parseInt(this.html.find('input[name="base-fatigue"]').val() ?? 0) const fatigueBase = parseInt(this.html.find('input[name="base-fatigue"]').val() ?? 0)
const actors = jQuery.map( this.getActorRows()
this.html.find('div.fatigue-actors-list li.list-item'), .map(row => this.$extractActorParameters(row))
it => this.$extractActor(this.html.find(it)) .filter(it => it.selected)
)
actors.filter(it => it.selected)
.forEach(async it => { .forEach(async it => {
const perteFatigue = fatigueBase + it.ajustement const perteFatigue = fatigueBase + it.ajustement
ChatMessage.create({ ChatMessage.create({
@ -161,16 +191,24 @@ export class DialogFatigueVoyage extends Dialog {
}) })
} }
$extractActor(actorRow) { getActorRows() {
const actor = game.actors.get(actorRow.data('actor-id')) return jQuery.map(
this.html.find('div.fatigue-actors-list li.list-item'),
it => this.html.find(it))
}
$extractActorParameters(actorRow) {
const actorId = actorRow.data('actor-id')
const actorParameters = this.parameters.playerActors.find(it => it.id == actorId)
const actor = game.actors.get(actorId)
if (!actor) { if (!actor) {
ui.notifications.warn(`Acteur ${it.actorId} introuvable`) ui.notifications.warn(`Acteur ${it.actorId} introuvable`)
return {}
} }
return { actorParameters.ajustement = parseInt(actorRow.find('input[name="ajustement-fatigue"]').val() ?? 0)
actor: actor, actorParameters.selected = actor && actorRow.find('input[name="selectionner-acteur"]').is(':checked')
ajustement: parseInt(actorRow.find('input[name="ajustement-fatigue"]').val() ?? 0), return actorParameters
selected: actor && actorRow.find('input[name="selectionner-acteur"]').is(':checked')
}
} }
async close() { async close() {

View File

@ -1,8 +1,8 @@
{ {
"id": "foundryvtt-reve-de-dragon", "id": "foundryvtt-reve-de-dragon",
"title": "Rêve de Dragon", "title": "Rêve de Dragon",
"version": "12.0.6", "version": "12.0.7",
"download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.6.zip", "download": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/archive/foundryvtt-reve-de-dragon-12.0.7.zip",
"manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json", "manifest": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/v11/system.json",
"changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md", "changelog": "https://www.uberwald.me/gitea/public/foundryvtt-reve-de-dragon/raw/branch/v11/changelog.md",
"compatibility": { "compatibility": {

View File

@ -42,7 +42,8 @@
<li class="competence-header flexrow"> <li class="competence-header flexrow">
<span class="flex-grow-2">Personnage</span> <span class="flex-grow-2">Personnage</span>
<span class="flex-grow-2">Survies</span> <span class="flex-grow-2">Survies</span>
<span class="flex-grow-1" data-tooltip="Ajustements à appliquer pour les personnages se reposant (par exemple, à cheval)">Ajustements</span> <span class="flex-grow-1" data-tooltip="Ajustements à appliquer (par exemple, repos à cheval)">Ajustements</span>
<span class="flex-grow-1" data-tooltip="Total de fatigue pour le voyageur">Total</span>
</li> </li>
{{#each playerActors as |selected|}} {{#each playerActors as |selected|}}
{{>'systems/foundryvtt-reve-de-dragon/templates/voyage/fatigue-actor.hbs' voyageur=selected survies=@root.typeTerrain.survies}} {{>'systems/foundryvtt-reve-de-dragon/templates/voyage/fatigue-actor.hbs' voyageur=selected survies=@root.typeTerrain.survies}}

View File

@ -8,16 +8,13 @@
</span> </span>
<span class="flex-grow-2"> <span class="flex-grow-2">
<div class="flexcol "> <div class="flexcol ">
<label class="voyage-liste-survies"> <label class="voyage-liste-survies">{{voyageur.survieCourante}}</label>
{{#each voyageur.competencesVoyage as |comp key|}}
{{#if (array-includes ../survies key)}}
{{key}} {{comp.system.niveau}},
{{/if}}
{{/each}}
</label>
</div> </div>
</span> </span>
<span class="flex-grow-1"> <span class="flex-grow-1">
<input type="number" name="ajustement-fatigue" class="number-x2 ajustement-fatigue" data-dtype="Number" value="{{voyageur.ajustementFatigue}}" min="-6" max="6"/> <input type="number" name="ajustement-fatigue" class="number-x2 ajustement-fatigue" data-dtype="Number" value="{{voyageur.ajustementFatigue}}" min="-6" max="6"/>
</span> </span>
<span class="flex-grow-1">
<input type="number" name="total-fatigue" class="number-x2 total-fatigue" data-dtype="Number" value="1" min="0" max="24" disabled/>
</span>
</li> </li>