2023-11-04 17:48:50 +01:00
import { MAX _ENDURANCE _FATIGUE , RdDUtility } from "../rdd-utility.js" ;
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js" ;
import { STATUSES } from "../settings/status-effects.js" ;
import { TYPES } from "../item.js" ;
import { RdDBaseActorReve } from "./base-actor-reve.js" ;
import { RdDDice } from "../rdd-dice.js" ;
import { RdDItemBlessure } from "../item/blessure.js" ;
/ * *
* Classe de base pour les acteurs qui peuvent subir des blessures
* - créatures
* - humanoides
* /
export class RdDBaseActorSang extends RdDBaseActorReve {
getForce ( ) { return Number ( this . system . carac . force ? . value ? ? 0 ) }
getBonusDegat ( ) { return Number ( this . system . attributs ? . plusdom ? . value ? ? 0 ) }
getProtectionNaturelle ( ) { return Number ( this . system . attributs ? . protection ? . value ? ? 0 ) }
getSConst ( ) { return 0 }
2023-11-24 02:17:20 +01:00
getEnduranceMax ( ) { return Math . max ( 1 , Math . min ( this . system . sante . endurance . max , MAX _ENDURANCE _FATIGUE ) ) }
2023-11-04 17:48:50 +01:00
getFatigueActuelle ( ) {
if ( ReglesOptionnelles . isUsing ( "appliquer-fatigue" ) ) {
2023-11-24 02:17:20 +01:00
return Math . max ( 0 , Math . min ( this . getFatigueMax ( ) , this . system . sante . fatigue ? . value ? ? 0 ) ) ;
2023-11-04 17:48:50 +01:00
}
return 0 ;
}
2023-11-24 02:17:20 +01:00
getFatigueRestante ( ) { return this . getFatigueMax ( ) - this . getFatigueActuelle ( ) }
getFatigueMin ( ) { return this . system . sante . endurance . max - this . system . sante . endurance . value }
2023-11-04 17:48:50 +01:00
getFatigueMax ( ) { return this . getEnduranceMax ( ) * 2 }
malusFatigue ( ) {
if ( ReglesOptionnelles . isUsing ( "appliquer-fatigue" ) ) {
return RdDUtility . calculMalusFatigue ( this . getFatigueActuelle ( ) , this . getEnduranceMax ( ) )
}
return 0 ;
}
/* -------------------------------------------- */
getEncombrementMax ( ) { return Number ( this . system . attributs ? . encombrement ? . value ? ? 0 ) }
isSurenc ( ) { return this . computeMalusSurEncombrement ( ) < 0 }
computeMalusSurEncombrement ( ) {
return Math . min ( 0 , Math . floor ( this . getEncombrementMax ( ) - this . encTotal ) ) ;
}
2023-11-24 02:17:20 +01:00
isDead ( ) { return this . system . sante . vie . value < - this . getSConst ( ) }
2023-11-04 17:48:50 +01:00
2023-11-24 02:17:20 +01:00
nbBlessuresLegeres ( ) { return this . itemTypes [ TYPES . blessure ] . filter ( it => it . isLegere ( ) ) . length }
nbBlessuresGraves ( ) { return this . itemTypes [ TYPES . blessure ] . filter ( it => it . isGrave ( ) ) . length }
nbBlessuresCritiques ( ) { return this . itemTypes [ TYPES . blessure ] . filter ( it => it . isCritique ( ) ) . length }
2023-11-11 19:51:26 +01:00
2023-11-04 17:48:50 +01:00
/* -------------------------------------------- */
computeResumeBlessure ( ) {
2023-11-11 19:51:26 +01:00
const nbLegeres = this . nbBlessuresLegeres ( )
const nbGraves = this . nbBlessuresGraves ( )
const nbCritiques = this . nbBlessuresCritiques ( )
2023-11-04 17:48:50 +01:00
if ( nbLegeres + nbGraves + nbCritiques == 0 ) {
return "Aucune blessure" ;
}
let resume = "Blessures:" ;
if ( nbLegeres > 0 ) {
resume += " " + nbLegeres + " légère" + ( nbLegeres > 1 ? "s" : "" ) ;
}
if ( nbGraves > 0 ) {
if ( nbLegeres > 0 )
resume += "," ;
resume += " " + nbGraves + " grave" + ( nbGraves > 1 ? "s" : "" ) ;
}
if ( nbCritiques > 0 ) {
if ( nbGraves > 0 || nbLegeres > 0 )
resume += "," ;
resume += " une CRITIQUE !" ;
}
return resume ;
}
blessuresASoigner ( ) { return [ ] }
async computeArmure ( attackerRoll ) { return this . getProtectionNaturelle ( ) }
async remiseANeuf ( ) { }
async appliquerAjoutExperience ( rollData , hideChatMessage = 'show' ) { }
/* -------------------------------------------- */
async onAppliquerJetEncaissement ( encaissement , attacker ) {
2024-05-02 14:08:02 +02:00
const santeOrig = foundry . utils . duplicate ( this . system . sante ) ;
2023-11-04 17:48:50 +01:00
const blessure = await this . ajouterBlessure ( encaissement , attacker ) ; // Will update the result table
const perteVie = await this . santeIncDec ( "vie" , - encaissement . vie ) ;
const perteEndurance = await this . santeIncDec ( "endurance" , - encaissement . endurance , blessure ? . isCritique ( ) ) ;
2024-05-01 09:13:21 +02:00
foundry . utils . mergeObject ( encaissement , {
2023-11-04 17:48:50 +01:00
resteEndurance : perteEndurance . newValue ,
sonne : perteEndurance . sonne ,
jetEndurance : perteEndurance . jetEndurance ,
endurance : perteEndurance . perte ,
vie : santeOrig . vie . value - perteVie . newValue ,
blessure : blessure
} ) ;
}
/* -------------------------------------------- */
async santeIncDec ( name , inc , isCritique = false ) {
if ( name == 'fatigue' && ! ReglesOptionnelles . isUsing ( "appliquer-fatigue" ) ) {
return ;
}
2024-05-02 14:08:02 +02:00
const sante = foundry . utils . duplicate ( this . system . sante )
2023-11-04 17:48:50 +01:00
let compteur = sante [ name ] ;
if ( ! compteur ) {
return ;
}
let result = {
sonne : false ,
} ;
let minValue = name == "vie" ? - this . getSConst ( ) - 1 : 0 ;
result . newValue = Math . max ( minValue , Math . min ( compteur . value + inc , compteur . max ) ) ;
//console.log("New value ", inc, minValue, result.newValue);
let fatigue = 0 ;
if ( name == "endurance" ) {
if ( result . newValue == 0 && inc < 0 && ! isCritique ) { // perte endurance et endurance devient 0 (sauf critique) -> -1 vie
sante . vie . value -- ;
result . perteVie = true ;
}
result . newValue = Math . max ( 0 , result . newValue ) ;
if ( inc > 0 ) { // le max d'endurance s'applique seulement à la récupération
result . newValue = Math . min ( result . newValue , this . _computeEnduranceMax ( ) )
}
const perte = compteur . value - result . newValue ;
result . perte = perte ;
if ( perte > 1 ) {
// Peut-être sonné si 2 points d'endurance perdus d'un coup
2024-05-01 09:13:21 +02:00
foundry . utils . mergeObject ( result , await this . jetEndurance ( result . newValue ) ) ;
2023-11-04 17:48:50 +01:00
} else if ( inc > 0 ) {
await this . setSonne ( false ) ;
}
if ( sante . fatigue && inc < 0 ) { // Each endurance lost -> fatigue lost
fatigue = perte ;
}
}
compteur . value = result . newValue ;
// If endurance lost, then the same amount of fatigue cannot be recovered
if ( ReglesOptionnelles . isUsing ( "appliquer-fatigue" ) && sante . fatigue && fatigue > 0 ) {
sante . fatigue . value = Math . max ( sante . fatigue . value + fatigue , this . getFatigueMin ( ) ) ;
}
await this . update ( { "system.sante" : sante } )
if ( this . isDead ( ) ) {
await this . setEffect ( STATUSES . StatusComma , true ) ;
}
return result
}
/* -------------------------------------------- */
2023-11-24 02:17:20 +01:00
_computeEnduranceMax ( ) {
const diffVie = this . system . sante . vie . max - this . system . sante . vie . value ;
const maxEndVie = this . system . sante . endurance . max - ( diffVie * 2 ) ;
const nbGraves = this . countBlessures ( it => it . isGrave ( ) ) > 0
const nbCritiques = this . countBlessures ( it => it . isCritique ( ) ) > 0
const maxEndGraves = Math . floor ( this . system . sante . endurance . max / ( 2 * nbGraves ) ) ;
const maxEndCritiques = nbCritiques > 0 ? 1 : this . system . sante . endurance . max ;
return Math . max ( 0 , Math . min ( maxEndVie , maxEndGraves , maxEndCritiques ) ) ;
}
2023-11-04 17:48:50 +01:00
/* -------------------------------------------- */
async ajouterBlessure ( encaissement , attacker = undefined ) {
if ( encaissement . gravite < 0 ) return ;
if ( encaissement . gravite > 0 ) {
while ( this . countBlessures ( it => it . system . gravite == encaissement . gravite ) >= RdDItemBlessure . maxBlessures ( encaissement . gravite ) && encaissement . gravite <= 6 ) {
// Aggravation
encaissement . gravite += 2
if ( encaissement . gravite > 2 ) {
encaissement . vie += 2 ;
}
}
}
const endActuelle = this . getEnduranceActuelle ( ) ;
const blessure = await RdDItemBlessure . createBlessure ( this , encaissement . gravite , encaissement . dmg . loc . label , attacker ) ;
if ( blessure . isCritique ( ) ) {
encaissement . endurance = endActuelle ;
}
if ( blessure . isMort ( ) ) {
this . setEffect ( STATUSES . StatusComma , true ) ;
encaissement . mort = true ;
ChatMessage . create ( {
2023-12-04 01:21:05 +01:00
content : ` <img class="chat-icon" src="icons/svg/skull.svg" data-tooltip="charge" />
2023-11-04 17:48:50 +01:00
< strong > $ { this . name } vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix ! < / s t r o n g > `
} ) ;
}
return blessure ;
}
async supprimerBlessures ( filterToDelete ) {
const toDelete = this . filterItems ( filterToDelete , TYPES . blessure )
. map ( it => it . id ) ;
await this . deleteEmbeddedDocuments ( 'Item' , toDelete ) ;
}
countBlessures ( filter = it => ! it . isContusion ( ) ) {
return this . filterItems ( filter , 'blessure' ) . length
}
/* -------------------------------------------- */
2023-11-11 19:51:26 +01:00
async jetDeVie ( ) {
if ( this . isDead ( ) ) {
ChatMessage . create ( { content : ` Jet de Vie: ${ this . name } est déjà mort, ce n'est pas la peine d'en rajouter !!!!! ` , whisper : ChatMessage . getWhisperRecipients ( this . name ) } ) ;
return
}
const jetDeVie = await RdDDice . roll ( "1d20" ) ;
const sConst = this . getSConst ( ) ;
const vie = this . system . sante . vie . value ;
const isCritique = this . nbBlessuresCritiques ( ) > 0 ;
const isGrave = this . nbBlessuresGraves ( ) ;
const isEchecTotal = jetDeVie . total == 20 ;
const isSuccess = jetDeVie . total == 1 || jetDeVie . total <= vie ;
const perte = isSuccess ? 0 : 1 + ( isEchecTotal ? vie + sConst : 0 )
const prochainJet = ( jetDeVie . total == 1 && vie > 0 ? 20 : 1 ) * ( isCritique ? 1 : isGrave > 0 ? sConst : 0 )
let msgText = ` Jet de Vie: <strong> ${ jetDeVie . total } / ${ vie } </strong> `
if ( isSuccess ) {
msgText += "<br>Réussi, pas de perte de point de vie."
2023-11-04 17:48:50 +01:00
} else {
2023-11-11 19:51:26 +01:00
msgText += ` <br>Echoué, perte ${ perte } point de vie ` ;
await this . santeIncDec ( "vie" , - perte ) ;
2023-11-04 17:48:50 +01:00
}
2023-11-11 19:51:26 +01:00
if ( this . isDead ( ) ) {
msgText += ` <br><strong> ${ this . name } est mort !!!!</strong> ` ;
}
else if ( prochainJet > 0 ) {
msgText += ` <br>Prochain jet de vie dans ${ prochainJet } ${ isCritique ? 'round' : 'minute' } ${ prochainJet > 1 ? 's' : '' } ${ isCritique ? '(état critique)' : '(état grave)' } `
}
ChatMessage . create ( { content : msgText , whisper : ChatMessage . getWhisperRecipients ( this . name ) } ) ;
2023-11-04 17:48:50 +01:00
}
/* -------------------------------------------- */
async jetEndurance ( resteEndurance = undefined ) {
const jetEndurance = ( await RdDDice . roll ( "1d20" ) ) . total ;
const sonne = jetEndurance == 20 || jetEndurance > ( resteEndurance ? ? this . system . sante . endurance . value )
if ( sonne ) {
await this . setSonne ( ) ;
}
return { jetEndurance , sonne }
}
async finDeRoundBlessures ( ) {
const nbGraves = this . filterItems ( it => it . isGrave ( ) , 'blessure' ) . length ;
if ( nbGraves > 0 ) {
// Gestion blessure graves : -1 pt endurance par blessure grave
await this . santeIncDec ( "endurance" , - nbGraves ) ;
}
}
async setSonne ( sonne = true ) {
if ( ! game . combat && sonne ) {
ui . notifications . info ( ` ${ this . name } est hors combat, il ne reste donc pas sonné ` ) ;
return ;
}
await this . setEffect ( STATUSES . StatusStunned , sonne ) ;
}
getSonne ( ) {
return this . getEffect ( STATUSES . StatusStunned ) ;
}
2024-05-26 22:43:07 +02:00
isEffectAllowed ( effectId ) { return true }
2023-11-04 17:48:50 +01:00
/* -------------------------------------------- */
2023-11-24 02:17:20 +01:00
async computeEtatGeneral ( ) { this . system . compteurs . etat . value = this . malusVie ( ) + this . malusFatigue ( ) + this . malusEthylisme ( ) }
getEtatGeneral ( options = { ethylisme : false } ) { return this . system . compteurs . etat . value }
2023-11-04 17:48:50 +01:00
2023-11-24 02:17:20 +01:00
malusVie ( ) { return Math . min ( this . system . sante . vie . value - this . system . sante . vie . max , 0 ) }
2023-11-04 17:48:50 +01:00
malusEthylisme ( ) { return 0 }
}