2024-12-08 23:46:22 +01:00
import { RdDUtility } from "../rdd-utility.js" ;
2023-11-04 17:48:50 +01:00
import { ReglesOptionnelles } from "../settings/regles-optionnelles.js" ;
import { STATUSES } from "../settings/status-effects.js" ;
2024-09-25 22:56:24 +02:00
import { ITEM _TYPES } from "../item.js" ;
2023-11-04 17:48:50 +01:00
import { RdDBaseActorReve } from "./base-actor-reve.js" ;
import { RdDDice } from "../rdd-dice.js" ;
import { RdDItemBlessure } from "../item/blessure.js" ;
2024-10-16 23:18:15 +02:00
import { ChatUtility } from "../chat-utility.js" ;
2024-12-04 15:55:09 +01:00
import { Misc } from "../misc.js" ;
2023-11-04 17:48:50 +01:00
/ * *
* Classe de base pour les acteurs qui peuvent subir des blessures
* - créatures
* - humanoides
* /
export class RdDBaseActorSang extends RdDBaseActorReve {
2024-12-04 15:55:09 +01:00
prepareActorData ( ) {
this . system . sante . vie . max = Math . ceil ( ( this . getTaille ( ) + this . getConstitution ( ) ) / 2 )
this . system . sante . vie . value = Math . min ( this . system . sante . vie . value , this . system . sante . vie . max )
super . prepareActorData ( )
this . system . attributs . encombrement . value = this . getEncombrementMax ( )
}
2023-11-04 17:48:50 +01:00
2024-12-04 15:55:09 +01:00
getForce ( ) { return Misc . toInt ( this . system . carac . force ? . value ) }
getConstitution ( ) { return Misc . toInt ( this . system . carac . constitution ? . value ) }
getVolonte ( ) { return Misc . toInt ( this . system . carac . volonte ? . value ) }
2023-11-04 17:48:50 +01:00
2024-12-04 15:55:09 +01:00
getVieMax ( ) { return Misc . toInt ( this . system . sante . vie ? . max ) }
getEnduranceMax ( ) { return Math . max ( 1 , this . getTaille ( ) + this . getConstitution ( ) ) }
getFatigueMax ( ) { return this . getEnduranceMax ( ) * 2 }
2023-11-04 17:48:50 +01:00
2024-12-04 15:55:09 +01:00
getProtectionNaturelle ( ) { return Misc . toInt ( this . system . attributs ? . protection ? . value ) }
2023-11-04 17:48:50 +01:00
getFatigueActuelle ( ) {
if ( ReglesOptionnelles . isUsing ( "appliquer-fatigue" ) ) {
2024-12-04 15:55:09 +01:00
return Math . max ( 0 , Math . min ( this . getFatigueMax ( ) , Misc . toInt ( this . system . sante . fatigue ? . value ) ) )
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
malusFatigue ( ) {
if ( ReglesOptionnelles . isUsing ( "appliquer-fatigue" ) ) {
return RdDUtility . calculMalusFatigue ( this . getFatigueActuelle ( ) , this . getEnduranceMax ( ) )
}
return 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
2024-09-25 22:56:24 +02:00
nbBlessuresLegeres ( ) { return this . itemTypes [ ITEM _TYPES . blessure ] . filter ( it => it . isLegere ( ) ) . length }
nbBlessuresGraves ( ) { return this . itemTypes [ ITEM _TYPES . blessure ] . filter ( it => it . isGrave ( ) ) . length }
nbBlessuresCritiques ( ) { return this . itemTypes [ ITEM _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' ) { }
/* -------------------------------------------- */
2024-10-26 01:33:20 +02:00
async onAppliquerJetEncaissement ( encaissement , attackerToken ) {
2024-05-02 14:08:02 +02:00
const santeOrig = foundry . utils . duplicate ( this . system . sante ) ;
2024-10-26 01:33:20 +02:00
const blessure = await this . ajouterBlessure ( encaissement , attackerToken ) ; // Will update the result table
2023-11-04 17:48:50 +01:00
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
/* -------------------------------------------- */
2024-10-26 01:33:20 +02:00
async ajouterBlessure ( encaissement , attackerToken = undefined ) {
2023-11-04 17:48:50 +01:00
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 ( ) ;
2024-10-26 01:33:20 +02:00
const blessure = await RdDItemBlessure . createBlessure ( this , encaissement . gravite , encaissement . dmg ? . loc . label ? ? '' , attackerToken ) ;
2023-11-04 17:48:50 +01:00
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" />
2024-11-15 00:01:55 +01:00
< strong > $ { this . getAlias ( ) } vient de succomber à une seconde blessure critique ! Que les Dragons gardent son Archétype en paix ! < / s t r o n g > `
2023-11-04 17:48:50 +01:00
} ) ;
}
return blessure ;
}
2024-10-16 23:18:15 +02:00
async supprimerBlessure ( { gravite } ) {
2024-10-11 00:15:15 +02:00
const toDelete = this . itemTypes [ ITEM _TYPES . blessure ] . find ( it => it . system . gravite == gravite ) ? . id
2024-10-16 23:18:15 +02:00
if ( toDelete ) {
2024-10-11 00:15:15 +02:00
await this . deleteEmbeddedDocuments ( 'Item' , [ toDelete ] ) ;
}
}
2023-11-04 17:48:50 +01:00
async supprimerBlessures ( filterToDelete ) {
2024-09-25 22:56:24 +02:00
const toDelete = this . filterItems ( filterToDelete , ITEM _TYPES . blessure )
2023-11-04 17:48:50 +01:00
. map ( it => it . id ) ;
await this . deleteEmbeddedDocuments ( 'Item' , toDelete ) ;
}
countBlessures ( filter = it => ! it . isContusion ( ) ) {
2024-10-11 00:15:15 +02:00
return this . filterItems ( filter , ITEM _TYPES . blessure ) . length
2023-11-04 17:48:50 +01:00
}
/* -------------------------------------------- */
2023-11-11 19:51:26 +01:00
async jetDeVie ( ) {
if ( this . isDead ( ) ) {
2024-10-16 23:18:15 +02:00
ChatMessage . create ( {
2024-11-15 00:01:55 +01:00
content : ` Jet de Vie: ${ this . getAlias ( ) } est déjà mort, ce n'est pas la peine d'en rajouter !!!!! ` ,
2024-10-16 23:18:15 +02:00
whisper : ChatUtility . getOwners ( this )
} )
2023-11-11 19:51:26 +01:00
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 ( ) ) {
2024-11-15 00:01:55 +01:00
msgText += ` <br><strong> ${ this . getAlias ( ) } est mort !!!!</strong> ` ;
2023-11-11 19:51:26 +01:00
}
else if ( prochainJet > 0 ) {
msgText += ` <br>Prochain jet de vie dans ${ prochainJet } ${ isCritique ? 'round' : 'minute' } ${ prochainJet > 1 ? 's' : '' } ${ isCritique ? '(état critique)' : '(état grave)' } `
}
2024-10-16 23:18:15 +02:00
ChatMessage . create ( {
content : msgText ,
whisper : ChatUtility . getOwners ( this )
} ) ;
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 ) {
2024-11-15 00:01:55 +01:00
ui . notifications . info ( ` ${ this . getAlias ( ) } est hors combat, il ne reste donc pas sonné ` ) ;
2023-11-04 17:48:50 +01:00
return ;
}
2024-11-03 23:31:56 +01:00
await this . setEffect ( STATUSES . StatusStunned , sonne )
2023-11-04 17:48:50 +01:00
}
2024-11-03 23:31:56 +01:00
isSonne ( ) {
return this . getEffect ( STATUSES . StatusStunned )
2023-11-04 17:48:50 +01:00
}
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 }
}