2022-07-19 23:16:03 +02:00
/* -------------------------------------------- */
import { CrucibleUtility } from "./crucible-utility.js" ;
import { CrucibleRollDialog } from "./crucible-roll-dialog.js" ;
/* -------------------------------------------- */
const coverBonusTable = { "nocover" : 0 , "lightcover" : 2 , "heavycover" : 4 , "entrenchedcover" : 6 } ;
const statThreatLevel = [ "agi" , "str" , "phy" , "com" , "def" , "per" ]
const _ _subkey2title = {
"melee-dmg" : "Melee Damage" , "melee-atk" : "Melee Attack" , "ranged-atk" : "Ranged Attack" ,
"ranged-dmg" : "Ranged Damage" , "dmg-res" : "Damare Resistance"
}
/* -------------------------------------------- */
/* -------------------------------------------- */
/ * *
* Extend the base Actor entity by defining a custom roll data structure which is ideal for the Simple system .
* @ extends { Actor }
* /
export class CrucibleActor extends Actor {
/* -------------------------------------------- */
/ * *
* Override the create ( ) function to provide additional SoS 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 .
*
* /
static async create ( data , options ) {
// Case of compendium global import
if ( data instanceof Array ) {
return super . create ( data , options ) ;
}
// If the created actor has items (only applicable to duplicated actors) bypass the new actor creation logic
if ( data . items ) {
let actor = super . create ( data , options ) ;
return actor ;
}
if ( data . type == 'character' ) {
const skills = await CrucibleUtility . loadCompendium ( "fvtt-crucible-rpg.skills" ) ;
2022-07-31 09:16:17 +02:00
data . items = skills . map ( i => i . toObject ( ) )
2022-07-19 23:16:03 +02:00
}
if ( data . type == 'npc' ) {
}
return super . create ( data , options ) ;
}
/* -------------------------------------------- */
prepareBaseData ( ) {
}
/* -------------------------------------------- */
async prepareData ( ) {
super . prepareData ( ) ;
}
2022-08-03 09:34:33 +02:00
/* -------------------------------------------- */
2022-08-04 10:25:40 +02:00
computeHitPoints ( ) {
2022-09-12 23:06:13 +02:00
if ( this . type == "character" ) {
let hp = duplicate ( this . system . secondary . hp )
let max = ( this . system . abilities . str . value + this . system . abilities . con . value ) * 6
if ( max != hp . max || hp . value > max ) {
hp . max = max
hp . value = max // Init case
this . update ( { 'system.secondary.hp' : hp } )
}
2022-08-03 09:34:33 +02:00
}
}
/* -------------------------------------------- */
2022-08-04 10:25:40 +02:00
computeEffortPoints ( ) {
2022-09-12 23:06:13 +02:00
if ( this . type == "character" ) {
let effort = duplicate ( this . system . secondary . effort )
let max = ( this . system . abilities . con . value + this . system . abilities . int . value ) * 6
if ( max != effort . max || effort . value > max ) {
effort . max = max
effort . value = max // Init case
this . update ( { 'system.secondary.effort' : effort } )
}
2022-08-03 09:34:33 +02:00
}
}
2022-07-19 23:16:03 +02:00
/* -------------------------------------------- */
prepareDerivedData ( ) {
2022-08-03 09:34:33 +02:00
if ( this . type == 'character' || game . user . isGM ) {
2022-08-16 22:29:27 +02:00
this . system . encCapacity = this . getEncumbranceCapacity ( )
2022-07-19 23:16:03 +02:00
this . buildContainerTree ( )
2022-08-03 09:34:33 +02:00
this . computeHitPoints ( )
this . computeEffortPoints ( )
2022-07-19 23:16:03 +02:00
}
super . prepareDerivedData ( ) ;
}
/* -------------------------------------------- */
_preUpdate ( changed , options , user ) {
super . _preUpdate ( changed , options , user ) ;
}
/* -------------------------------------------- */
getEncumbranceCapacity ( ) {
2022-07-25 19:13:52 +02:00
return 1 ;
2022-07-19 23:16:03 +02:00
}
/* -------------------------------------------- */
getMoneys ( ) {
2022-08-16 22:29:27 +02:00
let comp = this . items . filter ( item => item . type == 'money' ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-19 23:16:03 +02:00
return comp ;
}
/* -------------------------------------------- */
2022-07-30 22:54:08 +02:00
getFeats ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'feat' ) || [ ] ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-30 22:54:08 +02:00
return comp ;
}
/* -------------------------------------------- */
getFeatsWithDie ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'feat' && item . system . isfeatdie ) || [ ] ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-30 22:54:08 +02:00
return comp ;
}
getFeatsWithSL ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'feat' && item . system . issl ) || [ ] ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-30 22:54:08 +02:00
return comp ;
}
/* -------------------------------------------- */
getLore ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'spell' ) || [ ] ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-30 22:54:08 +02:00
return comp ;
}
getEquippedWeapons ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'weapon' && item . system . equipped ) || [ ] ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-30 22:54:08 +02:00
return comp ;
}
/* -------------------------------------------- */
2022-07-19 23:16:03 +02:00
getArmors ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'armor' ) || [ ] ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-19 23:16:03 +02:00
return comp ;
}
2022-08-04 10:25:40 +02:00
getEquippedArmor ( ) {
2022-08-16 22:29:27 +02:00
let comp = this . items . find ( item => item . type == 'armor' && item . system . equipped )
2022-08-04 10:25:40 +02:00
if ( comp ) {
return duplicate ( comp )
}
return undefined
}
2022-07-30 22:54:08 +02:00
/* -------------------------------------------- */
getShields ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'shield' ) || [ ] ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-30 22:54:08 +02:00
return comp ;
}
2022-08-04 10:25:40 +02:00
getEquippedShield ( ) {
2022-08-16 22:29:27 +02:00
let comp = this . items . find ( item => item . type == 'shield' && item . system . equipped )
2022-08-04 10:25:40 +02:00
if ( comp ) {
return duplicate ( comp )
}
return undefined
}
/* -------------------------------------------- */
2022-07-19 23:16:03 +02:00
getRace ( ) {
2022-08-16 22:29:27 +02:00
let race = this . items . filter ( item => item . type == 'race' )
2022-07-19 23:16:03 +02:00
return race [ 0 ] ? ? [ ] ;
}
/* -------------------------------------------- */
checkAndPrepareEquipment ( item ) {
}
/* -------------------------------------------- */
checkAndPrepareEquipments ( listItem ) {
for ( let item of listItem ) {
this . checkAndPrepareEquipment ( item )
}
return listItem
}
2022-08-16 23:01:30 +02:00
/* -------------------------------------------- */
getConditions ( ) {
let comp = duplicate ( this . items . filter ( item => item . type == 'condition' ) || [ ] ) ;
CrucibleUtility . sortArrayObjectsByName ( comp )
return comp ;
}
2022-07-19 23:16:03 +02:00
/* -------------------------------------------- */
getWeapons ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'weapon' ) || [ ] ) ;
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
2022-07-19 23:16:03 +02:00
return comp ;
}
/* -------------------------------------------- */
getItemById ( id ) {
2022-08-16 22:29:27 +02:00
let item = this . items . find ( item => item . id == id ) ;
2022-07-19 23:16:03 +02:00
if ( item ) {
item = duplicate ( item )
}
return item ;
}
/* -------------------------------------------- */
getSkills ( ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'skill' ) || [ ] )
2022-08-01 21:39:17 +02:00
for ( let skill of comp ) {
CrucibleUtility . updateSkill ( skill )
}
2022-07-31 19:32:54 +02:00
CrucibleUtility . sortArrayObjectsByName ( comp )
return comp
2022-07-19 23:16:03 +02:00
}
/* -------------------------------------------- */
getRelevantAbility ( statKey ) {
2022-08-16 22:29:27 +02:00
let comp = duplicate ( this . items . filter ( item => item . type == 'skill' && item . system . ability == ability ) || [ ] ) ;
2022-07-19 23:16:03 +02:00
return comp ;
}
/* -------------------------------------------- */
async equipItem ( itemId ) {
2022-08-16 22:29:27 +02:00
let item = this . items . find ( item => item . id == itemId )
if ( item && item . system ) {
2022-08-04 10:25:40 +02:00
if ( item . type == "armor" ) {
2022-08-16 22:29:27 +02:00
let armor = this . items . find ( item => item . id != itemId && item . type == "armor" && item . system . equipped )
2022-08-04 10:25:40 +02:00
if ( armor ) {
ui . notifications . warn ( "You already have an armor equipped!" )
return
}
}
if ( item . type == "shield" ) {
2022-08-16 22:29:27 +02:00
let shield = this . items . find ( item => item . id != itemId && item . type == "shield" && item . system . equipped )
2022-08-04 10:25:40 +02:00
if ( shield ) {
ui . notifications . warn ( "You already have a shield equipped!" )
return
}
}
2022-08-16 22:29:27 +02:00
let update = { _id : item . id , "system.equipped" : ! item . system . equipped } ;
2022-07-19 23:16:03 +02:00
await this . updateEmbeddedDocuments ( 'Item' , [ update ] ) ; // Updates one EmbeddedEntity
}
}
/* -------------------------------------------- */
compareName ( a , b ) {
if ( a . name < b . name ) {
return - 1 ;
}
if ( a . name > b . name ) {
return 1 ;
}
return 0 ;
}
/* ------------------------------------------- */
getEquipments ( ) {
2022-08-16 22:29:27 +02:00
return this . items . filter ( item => item . type == 'shield' || item . type == 'armor' || item . type == "weapon" || item . type == "equipment" ) ;
2022-07-19 23:16:03 +02:00
}
/* ------------------------------------------- */
getEquipmentsOnly ( ) {
2022-08-16 22:29:27 +02:00
return duplicate ( this . items . filter ( item => item . type == "equipment" ) || [ ] )
2022-07-19 23:16:03 +02:00
}
2022-07-26 10:03:23 +02:00
/* ------------------------------------------- */
2022-07-30 22:54:08 +02:00
getSaveRoll ( ) {
2022-07-26 10:03:23 +02:00
return {
reflex : {
2022-08-04 10:25:40 +02:00
"label" : "Reflex Save" ,
"img" : "systems/fvtt-crucible-rpg/images/icons/saves/reflex_save.webp" ,
2022-08-16 22:29:27 +02:00
"value" : this . system . abilities . agi . value + this . system . abilities . wit . value
2022-07-26 10:03:23 +02:00
} ,
fortitude : {
2022-08-04 10:25:40 +02:00
"label" : "Fortitude Save" ,
"img" : "systems/fvtt-crucible-rpg/images/icons/saves/fortitude_save.webp" ,
2022-08-16 22:29:27 +02:00
"value" : this . system . abilities . str . value + this . system . abilities . con . value
2022-07-26 10:03:23 +02:00
} ,
willpower : {
2022-08-04 10:25:40 +02:00
"label" : "Willpower Save" ,
"img" : "systems/fvtt-crucible-rpg/images/icons/saves/will_save.webp" ,
2022-08-16 22:29:27 +02:00
"value" : this . system . abilities . int . value + this . system . abilities . cha . value
2022-07-26 10:03:23 +02:00
}
2022-07-30 22:54:08 +02:00
}
2022-07-26 10:03:23 +02:00
}
2022-07-19 23:16:03 +02:00
/* ------------------------------------------- */
async buildContainerTree ( ) {
2022-08-16 22:29:27 +02:00
let equipments = duplicate ( this . items . filter ( item => item . type == "equipment" ) || [ ] )
2022-07-19 23:16:03 +02:00
for ( let equip1 of equipments ) {
2022-08-16 22:29:27 +02:00
if ( equip1 . system . iscontainer ) {
equip1 . system . contents = [ ]
equip1 . system . contentsEnc = 0
2022-07-19 23:16:03 +02:00
for ( let equip2 of equipments ) {
2022-08-16 22:29:27 +02:00
if ( equip1 . _id != equip2 . id && equip2 . system . containerid == equip1 . id ) {
equip1 . system . contents . push ( equip2 )
let q = equip2 . system . quantity ? ? 1
equip1 . system . contentsEnc += q * equip2 . system . weight
2022-07-19 23:16:03 +02:00
}
}
}
}
// Compute whole enc
let enc = 0
for ( let item of equipments ) {
2022-08-05 10:04:42 +02:00
//item.data.idrDice = CrucibleUtility.getDiceFromLevel(Number(item.data.idr))
2022-08-16 22:29:27 +02:00
if ( item . system . equipped ) {
if ( item . system . iscontainer ) {
enc += item . system . contentsEnc
} else if ( item . system . containerid == "" ) {
let q = item . system . quantity ? ? 1
enc += q * item . system . weight
2022-07-19 23:16:03 +02:00
}
}
}
2022-08-16 22:29:27 +02:00
for ( let item of this . items ) { // Process items/shields/armors
if ( ( item . type == "weapon" || item . type == "shield" || item . type == "armor" ) && item . system . equipped ) {
let q = item . system . quantity ? ? 1
enc += q * item . system . weight
2022-07-19 23:16:03 +02:00
}
}
// Store local values
this . encCurrent = enc
2022-08-16 22:29:27 +02:00
this . containersTree = equipments . filter ( item => item . system . containerid == "" ) // Returns the root of equipements without container
2022-07-19 23:16:03 +02:00
}
2022-08-14 10:10:26 +02:00
/* -------------------------------------------- */
2022-09-12 23:06:13 +02:00
async rollArmor ( rollData ) {
2022-08-14 10:10:26 +02:00
let armor = this . getEquippedArmor ( )
if ( armor ) {
}
2022-09-12 23:06:13 +02:00
return { armor : "none" }
2022-08-14 10:10:26 +02:00
}
/* -------------------------------------------- */
2022-09-12 23:06:13 +02:00
async incDecHP ( formula ) {
let dmgRoll = new Roll ( formula ) . roll ( { async : false } )
2022-08-14 10:10:26 +02:00
await CrucibleUtility . showDiceSoNice ( dmgRoll , game . settings . get ( "core" , "rollMode" ) )
2022-08-16 22:29:27 +02:00
let hp = duplicate ( this . system . secondary . hp )
2022-08-14 10:10:26 +02:00
hp . value = Number ( hp . value ) + Number ( dmgRoll . total )
2022-09-12 23:06:13 +02:00
this . update ( { 'system.secondary.hp' : hp } )
2022-08-14 10:10:26 +02:00
return Number ( dmgRoll . total )
}
2022-07-19 23:16:03 +02:00
/* -------------------------------------------- */
getAbility ( abilKey ) {
2022-08-16 22:29:27 +02:00
return this . system . abilities [ abilKey ] ;
2022-07-19 23:16:03 +02:00
}
/* -------------------------------------------- */
async addObjectToContainer ( itemId , containerId ) {
2022-08-16 22:29:27 +02:00
let container = this . items . find ( item => item . id == containerId && item . system . iscontainer )
let object = this . items . find ( item => item . id == itemId )
2022-07-19 23:16:03 +02:00
if ( container ) {
2022-08-16 22:29:27 +02:00
if ( object . system . iscontainer ) {
2022-07-19 23:16:03 +02:00
ui . notifications . warn ( "Only 1 level of container allowed" )
return
}
2022-08-16 22:29:27 +02:00
let alreadyInside = this . items . filter ( item => item . system . containerid && item . system . containerid == containerId ) ;
if ( alreadyInside . length >= container . system . containercapacity ) {
2022-07-19 23:16:03 +02:00
ui . notifications . warn ( "Container is already full !" )
return
} else {
2022-08-16 22:29:27 +02:00
await this . updateEmbeddedDocuments ( "Item" , [ { _id : object . id , 'system.containerid' : containerId } ] )
2022-07-19 23:16:03 +02:00
}
2022-08-16 22:29:27 +02:00
} else if ( object && object . system . containerid ) { // remove from container
2022-07-19 23:16:03 +02:00
console . log ( "Removeing: " , object )
2022-08-16 22:29:27 +02:00
await this . updateEmbeddedDocuments ( "Item" , [ { _id : object . id , 'system.containerid' : "" } ] ) ;
2022-07-19 23:16:03 +02:00
}
}
/* -------------------------------------------- */
async preprocessItem ( event , item , onDrop = false ) {
let dropID = $ ( event . target ) . parents ( ".item" ) . attr ( "data-item-id" ) // Only relevant if container drop
let objectID = item . id || item . _id
this . addObjectToContainer ( objectID , dropID )
return true
}
/* -------------------------------------------- */
async equipGear ( equipmentId ) {
2022-08-16 22:29:27 +02:00
let item = this . items . find ( item => item . id == equipmentId ) ;
if ( item && item . system ) {
let update = { _id : item . id , "system.equipped" : ! item . system . equipped } ;
2022-07-19 23:16:03 +02:00
await this . updateEmbeddedDocuments ( 'Item' , [ update ] ) ; // Updates one EmbeddedEntity
}
}
/* -------------------------------------------- */
getInitiativeScore ( combatId , combatantId ) {
if ( this . type == 'character' ) {
this . rollMR ( true , combatId , combatantId )
}
console . log ( "Init required !!!!" )
return - 1 ;
}
/* -------------------------------------------- */
getSubActors ( ) {
let subActors = [ ] ;
2022-08-16 22:29:27 +02:00
for ( let id of this . system . subactors ) {
2022-07-19 23:16:03 +02:00
subActors . push ( duplicate ( game . actors . get ( id ) ) )
}
return subActors ;
}
/* -------------------------------------------- */
async addSubActor ( subActorId ) {
2022-08-16 22:29:27 +02:00
let subActors = duplicate ( this . system . subactors ) ;
2022-07-19 23:16:03 +02:00
subActors . push ( subActorId ) ;
2022-08-16 22:29:27 +02:00
await this . update ( { 'system.subactors' : subActors } ) ;
2022-07-19 23:16:03 +02:00
}
/* -------------------------------------------- */
async delSubActor ( subActorId ) {
let newArray = [ ] ;
2022-08-16 22:29:27 +02:00
for ( let id of this . system . subactors ) {
2022-07-19 23:16:03 +02:00
if ( id != subActorId ) {
newArray . push ( id ) ;
}
}
2022-08-16 22:29:27 +02:00
await this . update ( { 'system.subactors' : newArray } ) ;
2022-07-19 23:16:03 +02:00
}
/* -------------------------------------------- */
syncRoll ( rollData ) {
this . lastRollId = rollData . rollId ;
CrucibleUtility . saveRollData ( rollData ) ;
}
/* -------------------------------------------- */
getOneSkill ( skillId ) {
2022-08-16 22:29:27 +02:00
let skill = this . items . find ( item => item . type == 'skill' && item . id == skillId )
2022-07-19 23:16:03 +02:00
if ( skill ) {
skill = duplicate ( skill ) ;
}
return skill ;
}
/* -------------------------------------------- */
async deleteAllItemsByType ( itemType ) {
2022-08-16 22:29:27 +02:00
let items = this . items . filter ( item => item . type == itemType ) ;
2022-07-19 23:16:03 +02:00
await this . deleteEmbeddedDocuments ( 'Item' , items ) ;
}
/* -------------------------------------------- */
async addItemWithoutDuplicate ( newItem ) {
2022-08-16 22:29:27 +02:00
let item = this . items . find ( item => item . type == newItem . type && item . name . toLowerCase ( ) == newItem . name . toLowerCase ( ) )
2022-07-19 23:16:03 +02:00
if ( ! item ) {
await this . createEmbeddedDocuments ( 'Item' , [ newItem ] ) ;
}
}
2022-07-30 23:29:55 +02:00
/* -------------------------------------------- */
async incrementSkillExp ( skillId , inc ) {
2022-08-16 22:29:27 +02:00
let skill = this . items . get ( skillId )
2022-07-30 23:29:55 +02:00
if ( skill ) {
2022-08-16 22:29:27 +02:00
await this . updateEmbeddedDocuments ( 'Item' , [ { _id : skill . id , 'system.exp' : skill . system . exp + inc } ] )
2022-07-30 23:29:55 +02:00
let chatData = {
user : game . user . id ,
rollMode : game . settings . get ( "core" , "rollMode" ) ,
whisper : [ game . user . id ] . concat ( ChatMessage . getWhisperRecipients ( 'GM' ) ) ,
2022-08-16 22:29:27 +02:00
content : ` <div> ${ this . name } has gained 1 exp in the skill ${ skill . name } (exp = ${ skill . system . exp } )</div `
2022-07-30 23:29:55 +02:00
}
ChatMessage . create ( chatData )
2022-08-16 22:29:27 +02:00
if ( skill . system . exp >= 25 ) {
await this . updateEmbeddedDocuments ( 'Item' , [ { _id : skill . id , 'system.exp' : 0 , 'system.explevel' : skill . system . explevel + 1 } ] )
2022-07-30 23:29:55 +02:00
let chatData = {
user : game . user . id ,
rollMode : game . settings . get ( "core" , "rollMode" ) ,
whisper : [ game . user . id ] . concat ( ChatMessage . getWhisperRecipients ( 'GM' ) ) ,
2022-08-16 22:29:27 +02:00
content : ` <div> ${ this . name } has gained 1 exp SL in the skill ${ skill . name } (new exp SL : ${ skill . system . explevel } ) !</div `
2022-07-30 23:29:55 +02:00
}
ChatMessage . create ( chatData )
}
}
}
2022-07-19 23:16:03 +02:00
/* -------------------------------------------- */
async incDecQuantity ( objetId , incDec = 0 ) {
2022-08-16 22:29:27 +02:00
let objetQ = this . items . get ( objetId )
2022-07-19 23:16:03 +02:00
if ( objetQ ) {
2022-08-16 22:29:27 +02:00
let newQ = objetQ . system . quantity + incDec
2022-07-19 23:16:03 +02:00
if ( newQ >= 0 ) {
2022-08-16 22:29:27 +02:00
const updated = await this . updateEmbeddedDocuments ( 'Item' , [ { _id : objetQ . id , 'system.quantity' : newQ } ] ) // pdates one EmbeddedEntity
2022-07-19 23:16:03 +02:00
}
}
}
/* -------------------------------------------- */
async incDecAmmo ( objetId , incDec = 0 ) {
2022-08-16 22:29:27 +02:00
let objetQ = this . items . get ( objetId )
2022-07-19 23:16:03 +02:00
if ( objetQ ) {
2022-08-16 22:29:27 +02:00
let newQ = objetQ . system . ammocurrent + incDec ;
if ( newQ >= 0 && newQ <= objetQ . system . ammomax ) {
const updated = await this . updateEmbeddedDocuments ( 'Item' , [ { _id : objetQ . id , 'system.ammocurrent' : newQ } ] ) ; // pdates one EmbeddedEntity
2022-07-19 23:16:03 +02:00
}
}
}
2022-08-17 17:07:45 +02:00
/* -------------------------------------------- */
isForcedAdvantage ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . advantage )
2022-08-17 17:07:45 +02:00
}
isForcedDisadvantage ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . disadvantage )
2022-08-17 17:07:45 +02:00
}
isForcedRollAdvantage ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . rolladvantage )
2022-08-17 17:07:45 +02:00
}
isForcedRollDisadvantage ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . rolldisadvantage )
2022-08-17 17:07:45 +02:00
}
isNoAdvantage ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . noadvantage )
2022-08-17 17:07:45 +02:00
}
isNoAction ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . noaction )
2022-08-17 17:07:45 +02:00
}
isAttackDisadvantage ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . attackdisadvantage )
2022-08-17 17:07:45 +02:00
}
isDefenseDisadvantage ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . defensedisadvantage )
2022-08-17 17:07:45 +02:00
}
isAttackerAdvantage ( ) {
2022-09-12 23:06:13 +02:00
return this . items . find ( cond => cond . type == "condition" && cond . system . targetadvantage )
2022-08-17 17:07:45 +02:00
}
2022-07-19 23:16:03 +02:00
/* -------------------------------------------- */
2022-07-25 21:33:00 +02:00
getCommonRollData ( abilityKey = undefined ) {
2022-08-17 17:07:45 +02:00
let noAction = this . isNoAction ( )
2022-09-12 23:06:13 +02:00
if ( noAction ) {
ui . notifications . warn ( "You can't do any actions du to the condition : " + noAction . name )
2022-08-17 17:07:45 +02:00
return
}
2022-07-19 23:16:03 +02:00
let rollData = CrucibleUtility . getBasicRollData ( )
rollData . alias = this . name
rollData . actorImg = this . img
rollData . actorId = this . id
rollData . img = this . img
2022-07-30 22:54:08 +02:00
rollData . featsDie = this . getFeatsWithDie ( )
rollData . featsSL = this . getFeatsWithSL ( )
2022-08-01 21:39:17 +02:00
rollData . armors = this . getArmors ( )
2022-08-17 17:07:45 +02:00
rollData . conditions = this . getConditions ( )
2022-07-30 22:54:08 +02:00
rollData . featDieName = "none"
2022-07-30 23:29:55 +02:00
rollData . featSLName = "none"
2022-07-31 19:32:54 +02:00
rollData . rollAdvantage = "none"
rollData . advantage = "none"
2022-08-01 21:39:17 +02:00
rollData . disadvantage = "none"
2022-08-17 17:07:45 +02:00
rollData . forceAdvantage = this . isForcedAdvantage ( )
rollData . forceDisadvantage = this . isForcedDisadvantage ( )
rollData . forceRollAdvantage = this . isForcedRollAdvantage ( )
rollData . forceRollDisadvantage = this . isForcedRollDisadvantage ( )
rollData . noAdvantage = this . isNoAdvantage ( )
2022-09-12 23:06:13 +02:00
if ( rollData . defenderTokenId ) {
2022-08-17 22:51:52 +02:00
let defenderToken = game . canvas . tokens . get ( rollData . defenderTokenId )
2022-09-12 23:06:13 +02:00
let defender = defenderToken . actor
2022-08-17 22:51:52 +02:00
// Distance management
2022-08-23 08:21:20 +02:00
let token = this . token
2022-09-12 23:06:13 +02:00
if ( ! token ) {
let tokens = this . getActiveTokens ( )
2022-08-23 08:21:20 +02:00
token = tokens [ 0 ]
}
2022-09-12 23:06:13 +02:00
if ( token ) {
2022-08-23 08:21:20 +02:00
const ray = new Ray ( token . object ? . center || token . center , defenderToken . center )
2022-09-12 23:06:13 +02:00
rollData . tokensDistance = canvas . grid . measureDistances ( [ { ray } ] , { gridSpaces : false } ) [ 0 ] / canvas . grid . grid . options . dimensions . distance
2022-08-17 22:51:52 +02:00
} else {
ui . notifications . info ( "No token connected to this actor, unable to compute distance." )
2022-08-23 08:21:20 +02:00
return
2022-08-17 22:51:52 +02:00
}
2022-09-12 23:06:13 +02:00
if ( defender ) {
2022-08-17 17:07:45 +02:00
rollData . forceAdvantage = defender . isAttackerAdvantage ( )
rollData . advantageFromTarget = true
}
}
2022-07-30 23:29:55 +02:00
2022-07-25 21:33:00 +02:00
if ( abilityKey ) {
rollData . ability = this . getAbility ( abilityKey )
rollData . selectedKill = undefined
2022-07-19 23:16:03 +02:00
}
console . log ( "ROLLDATA" , rollData )
return rollData
}
2022-07-25 21:33:00 +02:00
/* -------------------------------------------- */
rollAbility ( abilityKey ) {
let rollData = this . getCommonRollData ( abilityKey )
rollData . mode = "ability"
2022-08-16 22:29:27 +02:00
if ( rollData . target ) {
ui . notifications . warn ( "You are targetting a token with a skill : please use a Weapon instead." )
return
}
2022-07-25 21:33:00 +02:00
CrucibleUtility . rollCrucible ( rollData )
}
/* -------------------------------------------- */
rollSkill ( skillId ) {
2022-08-16 22:29:27 +02:00
let skill = this . items . get ( skillId )
2022-07-25 21:33:00 +02:00
if ( skill ) {
2022-08-16 22:29:27 +02:00
if ( skill . system . islore && skill . system . level == 0 ) {
2022-07-31 19:48:23 +02:00
ui . notifications . warn ( "You can't use Lore Skills with a SL of 0." )
return
}
2022-07-25 21:33:00 +02:00
skill = duplicate ( skill )
2022-08-01 21:39:17 +02:00
CrucibleUtility . updateSkill ( skill )
2022-08-16 22:29:27 +02:00
let abilityKey = skill . system . ability
2022-07-25 21:33:00 +02:00
let rollData = this . getCommonRollData ( abilityKey )
rollData . mode = "skill"
rollData . skill = skill
2022-07-31 19:32:54 +02:00
rollData . img = skill . img
2022-08-16 22:29:27 +02:00
if ( rollData . target ) {
ui . notifications . warn ( "You are targetting a token with a skill : please use a Weapon instead." )
return
}
2022-07-26 21:40:42 +02:00
this . startRoll ( rollData )
2022-07-25 21:33:00 +02:00
}
}
2022-07-19 23:16:03 +02:00
2022-08-01 21:39:17 +02:00
/* -------------------------------------------- */
rollWeapon ( weaponId ) {
2022-08-16 22:29:27 +02:00
let weapon = this . items . get ( weaponId )
2022-08-01 21:39:17 +02:00
if ( weapon ) {
weapon = duplicate ( weapon )
2022-08-16 22:29:27 +02:00
let skill = this . items . find ( item => item . name . toLowerCase ( ) == weapon . system . skill . toLowerCase ( ) )
2022-08-01 21:39:17 +02:00
if ( skill ) {
skill = duplicate ( skill )
CrucibleUtility . updateSkill ( skill )
2022-08-16 22:29:27 +02:00
let abilityKey = skill . system . ability
2022-08-01 21:39:17 +02:00
let rollData = this . getCommonRollData ( abilityKey )
rollData . mode = "weapon"
rollData . skill = skill
rollData . weapon = weapon
rollData . img = weapon . img
2022-09-12 23:06:13 +02:00
if ( ! rollData . forceDisadvantage ) { // This is an attack, check if disadvantaged
2022-08-17 17:07:45 +02:00
rollData . forceDisadvantage = this . isAttackDisadvantage ( )
}
2022-08-26 13:23:06 +02:00
/ * i f ( r o l l D a t a . w e a p o n . s y s t e m . i s r a n g e d & & r o l l D a t a . t o k e n s D i s t a n c e > C r u c i b l e U t i l i t y . g e t W e a p o n M a x R a n g e ( r o l l D a t a . w e a p o n ) ) {
2022-08-17 22:51:52 +02:00
ui . notifications . warn ( ` Your target is out of range of your weapon (max: ${ CrucibleUtility . getWeaponMaxRange ( rollData . weapon ) } - current : ${ rollData . tokensDistance } ) ` )
return
2022-08-26 13:23:06 +02:00
} * /
2022-08-01 21:39:17 +02:00
this . startRoll ( rollData )
} else {
ui . notifications . warn ( "Unable to find the relevant skill for weapon " + weapon . name )
}
}
}
2022-08-04 16:28:10 +02:00
2022-08-06 17:06:05 +02:00
/* -------------------------------------------- */
rollDefenseMelee ( attackRollData ) {
2022-08-16 22:29:27 +02:00
let weapon = this . items . get ( attackRollData . defenseWeaponId )
2022-08-06 17:06:05 +02:00
if ( weapon ) {
weapon = duplicate ( weapon )
2022-08-16 22:29:27 +02:00
let skill = this . items . find ( item => item . name . toLowerCase ( ) == weapon . system . skill . toLowerCase ( ) )
2022-08-06 17:06:05 +02:00
if ( skill ) {
skill = duplicate ( skill )
CrucibleUtility . updateSkill ( skill )
2022-08-16 22:29:27 +02:00
let abilityKey = skill . system . ability
2022-08-06 17:06:05 +02:00
let rollData = this . getCommonRollData ( abilityKey )
rollData . defenderTokenId = undefined // Cleanup
rollData . mode = "weapondefense"
rollData . shield = this . getEquippedShield ( )
rollData . attackRollData = duplicate ( attackRollData )
rollData . skill = skill
rollData . weapon = weapon
rollData . img = weapon . img
2022-09-12 23:06:13 +02:00
if ( ! rollData . forceDisadvantage ) { // This is an attack, check if disadvantaged
2022-08-17 17:07:45 +02:00
rollData . forceDisadvantage = this . isDefenseDisadvantage ( )
}
2022-08-06 17:06:05 +02:00
this . startRoll ( rollData )
} else {
ui . notifications . warn ( "Unable to find the relevant skill for weapon " + weapon . name )
}
} else {
ui . notifications . warn ( "Weapon not found ! " )
}
}
2022-08-17 22:51:52 +02:00
/* -------------------------------------------- */
rollDefenseRanged ( attackRollData ) {
let rollData = this . getCommonRollData ( )
rollData . defenderTokenId = undefined // Cleanup
rollData . mode = "rangeddefense"
2022-09-12 23:06:13 +02:00
if ( attackRollData ) {
rollData . attackRollData = duplicate ( attackRollData )
rollData . effectiveRange = CrucibleUtility . getWeaponRange ( attackRollData . weapon )
rollData . tokensDistance = attackRollData . tokensDistance // QoL copy
}
rollData . sizeDice = CrucibleUtility . getSizeDice ( this . system . biodata . size )
2022-08-26 13:23:06 +02:00
rollData . distanceBonusDice = 0 //Math.max(0, Math.floor((rollData.tokensDistance - rollData.effectiveRange) + 0.5))
2022-08-17 22:51:52 +02:00
rollData . hasCover = "none"
2022-09-12 23:06:13 +02:00
rollData . situational = "none"
rollData . useshield = false
2022-08-17 22:51:52 +02:00
rollData . shield = this . getEquippedShield ( )
this . startRoll ( rollData )
}
2022-08-04 16:28:10 +02:00
/* -------------------------------------------- */
rollShieldDie ( ) {
let shield = this . getEquippedShield ( )
if ( shield ) {
shield = duplicate ( shield )
let rollData = this . getCommonRollData ( )
rollData . mode = "shield"
rollData . shield = shield
2022-08-14 10:10:26 +02:00
rollData . useshield = true
2022-08-04 16:28:10 +02:00
rollData . img = shield . img
this . startRoll ( rollData )
}
}
/* -------------------------------------------- */
2022-08-14 10:10:26 +02:00
async rollArmorDie ( rollData = undefined ) {
2022-08-04 16:28:10 +02:00
let armor = this . getEquippedArmor ( )
if ( armor ) {
armor = duplicate ( armor )
2022-08-14 10:10:26 +02:00
let reduce = 0
let multiply = 1
let disadvantage = false
let advantage = false
2022-09-12 23:06:13 +02:00
let messages = [ "Armor applied" ]
2022-08-14 10:10:26 +02:00
if ( rollData ) {
2022-09-12 23:06:13 +02:00
if ( CrucibleUtility . isArmorLight ( armor ) && CrucibleUtility . isWeaponPenetrating ( rollData . attackRollData . weapon ) ) {
2022-08-14 10:10:26 +02:00
return { armorIgnored : true , nbSuccess : 0 , messages : [ "Armor ignored : Penetrating weapons ignore Light Armors." ] }
}
2022-09-12 23:06:13 +02:00
if ( CrucibleUtility . isWeaponPenetrating ( rollData . attackRollData . weapon ) ) {
2022-08-14 10:10:26 +02:00
messages . push ( "Armor reduced by 1 (Penetrating weapon)" )
reduce = 1
}
2022-09-12 23:06:13 +02:00
if ( CrucibleUtility . isWeaponLight ( rollData . attackRollData . weapon ) ) {
2022-08-14 10:10:26 +02:00
messages . push ( "Armor with advantage (Light weapon)" )
advantage = true
}
2022-09-12 23:06:13 +02:00
if ( CrucibleUtility . isWeaponHeavy ( rollData . attackRollData . weapon ) ) {
2022-08-14 10:10:26 +02:00
messages . push ( "Armor with disadvantage (Heavy weapon)" )
disadvantage = true
}
2022-09-12 23:06:13 +02:00
if ( CrucibleUtility . isWeaponHack ( rollData . attackRollData . weapon ) ) {
2022-08-14 10:10:26 +02:00
messages . push ( "Armor reduced by 1 (Hack weapon)" )
reduce = 1
}
2022-09-12 23:06:13 +02:00
if ( CrucibleUtility . isWeaponUndamaging ( rollData . attackRollData . weapon ) ) {
2022-08-14 10:10:26 +02:00
messages . push ( "Armor multiplied by 2 (Undamaging weapon)" )
multiply = 2
}
}
2022-08-16 22:29:27 +02:00
let diceColor = armor . system . absorprionroll
2022-09-12 23:06:13 +02:00
let armorResult = await CrucibleUtility . getRollTableFromDiceColor ( diceColor , false )
2022-08-16 22:29:27 +02:00
console . log ( "Armor log" , armorResult )
2022-09-12 23:06:13 +02:00
let armorValue = Math . max ( 0 , ( Number ( armorResult . text ) + reduce ) * multiply )
if ( advantage || disadvantage ) {
let armorResult2 = await CrucibleUtility . getRollTableFromDiceColor ( diceColor , false )
let armorValue2 = Math . max ( 0 , ( Number ( armorResult2 . text ) + reduce ) * multiply )
if ( advantage ) {
2022-08-14 10:10:26 +02:00
armorValue = ( armorValue2 > armorValue ) ? armorValue2 : armorValue
messages . push ( ` Armor advantage - Roll 1 = ${ armorValue } - Roll 2 = ${ armorValue2 } ` )
}
2022-09-12 23:06:13 +02:00
if ( disadvantage ) {
2022-08-14 10:10:26 +02:00
armorValue = ( armorValue2 < armorValue ) ? armorValue2 : armorValue
messages . push ( ` Armor disadvantage - Roll 1 = ${ armorValue } - Roll 2 = ${ armorValue2 } ` )
}
}
armorResult . armorValue = armorValue
2022-09-12 23:06:13 +02:00
if ( ! rollData ) {
ChatMessage . create ( { content : "Armor result : " + armorValue } )
2022-08-14 10:10:26 +02:00
}
2022-09-12 23:06:13 +02:00
messages . push ( "Armor result : " + armorValue )
2022-08-26 13:23:06 +02:00
return { armorIgnored : false , nbSuccess : armorValue , rawArmor : armorResult . text , messages : messages }
2022-08-04 16:28:10 +02:00
}
2022-08-14 10:10:26 +02:00
return { armorIgnored : true , nbSuccess : 0 , messages : [ "No armor equipped." ] }
2022-08-04 16:28:10 +02:00
}
2022-08-03 09:34:33 +02:00
/* -------------------------------------------- */
2022-08-04 10:25:40 +02:00
rollSave ( saveKey ) {
2022-08-03 09:34:33 +02:00
let saves = this . getSaveRoll ( )
let save = saves [ saveKey ]
if ( save ) {
save = duplicate ( save )
let rollData = this . getCommonRollData ( )
rollData . mode = "save"
rollData . save = save
2022-08-16 22:29:27 +02:00
if ( rollData . target ) {
ui . notifications . warn ( "You are targetting a token with a save roll - Not authorized." )
return
}
2022-08-03 09:34:33 +02:00
this . startRoll ( rollData )
}
2022-08-01 21:39:17 +02:00
2022-08-03 09:34:33 +02:00
}
2022-07-19 23:16:03 +02:00
/* -------------------------------------------- */
async startRoll ( rollData ) {
2022-07-26 21:40:42 +02:00
this . syncRoll ( rollData )
2022-07-19 23:16:03 +02:00
let rollDialog = await CrucibleRollDialog . create ( this , rollData )
2022-07-26 21:40:42 +02:00
rollDialog . render ( true )
2022-07-19 23:16:03 +02:00
}
}