Compare commits

..

No commits in common. "ae57e2f90e76e5b95f29a359b335933bf9bc1989" and "f67560a2b147369d9ef7700a10fc447511e15d88" have entirely different histories.

15 changed files with 102 additions and 584 deletions

View File

@ -27,7 +27,9 @@ import {CultureDataModel} from "./module/data/culture.mjs";
import {CultureSheet} from "./module/sheets/CultureSheet.mjs"; import {CultureSheet} from "./module/sheets/CultureSheet.mjs";
import {SpeciesSheet} from "./module/sheets/SpeciesSheet.mjs"; import {SpeciesSheet} from "./module/sheets/SpeciesSheet.mjs";
import {ProfessionSheet} from "./module/sheets/ProfessionSheet.mjs"; import {ProfessionSheet} from "./module/sheets/ProfessionSheet.mjs";
import {XmlImport} from "./module/xml-import/xml-import.mjs";
import {XmlImportDialog} from "./module/dialog/xmlImportDialog.mjs"; import {XmlImportDialog} from "./module/dialog/xmlImportDialog.mjs";
async function preloadHandlebarsTemplates() { async function preloadHandlebarsTemplates() {
return foundry.applications.handlebars.loadTemplates([ return foundry.applications.handlebars.loadTemplates([
// ui partials. // ui partials.

View File

@ -71,19 +71,6 @@ export class SpecialAbilityDataModel extends BaseItem {
} }
} }
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 {
this.mod
}
} else {
return []
}
}
isActive(options) { isActive(options) {
const requirements = this.#getRequirements() const requirements = this.#getRequirements()
@ -91,93 +78,88 @@ export class SpecialAbilityDataModel extends BaseItem {
let passes = true let passes = true
let mod = 0 let mod = 0
if (this.parent?.actor) { const flatActor = foundry.utils.flattenObject(this.parent.actor.system)
const flatActor = foundry.utils.flattenObject(this.parent.actor.system) for (let requirement of requirements) {
for (let requirement of requirements) {
let targetField = null let targetField = null
if (requirement.attribute) { if (requirement.attribute) {
targetField = flatActor?.[requirement.attribute.toLocaleLowerCase()] targetField = flatActor?.[requirement.attribute.toLocaleLowerCase()]
} }
if (requirement.talent) { if (requirement.talent) {
targetField = this.parent.actor.itemTypes["Skill"].find(p => p.name.toLocaleLowerCase() === requirement.talent.toLocaleLowerCase()).taw targetField = this.parent.actor.itemTypes["Skill"].find(p => p.name.toLocaleLowerCase() === requirement.talent.toLocaleLowerCase()).taw
} }
if (requirement.minValue) { if (requirement.minValue) {
passes = requirement.minValue <= targetField passes = requirement.minValue <= targetField
if (!passes) console.debug(`fails requirement ${requirement.attribute ?? requirement.talent} (${requirement.minValue} <= ${targetField})`) if (!passes) console.log(`fails requirement ${requirement.attribute ?? requirement.talent} (${requirement.minValue} <= ${targetField})`)
} }
if (requirement.maxValue) { if (requirement.maxValue) {
passes = targetField <= requirement.maxValue passes = targetField <= requirement.maxValue
if (!passes) console.debug(`fails requirement ${requirement.attribute ?? requirement.talent} (${targetField} <= ${requirement.maxValue})`) if (!passes) console.log(`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 if (requirement.sonderfertigkeit) {
const regexp = /(\w*)\W?(\w*)?/ passes = this.parent.actor.itemTypes["SpecialAbility"].find(p => p.name === requirement.sonderfertigkeit) != undefined
const [variantName, baseAbility, level] = regexp.exec(requirement.sonderfertigkeit) if (!passes) console.log(`fails requirement ${requirement.sonderfertigkeit} (not in possession)`)
}
passes = this.parent.actor.itemTypes["SpecialAbility"].find(p => p.name === baseAbility) != undefined if (requirement["compare"]) {
if (!passes) console.debug(`fails requirement ${requirement.sonderfertigkeit} (not in possession)`) const {ownAttribute, operation, targetAttribute} = requirement["compare"]
} if (options.target) {
if (requirement["compare"]) { const flatTarget = foundry.utils.flattenObject(options.target.system)
const {ownAttribute, operation, targetAttribute} = requirement["compare"] const foreignTargetField = flatTarget[targetAttribute]
if (options.target) { const ourTargetField = flatActor[ownAttribute]
const flatTarget = foundry.utils.flattenObject(options.target.system) switch (operation) {
const foreignTargetField = flatTarget[targetAttribute] case "lt":
const ourTargetField = flatActor[ownAttribute] passes = ourTargetField < foreignTargetField;
switch (operation) { break;
case "lt": case "lte":
passes = ourTargetField < foreignTargetField; passes = ourTargetField <= foreignTargetField;
break; break;
case "lte": case "eq":
passes = ourTargetField <= foreignTargetField; passes = ourTargetField == foreignTargetField;
break; break;
case "eq": case "neq":
passes = ourTargetField == foreignTargetField; passes = ourTargetField != foreignTargetField;
break; break;
case "neq": case "gte":
passes = ourTargetField != foreignTargetField; passes = ourTargetField >= foreignTargetField;
break; break;
case "gte": case "gt":
passes = ourTargetField >= foreignTargetField; passes = ourTargetField > foreignTargetField;
break; 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) {
if (!passes) { console.log(`fails compare requirement ${ownAttribute} ${operation} ${targetAttribute}`)
console.debug("fails atleast 1 requirement of ", this) }
break } else {
console.log(`fails compare requirement as no target has been selected`)
return false // cant pass as we dont have a target
} }
} }
if (passes) { if (!passes) {
if (options?.weapon) { console.log("fails atleast 1 requirement of ", this)
for (const waff of this.waffenLimit) { break
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
}
}
}
} }
} }
console.log(this.name, "requirements", passes)
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
}
}
}
}
console.log("return value", {passes, mod})
return {passes, mod} return {passes, mod}
} }
} }

View File

@ -53,7 +53,7 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
this._targetId = null this._targetId = null
this._skillId = null this._skillId = null
this._weaponId = null this._weaponId = null
this._defenseManeuverId = null this._combatManeuverId = null
this._actionManager = new ActionManager(this._actor) this._actionManager = new ActionManager(this._actor)
} }
@ -66,7 +66,7 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
static async #onSelectManeuver(event, target) { static async #onSelectManeuver(event, target) {
const {maneuverId} = target.dataset const {maneuverId} = target.dataset
this._defenseManeuverId = this._defenseManeuverId === maneuverId ? null : maneuverId this._combatManeuverId = this._combatManeuverId === maneuverId ? null : maneuverId
this.render({parts: ["form"]}) this.render({parts: ["form"]})
} }
@ -80,7 +80,7 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
static async #onSubmitForm(event, form, formData) { static async #onSubmitForm(event, form, formData) {
event.preventDefault() event.preventDefault()
const maneuver = this.#evaluateManeuvers().find(p => p.id === this._defenseManeuverId) const maneuver = this.#evaluateManeuvers().find(p => p.id === this._combatManeuverId)
const weapon = this._actor.itemTypes["Equipment"].find(p => p._id === this._weaponId) const weapon = this._actor.itemTypes["Equipment"].find(p => p._id === this._weaponId)
const skill = this._actor.itemTypes["Skill"].find(p => p._id === this._skillId) const skill = this._actor.itemTypes["Skill"].find(p => p._id === this._skillId)
const target = game.actors.get(game.scenes.current.tokens.find(p => p._id === this._targetId).actorId) const target = game.actors.get(game.scenes.current.tokens.find(p => p._id === this._targetId).actorId)
@ -235,7 +235,7 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
skill skill
}).filter(p => p.type === ActionManager.ATTACK).map(action => { }).filter(p => p.type === ActionManager.ATTACK).map(action => {
return { return {
isSelected: this._defenseManeuverId === action.name, isSelected: this._combatManeuverId === action.name,
id: action.name, id: action.name,
name: action.name, name: action.name,
type: action.type, type: action.type,
@ -265,7 +265,7 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
if (this._targetId && this._weaponId && this._skillId) { if (this._targetId && this._weaponId && this._skillId) {
context.maneuver = this.#evaluateManeuvers() context.maneuver = this.#evaluateManeuvers()
} }
const maneuver = this._maneuvers?.find(p => p.id === this._defenseManeuverId) const maneuver = this._maneuvers?.find(p => p.id === this._combatManeuverId)
if (maneuver) { if (maneuver) {
context.canMod = maneuver.mod != undefined context.canMod = maneuver.mod != undefined
} }
@ -274,7 +274,7 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
// TODO get W/M of weapon NOW // TODO get W/M of weapon NOW
context.ready = this._targetId && this._weaponId && this._skillId && this._defenseManeuverId context.ready = this._targetId && this._weaponId && this._skillId && this._combatManeuverId
return context return context
} else { } else {
ui.notifications.error(`Feature funktioniert nur wenn der Akteur ein Token auf der aktuellen Szene hat`); ui.notifications.error(`Feature funktioniert nur wenn der Akteur ein Token auf der aktuellen Szene hat`);
@ -286,7 +286,7 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
const target = this.element.querySelector(".actions button .value") const target = this.element.querySelector(".actions button .value")
const targetDescription = this.element.querySelector(".modResult") const targetDescription = this.element.querySelector(".modResult")
const at = Number(context.targetNumber) const at = Number(context.targetNumber)
const maneuver = this._maneuvers?.find(p => p.id === this._defenseManeuverId) const maneuver = this._maneuvers?.find(p => p.id === this._combatManeuverId)
const mod = Number(this.element.querySelector('[name="mod"]').value) const mod = Number(this.element.querySelector('[name="mod"]').value)
const penalty = 0 - (maneuver?.penalty ?? 0) + (maneuver?.mod?.(mod) ?? 0) ?? 0 const penalty = 0 - (maneuver?.penalty ?? 0) + (maneuver?.mod?.(mod) ?? 0) ?? 0
const circumstance = Number(this.element.querySelector('[name="circumstance"]').value) const circumstance = Number(this.element.querySelector('[name="circumstance"]').value)

View File

@ -1,303 +0,0 @@
import {ActionManager} from "../sheets/actions/action-manager.mjs";
const {ApplicationV2, HandlebarsApplicationMixin} = foundry.applications.api
/**
* @typedef TokenDistance
* @property {Number} x
* @property {Number} y
* @property {Number} d
* @property {Token} token
*/
export class DefenseActionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
static DEFAULT_OPTIONS = {
classes: ['dsa41', 'dialog', 'combat'],
tag: "form",
position: {
width: 480,
height: 640
},
window: {
resizable: false,
},
form: {
submitOnChange: false,
closeOnSubmit: true,
handler: DefenseActionDialog.#onSubmitForm
},
actions: {
selectWeaponAndSkill: DefenseActionDialog.#onSelectWeaponAndSkill,
selectManeuver: DefenseActionDialog.#onSelectManeuver,
}
}
static PARTS = {
form: {
template: 'systems/DSA_4-1/templates/dialog/defense-action.hbs',
}
}
/**
* @type {Actor}
* @private
*/
_actor = null
constructor(actor, attackData) {
super();
this._attackData = attackData ?? {
modToDefense: 0,
attacker: null,
weapon: null, // is important to note as weapons like Chain Weapons or Flails can ignore Shields
}
this._actor = actor
this._skillId = null
this._weaponId = null
this._defenseManeuverId = null
this._actionManager = new ActionManager(this._actor)
//if (this._actor) {
// this._actor.prepareDerivedData()
//}
}
static async #onSelectTarget(event, target) {
const {targetId} = target.dataset
this._targetId = this._targetId === targetId ? null : targetId
this.render({parts: ["form"]})
}
static async #onSelectManeuver(event, target) {
const {maneuverId} = target.dataset
this._defenseManeuverId = this._defenseManeuverId === maneuverId ? null : maneuverId
this.render({parts: ["form"]})
}
static async #onSelectWeaponAndSkill(event, target) {
const {weaponId, skillId} = target.dataset
this._weaponId = this._weaponId === weaponId ? null : weaponId
this._skillId = this._skillId === skillId ? null : skillId
this.render({parts: ["form"]})
}
static async #onSubmitForm(event, form, formData) {
event.preventDefault()
const attack = this._attackData
const maneuver = this.#evaluateManeuvers().find(p => p.id === this._defenseManeuverId)
this._actor.rollDefense({
weapon: this._weaponId,
skill: this._skillId,
attackData: attack,
maneuver,
mod: this._mod,
circumstance: this._circumstance,
penalty: this._penalty,
targetNumber: this._targetNumber,
modDescription: maneuver?.modDescription?.replace("{}", "" + this._mod) ?? ""
})
}
_configureRenderOptions(options) {
super._configureRenderOptions(options)
if (options.window) {
options.window.title = `Gegen einen Angriff verteidigen`
}
return options
}
#evaluateWeapons() {
// get equipped weapons and adjust AT/PA values by basis values from actor TODO: and W/M of weapons
const equips = this._actor.system.heldenausruestung[this._actor.system.setEquipped]
const weapons = []
const equippedWeapons = ["links", "rechts", "fernkampf"]
const baseAt = {
links: this._actor.system.at.links.aktuell, // TODO hook Beidhändigerkampf/linkhand
rechts: this._actor.system.at.rechts.aktuell,
fernkampf: this._actor.system.fk.aktuell,
}
const basePa = {
links: this._actor.system.pa.links.aktuell, // TODO hook Beidhändigerkampf/linkhand
rechts: this._actor.system.pa.rechts.aktuell,
fernkampf: 0,
}
equippedWeapons.forEach(slot => {
const equip = equips[slot]
const weapon = this._actor.itemTypes["Equipment"].find(p => p._id === equip)
if (weapon) {
const variantWeaponSkills = [...weapon.system.rangedSkills, ...weapon.system.meleeSkills]
variantWeaponSkills.forEach(weaponSkill => {
const skill = this._actor.itemTypes["Skill"].find(p => p.name === weaponSkill)
if (skill) {
const skillAt = skill.system.at
const skillPa = skill.system.pa
weapons.push({
isSelected: this._skillId === skill._id && this._weaponId === weapon._id,
weaponId: weapon._id,
skillId: skill._id,
name: weapon.name,
skillName: skill.name,
img: weapon.img,
combatStatistics: {
at: baseAt[slot] + weapon.system.attackModifier + skillAt,
pa: basePa[slot] + weapon.system.parryModifier + skillPa
}
})
}
})
}
})
// TODO: also do this for combatAction
const links = this._actor.system.heldenausruestung[this._actor.system.setEquipped].links
const rechts = this._actor.system.heldenausruestung[this._actor.system.setEquipped].rechts
if (!links && !rechts) {
const unarmedSkills = [this._actor.itemTypes["Skill"].find(p => p.name === "Ringen"), this._actor.itemTypes["Skill"].find(p => p.name === "Raufen")]
unarmedSkills.forEach(unarmedSkill => {
const [skillAt, skillPa] = [unarmedSkill.system.at, unarmedSkill.system.pa]
weapons.push({
isSelected: this._skillId === unarmedSkill._id,
weaponId: "",
skillId: unarmedSkill._id,
name: unarmedSkill.name,
skillName: unarmedSkill.name,
img: "",
combatStatistics: {
at: baseAt["rechts"] + skillAt,
pa: basePa["rechts"] + skillPa
}
})
})
}
// Ausweichen as Weapon
weapons.push({
isSelected: this._weaponId === "Ausweichen",
weaponId: "Ausweichen",
skillId: "Ausweichen",
name: "Ausweichen",
skillName: "Ausweichen",
img: "",
combatStatistics: {
at: 0,
pa: this._actor.system.ausweichen.aktuell
}
})
this._weapons = weapons.sort((a, b) => (a.isSelected ? 0 : 1) - (b.isSelected ? 0 : 1))
return this._weapons
}
#evaluateManeuvers() {
const manager = this._actionManager
const weapon = this._weaponId !== "Ausweichen" ? this._actor.itemTypes["Equipment"].find(p => p._id === this._weaponId) : "Ausweichen"
const skill = this._actor.itemTypes["Skill"].find(p => p._id === this._skillId)
//const target = game.actors.get(game.scenes.current.tokens.find(p => p._id === this._targetId).actorId)
this._maneuvers = manager.evaluate({
//target,
weapon,
skill
}).filter(p => p.type === ActionManager.DEFENSE).map(action => {
return {
isSelected: this._defenseManeuverId === action.name,
id: action.name,
name: action.name,
type: action.type,
source: action.source,
cost: action.cost,
penalty: action.eval?.mod ?? 0,
mod: action.mod,
modDescription: action.modDescription,
cooldown: action.cooldown,
activate: action.activate,
}
}).sort((a, b) => (a.isSelected ? 0 : 1) - (b.isSelected ? 0 : 1))
return this._maneuvers
}
async _prepareContext(options) {
const context = await super._prepareContext(options)
context.actor = this._actor
context.distanceUnit = game.scenes.current.grid.units
if (this._actor.getActiveTokens()[0]?.id) {
context.weapons = this.#evaluateWeapons()
if (this._skillId) {
context.maneuver = this.#evaluateManeuvers()
}
const maneuver = this._maneuvers?.find(p => p.id === this._defenseManeuverId)
if (maneuver) {
context.canMod = maneuver.mod != undefined
}
context.targetNumber = context.weapons.find(p => ((this._weaponId != "") || p.weaponId === this._weaponId) && p.skillId === this._skillId)?.combatStatistics.pa
// TODO get W/M of weapon NOW
context.ready = this._targetId && this._weaponId && this._skillId && this._defenseManeuverId
return context
} else {
ui.notifications.error(`Feature funktioniert nur wenn der Akteur ein Token auf der aktuellen Szene hat`);
}
}
#update(context) {
const target = this.element.querySelector(".actions button .value")
const targetDescription = this.element.querySelector(".modResult")
const at = Number(context.targetNumber)
const maneuver = this._maneuvers?.find(p => p.id === this._defenseManeuverId)
const mod = Number(this.element.querySelector('[name="mod"]').value)
const penalty = 0 - (maneuver?.penalty ?? 0) + (maneuver?.mod?.(mod) ?? 0) ?? 0
const circumstance = Number(this.element.querySelector('[name="circumstance"]').value)
this.element.querySelector('[name="penalty"]').value = penalty + circumstance
const result = (at + circumstance + penalty)
this._circumstance = circumstance
this._penalty = penalty
this._targetNumber = result
this._mod = mod
this._modDescription = maneuver?.modDescription?.replace("{}", "" + mod) ?? ""
target.textContent = `(${result})`
targetDescription.textContent = this._modDescription
if (result <= 0) {
context.ready = false
this.element.querySelector(".actions button").classList.remove("ready")
this.element.querySelector(".actions button").setAttribute("disabled", true)
} else {
context.ready = true
this.element.querySelector(".actions button").classList.add("ready")
this.element.querySelector(".actions button").removeAttribute("disabled")
}
}
_onRender(context, options) {
this.#update(context)
this.element.querySelectorAll('[name="mod"], [name="malus"], [name="circumstance"]').forEach(e => e.addEventListener('change', (event) => {
this.#update(context)
}))
}
}

View File

@ -94,10 +94,6 @@ export class Character extends Actor {
systemData.gs.basis = 6; systemData.gs.basis = 6;
systemData.gs.aktuell = systemData.gs.basis + (systemData.gs.mod ?? 0); // TOOD: get GS from spezien systemData.gs.aktuell = systemData.gs.basis + (systemData.gs.mod ?? 0); // TOOD: get GS from spezien
systemData.ausweichen = {}
systemData.ausweichen.basis = systemData.pa.basis
systemData.ausweichen.aktuell = systemData.ausweichen.basis + (systemData.ausweichen.mod ?? 0)
if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) { if (game.settings.get("DSA_4-1", "optional_ruestungzonen")) {
systemData.rs = { systemData.rs = {
@ -194,7 +190,6 @@ export class Character extends Actor {
this.prepareEmbeddedDocuments(); this.prepareEmbeddedDocuments();
} }
getRollData() { getRollData() {
const data = super.getRollData(); const data = super.getRollData();
this.prepareDerivedData() this.prepareDerivedData()
@ -257,31 +252,6 @@ export class Character extends Actor {
return false return false
} }
async rollDefense(data) {
const maneuver = data.manuever
const weapon = this.itemTypes["Equipment"].find(p => p._id === data.weapon)
const skill = data.skill !== "Ausweichen" ? this.itemTypes["Skill"].find(p => p._id === data.skill) : "Ausweichen"
//const target = game.actors.get(game.scenes.current.tokens.find(p => p._id === data.target).actorId)
const roll = new Roll("1d20cs<" + data.targetNumber)
const evaluated1 = (await roll.evaluate())
let flavor = ''
if (skill === "Ausweichen") {
flavor = `Versucht auszuweichen<br/>${data.modDescription}`
} else {
flavor = `Verteidigt sich gegen einen Angriff mit ${weapon.name} (${skill.name})<br/>${data.modDescription}`
}
await evaluated1.toMessage({
speaker: ChatMessage.getSpeaker({actor: this}),
flavor,
rollMode: "publicroll",
})
}
async rollAttack(data) { async rollAttack(data) {
const maneuver = data.manuever const maneuver = data.manuever
const weapon = this.itemTypes["Equipment"].find(p => p._id === data.weapon) const weapon = this.itemTypes["Equipment"].find(p => p._id === data.weapon)

View File

@ -23,12 +23,7 @@ export class ActionManager {
cost: ActionManager.FREE, cost: ActionManager.FREE,
type: ActionManager.DEFENSE, type: ActionManager.DEFENSE,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: (options) => { eval: (options) => true
if (options?.weapon && options.weapon === "Ausweichen") {
return true
}
return false
}
}, },
{ {
name: "Rufen", name: "Rufen",
@ -163,16 +158,11 @@ export class ActionManager {
} }
}, },
{ {
name: "Parade", name: "Abwehraktion",
type: ActionManager.DEFENSE, type: ActionManager.DEFENSE,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: (options) => { eval: (options) => true
if (options?.weapon && options.weapon !== "Ausweichen") {
return true
}
return false
}
}, },
{ {
name: "Meisterparade", name: "Meisterparade",
@ -180,7 +170,7 @@ export class ActionManager {
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.SF, source: ActionManager.SF,
modDescription: "erschwert nächste AT vom Ziel um {}", modDescription: "erschwert nächste AT vom Ziel um {}",
mod: (value) => -value, mod: (value) => value,
eval: (options) => { eval: (options) => {
const step1 = this.#hatWaffeinHand(options) && this.#hatSonderfertigkeit("Meisterparade", options) const step1 = this.#hatWaffeinHand(options) && this.#hatSonderfertigkeit("Meisterparade", options)
const step2WithBenefits = this.#evalSonderfertigkeitRequirements("Meisterparade", options) const step2WithBenefits = this.#evalSonderfertigkeitRequirements("Meisterparade", options)

View File

@ -28,7 +28,7 @@ export default {
actorData.itemTypes.SpecialAbility.forEach((item) => { actorData.itemTypes.SpecialAbility.forEach((item) => {
context.specialAbilities.push({ context.specialAbilities.push({
id: item._id, id: item._id,
name: item.system.value ? item.system.value : item.name, name: item.name,
}); });
} }
); );

View File

@ -9,7 +9,6 @@ import Social from "./character/social.mjs";
import Spells from "./character/spells.mjs" import Spells from "./character/spells.mjs"
import {CombatActionDialog} from "../dialog/combatAction.mjs"; import {CombatActionDialog} from "../dialog/combatAction.mjs";
import {ActionManager} from "./actions/action-manager.mjs"; import {ActionManager} from "./actions/action-manager.mjs";
import {DefenseActionDialog} from "../dialog/defenseAction.mjs";
const {HandlebarsApplicationMixin} = foundry.applications.api const {HandlebarsApplicationMixin} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets const {ActorSheetV2} = foundry.applications.sheets
@ -196,15 +195,8 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
this.document.itemTypes["Species"]?.[0]?.sheet.render(true) this.document.itemTypes["Species"]?.[0]?.sheet.render(true)
} }
static #openCombatAction(event, target) { static #openCombatAction() {
switch (target.dataset.mode) { new CombatActionDialog(this.document).render(true)
case "attack":
new CombatActionDialog(this.document).render(true)
break
case "defense":
new DefenseActionDialog(this.document).render(true)
break
}
} }
/** /**

View File

@ -4,7 +4,7 @@ export class SpecialAbilitySheet extends HandlebarsApplicationMixin(DocumentShee
/** @inheritDoc */ /** @inheritDoc */
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
position: {width: 520, height: 600}, position: {width: 520, height: 480},
classes: ['dsa41', 'sheet', 'item', 'specialability'], classes: ['dsa41', 'sheet', 'item', 'specialability'],
tag: 'form', tag: 'form',
form: { form: {
@ -57,20 +57,6 @@ export class SpecialAbilitySheet extends HandlebarsApplicationMixin(DocumentShee
context.flags = specialabilityData.flags; context.flags = specialabilityData.flags;
context.text = specialabilityData.system.text; context.text = specialabilityData.system.text;
context.aktionsText = specialabilityData.system.aktionsText; context.aktionsText = specialabilityData.system.aktionsText;
context.hasChoices = context.system.auswahl.length > 0;
context.choices = {}
context.value = context.system.value
context.system.auswahl.forEach(a => {
context.choices[a.name] = a.name
})
context.isActive = this.document.system.isActive()?.passes
context.mod = this.document.system.getActiveMod()?.map(mod => {
return {
name: mod.name,
value: mod.value > 0 ? "+" + mod.value : mod.value,
}
})
context.hasModality = context.system.value != null
return context; return context;
} }

View File

@ -321,7 +321,7 @@ export class XmlImport {
#getAttributeJson(attributes, name) { #getAttributeJson(attributes, name) {
let attribute = this.#filterAttribute(attributes, name) let attribute = this.#filterAttribute(attributes, name)
return { return {
start: parseInt(attribute.value), start: parseInt(attribute.startwert),
aktuell: parseInt(attribute.value), aktuell: parseInt(attribute.value),
mod: parseInt(attribute.mod), mod: parseInt(attribute.mod),
} }
@ -564,21 +564,10 @@ export class XmlImport {
} }
specialAbilities.forEach((specialAbility) => { specialAbilities.forEach((specialAbility) => {
const compendiumOfSF = game.packs.get('DSA_4-1.sonderfertigkeiten'); const compendiumOfSF = game.packs.get('DSA_4-1.sonderfertigkeiten');
const regexp = /(\w*)\W?(\w*)?/ const sfId = compendiumOfSF?.index.find(sf => sf.name === specialAbility.name)
const [variantName, baseAbility, level] = regexp.exec(specialAbility.name)
const sfId = compendiumOfSF?.index.find(sf => sf.name === baseAbility)
if (sfId) { if (sfId) {
if (variantName) { compendiumOfSF.getDocument(sfId._id).then(sf => actor.createEmbeddedDocuments('Item', [sf]))
console.log(baseAbility + " to be imported as " + variantName) // TODO if baseAbility already imported, adjust its level instead of adding a new embeddedDocument
}
compendiumOfSF.getDocument(sfId._id).then(sf => {
actor.createEmbeddedDocuments('Item', [sf]).then(_ => {
actor.itemTypes["SpecialAbility"].find(p => p.name === baseAbility).update({
"system.value": variantName
})
})
})
} else { } else {
actor.createEmbeddedDocuments('Item', [ actor.createEmbeddedDocuments('Item', [
new SpecialAbility({ new SpecialAbility({

View File

@ -1,19 +0,0 @@
.row {
display: flex;
flex-direction: row;
gap: 8px;
> * {
flex: 1;
}
}
.column {
display: flex;
flex-direction: column;
gap: 8px;
> * {
flex: 1;
}
}

View File

@ -6,7 +6,6 @@
@use "molecules/lists"; @use "molecules/lists";
@use "molecules/attributes"; @use "molecules/attributes";
@use "molecules/sidebar-elements"; @use "molecules/sidebar-elements";
@use "molecules/rows-and-columns";
@use "molecules/tabs"; @use "molecules/tabs";
@use "molecules/paperdoll"; @use "molecules/paperdoll";

View File

@ -1,50 +0,0 @@
<section>
<fieldset>
<legend>Waffe auswählen</legend>
<ul>
{{#each weapons}}
<li class="{{#if isSelected}}selected{{/if}}" data-action="selectWeaponAndSkill"
data-weapon-id="{{this.weaponId}}" data-skill-id="{{this.skillId}}">
{{#if this.img}}<img src="{{this.img}}" style="width: 32px; height: 32px"/>{{else}}
<span style="width: 32px"></span> {{/if}}
<span>{{this.name}}
{{#if (ne this.skillName this.name)}}({{this.skillName}}){{/if}}</span>
<span>{{#if this.combatStatistics}}
(AT: {{this.combatStatistics.at}} PA: {{this.combatStatistics.pa}}){{/if}}</span></li>
{{/each}}
</ul>
</fieldset>
<fieldset>
<legend>Manöver auswählen</legend>
<ul>
{{#each maneuver}}
<li class="{{#if isSelected}}selected{{/if}} name-only" data-action="selectManeuver"
data-maneuver-id="{{this.id}}" class="{{this.source}}">{{this.name}}</li>
{{/each}}
</ul>
</fieldset>
<fieldset class="modding">
<legend>Erschwernisse und Ansagen</legend>
<div class="malus-and-mod">
<label><span>Umstände</span>
<input name="circumstance" type="number">
</label>
<label><span>Ansage</span>
<input name="mod" type="number" {{disabled (not canMod)}}>
</label>
<label><span>Erschwernis</span>
<input name="penalty" type="number" {{disabled true}}>
</label>
</div>
<output class="modResult"></output>
</fieldset>
<div class="actions">
<button {{#if ready}}class="ready"{{/if}} type="submit"><i class="fa-solid fa-shield"></i>Verteidigen <span
class="value"></span></button>
</div>
</section>

View File

@ -1,11 +1,11 @@
<section class="tab {{tabs.advantage.id}} {{tabs.advantage.cssClass}}" <section class="tab {{tabs.advantage.id}} {{tabs.advantage.cssClass}}"
data-tab="{{tabs.advantage.id}}" data-tab="{{tabs.advantage.id}}"
data-group="{{tabs.advantage.group}}"> data-group="{{tabs.advantage.group}}">
<div class="row"> <div>
<div> <label>Name</label>
<label>Name</label> <input name="system.name" value="{{system.name}}"/>
<input type="text" name="system.name" value="{{system.name}}"/>
</div> </div>
{{#if hasModality}} {{#if hasModality}}
<div> <div>
<label for="{{this._id}}.choice">Auswahl</label> <label for="{{this._id}}.choice">Auswahl</label>
@ -18,7 +18,6 @@
{{/if}} {{/if}}
</div> </div>
{{/if}} {{/if}}
</div>
<div class="body"> <div class="body">
<label>Beschreibung</label> <label>Beschreibung</label>
<prose-mirror <prose-mirror

View File

@ -2,24 +2,10 @@
data-tab="{{tabs.specialability.id}}" data-tab="{{tabs.specialability.id}}"
data-group="{{tabs.specialability.group}}"> data-group="{{tabs.specialability.group}}">
<div> <div>
<div class="row">
<div> <div>
<label>Name</label> <label>Name</label>
<input type="text" name="system.name" value="{{system.name}}"/> <input name="system.name" value="{{system.name}}"/>
</div>
{{#if hasModality}}
<div>
<label for="{{this._id}}.choice">Auswahl</label>
{{#if hasChoices}}
<select id="{{this._id}}.choice" name="system.value">
{{selectOptions choices selected=system.value inverted=true}}
</select>
{{else}}
<input id="{{this._id}}.choice" name="system.value" value="{{system.value}}"/>
{{/if}}
</div>
{{/if}}
</div> </div>
<div class="body"> <div class="body">
<label>Aktionstext</label> <label>Aktionstext</label>
@ -43,12 +29,7 @@
{{{text}}} {{{text}}}
</prose-mirror> </prose-mirror>
</div> </div>
<div class="mods">
{{#each mod}}
<span>{{this.name}} {{this.value}}</span>
{{/each}}
</div>
</div> </div>
</section> </div>