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} } }