2021-03-04 00:14:16 +01:00
import { DS4Actor } from "../actor/actor" ;
import { DS4 } from "../config" ;
import { createCheckRoll } from "../rolls/check-factory" ;
import { AttackType , DS4ItemData } from "./item-data" ;
2020-12-23 18:23:26 +01:00
2020-12-23 16:52:20 +01:00
/ * *
2021-02-07 11:51:36 +01:00
* The Item class for DS4
2020-12-23 16:52:20 +01:00
* /
2021-01-26 03:55:18 +01:00
export class DS4Item extends Item < DS4ItemData > {
2020-12-23 16:52:20 +01:00
/ * *
2021-02-07 11:51:36 +01:00
* @override
2020-12-23 16:52:20 +01:00
* /
2020-12-23 18:23:26 +01:00
prepareData ( ) : void {
2020-12-23 16:52:20 +01:00
super . prepareData ( ) ;
2021-01-06 01:24:37 +01:00
this . prepareDerivedData ( ) ;
2020-12-23 16:52:20 +01:00
}
2021-01-06 01:24:37 +01:00
prepareDerivedData ( ) : void {
2021-02-05 03:42:42 +01:00
if ( this . data . type === "talent" ) {
const data = this . data . data ;
2021-01-06 11:52:11 +01:00
data . rank . total = data . rank . base + data . rank . mod ;
2021-01-06 01:24:37 +01:00
}
2021-03-04 00:14:16 +01:00
if ( this . data . type === "weapon" ) {
this . data . data . rollable = true ;
}
2021-01-06 01:24:37 +01:00
}
2021-02-16 03:26:26 +01:00
isNonEquippedEuipable ( ) : boolean {
return "equipped" in this . data . data && ! this . data . data . equipped ;
}
/ * *
* The number of times that active effect changes originating from this item should be applied .
* /
2021-02-18 13:36:36 +01:00
get activeEffectFactor ( ) : number | undefined {
2021-02-16 03:26:26 +01:00
if ( this . data . type === "talent" ) {
2021-02-18 13:36:36 +01:00
return this . data . data . rank . total ;
2021-02-16 03:26:26 +01:00
}
return 1 ;
}
2021-03-04 00:14:16 +01:00
/ * *
* Roll a check for a action with this item .
* /
async roll ( ) : Promise < void > {
if ( ! this . isOwnedItem ( ) ) {
throw new Error ( game . i18n . format ( "DS4.ErrorCannotRollUnownedItem" , { name : this.name , id : this.id } ) ) ;
}
if ( this . data . type === "weapon" ) {
await this . rollWeapon ( ) ;
} else {
throw new Error ( game . i18n . format ( "DS4.ErrorRollingForItemTypeNotPossible" , { type : this . data . type } ) ) ;
}
}
private async rollWeapon ( this : this & { readonly isOwned : true } ) : Promise < void > {
if ( ! ( this . data . type === "weapon" ) ) {
throw new Error (
game . i18n . format ( "DS4.ErrorWrongItemType" , {
actualType : this.data.type ,
expectedType : "weapon" ,
id : this.id ,
name : this.name ,
} ) ,
) ;
}
const owner = ( this . actor as unknown ) as DS4Actor ; // TODO(types): Improve so that the concrete Actor type is known here
const weaponBonus = this . data . data . weaponBonus ;
const combatValue = await this . getCombatValueKeyForAttackType ( this . data . data . attackType ) ;
const checkTargetValue = ( owner . data . data . combatValues [ combatValue ] . total as number ) + weaponBonus ;
await createCheckRoll ( checkTargetValue , { rollMode : game.settings.get ( "core" , "rollMode" ) } ) ; // TODO: Get maxCritSuccess and minCritFailure from Actor once we store them there
}
private async getCombatValueKeyForAttackType ( attackType : AttackType ) : Promise < "meleeAttack" | "rangedAttack" > {
if ( attackType === "meleeRanged" ) {
const { melee , ranged } = { . . . DS4 . i18n . attackTypes } ;
const identifier = "attack-type-selection" ;
const label = game . i18n . localize ( "DS4.AttackType" ) ;
const answer = Dialog . prompt ( {
title : game.i18n.localize ( "DS4.AttackTypeSelection" ) ,
content : await renderTemplate ( "systems/ds4/templates/common/simple-select-form.hbs" , {
label ,
identifier ,
options : { melee , ranged } ,
} ) ,
label : game.i18n.localize ( "DS4.GenericOkButton" ) ,
callback : ( html ) = > {
const selectedAttackType = html . find ( ` # ${ identifier } ` ) . val ( ) ;
if ( selectedAttackType !== "melee" && selectedAttackType !== "ranged" ) {
throw new Error (
game . i18n . format ( "DS4.ErrorUnexpectedAttackType" , {
actualType : selectedAttackType ,
expectedTypes : "'melee', 'ranged'" ,
} ) ,
) ;
}
return ` ${ selectedAttackType } Attack ` as const ;
} ,
render : ( ) = > undefined , // TODO(types): This is actually optional, remove when types are updated )
options : { jQuery : true } ,
} ) ;
return answer ;
} else {
return ` ${ attackType } Attack ` as const ;
}
}
/ * *
* Type - guarding variant to check if the item is owned .
* /
isOwnedItem ( ) : this is this & { readonly isOwned : true } {
return this . isOwned ;
}
2020-12-23 16:52:20 +01:00
}