2020-05-21 21:48:20 +02:00
/ * *
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system .
* @ extends { Actor }
* /
2020-05-22 22:37:02 +02:00
import { RdDUtility } from "./rdd-utility.js" ;
2020-07-25 10:29:28 +02:00
import { TMRUtility } from "./tmr-utility.js" ;
2020-06-03 21:35:18 +02:00
import { RdDRollDialog } from "./rdd-roll-dialog.js" ;
2020-12-06 20:11:30 +01:00
import { RdDRollDialogEthylisme } from "./rdd-roll-ethylisme.js" ;
2020-12-06 19:29:10 +01:00
import { RdDRoll } from "./rdd-roll.js" ;
2020-07-05 21:45:25 +02:00
import { RdDTMRDialog } from "./rdd-tmr-dialog.js" ;
2020-11-14 03:16:03 +01:00
import { Misc } from "./misc.js" ;
2020-12-11 08:29:24 +01:00
import { RdDAstrologieJoueur } from "./rdd-astrologie-joueur.js" ;
2020-11-12 16:35:51 +01:00
import { RdDResolutionTable } from "./rdd-resolution-table.js" ;
2020-11-16 04:32:42 +01:00
import { RdDDice } from "./rdd-dice.js" ;
import { RdDRollTables } from "./rdd-rolltables.js" ;
2020-11-24 15:20:05 +01:00
import { ChatUtility } from "./chat-utility.js" ;
2020-12-04 20:52:04 +01:00
import { RdDItemSort } from "./item-sort.js" ;
2020-12-08 03:04:00 +01:00
import { Grammar } from "./grammar.js" ;
2020-12-12 21:58:44 +01:00
import { RdDItemArme } from "./item-arme.js" ;
import { RdDCombat } from "./rdd-combat.js" ;
2020-05-22 22:37:02 +02:00
2020-05-22 00:48:43 +02:00
export class RdDActor extends Actor {
2020-05-22 22:37:02 +02:00
2020-05-24 20:19:57 +02:00
/* -------------------------------------------- */
/ * *
* Override the create ( ) function to provide additional RdD functionality .
*
* This overrided create ( ) function adds initial items
* Namely : Basic skills , money ,
*
* @ param { Object } data Barebones actor data which this function adds onto .
* @ param { Object } options ( Unused ) Additional options which customize the creation workflow .
*
* /
2020-06-10 08:23:58 +02:00
2020-05-24 20:19:57 +02:00
static async create ( data , options ) {
2020-11-18 16:33:12 +01:00
// Case of compendium global import
2020-12-01 17:36:13 +01:00
if ( data instanceof Array ) {
2020-11-18 16:33:12 +01:00
return super . create ( data , options ) ;
2020-12-01 17:36:13 +01:00
}
2020-05-24 20:19:57 +02:00
// If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic
if ( data . items ) {
return super . create ( data , options ) ;
}
2020-09-20 17:38:21 +02:00
2020-06-22 10:18:03 +02:00
data . items = [ ] ;
2020-09-20 17:38:21 +02:00
let compendiumName = "" ;
2020-11-14 23:24:01 +01:00
if ( data . type == "personnage" ) {
2020-09-20 17:38:21 +02:00
compendiumName = "foundryvtt-reve-de-dragon.competences" ;
2020-11-14 23:24:01 +01:00
} else if ( data . type == "humanoide" ) {
2020-11-04 16:29:10 +01:00
compendiumName = "foundryvtt-reve-de-dragon.competences-humanoides" ;
2020-11-14 23:24:01 +01:00
} else if ( data . type == "creature" ) {
2020-09-20 17:38:21 +02:00
compendiumName = "foundryvtt-reve-de-dragon.competences-creatures" ;
2020-11-14 23:24:01 +01:00
} else if ( data . type == "entite" ) {
compendiumName = "foundryvtt-reve-de-dragon.competences-entites" ;
2020-06-22 10:18:03 +02:00
}
2020-09-20 16:36:39 +02:00
let competences = [ ] ;
const pack = game . packs . get ( compendiumName ) ;
await pack . getIndex ( ) . then ( index => competences = index ) ;
for ( let comp of competences )
{
let compItem = undefined ;
await pack . getEntity ( comp . _id ) . then ( skill => compItem = skill ) ;
data . items . push ( compItem ) ;
}
2020-09-20 17:38:21 +02:00
2020-09-27 22:33:02 +02:00
return super . create ( data , options ) ;
2020-09-20 16:36:39 +02:00
}
2020-09-20 17:38:21 +02:00
/* -------------------------------------------- */
2020-09-20 16:36:39 +02:00
/* -------------------------------------------- */
2020-05-22 00:48:43 +02:00
prepareData ( ) {
super . prepareData ( ) ;
2020-05-21 21:48:20 +02:00
2020-05-22 00:48:43 +02:00
const actorData = this . data ;
2020-05-22 19:28:01 +02:00
2020-11-11 14:42:11 +01:00
// Dynamic computing fields
this . encombrementTotal = 0 ;
2020-12-04 10:15:55 +01:00
/ *
// Auto-resize token
if ( this . isToken ) {
let tokenSize = actorData . data . carac . taille . value / 10 ;
this . token . update ( { height : tokenSize , width : tokenSize } ) ;
} * /
2020-05-22 00:48:43 +02:00
// Make separate methods for each Actor type (character, npc, etc.) to keep
// things organized.
if ( actorData . type === 'personnage' ) this . _prepareCharacterData ( actorData ) ;
2020-09-20 21:52:46 +02:00
if ( actorData . type === 'creature' ) this . computeEtatGeneral ( actorData ) ;
2020-11-04 16:29:10 +01:00
if ( actorData . type === 'humanoide' ) this . computeEtatGeneral ( actorData ) ;
2020-05-22 00:48:43 +02:00
}
2020-06-03 21:35:18 +02:00
/* -------------------------------------------- */
2020-05-22 00:48:43 +02:00
/ * *
* Prepare Character type specific data
* /
_prepareCharacterData ( actorData ) {
2020-05-24 20:19:57 +02:00
// Initialize empty items
RdDUtility . computeCarac ( actorData . data ) ;
2020-12-02 14:00:54 +01:00
this . computeEncombrementTotalEtMalusArmure ( ) ;
2020-06-07 23:16:29 +02:00
this . computeEtatGeneral ( ) ;
2020-05-22 00:48:43 +02:00
}
2020-05-24 20:19:57 +02:00
2020-12-12 21:58:44 +01:00
/* -------------------------------------------- */
isCreature ( ) {
return this . data . type == 'creature' || this . data . type == 'entite' ;
}
2020-07-14 22:19:29 +02:00
/* -------------------------------------------- */
2020-11-16 04:01:36 +01:00
getReveActuel ( ) {
2020-07-14 22:19:29 +02:00
return this . data . data . reve . reve . value ;
}
2020-11-12 14:20:10 +01:00
2020-12-06 19:29:10 +01:00
getChanceActuel ( ) {
return this . data . data . compteurs . chance . value ;
}
2020-12-15 02:20:24 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
getForceValue ( ) {
return this . data . data . carac . force ? this . data . data . carac . force . value : this . data . data . carac . reve . value ;
}
2020-12-15 02:20:24 +01:00
/* -------------------------------------------- */
getBonusDegat ( ) {
2020-12-15 18:36:18 +01:00
return Misc . toInt ( this . data . data . attributs . plusdom . value ) ;
}
getProtectionNaturelle ( ) {
return Misc . toInt ( this . data . data . attributs . protection . value ) ;
2020-12-15 02:20:24 +01:00
}
2020-12-12 21:58:44 +01:00
/* -------------------------------------------- */
getCompetence ( compName ) {
return RdDUtility . findCompetence ( this . data . items , compName ) ;
}
2020-07-14 22:19:29 +02:00
/* -------------------------------------------- */
getBestDraconic ( ) {
2020-11-12 14:20:10 +01:00
const list = this . getDraconicList ( ) . sort ( ( a , b ) => b . data . niveau - a . data . niveau ) ;
if ( list . length == 0 )
{
return { name : "none" , niveau : - 11 } ;
2020-07-14 22:19:29 +02:00
}
2020-11-12 14:20:10 +01:00
return duplicate ( list [ 0 ] ) ;
2020-07-14 22:19:29 +02:00
}
2020-11-12 14:20:10 +01:00
2020-07-26 18:44:03 +02:00
/* -------------------------------------------- */
async deleteSortReserve ( coordTMR ) {
let reserve = duplicate ( this . data . data . reve . reserve ) ;
let len = reserve . list . length ;
let i = 0 ;
let newTable = [ ] ;
for ( i = 0 ; i < len ; i ++ ) {
if ( reserve . list [ i ] . coord != coordTMR )
newTable . push ( reserve . list [ i ] ) ;
}
if ( newTable . length != len ) {
reserve . list = newTable ;
await this . update ( { "data.reve.reserve" : reserve } ) ;
}
}
2020-05-22 22:37:02 +02:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
async performRoll ( rollData , attacker = undefined ) {
2020-12-15 02:20:24 +01:00
rollData . surprise = this . getSurprise ( ) ;
2020-12-12 21:58:44 +01:00
// Manage weapon categories when parrying (cf. page 115 )
if ( rollData . arme && rollData . attackerRoll ) { // Manage parade depending on weapon type, and change roll results
let attCategory = RdDItemArme . getCategorieArme ( rollData . attackerRoll . arme ) ;
let defCategory = RdDItemArme . getCategorieArme ( rollData . arme ) ;
if ( defCategory == "bouclier" )
rollData . needSignificative = false ;
else if ( attCategory != defCategory )
rollData . needSignificative = true ;
// Do we need to make resistance roll for defender ?
if ( attCategory . match ( "epee" ) && ( defCategory == "hache" || defCategory == "lance" ) )
rollData . needResist = true ;
}
if ( ! this . isEntiteCauchemar ( ) && rollData . particuliereAttaque == "finesse" ) {
rollData . needSignificative = true ;
}
2020-12-01 17:36:13 +01:00
// garder le résultat
2020-12-09 00:00:59 +01:00
await RdDResolutionTable . rollData ( rollData ) ;
2020-12-01 17:36:13 +01:00
//console.log("performRoll", rollData)
if ( ! rollData . attackerRoll ) { // Store in the registry if not a defense roll
2020-11-17 09:58:46 +01:00
game . system . rdd . rollDataHandler [ this . data . _id ] = rollData ;
2020-12-01 17:36:13 +01:00
}
2020-11-17 09:58:46 +01:00
2020-12-01 17:36:13 +01:00
if ( rollData . rolled . isPart && rollData . arme && ! rollData . attackerRoll ) { // Réussite particulière avec attaque -> choix !
2020-11-14 21:38:28 +01:00
let message = "<strong>Réussite particulière en attaque</strong>" ;
2020-12-12 21:58:44 +01:00
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='force' data-attackerId='" + this . data . _id + "'>Attaquer en Force</a>" ;
2020-11-14 21:34:34 +01:00
// Finesse et Rapidité seulement en mêlée et si la difficulté libre est de -1 minimum
2020-11-15 09:35:05 +01:00
if ( rollData . selectedCarac . label == "Mêlée" && rollData . diffLibre < 0 ) {
2020-12-12 21:58:44 +01:00
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='rapidite' data-attackerId='" + this . data . _id + "'>Attaquer en Rapidité</a>" ;
message = message + "<br><a class='chat-card-button' id='particuliere-attaque' data-mode='finesse' data-attackerId='" + this . data . _id + "'>Attaquer en Finesse</a>" ;
2020-11-14 21:34:34 +01:00
}
2020-11-14 21:22:29 +01:00
ChatMessage . create ( { content : message , whisper : ChatMessage . getWhisperRecipients ( this . name ) } ) ;
} else {
2020-12-01 17:36:13 +01:00
this . continueRoll ( rollData , attacker ) ;
2020-11-14 21:22:29 +01:00
}
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-15 21:48:28 +01:00
async computeDeteriorationArme ( rollData ) {
const attackerRoll = rollData . attackerRoll ;
if ( rollData . arme && attackerRoll ) { // C'est une parade
2020-12-05 22:21:13 +01:00
// Est-ce que l'attaque est une particulière, en force ou charge et que l'attaque n'en est pas une ?
2020-12-15 21:48:28 +01:00
if ( ( rollData . needResist || attackerRoll . particuliereAttaque == 'force' || attackerRoll . isCharge )
&& ! rollData . rolled . isPart ) {
const dmg = attackerRoll . dmg . dmgArme + attackerRoll . dmg . dmgActor ;
let resistance = Misc . toInt ( rollData . arme . data . resistance ) ;
2020-12-05 22:29:39 +01:00
let msg = "" ;
2020-12-15 21:48:28 +01:00
// Jet de résistance de l'arme de parade (p.132)
let resistRoll = await RdDResolutionTable . roll ( resistance , - dmg ) ;
if ( resistRoll . isSuccess ) { // Perte de résistance
msg = "Votre " + rollData . arme . name + " tient le choc de la parade. "
2020-12-05 22:29:39 +01:00
} else {
2020-12-15 21:48:28 +01:00
resistance -= dmg ;
if ( resistance <= 0 ) {
2020-12-05 22:21:13 +01:00
this . deleteEmbeddedEntity ( "OwnedItem" , rollData . arme . _id ) ;
2020-12-15 21:48:28 +01:00
msg = "Sous la violence de la parade, votre " + rollData . arme . name + " s'est brisée sous le coup!" ;
2020-12-05 22:21:13 +01:00
} else {
2020-12-15 21:48:28 +01:00
this . updateEmbeddedEntity ( "OwnedItem" , { _id : rollData . arme . _id , 'data.resistance' : resistance } ) ;
msg = "En parant, vous endommagez votre " + rollData . arme . name + ", qui perd " + dmg + " de résistance. " ;
2020-12-05 22:21:13 +01:00
}
}
// Jet de désarmement
2020-12-15 21:48:28 +01:00
if ( resistance > 0 && ! rollData . arme . name . toLowerCase ( ) . includes ( 'bouclier' ) ) { // Si l'arme de parade n'est pas un bouclier, jet de désarmement (p.132)
let desarme = await RdDResolutionTable . roll ( this . data . data . carac . force . value , Misc . toInt ( rollData . competence . data . niveau ) - dmg ) ;
if ( desarme . isEchec ) {
msg += "Vous ne parvenez pas à garder votre arme en main, elle tombe au sol à vos pieds" ;
2020-12-05 22:21:13 +01:00
}
}
2020-12-05 22:29:39 +01:00
ChatMessage . create ( { content : msg ,
user : game . user . _id ,
whisper : [ game . user . _id , ChatMessage . getWhisperRecipients ( "GM" ) ] } ) ;
2020-12-05 22:21:13 +01:00
}
}
}
2020-12-05 21:24:31 +01:00
2020-12-05 22:21:13 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
async computeRecul ( rollData , encaisser = undefined ) { // Calcul du recul (p. 132)
2020-12-05 22:21:13 +01:00
if ( rollData . arme || encaisser ) {
if ( ( rollData . attackerRoll . particuliereAttaque && rollData . attackerRoll . particuliereAttaque == 'force' ) || rollData . attackerRoll . isCharge ) {
2020-12-12 21:58:44 +01:00
let reculNiveau = Misc . toInt ( this . data . data . carac . taille . value ) - ( rollData . attackerRoll . forceValue + rollData . attackerRoll . arme . data . dommagesReels ) ;
let recul = await RdDResolutionTable . roll ( 10 , reculNiveau ) ;
2020-12-05 22:29:39 +01:00
let msg = "" ;
if ( recul . isSuccess ) {
2020-12-15 21:48:28 +01:00
msg = " Vous ne reculez pas malgré la force du coup." ;
2020-12-05 22:29:39 +01:00
} else {
2020-12-12 21:58:44 +01:00
let chute = await RdDResolutionTable . roll ( this . data . data . carac . agilite . value , reculNiveau ) ;
2020-12-05 22:21:13 +01:00
if ( ! chute . isSuccess || recul . isETotal ) {
2020-12-15 21:48:28 +01:00
msg = "Sous la violence du coup, vous reculez et chutez au sol ! Vous ne pouvez plus attaquer ce round." ;
2020-12-05 22:21:13 +01:00
} else {
2020-12-15 21:48:28 +01:00
msg = "La violence du choc vous fait reculer de quelques mètres ! Vous ne pouvez plus attaquer ce round." ;
2020-12-05 22:21:13 +01:00
}
2020-12-05 23:05:59 +01:00
}
2020-12-12 21:58:44 +01:00
ChatMessage . create ( { content : msg ,
2020-12-05 22:29:39 +01:00
user : game . user . _id ,
whisper : [ game . user . _id , ChatMessage . getWhisperRecipients ( "GM" ) ] } ) ;
2020-12-05 22:21:13 +01:00
}
2020-12-05 21:24:31 +01:00
}
}
2020-11-14 21:22:29 +01:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
async continueRoll ( rollData , attacker = undefined ) {
2020-11-14 21:22:29 +01:00
let rolled = rollData . rolled ;
let quality = rolled . quality
2020-11-12 16:35:51 +01:00
console . log ( ">>> ROLL" , rollData , rolled ) ;
2020-12-15 02:20:24 +01:00
this . _appliquerAjoutExperience ( rollData )
2020-11-12 16:35:51 +01:00
2020-11-15 02:07:41 +01:00
let resumeCompetence = ( rollData . competence ) ? rollData . competence . name : ( rollData . diffLibre + rollData . diffConditions ) ;
let explications = "<br>Points de taches : " + rolled . ptTache + ", ajustement qualité: " + rolled . ptQualite ;
2020-11-12 16:35:51 +01:00
2020-06-10 08:23:58 +02:00
// Fight management !
2020-06-07 23:16:29 +02:00
let defenseMsg ;
2020-06-11 00:29:32 +02:00
let encaisser = false ;
2020-11-13 11:24:56 +01:00
if ( rollData . arme || ( rollData . competence && rollData . competence . name . toLowerCase ( ) == 'esquive' ) ) {
2020-11-14 03:16:03 +01:00
explications = ""
2020-11-12 16:35:51 +01:00
// In case of fight, replace the message per dommages + localization. it indicates if result is OK or not
if ( rollData . attackerRoll ) { // Defense case !
2020-12-01 17:36:13 +01:00
if ( rolled . isSign || ( ! rollData . needSignificative && rolled . isSuccess ) ) {
2020-12-15 21:48:28 +01:00
await this . computeDeteriorationArme ( rollData ) ;
2020-11-14 21:22:29 +01:00
explications += "<br><strong>Attaque parée/esquivée !</strong>" ;
} else {
2020-11-14 03:16:03 +01:00
explications += "<br><strong>Esquive/Parade échouée, encaissement !</strong>" ;
2020-11-21 23:24:00 +01:00
if ( rollData . needSignificative )
2020-12-01 17:36:13 +01:00
explications += " Significative nécessaire!" ;
2020-11-12 16:35:51 +01:00
}
2020-12-01 17:36:13 +01:00
encaisser = rollData . needSignificative ? ! rolled . isSign : ! rolled . isSuccess ;
2020-12-12 21:58:44 +01:00
await this . computeRecul ( rollData , encaisser ) ;
2020-06-17 20:31:43 +02:00
} else { // This is the attack roll!
2020-11-13 11:24:56 +01:00
if ( rolled . isSuccess ) {
2020-12-06 18:41:54 +01:00
let target = this . _getTarget ( ) ;
2020-12-01 17:36:13 +01:00
if ( await this . targetEntiteNonAccordee ( target , 'avant-defense' ) ) {
return ;
}
2020-11-14 21:53:46 +01:00
// Message spécial pour la rapidité, qui reste difficile à gérer automatiquement
if ( rollData . particuliereAttaque == 'rapidite' ) {
2020-11-24 15:44:50 +01:00
ChatMessage . create ( { content : "Vous avez attaqué en Rapidité. Ce cas n'est pas géré autmatiquement, donc suivez les directives de votre MJ pour gérer ce cas." ,
2020-11-14 21:53:46 +01:00
whisper : ChatMessage . getWhisperRecipients ( this . name ) } ) ;
}
2020-12-15 02:20:24 +01:00
rollData . dmg = RdDCombat . calculBonusDegats ( rollData , this ) ;
2020-12-01 17:36:13 +01:00
if ( target )
{
rollData . mortalite = RdDActor . _calculMortaliteEncaissement ( rollData , target ) ;
2020-11-12 16:35:51 +01:00
defenseMsg = RdDUtility . buildDefenseChatCard ( this , target , rollData ) ;
2020-11-14 03:16:03 +01:00
explications += "<br><strong>Cible</strong> : " + target . actor . data . name ;
2020-06-11 00:29:32 +02:00
}
2020-12-15 02:20:24 +01:00
explications += "<br>Encaissement : " + rollData . degats + "<br>Localisation : " + rollData . dmg . loc . label ;
2020-06-11 00:29:32 +02:00
} else {
2020-11-18 23:49:05 +01:00
explications = "<br>Echec ! Pas de dégâts" ;
2020-06-07 23:16:29 +02:00
}
}
}
2020-11-12 16:35:51 +01:00
2020-07-27 18:58:10 +02:00
// Save it for fight in the flags area
2020-11-12 23:50:37 +01:00
game . system . rdd . rollDataHandler [ this . data . _id ] = duplicate ( rollData ) ;
2020-11-12 16:35:51 +01:00
2020-07-25 10:29:28 +02:00
// Final chat message
2020-11-12 16:35:51 +01:00
let chatOptions = {
2020-11-14 03:16:03 +01:00
content : "<strong>Test : " + rollData . selectedCarac . label + " / " + resumeCompetence + "</strong>"
2020-11-15 02:07:41 +01:00
+ "<br>Difficultés <strong>libre : " + rollData . diffLibre + "</strong> / conditions : " + Misc . toSignedString ( rollData . diffConditions ) + " / état : " + rollData . etat
2020-11-16 04:32:42 +01:00
+ RdDResolutionTable . explain ( rolled )
2020-12-15 02:20:24 +01:00
+ explications
2020-11-12 16:35:51 +01:00
}
2020-11-24 15:20:05 +01:00
ChatUtility . chatWithRollMode ( chatOptions , this . name )
2020-11-12 16:35:51 +01:00
2020-06-11 00:29:32 +02:00
// This an attack, generate the defense message
2020-11-12 16:35:51 +01:00
if ( defenseMsg ) {
2020-11-12 23:50:37 +01:00
defenseMsg . rollData = duplicate ( rollData ) ;
2020-11-12 16:35:51 +01:00
if ( defenseMsg . toSocket ) {
2020-07-28 09:20:01 +02:00
game . socket . emit ( "system.foundryvtt-reve-de-dragon" , {
msg : "msg_defense" ,
2020-11-12 16:35:51 +01:00
data : defenseMsg
} ) ;
2020-11-17 09:58:46 +01:00
if ( game . user . isGM ) { // Always push the message to the MJ
ChatMessage . create ( defenseMsg ) ;
}
2020-11-12 16:35:51 +01:00
} else {
defenseMsg . whisper = [ game . user ] ;
ChatMessage . create ( defenseMsg ) ;
2020-07-28 09:20:01 +02:00
}
2020-06-11 00:29:32 +02:00
}
2020-07-28 09:20:01 +02:00
2020-06-11 00:29:32 +02:00
// Get damages!
2020-11-12 16:35:51 +01:00
if ( encaisser ) {
2020-12-01 17:36:13 +01:00
this . encaisserDommages ( rollData . attackerRoll , attacker ) ;
2020-06-11 00:29:32 +02:00
}
2020-11-12 16:35:51 +01:00
}
2020-12-14 10:38:43 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
getSurprise ( ) {
if ( this . isEntiteCauchemar ( ) ) {
return '' ;
}
if ( this . data . data . sante . sonne . value ) {
return 'demi' ;
}
return '' ;
}
2020-12-14 10:38:43 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
isDemiSurprise ( ) {
return this . getSurprise ( ) == 'demi' ;
}
2020-12-14 10:38:43 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
isSurpriseTotale ( ) {
return this . getSurprise ( ) == 'totale' ;
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
static _calculMortaliteEncaissement ( rollData , target ) {
const mortalite = target . actor . isEntiteCauchemar ( ) ? "cauchemar" : ( rollData . mortalite ? rollData . mortalite : "mortel" ) ;
console . log ( "Mortalité : " , mortalite , target . actor . data . type ) ;
return mortalite ;
}
2020-12-04 20:52:04 +01:00
/* -------------------------------------------- */
2020-11-24 18:54:13 +01:00
async dormirChateauDormant ( ) {
let message = {
whisper : ChatUtility . getWhisperRecipientsAndGMs ( this . name ) ,
content : ""
} ;
const blessures = duplicate ( this . data . data . blessures ) ;
console . log ( "dormirChateauDormant" , blessures )
await this . _recupererBlessures ( message , "legere" , blessures . legeres . liste . filter ( b => b . active ) , [ ] ) ;
await this . _recupererBlessures ( message , "grave" , blessures . graves . liste . filter ( b => b . active ) , blessures . legeres . liste ) ;
await this . _recupererBlessures ( message , "legere" , blessures . critiques . liste . filter ( b => b . active ) , blessures . graves . liste ) ;
await this . update ( { "data.blessures" : blessures } ) ;
await this . _recupererVie ( message ) ;
await this . transformerStress ( message ) ;
await this . retourSeuilDeReve ( message ) ;
message . content = "A la fin Chateau Dormant, " + message . content + "<br>Un nouveau jour se lève" ;
ChatMessage . create ( message ) ;
}
2020-12-04 20:52:04 +01:00
/* -------------------------------------------- */
2020-11-24 18:54:13 +01:00
async _recupererBlessures ( message , type , liste , moindres ) {
let count = 0 ;
const definitions = RdDUtility . getDefinitionsBlessures ( ) ;
let definition = definitions . find ( d => d . type == type ) ;
for ( let blessure of liste ) {
if ( blessure . jours >= definition . facteur ) {
let rolled = await this . _jetRecuperationConstitution ( Misc . toInt ( blessure . soins _complets ) , message ) ;
blessure . soins _complets = 0 ;
if ( rolled . isSuccess && this . _retrograderBlessure ( type , blessure , moindres ) ) {
message . content += " -- une blessure " + type + " cicatrise" ;
count ++ ;
}
else if ( rolled . isETotal ) {
message . content += " -- une blessure " + type + " s'infecte (temps de guérison augmenté de " + definition . facteur + " jours, perte de vie)" ;
blessure . jours = 0 ;
await this . santeIncDec ( "vie" , - 1 ) ;
}
else {
message . content += " -- une blessure " + type + " reste stable" ;
}
}
else {
blessure . jours ++ ;
}
}
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-11-24 18:54:13 +01:00
_retrograderBlessure ( type , blessure , blessuresMoindres )
{
if ( type != "legere" ) {
let retrograde = blessuresMoindres . find ( b => ! b . active ) ;
if ( ! retrograde ) {
return false ;
}
2020-12-15 02:20:24 +01:00
mergeObject ( retrograde , { "active" : true , "premiers_soins" : 0 , "soins_complets" : 0 , "jours" : 0 , "loc" : blessure . loc } ) ;
2020-11-24 18:54:13 +01:00
}
2020-12-01 01:17:18 +01:00
this . _supprimerBlessure ( blessure ) ;
2020-11-24 18:54:13 +01:00
return true ;
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-01 01:17:18 +01:00
_supprimerBlessure ( blessure ) {
2020-12-15 02:20:24 +01:00
mergeObject ( blessure , { "active" : false , "premiers_soins" : 0 , "soins_complets" : 0 , "jours" : 0 , "loc" : "" } ) ;
2020-12-01 01:17:18 +01:00
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-11-24 18:54:13 +01:00
async _recupererVie ( message ) {
let blessures = [ ] . concat ( this . data . data . blessures . legeres . liste ) . concat ( this . data . data . blessures . graves . liste ) . concat ( this . data . data . blessures . critiques . liste ) ;
let nbBlessures = blessures . filter ( b => b . active ) ;
let vieManquante = this . data . data . sante . vie . max - this . data . data . sante . vie . value ;
if ( nbBlessures == 0 && vieManquante > 0 ) {
let bonusSoins = 0 ;
for ( let b of blessures )
{
bonusSoins = Math . max ( bonusSoins , Misc . toInt ( b . soins _complets ) ) ;
}
let rolled = await this . _jetRecuperationConstitution ( bonusSoins , message )
if ( rolled . isSuccess ) {
const gain = Math . min ( rolled . isPart ? 2 : 1 , vieManquante ) ;
message . content += " -- récupération de vie: " + gain ;
await this . santeIncDec ( "vie" , gain ) ;
}
else if ( rolled . isETotal ) {
message . content += " -- perte de vie: 1" ;
await this . santeIncDec ( "vie" , - 1 ) ;
}
else {
message . content += " -- vie stationnaire " ;
}
}
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-11-24 18:54:13 +01:00
async _jetRecuperationConstitution ( bonusSoins , message = undefined ) {
let difficulte = Misc . toInt ( bonusSoins ) + Math . min ( 0 , this . data . data . sante . vie . value - this . data . data . sante . vie . max ) ;
let rolled = await RdDResolutionTable . roll ( this . data . data . carac . constitution . value , difficulte ) ;
if ( message ) {
message . content += RdDResolutionTable . explain ( rolled ) . replace ( /Jet :/ , "Constitution :" ) ;
}
return rolled ;
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-01 01:17:18 +01:00
async remiseANeuf ( ) {
let message = {
whisper : ChatUtility . getWhisperRecipientsAndGMs ( this . name ) ,
content : "Remise à neuf de " + this . name
} ;
2020-12-15 02:20:24 +01:00
if ( this . data . data . blessures ) {
const blessures = duplicate ( this . data . data . blessures ) ;
for ( let listeBlessures of [ blessures . legeres . liste , blessures . graves . liste , blessures . critiques . liste ] ) {
for ( let blessure of listeBlessures ) {
this . _supprimerBlessure ( blessure ) ;
}
2020-12-01 01:17:18 +01:00
}
2020-12-15 02:20:24 +01:00
await this . update ( { "data.blessures" : blessures } ) ;
2020-12-01 01:17:18 +01:00
}
await this . santeIncDec ( "vie" , this . data . data . sante . vie . max - this . data . data . sante . vie . value ) ;
await this . santeIncDec ( "endurance" , this . data . data . sante . endurance . max - this . data . data . sante . endurance . value ) ;
2020-12-15 02:20:24 +01:00
if ( this . data . data . sante . fatigue ) {
let fatigue = duplicate ( this . data . data . sante . fatigue )
fatigue . value = 0 ;
await this . update ( { "data.sante.fatigue" : fatigue } ) ;
}
2020-12-01 01:17:18 +01:00
ChatMessage . create ( message ) ;
}
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-16 04:32:42 +01:00
async dormir ( heures = 1 ) {
2020-11-24 15:43:03 +01:00
let message = {
whisper : ChatUtility . getWhisperRecipientsAndGMs ( this . name ) ,
content : "Vous dormez " + heures + " heure" + ( heures > 1 ? "s" : "" )
} ;
2020-11-20 11:38:27 +01:00
await this . recupereEndurance ( message ) ;
2020-11-16 04:32:42 +01:00
for ( let i = 0 ; i < heures ; i ++ ) {
2020-11-20 11:38:27 +01:00
await this . recupererFatigue ( message ) ;
await this . recuperationReve ( message ) ;
2020-11-16 04:32:42 +01:00
}
2020-11-17 13:08:52 +01:00
ChatMessage . create ( message ) ;
2020-11-16 04:32:42 +01:00
}
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-20 11:38:27 +01:00
async recupereEndurance ( message ) {
const manquant = this . _computeEnduranceMax ( ) - this . data . data . sante . endurance . value ;
if ( manquant > 0 ) {
await this . santeIncDec ( "endurance" , manquant ) ;
message . content += "<br>Vous récuperez " + manquant + " points d'endurance" ;
2020-11-17 13:08:52 +01:00
}
}
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-20 11:38:27 +01:00
async recupererFatigue ( message ) {
2020-11-17 13:08:52 +01:00
let fatigue = duplicate ( this . data . data . sante . fatigue )
2020-11-20 11:38:27 +01:00
const fatigueMin = this . _computeFatigueMin ( ) ;
if ( fatigue . value <= fatigueMin ) {
2020-11-17 13:08:52 +01:00
message . content += "<br>Vous êtes déjà reposé" ;
return ;
}
2020-11-20 11:38:27 +01:00
fatigue . value = Math . max ( fatigueMin , this . _calculRecuperationSegment ( fatigue . value ) ) ;
console . log ( "recupererFatigue" , fatigue )
await this . update ( { "data.sante.fatigue" : fatigue } ) ;
if ( fatigue . value == 0 )
{
message . content += "<br>Vous êtes bien reposé" ;
}
}
2020-11-21 08:27:28 +01:00
/* -------------------------------------------- */
2020-11-20 11:38:27 +01:00
_calculRecuperationSegment ( actuel )
{
2020-11-17 13:08:52 +01:00
const segments = RdDUtility . getSegmentsFatigue ( this . data . data . sante . endurance . max ) ;
let cumul = 0 ;
let i ;
for ( i = 0 ; i < 11 ; i ++ ) {
cumul += segments [ i ] ;
2020-11-20 11:38:27 +01:00
let diff = cumul - actuel ;
2020-11-17 13:08:52 +01:00
if ( diff >= 0 )
{
const limit2Segments = Math . floor ( segments [ i ] / 2 ) ;
if ( diff > limit2Segments && i > 0 ) {
cumul -= segments [ i - 1 ] ; // le segment est à moins de la moitié, il est récupéré
2020-11-16 04:32:42 +01:00
}
2020-11-17 13:08:52 +01:00
cumul -= segments [ i ] ;
break ;
}
2020-11-20 11:38:27 +01:00
} ;
return cumul ;
2020-11-17 13:08:52 +01:00
}
2020-11-24 15:45:41 +01:00
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-20 11:38:27 +01:00
async recuperationReve ( message ) {
2020-11-17 13:08:52 +01:00
const seuil = this . data . data . reve . seuil . value ;
2020-11-25 00:49:21 +01:00
const reveActuel = this . getReveActuel ( ) ;
if ( reveActuel >= seuil ) {
message . content += "<br>Vous avez suffisament rêvé (seuil " + seuil + ", rêve actuel " + reveActuel + ")" ;
2020-11-17 13:08:52 +01:00
}
else {
2020-11-24 15:45:41 +01:00
let deRecuperation = await RdDDice . deDraconique ( ) ;
2020-11-17 13:08:52 +01:00
console . log ( "recuperationReve" , deRecuperation ) ;
if ( deRecuperation >= 7 )
{
// Rêve de Dragon !
message . content += "<br>Vous faites un <strong>Rêve de Dragon</strong> de " + deRecuperation + " Points de rêve" ;
2020-11-25 00:49:21 +01:00
message . content += await this . combattreReveDeDragon ( deRecuperation ) ;
2020-11-16 04:32:42 +01:00
}
2020-11-17 13:08:52 +01:00
else {
message . content += "<br>Vous récupérez " + deRecuperation + " Points de rêve" ;
2020-11-25 00:49:21 +01:00
await this . reveActuelIncDec ( deRecuperation ) ;
2020-11-17 13:08:52 +01:00
}
}
2020-11-16 04:32:42 +01:00
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-11-24 18:54:13 +01:00
async retourSeuilDeReve ( message ) {
const seuil = this . data . data . reve . seuil . value ;
const reveActuel = this . getReveActuel ( ) ;
if ( reveActuel > seuil ) {
message . content += "<br>Votre rêve redescend vers son seuil naturel (seuil " + seuil + ", nouveau rêve actuel " + ( reveActuel - 1 ) + ")" ;
await this . reveActuelIncDec ( - 1 ) ;
}
}
2020-11-16 04:32:42 +01:00
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-21 09:10:31 +01:00
async combattreReveDeDragon ( force ) {
2020-11-16 04:32:42 +01:00
let draconic = this . getBestDraconic ( ) ;
let niveau = Math . max ( 0 , draconic . data . niveau ) ;
let etat = this . data . data . compteurs . etat . value ;
let difficulte = niveau - etat - force ;
let reveActuel = this . getReveActuel ( ) ;
2020-11-21 09:10:31 +01:00
let rolled = await RdDResolutionTable . roll ( reveActuel , difficulte ) ;
2020-11-17 13:08:52 +01:00
// TODO: xp particulière
2020-11-17 14:48:04 +01:00
console . log ( "combattreReveDeDragon" , rolled ) ;
2020-11-25 23:41:08 +01:00
return await this . appliquerReveDeDragon ( rolled , force ) ;
2020-11-16 04:32:42 +01:00
}
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-25 23:41:08 +01:00
async appliquerReveDeDragon ( roll , force ) {
2020-11-16 04:32:42 +01:00
let message = "" ;
if ( roll . isSuccess ) {
message += "<br>Vous gagnez " + force + " points de Rêve" ;
2020-11-25 23:41:08 +01:00
await this . updatePointDeSeuil ( ) ;
await this . reveActuelIncDec ( force ) ;
2020-11-16 04:32:42 +01:00
}
if ( roll . isPart ) {
// TODO: Dialog pour choix entre HR opu général?
let tete = "à déterminer" ;
message += "<br>Vous gagnez une Tête de dragon: " + tete ;
}
if ( roll . isEchec ) {
message += "<br>Vous subissez une Queue de Dragon" ;
this . ajouterQueue ( ) ;
}
if ( roll . isETotal ) {
message += "<br>A cause de votre échec total, vous subissez une deuxième Queue de Dragon !"
this . ajouterQueue ( ) ;
}
return message ;
}
2020-11-15 11:15:36 +01:00
/* -------------------------------------------- */
2020-11-14 03:16:03 +01:00
async sortMisEnReserve ( rollData , sort ) {
let reserve = duplicate ( this . data . data . reve . reserve ) ;
reserve . list . push ( { coord : rollData . coord , sort : sort , draconic : duplicate ( rollData . selectedDraconic ) } ) ;
await this . update ( { "data.reve.reserve" : reserve } ) ;
this . currentTMR . updateSortReserve ( ) ;
}
2020-05-24 20:19:57 +02:00
/* -------------------------------------------- */
updateCarac ( caracName , caracValue )
{
2020-06-07 23:16:29 +02:00
let caracpath = "data.carac." + caracName + ".value"
2020-11-18 18:38:21 +01:00
if ( caracName == "reve" ) {
2020-11-16 04:32:42 +01:00
if ( caracValue > Misc . toInt ( this . data . data . reve . seuil . value ) ) {
2020-11-18 18:38:21 +01:00
this . setPointsDeSeuil ( caracValue ) ;
2020-11-16 04:32:42 +01:00
}
}
2020-06-07 23:16:29 +02:00
this . update ( { caracpath : caracValue } ) ;
2020-05-24 20:19:57 +02:00
}
2020-05-28 23:36:09 +02:00
2020-09-20 17:38:21 +02:00
/* -------------------------------------------- */
async updateCreatureCompetence ( compName , fieldName , compValue )
{
2020-12-12 21:58:44 +01:00
let comp = this . getCompetence ( compName ) ;
2020-09-20 19:17:31 +02:00
console . log ( comp ) ;
2020-09-20 17:38:21 +02:00
if ( comp ) {
const update = { _id : comp . _id }
if ( fieldName == "niveau" )
2020-09-20 19:17:31 +02:00
update [ 'data.niveau' ] = compValue ;
2020-09-20 17:38:21 +02:00
else if ( fieldName == "dommages" )
2020-09-20 19:17:31 +02:00
update [ 'data.dommages' ] = compValue ;
2020-09-20 17:38:21 +02:00
else
2020-09-20 19:17:31 +02:00
update [ 'data.carac_value' ] = compValue ;
console . log ( update ) ;
2020-09-20 17:38:21 +02:00
const updated = await this . updateEmbeddedEntity ( "OwnedItem" , update ) ; // Updates one EmbeddedEntity
}
}
2020-06-01 23:50:10 +02:00
/* -------------------------------------------- */
async updateCompetence ( compName , compValue )
{
2020-12-12 21:58:44 +01:00
let comp = this . getCompetence ( compName ) ;
2020-06-01 23:50:10 +02:00
if ( comp ) {
2020-08-13 22:28:56 +02:00
let troncList = RdDUtility . isTronc ( compName ) ;
let maxNiveau = compValue ;
if ( troncList ) {
2020-09-05 22:56:33 +02:00
let message = "Vous avez modifié une compétence 'tronc'. Vérifiez que les compétences suivantes évoluent ensemble jusqu'au niveau 0 : " ;
2020-08-13 22:28:56 +02:00
for ( let troncName of troncList ) {
2020-09-05 22:56:33 +02:00
message += "<br>" + troncName ;
2020-08-13 22:28:56 +02:00
}
2020-11-16 04:01:36 +01:00
ChatMessage . create ( { title : "Compétence Tronc" ,
2020-09-05 22:56:33 +02:00
content : message } ) ;
2020-08-13 22:28:56 +02:00
}
const update = { _id : comp . _id , 'data.niveau' : maxNiveau } ;
2020-06-01 23:50:10 +02:00
const updated = await this . updateEmbeddedEntity ( "OwnedItem" , update ) ; // Updates one EmbeddedEntity
2020-06-12 22:46:04 +02:00
} else {
console . log ( "Competence not found" , compName ) ;
}
}
/* -------------------------------------------- */
async updateCompetenceXP ( compName , compValue )
{
2020-12-12 21:58:44 +01:00
let comp = this . getCompetence ( compName ) ;
2020-06-12 22:46:04 +02:00
if ( comp ) {
const update = { _id : comp . _id , 'data.xp' : compValue } ;
const updated = await this . updateEmbeddedEntity ( "OwnedItem" , update ) ; // Updates one EmbeddedEntity
2020-06-01 23:50:10 +02:00
} else {
console . log ( "Competence not found" , compName ) ;
}
}
2020-08-29 22:52:41 +02:00
/* -------------------------------------------- */
async updateCompteurValue ( fieldName , fieldValue )
{
//console.log("Update", fieldName, fieldValue);
let content ;
let compteurs = duplicate ( this . data . data . compteurs ) ;
compteurs [ fieldName ] . value = fieldValue ;
await this . update ( { "data.compteurs" : compteurs } ) ;
}
2020-11-12 14:43:08 +01:00
/* -------------------------------------------- */
2020-11-15 09:35:05 +01:00
/ * * T e s t e s i l e c o n t e n e u r d e d e s t i n a t i o n a s u f f i s a m e n t d e c a p a c i t é
* pour recevoir le nouvel objet
* /
testConteneurCapacite ( itemId , conteneurId ) {
if ( ! conteneurId ) return true ; // pas de conteneur (porté sur soi), donc toujours OK.
let conteneur = this . items . find ( conteneur => conteneurId == conteneur . _id ) ; // recup conteneur
//console.log("Conteneur trouvé : ", conteneur);
if ( conteneur && conteneur . type == "conteneur" ) {
let currentEnc = 0 ; // Calculer le total actuel des contenus
for ( let id of conteneur . data . data . contenu ) {
let objet = this . items . find ( objet => ( id == objet . _id ) ) ;
currentEnc += ( objet ) ? objet . data . data . encombrement : 0 ;
}
// Et gérer le nouvel objet
let nouvelObjet = this . items . find ( objet => ( itemId == objet . _id ) ) ;
if ( currentEnc + nouvelObjet . data . data . encombrement > Number ( conteneur . data . data . capacite ) )
return false ;
}
return true ;
}
/* -------------------------------------------- */
2020-11-12 14:43:08 +01:00
/ * * S u p p r i m e u n i t e m d ' u n c o n t e n e u r , s u r l a b a s e
* de leurs ID * /
async enleverDeConteneur ( itemId , conteneurId ) {
if ( ! conteneurId ) return ; // pas de conteneur (porté sur soi)
let conteneur = this . items . find ( conteneur => conteneurId == conteneur . _id ) ; // recup conteneur
if ( conteneur ) { // Si présent
2020-11-28 09:59:30 +01:00
let data2use = duplicate ( conteneur . data ) ;
2020-11-12 14:43:08 +01:00
//console.log("Suppression du conteneur1", conteneurId, itemId, conteneur.data.data.contenu);
2020-11-28 09:59:30 +01:00
let contenu = data2use . data . contenu ;
2020-11-28 10:05:53 +01:00
let index = contenu . indexOf ( itemId ) ;
while ( index >= 0 ) { // Force cleanup, itemId is unique
contenu . splice ( index , 1 ) ;
index = contenu . indexOf ( itemId ) ;
}
2020-11-28 09:59:30 +01:00
await this . updateEmbeddedEntity ( "OwnedItem" , data2use ) ;
2020-11-12 14:43:08 +01:00
}
}
/* -------------------------------------------- */
/ * * A j o u t e u n i t e m d a n s u n c o n t e n e u r , s u r l a b a s e
* de leurs ID * /
async ajouterAConteneur ( itemId , conteneurId ) {
if ( ! conteneurId ) return ; // pas de conteneur (porté sur soi)
let conteneur = this . items . find ( conteneur => conteneurId == conteneur . _id ) ;
if ( conteneur && conteneur . type == 'conteneur' ) {
2020-11-28 09:59:30 +01:00
let data2use = duplicate ( conteneur . data ) ;
data2use . data . contenu . push ( itemId ) ;
await this . updateEmbeddedEntity ( "OwnedItem" , data2use ) ;
2020-11-12 14:43:08 +01:00
}
}
2020-11-11 14:42:11 +01:00
/* -------------------------------------------- */
detectSurEncombrement ( ) {
let diffEnc = Number ( this . encombrementTotal ) - Number ( this . data . data . attributs . encombrement . value ) ;
if ( diffEnc > 0 ) { // Sur-encombrement
let malus = Math . round ( diffEnc ) ;
malus = ( malus == 0 ) ? 1 : malus ; // Always 1 at least
2020-11-12 14:43:08 +01:00
//console.log("Sur enc malus", malus);
2020-11-11 14:42:11 +01:00
return malus ;
}
return 0 ;
}
2020-11-11 11:43:13 +01:00
/* -------------------------------------------- */
2020-12-02 14:00:54 +01:00
async computeEncombrementTotalEtMalusArmure ( ) {
2020-11-11 11:43:13 +01:00
let totalEnc = 0 ;
2020-12-02 14:00:54 +01:00
let malusArmureData = duplicate ( this . data . data . attributs . malusarmure ) ;
let newMalusArmure = 0 ;
2020-11-11 11:43:13 +01:00
for ( const item of this . data . items ) {
2020-12-02 14:00:54 +01:00
if ( item . type == 'armure' && item . data . equipe ) { // Armure équipée, intégration du malus armure total
newMalusArmure += item . data . malus ;
}
// Calcul encombrement
2020-11-27 09:40:48 +01:00
if ( item . data && item . data . encombrement != undefined ) {
if ( ! Number ( item . data . encombrement ) ) item . data . encombrement = 0 ; // Auto-fix
if ( ! item . data . quantite ) item . data . quantite = 1 ; // Auto-fix
item . data . encTotal = Number ( item . data . encombrement ) * Number ( item . data . quantite ) ;
//console.log("Enc:", item.name, item.data.encombrement, item.data.quantite, item.data.encTotal);
totalEnc += item . data . encTotal ;
} else {
item . data . encTotal = 0 ; // Force default enc
2020-11-11 11:43:13 +01:00
}
}
2020-12-02 14:00:54 +01:00
// Mise à jour valeur totale et états
2020-11-11 14:42:11 +01:00
this . encombrementTotal = totalEnc ;
this . detectSurEncombrement ( ) ;
2020-12-02 14:00:54 +01:00
// Mise à jour éventuelle du malus armure
if ( newMalusArmure != malusArmureData . value ) {
malusArmureData . value = newMalusArmure ;
await this . update ( { "data.attributs.malusarmure" : malusArmureData } ) ;
}
2020-11-11 11:43:13 +01:00
}
2020-12-14 10:38:43 +01:00
/* -------------------------------------------- */
2020-12-05 02:22:37 +01:00
computeResumeBlessure ( blessures = this . data . data . blessures ) {
let nbLegeres = this . countBlessures ( blessures . legeres . liste ) ;
let nbGraves = this . countBlessures ( blessures . graves . liste ) ;
let nbCritiques = this . countBlessures ( blessures . critiques . liste ) ;
let resume = "Blessures:" ;
if ( nbCritiques > 0 || nbGraves > 0 || nbLegeres > 0 ) {
if ( nbLegeres > 0 ) {
resume += " " + nbLegeres + " légères" ;
}
if ( nbGraves > 0 ) {
if ( nbLegeres > 0 )
resume += "," ;
resume += " " + nbGraves + " graves" ;
}
if ( nbCritiques > 0 ) {
if ( nbGraves > 0 || nbLegeres > 0 )
resume += "," ;
resume += " une CRITIQUE !" ;
}
}
else {
resume += " aucune" ;
}
return resume ;
}
2020-05-29 00:43:16 +02:00
/* -------------------------------------------- */
2020-11-27 12:20:13 +01:00
computeEtatGeneral ( )
2020-05-29 00:43:16 +02:00
{
let data = this . data . data ;
2020-11-15 11:15:36 +01:00
// Pas d'état général pour les entités forçage à 0
if ( this . data . type == 'entite' ) {
data . compteurs . etat . value = 0 ;
return ;
}
// Pour les autres
2020-11-27 12:20:13 +01:00
let state = 0 , surenc = 0 ;
2020-05-29 00:43:16 +02:00
state = state - ( data . sante . vie . max - data . sante . vie . value ) ;
2020-09-20 21:52:46 +02:00
if ( data . sante . fatigue ) // Creatures n'ont pas de fatigue
state = state + RdDUtility . currentFatigueMalus ( data . sante . fatigue . value , data . sante . endurance . max ) ;
2020-12-06 21:11:30 +01:00
if ( data . compteurs && data . compteurs . ethylisme ) // Ajout de l'éthylisme
state = state + data . compteurs . ethylisme . value ;
2020-11-27 12:20:13 +01:00
state = state ;
data . compteurs . etat . value = state ;
2020-12-08 21:40:41 +01:00
if ( data . compteurs && data . compteurs . surenc ) {
surenc = - this . detectSurEncombrement ( ) ;
data . compteurs . surenc . value = surenc ;
}
2020-05-29 00:43:16 +02:00
}
2020-07-17 22:04:35 +02:00
/* -------------------------------------------- */
async ajouterRefoulement ( value = 1 ) {
let ret = "none" ;
let refoulement = duplicate ( this . data . data . reve . refoulement ) ;
refoulement . value = refoulement . value + value ;
2020-11-14 03:16:03 +01:00
2020-12-04 20:52:04 +01:00
let total = new Roll ( "1d20" ) . roll ( ) . total ;
2020-07-25 10:29:28 +02:00
if ( total <= refoulement . value ) {
2020-07-17 22:04:35 +02:00
refoulement . value = 0 ;
2020-11-16 04:32:42 +01:00
this . ajouterSouffle ( ) ;
2020-07-17 22:04:35 +02:00
ret = "souffle" ;
}
2020-11-14 03:16:03 +01:00
2020-07-17 22:04:35 +02:00
await this . update ( { "data.reve.refoulement" : refoulement } ) ;
return ret ;
}
2020-11-16 04:32:42 +01:00
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-16 04:32:42 +01:00
ajouterSouffle ( ) {
let souffle = RdDRollTables . getSouffle ( ) ;
// ChatMessage.create({
// title: "Souffle de Dragon",
// content: this.name + " subit un Souffle de Dragon : " + souffle.name
// });
// this.actor.createOwnedItem(souffle);
}
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-16 04:32:42 +01:00
async ajouterQueue ( ) {
// TODO: Déterminer si Thanatos a été utilisé? => laisser le joueur ne pas choisir Thanatos => choisir sa voie?
let utiliseThanatos = false ;
let queue ;
if ( utiliseThanatos ) {
queue = await RdDRollTables . getOmbre ( ) ;
// mettre à jour: plus d'ombre en vue
}
else {
queue = await RdDRollTables . getQueue ( ) ;
}
/ *
// TODO: convertir la queue obtenue en nouvel item ...
// ou bien l'ajouter à la liste spécifique => this.data.data.reve.queues
this . createOwnedItem ( queue ) ;
ChatMessage . create ( {
content : this . name + " subit un Queue de Dragon : " + queue . name
} ) ;
return queue . name ;
* /
}
2020-07-21 23:51:24 +02:00
/* -------------------------------------------- */
async deleteTMRRencontreAtPosition ( ) {
let rencontres = duplicate ( this . data . data . reve . rencontre ) ;
let len = rencontres . list . length ;
let i = 0 ;
//console.log("List", rencontres, len);
let newTable = [ ] ;
for ( i = 0 ; i < len ; i ++ ) {
if ( rencontres . list [ i ] . coord != this . data . data . reve . tmrpos . coord )
newTable . push ( rencontres . list [ i ] ) ;
}
if ( newTable . length != len ) {
rencontres . list = newTable ;
//console.log("Result: ", rencontres);
await this . update ( { "data.reve.rencontre" : rencontres } ) ;
}
}
/* -------------------------------------------- */
async addTMRRencontre ( currentRencontre ) {
let rencontres = duplicate ( this . data . data . reve . rencontre ) ;
let len = rencontres . list . length ;
let i = 0 ;
let already = false ;
for ( i = 0 ; i < len ; i ++ ) {
if ( rencontres . list [ i ] . coord == this . data . data . reve . tmrpos . coord )
already = true ;
}
if ( ! already ) {
rencontres . list . push ( { coord : this . data . data . reve . tmrpos . coord , rencontre : currentRencontre } ) ;
await this . update ( { "data.reve.rencontre" : rencontres } ) ;
}
}
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
async updateCoordTMR ( coord ) {
let tmrPos = duplicate ( this . data . data . reve . tmrpos ) ;
tmrPos . coord = coord ;
await this . update ( { "data.reve.tmrpos" : tmrPos } ) ;
}
2020-07-21 23:51:24 +02:00
2020-07-17 22:04:35 +02:00
/* -------------------------------------------- */
2020-12-06 19:29:10 +01:00
async reveActuelIncDec ( value ) {
2020-07-17 22:04:35 +02:00
let reve = duplicate ( this . data . data . reve . reve ) ;
2020-11-14 03:16:03 +01:00
reve . value = Math . max ( reve . value + value , 0 ) ;
2020-07-17 22:04:35 +02:00
await this . update ( { "data.reve.reve" : reve } ) ;
}
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-16 03:52:34 +01:00
async updatePointDeSeuil ( value = 1 ) {
const seuil = Misc . toInt ( this . data . data . reve . seuil . value ) ;
const reve = Misc . toInt ( this . data . data . carac . reve . value ) ;
if ( seuil < reve ) {
await this . setPointsDeSeuil ( Math . min ( seuil + value , reve ) ) ;
}
}
2020-07-17 22:04:35 +02:00
2020-11-17 16:30:03 +01:00
/* -------------------------------------------- */
2020-11-16 03:52:34 +01:00
async setPointsDeSeuil ( value ) {
let seuil = duplicate ( this . data . data . reve . seuil ) ;
seuil . value = value ;
await this . update ( { "data.reve.seuil" : seuil } ) ;
}
2020-05-31 23:06:25 +02:00
/* -------------------------------------------- */
2020-06-07 23:16:29 +02:00
testSiSonne ( sante , endurance )
2020-05-31 23:06:25 +02:00
{
2020-12-04 20:52:04 +01:00
let result = new Roll ( "1d20" ) . roll ( ) . total ;
2020-11-20 11:38:27 +01:00
if ( result <= endurance )
2020-06-07 23:16:29 +02:00
sante . sonne . value = false ;
2020-11-20 11:38:27 +01:00
if ( result > endurance || result == 20 ) // 20 is always a failure
2020-06-07 23:16:29 +02:00
sante . sonne . value = true ;
2020-05-31 23:06:25 +02:00
if ( result == 1 ) {
2020-06-07 23:16:29 +02:00
sante . sonne . value = false ;
2020-11-16 04:01:36 +01:00
let xp = Misc . toInt ( this . data . data . carac . constitution . xp ) + 1 ;
2020-06-07 23:16:29 +02:00
this . update ( { "data.carac.constitution.xp" : xp } ) ; // +1 XP !
// TODO : Output to chat
2020-05-31 23:06:25 +02:00
}
}
2020-07-27 16:27:41 +02:00
/* -------------------------------------------- */
2020-11-25 00:50:20 +01:00
countBlessures ( blessuresListe )
2020-07-27 16:27:41 +02:00
{
2020-11-25 00:50:20 +01:00
return blessuresListe . filter ( b => b . active ) . length
2020-07-27 16:27:41 +02:00
}
2020-12-06 21:39:55 +01:00
/* -------------------------------------------- */
async jetVie ( ) {
let myRoll = new Roll ( "1d20" ) . roll ( ) ;
myRoll . showDice = true ;
await RdDDice . show ( myRoll ) ;
let msgText = "Jet de Vie : " + myRoll . total + " / " + this . data . data . sante . vie . value + "<br>" ;
if ( myRoll . total <= this . data . data . sante . vie . value ) {
msgText += "Jet réussi, pas de perte de point de vie (prochain jet dans 1 round pour 1 critique, SC minutes pour une grave)" ;
if ( myRoll . total == 1 ) {
msgText += "La durée entre 2 jets de vie est multipliée par 20 (20 rounds pour une critique, SCx20 minutes pour une grave)" ;
}
} else {
msgText += "Jet échoué, vous perdez 1 point de vie" ;
await this . santeIncDec ( "vie" , - 1 ) ;
if ( myRoll . total == 20 ) {
msgText += "Votre personnage est mort !!!!!" ;
}
}
const message = {
content : msgText ,
whisper : ChatMessage . getWhisperRecipients ( game . user . name )
} ;
ChatMessage . create ( message ) ;
}
2020-08-29 22:52:41 +02:00
2020-05-28 23:36:09 +02:00
/* -------------------------------------------- */
2020-12-01 00:21:53 +01:00
async santeIncDec ( name , inc , isCritique = false ) {
2020-06-07 23:16:29 +02:00
const sante = duplicate ( this . data . data . sante ) ;
let data = sante [ name ] ;
2020-12-01 17:36:13 +01:00
if ( data == undefined ) {
return ;
}
2020-11-21 23:24:00 +01:00
let minValue = 0 ;
2020-12-01 00:21:53 +01:00
if ( this . type == 'personnage' ) {
// TODO: les animaux/humanoïdes on théoriquement aussi un sconst, mais la SPA n'est pas passé par là
minValue = name == "vie" ? - Number ( this . data . data . attributs . sconst . value ) : 0 ;
}
2020-11-20 11:38:27 +01:00
let newValue = Math . max ( minValue , Math . min ( data . value + inc , data . max ) ) ;
2020-11-30 23:59:16 +01:00
//console.log("New value ", inc, minValue, newValue);
2020-11-20 11:38:27 +01:00
2020-11-15 11:15:36 +01:00
if ( name == "endurance" && this . data . type != 'entite' ) {
2020-11-17 11:35:05 +01:00
if ( sante . fatigue && inc < 0 ) { // Each endurance lost -> fatigue lost
2020-06-07 23:16:29 +02:00
sante . fatigue . value = sante . fatigue . value - inc
2020-11-17 11:35:05 +01:00
}
2020-12-01 00:06:55 +01:00
if ( ! isCritique && newValue == 0 && inc < 0 ) { // perte endurance et endurance devient 0 -> -1 vie sauf si coup critique
2020-06-07 23:16:29 +02:00
sante . vie . value = sante . vie . value - 1 ;
2020-05-31 23:06:25 +02:00
}
2020-11-20 11:38:27 +01:00
newValue = Math . max ( 0 , newValue ) ;
if ( inc > 0 ) { // le max d'endurance s'applique seulement à la récupération
2020-12-04 23:56:03 +01:00
newValue = Math . min ( newValue , this . _computeEnduranceMax ( ) )
2020-11-20 11:38:27 +01:00
}
if ( data . value - newValue > 1 ) {
this . testSiSonne ( sante , newValue ) ; // Peut-être sonné si 2 points d'endurance perdus d'un coup
} else if ( inc > 0 ) {
sante . sonne . value = false ;
2020-05-31 23:06:25 +02:00
}
}
2020-11-20 11:38:27 +01:00
data . value = newValue ;
2020-11-20 16:45:20 +01:00
//console.log(name, inc, data.value, newValue, minValue, data.max);
2020-11-20 11:38:27 +01:00
if ( sante . fatigue ) { // If endurance lost, then the same amount of fatigue cannot be recovered
sante . fatigue . value = Math . max ( sante . fatigue . value , this . _computeFatigueMin ( ) ) ;
}
2020-07-25 10:29:28 +02:00
//console.log("SANTE::::", sante);
2020-06-07 23:16:29 +02:00
await this . update ( { "data.sante" : sante } ) ;
}
2020-08-29 22:52:41 +02:00
2020-11-20 16:45:20 +01:00
/* -------------------------------------------- */
2020-11-20 11:38:27 +01:00
_computeFatigueMin ( ) {
return this . data . data . sante . endurance . max - this . data . data . sante . endurance . value ;
}
2020-11-20 16:45:20 +01:00
/* -------------------------------------------- */
2020-11-20 11:38:27 +01:00
_computeEnduranceMax ( ) {
let blessures = this . data . data . blessures ;
let diffVie = this . data . data . sante . vie . max - this . data . data . sante . vie . value ;
let maxEndVie = this . data . data . sante . endurance . max - ( diffVie * 2 ) ;
2020-11-25 00:50:20 +01:00
let nbGraves = this . countBlessures ( blessures . graves . liste ) ;
let nbCritiques = this . countBlessures ( blessures . critiques . liste ) ;
2020-11-20 11:38:27 +01:00
let maxEndGraves = Math . floor ( this . data . data . sante . endurance . max / ( 2 * nbGraves ) ) ;
let maxEndCritiques = nbCritiques > 0 ? 1 : this . data . data . sante . endurance . max ;
return Math . max ( 0 , Math . min ( maxEndVie , maxEndGraves , maxEndCritiques ) ) ;
}
2020-07-20 12:02:07 +02:00
/* -------------------------------------------- */
2020-07-27 16:27:41 +02:00
async manageBlessureFromSheet ( bType , index , active ) {
let bList = duplicate ( this . data . data . blessures ) ;
let blessure = bList [ bType + "s" ] . liste [ index ] ;
2020-07-20 12:02:07 +02:00
blessure . active = ! blessure . active ;
2020-07-27 16:27:41 +02:00
if ( ! blessure . active ) {
blessure . premiers _soins = 0 ;
blessure . soins _complets = 0 ;
blessure . jours = 0 ;
2020-12-15 02:20:24 +01:00
blessure . loc = "" ;
2020-07-27 16:27:41 +02:00
}
//console.log("Blessure update", bType, index, blessure, bList );
await this . update ( { 'data.blessures' : bList } ) ;
2020-07-20 12:02:07 +02:00
}
2020-07-27 16:27:41 +02:00
/* -------------------------------------------- */
async setDataBlessureFromSheet ( bType , index , psoins , pcomplets , jours , loc ) {
let bList = duplicate ( this . data . data . blessures ) ;
let blessure = bList [ bType + "s" ] . liste [ index ] ;
blessure . premiers _soins = psoins ;
blessure . soins _complets = pcomplets ;
blessure . jours = jours ;
2020-12-15 02:20:24 +01:00
blessure . loc = loc ;
2020-07-27 16:27:41 +02:00
await this . update ( { 'data.blessures' : bList } ) ;
}
2020-06-07 23:16:29 +02:00
/* -------------------------------------------- */
2020-12-15 02:20:24 +01:00
manageBlessures ( blessuresData )
2020-06-07 23:16:29 +02:00
{
2020-11-07 21:06:37 +01:00
// Fast exit
2020-11-15 11:15:36 +01:00
if ( this . data . type == 'entite' ) return ; // Une entité n'a pas de blessures
2020-11-07 21:06:37 +01:00
if ( blessuresData . legeres + blessuresData . graves + blessuresData . critiques == 0 ) return ;
2020-11-15 11:15:36 +01:00
let workData = duplicate ( blessuresData ) ;
2020-11-07 21:06:37 +01:00
let blessures = duplicate ( this . data . data . blessures ) ;
// Manage blessures
if ( workData . legeres > 0 ) {
for ( let k = 0 ; k < blessures . legeres . liste . length ; k ++ ) {
let bless = blessures . legeres . liste [ k ] ;
if ( ! bless . active ) {
bless . active = true ;
bless . loc = workData . locName ;
workData . legeres -- ;
2020-06-22 10:18:03 +02:00
}
2020-11-07 21:06:37 +01:00
if ( workData . legeres == 0 ) break ;
2020-06-22 10:18:03 +02:00
}
2020-11-07 21:06:37 +01:00
}
if ( workData . legeres > 0 ) {
workData . graves += 1 ;
blessuresData . graves += 1 ;
}
2020-06-22 10:18:03 +02:00
2020-11-07 21:06:37 +01:00
if ( workData . graves > 0 ) {
for ( let k = 0 ; k < blessures . graves . liste . length ; k ++ ) {
let bless = blessures . graves . liste [ k ] ;
if ( ! bless . active ) {
bless . active = true ;
bless . loc = workData . locName ;
workData . graves -- ;
2020-06-22 10:18:03 +02:00
}
2020-11-07 21:06:37 +01:00
if ( workData . graves == 0 ) break ;
2020-06-22 10:18:03 +02:00
}
2020-11-07 21:06:37 +01:00
}
2020-06-22 10:18:03 +02:00
2020-11-07 21:06:37 +01:00
if ( workData . graves > 0 ) {
workData . critiques = 1 ;
blessuresData . critiques = 1 ;
}
2020-06-22 10:18:03 +02:00
2020-11-07 21:06:37 +01:00
if ( workData . critiques > 0 ) {
workData . endurance = this . data . data . sante . endurance . value ; // Patch with real endurance current value (ie end -> 0 when critique)
blessures . critiques . liste [ 0 ] . active = true ;
blessures . critiques . liste [ 0 ] . loc = workData . locName ;
2020-06-22 10:18:03 +02:00
}
2020-11-07 21:06:37 +01:00
this . update ( { "data.blessures" : blessures } ) ;
2020-05-28 23:36:09 +02:00
}
2020-08-29 22:52:41 +02:00
2020-12-06 20:11:30 +01:00
/* -------------------------------------------- */
async ethylismeTest ( ) {
let rollData = {
vieValue : this . data . data . sante . vie . value ,
2020-12-06 21:11:30 +01:00
etat : this . data . data . compteurs . etat . value - this . data . data . compteurs . etat . value , // Pour les jets d'Ethylisme, on ignore le degré d'éthylisme (p.162)
2020-12-06 20:11:30 +01:00
niveauEthylisme : this . data . data . compteurs . ethylisme . value ,
nbDoses : this . data . data . compteurs . ethylisme . nb _doses || 0 ,
finalLevel : 0 ,
diffConditions : 0 ,
ajustementsConditions : CONFIG . RDD . ajustementsConditions ,
forceAlcool : 0
}
let html = await renderTemplate ( 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-ethylisme.html' , rollData ) ;
new RdDRollDialogEthylisme ( html , rollData , this ) . render ( true ) ;
}
2020-12-06 21:11:30 +01:00
2020-12-06 20:11:30 +01:00
/* -------------------------------------------- */
async performEthylisme ( rollData ) {
let ethylisme = duplicate ( this . data . data . compteurs . ethylisme ) ;
2020-12-06 21:11:30 +01:00
// Je d'ethylisme
let rollEthylisme = await RdDResolutionTable . roll ( rollData . vieValue , rollData . finalLevel ) ;
let msgText = RdDResolutionTable . explain ( rollEthylisme ) + "<br>" ;
if ( rollEthylisme . isSuccess ) {
2020-12-06 20:11:30 +01:00
ethylisme . nb _doses = ethylisme . nb _doses + 1 ;
2020-12-06 21:11:30 +01:00
msgText += "Vous avez réussi votre jet d'éthylisme, votre vous avez désormais " + ethylisme . nb _doses + " doses sans effet." ;
} else {
ethylisme . value = ethylisme . value - 1 ;
if ( ethylisme . value > 7 ) ethylisme . value = 7 ; // Niveau max
let enduranceLost = new Roll ( "1d6" ) . roll ( ) . total ;
await this . santeIncDec ( "endurance" , - enduranceLost ) ;
msgText += "Vous avez échoué à votre jet d'éthylisme, votre niveau d'éthylisme est de " + ethylisme . value
+ "(" + RdDUtility . getNomEthylisme ( ethylisme . value ) + ")." ;
// Qui a bu boira (p 164)
let rollVolonte = await RdDResolutionTable . roll ( this . data . data . carac . volonte . value , - ethylisme . value ) ;
msgText += "<br>" + RdDResolutionTable . explain ( rollVolonte ) + "<br>" ;
if ( rollVolonte . isSuccess )
msgText += "Qui a bu boira : vous êtes libre de continuer à boire ou pas." ;
else
msgText += "Qui a bu boira : vous avez une envie irrépréssible de reprendre un verre." ;
2020-12-06 20:11:30 +01:00
}
2020-12-06 21:11:30 +01:00
await this . update ( { 'data.compteurs.ethylisme' : ethylisme } ) ;
2020-12-06 20:11:30 +01:00
const message = {
content : msgText ,
whisper : ChatMessage . getWhisperRecipients ( game . user . name )
} ;
2020-12-06 21:11:30 +01:00
ChatMessage . create ( message ) ;
2020-12-06 20:11:30 +01:00
}
2020-11-12 16:35:51 +01:00
/* -------------------------------------------- */
async stressTest ( ) {
2020-11-24 18:54:13 +01:00
const message = {
content : "" ,
2020-11-12 16:35:51 +01:00
whisper : ChatMessage . getWhisperRecipients ( game . user . name )
2020-11-24 18:54:13 +01:00
} ;
await this . transformerStress ( message ) ;
ChatMessage . create ( message ) ;
}
2020-12-06 20:11:30 +01:00
/* -------------------------------------------- */
2020-11-24 18:54:13 +01:00
async transformerStress ( message ) {
const stress = Misc . toInt ( this . data . data . compteurs . stress . value ) ;
if ( stress <= 0 ) {
return ;
}
let stressRoll = await this . _stressRoll ( ) ;
let convertis = Math . floor ( stress * stressRoll . factor ) ;
let compteurs = duplicate ( this . data . data . compteurs ) ;
compteurs . experience . value += convertis ;
compteurs . stress . value = Math . max ( stress - convertis - 1 , 0 ) ;
message . content += "<br>Vous transformez " + convertis + " points de Stress en Expérience" + stressRoll . comment ;
2020-11-12 16:35:51 +01:00
await this . update ( { "data.compteurs" : compteurs } ) ;
2020-08-29 22:52:41 +02:00
}
2020-11-14 21:34:34 +01:00
/* -------------------------------------------- */
2020-11-21 09:10:31 +01:00
async _stressRoll ( ) {
2020-11-25 00:49:21 +01:00
let reveActuel = this . getReveActuel ( ) ;
let result = await RdDResolutionTable . roll ( reveActuel , 0 ) ;
2020-11-17 16:30:03 +01:00
console . log ( "_stressRoll" , result ) ;
switch ( result . code ) {
case "sign" : return { factor : 0.75 , comment : " (75%): " + result . quality + " - " + result . roll + " sur " + result . score + "%" }
case "norm" : return { factor : 0.5 , comment : " (50%): " + result . quality + " - " + result . roll + " sur " + result . score + "%" }
case "echec" : return { factor : 0.2 , comment : " (20%): " + result . quality + " - " + result . roll + " sur " + result . score + "%" }
case "epart" : return { factor : 0.1 , comment : " (10%): " + result . quality + " - " + result . roll + " sur " + result . score + "%" }
case "etotal" : return { factor : 0 , comment : " (0%): " + result . quality + " - " + result . roll + " sur " + result . score + "%" }
case "part" :
{
2020-11-25 00:49:21 +01:00
let second = await RdDResolutionTable . roll ( reveActuel , 0 ) ;
2020-11-17 16:30:03 +01:00
console . log ( "_stressRoll" , second ) ;
switch ( second . code ) {
case "part" : case "sign" :
return { factor : 1.5 , comment : " (150%): Double Particulière - " + result . roll + " puis " + second . roll + " sur " + result . score + "%" }
default :
return { factor : 1 , comment : " (150%): " + result . quality + " - " + result . roll + " puis " + second . roll + " sur " + result . score + "%" }
}
2020-11-17 11:35:05 +01:00
}
2020-11-17 16:30:03 +01:00
}
2020-11-12 16:35:51 +01:00
}
2020-11-17 11:35:05 +01:00
2020-12-06 23:31:23 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
createCallbackExperience ( ) {
2020-12-06 23:31:23 +01:00
return {
condition : r => r . rolled . isPart && r . finalLevel < 0 && game . settings . get ( "core" , "rollMode" ) != 'selfroll' ,
action : r => this . _appliquerAjoutExperience ( r )
} ;
}
2020-12-12 21:58:44 +01:00
2020-12-11 08:29:24 +01:00
/* -------------------------------------------- */
2020-12-13 23:32:16 +01:00
async _appliquerAjoutExperience ( rollData ) {
2020-12-14 10:38:43 +01:00
let xpResult = this . appliquerExperience ( rollData . rolled , rollData . selectedCarac . label , ( rollData . competence ) ? rollData . competence . data . name : undefined ) ;
if ( xpResult . result ) {
let xpmsg = "<br>Points d'expérience gagnés ! Carac: " + xpResult . xpCarac + ", Comp: " + xpResult . xpCompetence ;
let message = ChatUtility . prepareChatMessage ( 'gmroll' , this . name ) ;
message . content = "<strong>" + rollData . selectedCarac . label + "</strong>"
+ xpmsg ;
ChatMessage . create ( message ) ;
}
2020-12-06 23:31:23 +01:00
}
2020-12-08 23:07:41 +01:00
/* -------------------------------------------- */
async rollUnSort ( coord ) {
let sortList = duplicate ( this . getSortList ( ) ) ; // Duplication car les pts de reve sont modifiés dans le sort
if ( ! sortList || sortList . length == 0 )
{
ui . notifications . info ( "Aucun sort disponible!" ) ;
return ;
}
let rollData = {
selectedCarac : this . data . data . carac . reve ,
draconicList : this . getDraconicList ( ) ,
sortList : sortList ,
selectedDraconic : this . getBestDraconic ( ) ,
selectedSort : sortList [ 0 ] ,
coord : coord ,
coordLabel : TMRUtility . getTMRDescription ( coord ) . label ,
diffLibre : sortList [ 0 ] . data . difficulte , // Per default at startup
coutreve : Array ( 20 ) . fill ( ) . map ( ( item , index ) => 1 + index )
}
if ( this . currentTMR ) this . currentTMR . minimize ( ) ; // Hide
const dialog = await RdDRoll . create ( this , rollData ,
{ html : 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-sort.html' } ,
{
name : 'lancer-un-sort' ,
label : 'Lancer un sort' ,
callbacks : [
2020-12-12 21:58:44 +01:00
this . createCallbackExperience ( ) ,
2020-12-08 23:07:41 +01:00
{ action : r => this . _rollUnSortResult ( r , false ) }
]
} ,
{
name : 'mettre-en-reserve' ,
label : 'Mettre un sort en réserve' ,
callbacks : [
2020-12-12 21:58:44 +01:00
this . createCallbackExperience ( ) ,
2020-12-08 23:07:41 +01:00
{ action : r => this . _rollUnSortResult ( r , true ) }
]
}
) ;
dialog . render ( true ) ;
}
async _rollUnSortResult ( rollData , isSortReserve = false ) {
rollData . isSortReserve = isSortReserve ;
let rolled = rollData . rolled ;
let sort = rollData . selectedSort ;
let closeTMR = ! rollData . isSortReserve ;
2020-12-11 20:37:00 +01:00
if ( sort . data . isrituel && isSortReserve ) {
ui . notifications . error ( "Impossible de mettre le rituel '" + sort . name + "' en réserve" ) ;
this . currentTMR . close ( ) ; // Close TMR !
return ;
}
2020-12-08 23:07:41 +01:00
let explications = rollData . isSortReserve
? ( "<br>Mise en réserve du sort en " + rollData . coordLabel + "(" + rollData . coord + ")<strong>" )
: "<br>Lancement du sort <strong>" ;
explications += sort . name + "</strong> : " + Misc . upperFirst ( sort . data . draconic )
+ " pour " + sort . data . ptreve _reel + " points de Rêve"
+ "<br>Depuis la case " + rollData . coord + " (" + TMRUtility . getTMRDescription ( rollData . coord ) . label + ")" ;
let depenseReve = sort . data . ptreve _reel ;
let myReve = duplicate ( this . data . data . reve . reve ) ;
if ( rolled . isSuccess ) { // Réussite du sort !
//sort.ptreve_reel = coutReve;
if ( rolled . isPart ) {
depenseReve = Math . max ( Math . floor ( depenseReve / 2 ) , 1 ) ;
}
if ( rollData . isSortReserve ) {
depenseReve ++ ;
}
if ( myReve . value > depenseReve ) {
explications += "<br>Réussite du sort: " + depenseReve + " points de Rêve sont dépensés (Bonus de case en " + rollData . coord + ": +" + rolled . bonus + "%)" ;
// Incrémenter/gére le bonus de case
RdDItemSort . incrementBonusCase ( this , sort , rollData . coord ) ;
if ( rollData . isSortReserve ) {
await this . sortMisEnReserve ( rollData , sort ) ;
closeTMR = false ;
}
}
else {
// Todo 0 pts de reve !!!!
depenseReve = 0 ;
explications += "<br>Pas assez de rêve" ;
mergeObject ( rollData , RdDResolutionTable . getResultat ( "echec" ) ) ;
}
} else {
if ( rolled . isETotal ) { // Echec total !
depenseReve = Math . max ( myReve . value , Math . floor ( depenseReve * 1.5 ) )
explications += "<br><strong>Echec TOTAL</strong> du sort : " + depenseReve + " Points de Rêve" ;
// TODO: mise en réserve d'un échec total...
} else {
depenseReve = 0
explications += "<br>Echec du sort !" ;
}
}
myReve . value = Math . max ( myReve . value - depenseReve , 0 ) ;
await this . update ( { "data.reve.reve" : myReve } ) ;
if ( myReve . value == 0 ) { // 0 points de reve
ChatMessage . create ( { content : this . name + " est réduit à 0 Points de Rêve, et tombe endormi !" } ) ;
closeTMR = true ;
}
if ( closeTMR ) {
this . currentTMR . close ( ) ; // Close TMR !
} else {
this . currentTMR . maximize ( ) ; // Re-display TMR
}
// Final chat message
let chatOptions = {
content : "<strong>Test : " + rollData . selectedCarac . label + " / " + rollData . selectedDraconic . name + " / " + rollData . selectedSort . name + "</strong>"
+ "<br>Difficultés <strong>libre : " + rollData . diffLibre + "</strong> / conditions : " + Misc . toSignedString ( rollData . diffConditions ) + " / état : " + rollData . etat
+ RdDResolutionTable . explain ( rolled )
+ explications
}
ChatUtility . chatWithRollMode ( chatOptions , this . name )
}
2020-12-15 08:37:52 +01:00
/* -------------------------------------------- */
getCompetenceList ( ) {
return this . data . items . filter ( ( item ) => item . type == 'competence' ) ;
}
2020-06-12 22:46:04 +02:00
/* -------------------------------------------- */
2020-12-08 03:04:00 +01:00
async rollCarac ( caracName ) {
let rollData = {
selectedCarac : this . getCaracByName ( caracName ) ,
needSignificative : ! this . isEntiteCauchemar ( ) && this . data . data . sante . sonne . value
} ;
2020-12-06 23:31:23 +01:00
const dialog = await RdDRoll . create ( this , rollData ,
{ html : 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html' } ,
{
name : 'jet-' + caracName ,
2020-12-08 03:04:00 +01:00
label : 'Jet ' + Grammar . apostrophe ( 'de' , rollData . selectedCarac . label ) ,
2020-12-06 23:31:23 +01:00
callbacks : [
2020-12-12 21:58:44 +01:00
this . createCallbackExperience ( ) ,
2020-12-06 23:31:23 +01:00
{ action : this . _rollCaracResult }
]
}
) ;
dialog . render ( true ) ;
}
2020-12-12 23:31:19 +01:00
/* -------------------------------------------- */
2020-12-06 23:31:23 +01:00
async _rollCaracResult ( rollData ) {
let rolled = rollData . rolled ;
let resumeCompetence = ( rollData . diffLibre + rollData . diffConditions ) ;
let explications = "<br>Points de taches : " + rolled . ptTache ;
// Final chat message
let chatOptions = {
content : "<strong>Test : " + rollData . selectedCarac . label + " / " + resumeCompetence + "</strong>"
+ "<br>Difficultés <strong>libre : " + rollData . diffLibre + "</strong> / conditions : " + Misc . toSignedString ( rollData . diffConditions ) + " / état : " + rollData . etat
+ RdDResolutionTable . explain ( rolled )
+ explications
2020-11-15 02:07:41 +01:00
}
2020-12-06 23:31:23 +01:00
ChatUtility . chatWithRollMode ( chatOptions , this . name )
2020-12-06 18:41:54 +01:00
}
2020-12-08 03:04:00 +01:00
/* -------------------------------------------- */
async rollCompetence ( name ) {
let rollData = {
2020-12-12 21:58:44 +01:00
competence : duplicate ( this . getCompetence ( name ) ) ,
2020-12-08 03:04:00 +01:00
needSignificative : ! this . isEntiteCauchemar ( ) && this . data . data . sante . sonne . value
}
if ( rollData . competence . type == 'competencecreature' ) {
// Fake competence pour créature
2020-12-12 21:58:44 +01:00
rollData . competence . data = { defaut _carac : "carac_creature" , categorie : "creature" } ;
2020-12-08 03:04:00 +01:00
rollData . carac = { carac _creature : { label : competence . name , value : competence . data . carac _value } } ;
}
else {
rollData . carac = this . data . data . carac ;
}
2020-12-12 21:58:44 +01:00
console . log ( "rollCompetence !!!" , rollData ) ;
2020-12-08 03:04:00 +01:00
2020-12-11 08:29:24 +01:00
const dialog = await RdDRoll . create ( this , rollData , { html : 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' } , {
2020-12-08 03:04:00 +01:00
name : 'jet-competence' ,
label : 'Jet ' + Grammar . apostrophe ( 'de' , name ) ,
callbacks : [
2020-12-12 21:58:44 +01:00
this . createCallbackExperience ( ) ,
2020-12-08 03:04:00 +01:00
{ action : this . _competenceResult }
]
2020-12-11 08:29:24 +01:00
} ) ;
2020-12-08 03:04:00 +01:00
dialog . render ( true ) ;
}
2020-12-15 21:28:55 +01:00
/* -------------------------------------------- */
async creerTacheDepuisLivre ( item ) {
console . log ( "FROM ITEM" , item ) ;
let tache = { name : "Lire " + item . name , type : 'tache' ,
data : {
carac : 'intellect' ,
competence : 'Ecriture' ,
difficulte : item . data . data . difficulte ,
periodicite : "60 minutes" ,
fatigue : 2 ,
points _de _tache : item . data . data . points _de _tache ,
points _de _tache _courant : 0 ,
description : "Lecture du livre " + item . name +
" - XP : " + item . data . data . xp + " - Compétences : " + item . data . data . competence
}
}
await this . createOwnedItem ( tache , { renderSheet : true } ) ;
}
2020-12-15 08:37:52 +01:00
/* -------------------------------------------- */
getTache ( id ) {
return this . data . items . find ( item => item . _id == id ) ;
}
/* -------------------------------------------- */
async rollTache ( id ) {
let tache = duplicate ( this . getTache ( id ) ) ;
let competence = duplicate ( this . getCompetence ( tache . data . competence ) ) ;
competence . data . defaut _carac = tache . data . carac ; // Patch !
let rollData = {
competence : competence ,
needSignificative : this . data . data . sante . sonne . value ,
tache : tache ,
diffConditions : tache . data . difficulte ,
editLibre : false ,
editConditions : false ,
actor : this
}
rollData . carac = { } ;
rollData . carac [ tache . data . carac ] = duplicate ( this . data . data . carac [ tache . data . carac ] ) ; // Single carac
console . log ( "rollTache !!!" , duplicate ( rollData ) ) ;
const dialog = await RdDRoll . create ( this , rollData , { html : 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' } , {
name : 'jet-competence' ,
label : 'Jet de Tâche ' + tache . name ,
callbacks : [
this . createCallbackExperience ( ) ,
2020-12-15 21:28:55 +01:00
{ action : r => this . _tacheResult ( r ) }
2020-12-15 08:37:52 +01:00
]
} ) ;
2020-12-15 21:28:55 +01:00
dialog . render ( true ) ;
2020-12-15 08:37:52 +01:00
}
/* -------------------------------------------- */
_tacheResult ( rollData ) {
2020-12-15 21:28:55 +01:00
// Mise à jour de la tache
rollData . tache . data . points _de _tache _courant += rollData . rolled . ptTache ;
this . updateEmbeddedEntity ( "OwnedItem" , rollData . tache ) ;
this . santeIncDec ( "fatigue" , - rollData . tache . data . fatigue ) ;
// Message de résultat
2020-12-15 08:37:52 +01:00
ChatUtility . chatWithRollMode ( {
content : "<strong>Test de Tache : " + rollData . tache . name + " - " + rollData . selectedCarac . label + " / " + rollData . competence . name + "</strong>"
+ "<br>Difficultés <strong>libre : " + rollData . diffLibre + "</strong> / conditions : " + Misc . toSignedString ( rollData . diffConditions ) + " / état : " + rollData . etat
2020-12-15 21:28:55 +01:00
+ "<br>" + RdDResolutionTable . explain ( rollData . rolled )
2020-12-15 08:37:52 +01:00
+ "<br>Points de taches : " + rollData . rolled . ptTache + ", ajustement qualité: " + rollData . rolled . ptQualite
} , this . name ) ;
2020-12-15 21:28:55 +01:00
// Message spécifique de la tâche
ChatUtility . chatWithRollMode ( {
content : "Votre tâche <strong>" + rollData . tache . name + "</strong> a duré " + rollData . tache . data . periodicite + "."
+ "<br>Votre avancement est désormais de " + rollData . tache . data . points _de _tache _courant + " Points de Tache sur un objectif de "
+ rollData . tache . data . points _de _tache + "."
+ "<br>Et vous vous êtes fatigué de " + rollData . tache . data . fatigue + " cases."
} , this . name ) ;
2020-12-15 08:37:52 +01:00
}
2020-12-11 08:29:24 +01:00
/* -------------------------------------------- */
2020-12-08 03:04:00 +01:00
_competenceResult ( rollData ) {
ChatUtility . chatWithRollMode ( {
content : "<strong>Test : " + rollData . selectedCarac . label + " / " + rollData . competence . name + "</strong>"
+ "<br>Difficultés <strong>libre : " + rollData . diffLibre + "</strong> / conditions : " + Misc . toSignedString ( rollData . diffConditions ) + " / état : " + rollData . etat
+ RdDResolutionTable . explain ( rollData . rolled )
+ "<br>Points de taches : " + rollData . rolled . ptTache + ", ajustement qualité: " + rollData . rolled . ptQualite
2020-12-15 08:37:52 +01:00
} , this . name ) ;
2020-12-08 03:04:00 +01:00
}
2020-12-06 23:31:23 +01:00
2020-12-06 21:11:30 +01:00
/* -------------------------------------------- */
2020-12-06 23:31:23 +01:00
async rollAppelChance ( )
2020-12-06 19:29:10 +01:00
{
2020-12-11 03:23:34 +01:00
let rollData = { selectedCarac : this . getCaracByName ( 'chance-actuelle' ) } ;
2020-12-06 23:31:23 +01:00
const dialog = await RdDRoll . create ( this , rollData ,
{ html : 'systems/foundryvtt-reve-de-dragon/templates/dialog-roll-carac.html' } ,
2020-11-15 02:07:41 +01:00
{
2020-12-06 19:29:10 +01:00
name : 'appelChance' ,
label : 'Appel à la chance' ,
callbacks : [
2020-12-12 21:58:44 +01:00
this . createCallbackExperience ( ) ,
2020-12-11 02:31:33 +01:00
{ action : r => this . _appelChanceResult ( r ) }
2020-12-06 19:29:10 +01:00
]
2020-11-15 02:07:41 +01:00
}
2020-12-06 19:29:10 +01:00
) ;
dialog . render ( true ) ;
}
2020-12-14 10:38:43 +01:00
/* -------------------------------------------- */
2020-12-11 02:31:33 +01:00
async _appelChanceResult ( rollData ) {
2020-12-06 19:29:10 +01:00
const message = {
user : game . user . _id ,
alias : this . name ,
content : this . name + " fait appel à la chance" + RdDResolutionTable . explain ( rollData . rolled )
} ;
if ( rollData . rolled . isSuccess ) {
2020-12-06 23:31:23 +01:00
message . content += "<br>Un point de chance est dépensée, l'action peut être retentée"
2020-12-11 02:31:33 +01:00
await this . chanceActuelleIncDec ( - 1 )
2020-11-15 02:07:41 +01:00
}
2020-12-06 19:29:10 +01:00
ChatMessage . create ( message ) ;
}
2020-12-06 23:31:23 +01:00
2020-12-06 21:11:30 +01:00
/* -------------------------------------------- */
2020-12-06 19:29:10 +01:00
async chanceActuelleIncDec ( value ) {
let chance = duplicate ( this . data . data . compteurs . chance ) ;
chance . value = Math . max ( chance . value + value , 0 ) ;
await this . update ( { "data.compteurs.chance" : chance } ) ;
}
2020-12-06 21:11:30 +01:00
/* -------------------------------------------- */
2020-12-06 19:29:10 +01:00
ajustementAstrologique ( ) {
2020-12-15 02:20:24 +01:00
if ( this . isCreature ( ) ) {
return 0 ;
}
2020-12-11 03:23:34 +01:00
// selon l'heure de naissance...
return game . system . rdd . calendrier . getAjustementAstrologique ( this . data . data . heure ) ;
2020-12-06 19:29:10 +01:00
}
2020-12-13 23:32:16 +01:00
/* -------------------------------------------- */
2020-12-14 10:38:43 +01:00
checkDesirLancinant ( ) {
let queue = this . data . items . filter ( ( item ) => item . name . toLowerCase ( ) . includes ( 'lancinant' ) ) ;
return ( queue . length > 0 ) ;
}
/* -------------------------------------------- */
async appliquerExperience ( rolled , caracName , competenceName = undefined ) {
2020-12-14 10:04:14 +01:00
2020-12-13 23:32:16 +01:00
if ( rolled . isPart && rolled . finalLevel < 0 ) {
2020-12-14 10:38:43 +01:00
// Cas de désir lancinant, pas d'expérience sur particulière
if ( this . checkDesirLancinant ( ) ) {
2020-12-14 10:42:31 +01:00
ChatMessage . create ( { content : ` Vous souffrez au moins d'un Désir Lancinant, vous ne pouvez pas gagner d'expérience sur une Particulière tant que le désir n'est pas assouvi ` ,
2020-12-14 10:38:43 +01:00
whisper : ChatMessage . getWhisperRecipients ( game . user . name ) } ) . create ( ) ;
return { result : false , xpcarac : 0 , xpCompetence : 0 } ;
}
2020-12-12 21:58:44 +01:00
if ( caracName == 'derobee' ) caracName = 'agilite' ;
2020-12-14 10:38:43 +01:00
let carac = duplicate ( this . actor . data . data . carac ) ;
2020-12-12 21:58:44 +01:00
let xp = Math . abs ( rolled . finalLevel ) ;
let xpCarac = Math . floor ( xp / 2 ) ; // impair: arrondi inférieur en carac
2020-12-15 02:26:28 +01:00
2020-12-15 08:40:07 +01:00
let xpComp = 0 ;
2020-12-14 10:38:43 +01:00
if ( competenceName ) {
2020-12-15 08:40:07 +01:00
xpComp = xp - xpCarac ;
2020-12-14 10:38:43 +01:00
let competence = duplicate ( RdDUtility . findCompetence ( this . data . items , competenceName ) ) ;
2020-12-12 21:58:44 +01:00
competence . data . xp += xpComp ;
2020-12-14 10:38:43 +01:00
await this . updateEmbeddedEntity ( "OwnedItem" , competence ) ;
2020-12-15 08:37:52 +01:00
} else {
2020-12-15 08:40:07 +01:00
xpCarac = Math . max ( xpCarac , 1 ) ;
}
2020-12-14 10:38:43 +01:00
if ( ! carac [ caracName ] . isderivee ) {
carac [ caracName ] . xp += xpCarac ;
await this . update ( { "data.carac" : carac } ) ;
2020-12-13 23:32:16 +01:00
} else {
2020-12-14 10:38:43 +01:00
ChatMessage . create ( { content : ` Vous avez ${ xpCarac } à répartir pour la caractérisque dérivée ${ caracName } . Vous devez le faire manuellement. ` ,
whisper : ChatMessage . getWhisperRecipients ( game . user . name ) } ) . create ( ) ;
2020-12-13 23:32:16 +01:00
}
2020-12-14 10:38:43 +01:00
return { result : true , xpcarac : xpCarac , xpCompetence : xpComp } ; //XP
2020-12-13 23:32:16 +01:00
}
2020-12-14 10:38:43 +01:00
return { result : false , xpcarac : 0 , xpCompetence : 0 } ; // Pas d'XP
2020-12-13 23:32:16 +01:00
}
2020-12-13 23:11:58 +01:00
/* -------------------------------------------- */
async ajouteNombreAstral ( data ) {
2020-12-13 23:32:16 +01:00
// Gestion expérience (si existante)
this . appliquerExperience ( request . rolled , "vue" , "astrologie" ) ;
2020-12-13 23:11:58 +01:00
// Ajout du nombre astral
const item = { name : "Nombre Astral" , type : "nombreastral" , data :
{ value : data . nbAstral , istrue : data . isvalid , jourindex : Number ( data . date ) , jourlabel : game . system . rdd . calendrier . getDateFromIndex ( Number ( data . date ) ) } } ;
await this . createEmbeddedEntity ( "OwnedItem" , item ) ;
// Suppression des anciens nombres astraux
let toDelete = this . data . items . filter ( ( item ) => item . data . jourindex < game . system . rdd . calendrier . getCurrentDayIndex ( ) ) ;
const deletions = toDelete . map ( i => i . _id ) ;
await this . deleteEmbeddedEntity ( "OwnedItem" , deletions ) ;
// Affichage Dialog
this . astrologieNombresAstraux ( ) ;
}
2020-12-06 19:29:10 +01:00
2020-12-11 08:29:24 +01:00
/* -------------------------------------------- */
2020-12-12 23:31:19 +01:00
async astrologieNombresAstraux ( ) {
2020-12-11 08:29:24 +01:00
// Afficher l'interface spéciale
2020-12-13 23:11:58 +01:00
const astrologieDialog = await RdDAstrologieJoueur . create ( this , { } ) ;
astrologieDialog . render ( true ) ;
2020-12-11 08:29:24 +01:00
}
2020-12-06 21:11:30 +01:00
/* -------------------------------------------- */
2020-12-06 18:41:54 +01:00
getCaracByName ( caracName ) {
switch ( caracName )
2020-11-15 02:07:41 +01:00
{
2020-12-06 21:56:59 +01:00
case 'reve-actuel' :
2020-12-06 18:41:54 +01:00
return {
label : 'Rêve Actuel' ,
value : this . getReveActuel ( ) ,
type : "number" ,
ignoreEtatGeneral : true
} ;
case 'chance-actuelle' :
return {
type : "number" ,
value : this . getChanceActuel ( ) ,
label : 'Chance actuelle' ,
ignoreEtatGeneral : true
} ;
default :
return this . data . data . carac [ caracName ] ; // Per default
2020-11-15 02:07:41 +01:00
}
2020-12-06 18:41:54 +01:00
}
/* -------------------------------------------- */
getSortList ( ) {
return this . data . items . filter ( item => item . type == "sort" ) ;
}
/* -------------------------------------------- */
getDraconicList ( ) {
return this . data . items . filter ( item => item . data . categorie == 'draconic' )
}
/* -------------------------------------------- */
async displayTMR ( mode = "normal" )
{
let isRapide = mode == "rapide"
if ( mode != "visu" )
2020-11-15 02:07:41 +01:00
{
2020-12-06 18:41:54 +01:00
let minReveValue = ( isRapide ) ? 3 : 2 ;
if ( this . getReveActuel ( ) < minReveValue ) {
ChatMessage . create ( {
content : "Vous n'avez plus assez de Points de Reve pour monter dans les Terres Médianes" ,
whisper : ChatMessage . getWhisperRecipients ( game . user . name ) } ) ;
return ;
}
2020-09-20 19:17:31 +02:00
}
2020-11-15 02:07:41 +01:00
2020-12-06 18:41:54 +01:00
// Notification au MJ
ChatMessage . create ( { content : game . user . name + " est monté dans les TMR en mode : " + mode , whisper : ChatMessage . getWhisperRecipients ( "GM" ) } ) ;
let data = {
fatigue : {
malus : RdDUtility . calculMalusFatigue ( this . data . data . sante . fatigue . value , this . data . data . sante . endurance . max ) ,
html : "<table class='table-fatigue'>" + RdDUtility . makeHTMLfatigueMatrix ( this . data . data . sante . fatigue . value , this . data . data . sante . endurance . max ) . html ( ) + "</table>"
} ,
draconic : this . getDraconicList ( ) ,
sort : this . getSortList ( ) ,
caracReve : this . data . data . carac . reve . value ,
pointsReve : this . getReveActuel ( ) ,
isRapide : isRapide
}
let html = await renderTemplate ( 'systems/foundryvtt-reve-de-dragon/templates/dialog-tmr.html' , data ) ;
this . currentTMR = new RdDTMRDialog ( html , this , data , mode ) ;
this . currentTMR . render ( true ) ;
}
2020-12-08 03:04:00 +01:00
2020-12-06 18:41:54 +01:00
2020-12-11 08:29:24 +01:00
/* -------------------------------------------- */
2020-12-08 03:04:00 +01:00
async rollCompetenceCreature ( compName ) {
2020-12-12 21:58:44 +01:00
let competence = this . getCompetence ( compName ) ;
2020-12-08 03:04:00 +01:00
if ( competence . type == 'competencecreature' && competence . data . iscombat ) {
this . rollCompetenceCombat ( competence , armeItem ) ;
}
else {
this . rollCompetence ( name ) ;
}
}
2020-12-06 18:41:54 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
rollArme ( compName , armeName = undefined ) {
2020-12-08 03:04:00 +01:00
2020-12-12 21:58:44 +01:00
let armeItem = this . data . items . find ( item => item . type === "arme" && ( item . name === armeName ) ) ;
if ( armeItem && compName == undefined ) compName = armeItem . data . competence ;
let competence = this . getCompetence ( compName == undefined ? armeName : compName ) ;
if ( armeItem || armeName || ( competence . type == 'competencecreature' && competence . data . iscombat ) ) {
this . rollCompetenceCombat ( compName , armeItem ) ;
2020-12-06 18:41:54 +01:00
} else {
2020-12-08 03:04:00 +01:00
this . rollCompetence ( competence . name ) ;
2020-12-06 18:41:54 +01:00
}
}
2020-12-12 21:58:44 +01:00
2020-11-15 11:15:36 +01:00
/* -------------------------------------------- */
2020-12-12 21:58:44 +01:00
async rollCompetenceCombat ( compName , armeItem = undefined , attackerRoll = undefined , attacker = undefined ) {
let competence = this . getCompetence ( compName ) ;
if ( RdDCombat . isActive ( ) ) {
const assaut = RdDCombat . createUsingTarget ( this ) ;
assaut . attaque ( competence , armeItem ) ;
return ;
}
2020-12-08 03:04:00 +01:00
if ( competence . type == 'competencecreature' && competence . data . iscombat ) {
2020-12-12 21:58:44 +01:00
armeItem = { name : compName , data : { dommages : competence . data . dommages , dommagesReels : competence . data . dommages } } ;
2020-12-08 03:04:00 +01:00
}
console . log ( "rollCompetenceCombat !!!" , competence , armeItem , attackerRoll ) ;
2020-11-15 11:15:36 +01:00
// Common rollData values
let rollData = {
ajustementsConditions : CONFIG . RDD . ajustementsConditions ,
difficultesLibres : CONFIG . RDD . difficultesLibres ,
etat : this . data . data . compteurs . etat . value ,
diffConditions : 0 ,
2020-12-12 21:58:44 +01:00
forceValue : attackerRoll ? this . getForceValue ( ) : 0 , // Utilisé pour le jet de recul
2020-11-15 11:15:36 +01:00
diffLibre : ( attackerRoll ) ? attackerRoll . diffLibre : 0 ,
attackerRoll : attackerRoll ,
finalLevel : 0 ,
2020-11-27 12:20:13 +01:00
coupsNonMortels : false ,
2020-12-08 22:27:28 +01:00
malusArmureValue : 0 ,
surencMalusFlag : false ,
surencMalusValue : 0 ,
2020-11-27 15:47:18 +01:00
surencMalusApply : false ,
2020-12-08 22:27:28 +01:00
isNatation : false ,
2020-11-27 15:47:18 +01:00
useEncForNatation : false ,
2020-12-08 22:27:28 +01:00
encValueForNatation : 0
}
if ( this . type == 'personnage ' ) {
2020-12-08 03:04:00 +01:00
rollData . malusArmureValue = ( this . data . data . attributs && this . data . data . attributs . malusarmure ) ? this . data . data . attributs . malusarmure . value : 0 ,
2020-12-08 22:27:28 +01:00
rollData . surencMalusFlag = ( this . data . data . compteurs . surenc . value < 0 ) ;
rollData . surencMalusValue = this . data . data . compteurs . surenc . value ;
rollData . surencMalusApply = false ;
2020-12-12 21:58:44 +01:00
rollData . isNatation = compName . toLowerCase ( ) . includes ( "natation" ) ;
2020-12-08 22:27:28 +01:00
rollData . useEncForNatation = false ;
rollData . encValueForNatation = ( this . encombrementTotal ) ? Math . round ( this . encombrementTotal ) : 0 ;
2020-11-15 11:15:36 +01:00
}
2020-11-15 02:07:41 +01:00
2020-11-15 11:15:36 +01:00
if ( competence . type == 'competencecreature' ) { // Specific case for Creatures
2020-11-14 03:16:03 +01:00
competence . data . defaut _carac = "carac_creature" ; // Fake default competence
competence . data . categorie = "creature" ; // Fake default competence
rollData . competence = competence ;
2020-11-12 23:50:37 +01:00
rollData . arme = armeItem ;
2020-12-12 21:58:44 +01:00
rollData . carac = { carac _creature : { label : compName , value : competence . data . carac _value } } ;
2020-11-12 23:50:37 +01:00
} else { // Usual competence
2020-11-14 03:16:03 +01:00
rollData . competence = competence ;
2020-12-12 21:58:44 +01:00
if ( armeItem ) {
armeItem = RdDItemArme . armeUneOuDeuxMains ( armeItem , compName . toLowerCase ( ) . includes ( "1 main" ) ) ;
2020-11-23 20:40:56 +01:00
}
2020-11-12 23:50:37 +01:00
rollData . arme = armeItem ;
rollData . carac = this . data . data . carac ;
}
2020-06-03 21:35:18 +02:00
let html = await renderTemplate ( 'systems/foundryvtt-reve-de-dragon/templates/dialog-competence.html' , rollData ) ;
2020-11-14 03:16:03 +01:00
if ( rollData . arme ) {
2020-12-06 18:41:54 +01:00
if ( await this . targetEntiteNonAccordee ( this . _getTarget ( ) , 'avant-attaque' ) ) {
2020-12-01 17:36:13 +01:00
return ;
}
new RdDRollDialog ( "arme" , html , rollData , this , attacker ) . render ( true ) ;
2020-06-07 23:16:29 +02:00
} else {
2020-12-01 17:36:13 +01:00
new RdDRollDialog ( "competence" , html , rollData , this , attacker ) . render ( true ) ;
2020-06-07 23:16:29 +02:00
}
2020-05-22 22:37:02 +02:00
}
2020-12-01 17:36:13 +01:00
2020-12-06 18:41:54 +01:00
_getTarget ( ) {
2020-12-01 17:36:13 +01:00
if ( game . user . targets && game . user . targets . size == 1 ) {
for ( let target of game . user . targets ) {
return target ;
}
}
return undefined ;
}
2020-06-07 23:16:29 +02:00
2020-06-23 23:34:12 +02:00
/* -------------------------------------------- */
2020-12-06 18:41:54 +01:00
async equiperObjet ( itemID ) {
2020-06-23 23:34:12 +02:00
let item = this . getOwnedItem ( itemID ) ;
2020-06-24 00:22:40 +02:00
if ( item && item . data . data ) {
2020-11-11 10:38:27 +01:00
let update = { _id : item . _id , "data.equipe" : ! item . data . data . equipe } ;
await this . updateEmbeddedEntity ( "OwnedItem" , update ) ;
2020-12-02 14:00:54 +01:00
this . computeEncombrementTotalEtMalusArmure ( ) ; // Mise à jour encombrement
2020-06-24 00:22:40 +02:00
}
2020-06-23 23:34:12 +02:00
}
2020-06-07 23:16:29 +02:00
/* -------------------------------------------- */
2020-12-15 18:13:15 +01:00
computeArmure ( attackerRoll ) {
let locData = attackerRoll . loc ;
2020-12-15 21:48:28 +01:00
let dmg = attackerRoll . dmg . dmgArme + attackerRoll . dmg . dmgActor ;
2020-12-15 18:13:15 +01:00
let arme = attackerRoll . arme ;
2020-12-15 02:20:24 +01:00
// TODO: arc ignore armure
2020-06-23 23:34:12 +02:00
let protection = 0 ;
for ( const item of this . data . items ) {
if ( item . type == "armure" && item . data . equipe ) {
2020-06-24 00:22:40 +02:00
let update = duplicate ( item ) ;
2020-08-29 22:52:41 +02:00
protection += new Roll ( update . data . protection . toString ( ) ) . roll ( ) . total ;
2020-12-15 18:13:15 +01:00
update . data . deterioration = Misc . toInt ( update . data . deterioration ) + dmg ;
dmg = 0 ; // Reset it
2020-06-24 00:22:40 +02:00
if ( update . data . deterioration >= 10 ) {
update . data . deterioration = 0 ;
if ( update . data . protection . toString ( ) . length == 1 )
2020-12-05 21:24:31 +01:00
update . data . protection = "1d" + update . data . protection + "-0" ;
2020-06-24 00:22:40 +02:00
else {
let regex = /d\(d+)\-(\d+)/g ;
let res = regex . exec ( update . data . protection ) ;
2020-12-05 21:24:31 +01:00
update . data . protection = "1d" + res [ 1 ] + "-" + ( parseInt ( res [ 2 ] ) + 1 ) ;
2020-06-24 00:22:40 +02:00
}
2020-12-05 21:24:31 +01:00
ChatMessage . create ( { content : "Détérioration d'armure: " + update . data . protection } ) ;
2020-06-24 00:22:40 +02:00
}
this . updateEmbeddedEntity ( "OwnedItem" , update ) ;
2020-06-23 23:34:12 +02:00
}
}
2020-12-15 18:36:18 +01:00
protection += this . getProtectionNaturelle ( ) ;
2020-06-23 23:34:12 +02:00
console . log ( "Final protect" , protection ) ;
return protection ;
2020-06-07 23:16:29 +02:00
}
2020-11-11 04:21:25 +01:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
async encaisserDommages ( attackerRoll , attacker = undefined ) {
if ( attacker && ! await attacker . accorder ( this , 'avant-encaissement' ) ) {
return ;
}
2020-11-11 04:21:25 +01:00
console . log ( "encaisserDommages" , attackerRoll )
2020-12-15 18:13:15 +01:00
const armure = this . computeArmure ( attackerRoll ) ;
2020-12-15 02:20:24 +01:00
const rollEncaissement = new Roll ( "2d10 + @dmg - @armure" , {
dmg : attackerRoll . dmg . total ,
armure : armure
} ) . roll ( ) ;
RdDDice . show ( rollEncaissement , )
let result = RdDUtility . computeBlessuresSante ( rollEncaissement . total , attackerRoll . mortalite , attackerRoll . dmg . loc ) ;
2020-12-06 21:31:41 +01:00
result . endurance = Math . max ( result . endurance , - Number ( this . data . data . sante . endurance . value ) ) ;
2020-12-01 00:21:53 +01:00
await this . santeIncDec ( "vie" , result . vie ) ;
await this . santeIncDec ( "endurance" , result . endurance , ( result . critiques > 0 ) ) ;
2020-11-11 04:21:25 +01:00
this . manageBlessures ( result ) ; // Will upate the result table
const blessureLegere = ( result . legeres > 0 ? "une blessure légère" : "" ) ;
const blessureGrave = ( result . graves > 0 ? "une blessure grave" : "" ) ;
const blessureCritique = ( result . critiques > 0 ? "une blessure critique" : "" ) ;
2020-12-15 02:20:24 +01:00
let commonMsg = {
title : "Blessures !" ,
roll : rollEncaissement ,
content : this . data . name + " a encaissé " + blessureLegere + blessureGrave + blessureCritique
}
2020-11-21 23:24:00 +01:00
let addonMsg = "<br>Et a perdu : <br>" + result . endurance + " Endurance et " + result . vie + " Points de Vie" ;
if ( this . hasPlayerOwner ) {
commonMsg . content += addonMsg ; // Message pour tout le monde
ChatMessage . create ( commonMsg ) ;
} else { // Le defenseur n'est pas un PJ, donc message complet uniquement pour le MJ
ChatMessage . create ( commonMsg ) ; // Message pour tout le monde
let gmMsg = duplicate ( commonMsg ) ;
gmMsg . content = addonMsg ; // Et message complémentaire uniquement pour le MJ
gmMsg . whisper = ChatMessage . getWhisperRecipients ( "GM" ) ;
ChatMessage . create ( gmMsg ) ;
}
2020-11-11 04:21:25 +01:00
2020-06-07 23:16:29 +02:00
this . computeEtatGeneral ( ) ;
this . sheet . render ( true ) ;
}
2020-11-07 21:06:37 +01:00
2020-06-07 23:16:29 +02:00
2020-06-10 08:23:58 +02:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
parerAttaque ( attackerRoll , armeId , attacker = undefined )
2020-06-10 08:23:58 +02:00
{
2020-06-11 00:29:32 +02:00
let armeItem = this . getOwnedItem ( armeId ) ; // Item.data.data !
2020-11-15 02:07:41 +01:00
console . log ( "Going to PARY !!!!!!!!!" , armeItem , attackerRoll . diffLibre ) ;
2020-12-08 22:27:28 +01:00
if ( armeItem . type == 'competencecreature' ) {
2020-12-08 23:35:44 +01:00
this . rollCompetenceCombat ( armeItem . name , armeItem . data , attackerRoll , attacker ) ;
2020-12-08 22:27:28 +01:00
} else {
2020-12-08 23:35:44 +01:00
this . rollCompetenceCombat ( armeItem . data . data . competence , armeItem . data , attackerRoll , attacker ) ;
2020-12-08 22:27:28 +01:00
}
2020-06-10 08:23:58 +02:00
}
2020-07-27 18:58:10 +02:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
esquiverAttaque ( attackerRoll , attacker = undefined )
2020-07-27 18:58:10 +02:00
{
2020-12-08 03:04:00 +01:00
this . rollCompetenceCombat ( "esquive" , undefined , attackerRoll , attacker ) ;
2020-07-27 18:58:10 +02:00
}
2020-05-24 20:19:57 +02:00
/* -------------------------------------------- */
2020-05-21 21:48:20 +02:00
/** @override */
getRollData ( ) {
const data = super . getRollData ( ) ;
return data ;
}
2020-12-01 17:36:13 +01:00
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
/* -- entites -- */
/* retourne true si on peut continuer, false si on ne peut pas continuer */
async targetEntiteNonAccordee ( target , when = 'avant-encaissement' )
{
if ( target )
{
return ! await this . accorder ( target . actor , when ) ;
}
return false ;
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
async accorder ( entite , when = 'avant-encaissement' )
{
if ( when != game . settings . get ( "foundryvtt-reve-de-dragon" , "accorder-entite-cauchemar" )
|| ! entite . isEntiteCauchemar ( )
|| entite . isEntiteCauchemarAccordee ( this ) ) {
return true ;
}
let rolled = await RdDResolutionTable . roll ( this . getReveActuel ( ) , - Number ( entite . data . data . carac . niveau . value ) ) ;
let message = {
content : "Jet de points actuels de rêve à " + rolled . finalLevel + RdDResolutionTable . explain ( rolled ) + "<br>" ,
whisper : ChatMessage . getWhisperRecipients ( this . name )
} ;
if ( rolled . isSuccess ) {
await entite . setEntiteReveAccordee ( this ) ;
message . content += this . name + " s'est accordé avec " + entite . name ;
}
else {
message . content += this . name + " n'est pas accordé avec " + entite . name ;
}
ChatMessage . create ( message ) ;
return rolled . isSuccess ;
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
isEntiteCauchemar ( )
{
return this . data . type == 'entite' ;
}
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
isEntiteCauchemarAccordee ( attaquant )
{
if ( ! this . isEntiteCauchemar ( ) ) { return true ; }
let resonnance = this . data . data . sante . resonnance ;
return ( resonnance . actors . find ( it => it == attaquant . _id ) ) ;
}
2020-11-14 03:16:03 +01:00
2020-12-05 21:24:31 +01:00
/* -------------------------------------------- */
2020-12-01 17:36:13 +01:00
async setEntiteReveAccordee ( attaquant )
{
if ( ! this . isEntiteCauchemar ( ) ) {
ui . notifications . error ( "Impossible de s'accorder à " + this . name + ": ce n'est pas une entite de cauchemer/rêve" ) ;
return ;
}
let resonnance = duplicate ( this . data . data . sante . resonnance ) ;
if ( resonnance . actors . find ( it => it == attaquant . _id ) ) {
// déjà accordé
return ;
}
resonnance . actors . push ( attaquant . _id ) ;
await this . update ( { "data.sante.resonnance" : resonnance } ) ;
return ;
}
2020-05-21 21:48:20 +02:00
}
2020-11-14 03:16:03 +01:00