foundry-dsa41-game/src/module/data/vornachteile.mjs

188 lines
8.4 KiB
JavaScript

import BaseItem from "./base-item.mjs";
const {ArrayField, SchemaField, BooleanField, NumberField, StringField, HTMLField} = foundry.data.fields;
export class VornachteileDataModel extends BaseItem {
static defineSchema() {
return {
name: new StringField({required: true}),
description: new HTMLField(),
nachteil: new BooleanField({required: true, initialValue: false}),
schlechteEigenschaft: new BooleanField({required: true, initialValue: false}),
// Optional Fields
value: new StringField({required: false, nullable: true}),
mod: new ArrayField(new SchemaField({
name: new StringField(),
talent: new StringField({required: false}),
value: new NumberField(),
}), {required: false}),
auswahl: new ArrayField(
new SchemaField({
name: new StringField(),
requirement: new ArrayField(
new SchemaField({
attribute: new StringField(),
minValue: new NumberField(),
maxValue: new NumberField(),
sonderfertigkeit: new StringField(),
talent: new StringField(),
compare: new SchemaField({
ownAttribute: new StringField(),
targetAttribute: new StringField(),
operation: new StringField(),
}, {required: false}),
})
),
mod: new ArrayField(new SchemaField({
name: new StringField(),
talent: new StringField({required: false}),
value: new NumberField(),
}))
}), {required: false}
),
}
/*
name: String, // Name of Vornachteil will be used for rendering and referencing by other Items
description: HTMLString, // only used for rendering
variant: [String]?, // variant name of Vornachteil e.g. "Mut" in the case of "Herausragende Eigenschaft"
levels: [Number]?, // available levels e.g. 1, 2 in the case of "Flink"
mods: [
{
level: Number?, // in reference to level of the Vornachteil, is null when it does not have any levels or is the only modification
field: String, // Reference to Actor Data e.g. "FF" maps to "FF.mod"
value: Number, // value of the Modification e.g. "+2" maps to 2
requirement: {
field: String // Reference to Actor Data e.g. "BE" maps "be.aktuell"
operation: String // Supported: "<=", ">"
value: Number // Target Value the referenced field has to compare against
}? // optional when the mod does not have an active requirement
}
]
*/
}
#getRequirements() {
if (this.value && this.auswahl?.find(p => p.name === this.value)) {
const auswahl = this.auswahl?.find(p => p.name === this.value)
return auswahl.requirement
} else {
return this.requirement
}
}
getActiveMod(options) {
if (this.isActive(options)) {
if (this.value && this.auswahl?.find(p => p.name === this.value)) {
const auswahl = this.auswahl?.find(p => p.name === this.value)
return auswahl.mod
} else {
return this.mod
}
} else {
return []
}
}
isActive(options) {
const requirements = this.#getRequirements()
let passes = true
let mod = 0
if (this.parent?.actor) {
const flatActor = foundry.utils.flattenObject(this.parent.actor.system)
if (requirements) for (let requirement of requirements) {
let targetField = null
if (requirement.attribute) {
targetField = flatActor?.[requirement.attribute.toLocaleLowerCase()]
}
if (requirement.talent) {
targetField = this.parent.actor.itemTypes["Skill"].find(p => p.name.toLocaleLowerCase() === requirement.talent.toLocaleLowerCase())?.taw ?? Number.NaN
}
if (requirement.minValue) {
passes = requirement.minValue <= targetField
if (!passes) console.debug(`fails requirement ${requirement.attribute ?? requirement.talent} (${requirement.minValue} <= ${targetField})`)
}
if (requirement.maxValue) {
passes = targetField <= requirement.maxValue
if (!passes) console.debug(`fails requirement ${requirement.attribute ?? requirement.talent} (${targetField} <= ${requirement.maxValue})`)
}
if (requirement.sonderfertigkeit) { // FIXME fails when it tries to self reference itself e.g. Ausweichen II has Ausweichen I as requirement
const regexp = /(\w*)\W?(\w*)?/
const [variantName, baseAbility, level] = regexp.exec(requirement.sonderfertigkeit)
passes = this.parent.actor.itemTypes["SpecialAbility"].find(p => p.name === baseAbility) !== undefined
if (!passes) console.debug(`fails requirement ${requirement.sonderfertigkeit} (not in possession)`)
}
if (requirement["compare"]) {
const {ownAttribute, operation, targetAttribute} = requirement["compare"]
if (options.target) {
const flatTarget = foundry.utils.flattenObject(options.target.system)
const foreignTargetField = flatTarget[targetAttribute]
const ourTargetField = flatActor[ownAttribute]
switch (operation) {
case "lt":
passes = ourTargetField < foreignTargetField;
break;
case "lte":
passes = ourTargetField <= foreignTargetField;
break;
case "eq":
passes = ourTargetField == foreignTargetField;
break;
case "neq":
passes = ourTargetField != foreignTargetField;
break;
case "gte":
passes = ourTargetField >= foreignTargetField;
break;
case "gt":
passes = ourTargetField > foreignTargetField;
break;
}
if (!passes) {
console.debug(`fails compare requirement ${ownAttribute} ${operation} ${targetAttribute}`)
}
} else {
console.debug(`fails compare requirement as no target has been selected`)
return false // cant pass as we dont have a target
}
}
if (!passes) {
console.debug("fails atleast 1 requirement of ", this)
break
}
}
if (passes) {
if (options?.weapon) {
for (const waff of this.waffenLimit) {
if (waff.waffe) {
passes = options?.weapon?.name === waff.waffe ?? false
if (waff.mod) mod = waff.mod
if (passes)
break
}
if (waff.gruppe) {
passes = options?.skill?.name === waff.gruppe ?? false
if (waff.mod) mod = waff.mod
if (passes)
break
}
}
}
}
}
return {passes, mod}
}
}