Compare commits
2 Commits
f67560a2b1
...
ae57e2f90e
| Author | SHA1 | Date |
|---|---|---|
|
|
ae57e2f90e | |
|
|
3f6b4a0303 |
|
|
@ -27,9 +27,7 @@ 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.
|
||||||
|
|
|
||||||
|
|
@ -71,6 +71,19 @@ 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()
|
||||||
|
|
@ -78,6 +91,7 @@ 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) {
|
||||||
|
|
||||||
|
|
@ -91,15 +105,18 @@ export class SpecialAbilityDataModel extends BaseItem {
|
||||||
}
|
}
|
||||||
if (requirement.minValue) {
|
if (requirement.minValue) {
|
||||||
passes = requirement.minValue <= targetField
|
passes = requirement.minValue <= targetField
|
||||||
if (!passes) console.log(`fails requirement ${requirement.attribute ?? requirement.talent} (${requirement.minValue} <= ${targetField})`)
|
if (!passes) console.debug(`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.log(`fails requirement ${requirement.attribute ?? requirement.talent} (${targetField} <= ${requirement.maxValue})`)
|
if (!passes) console.debug(`fails requirement ${requirement.attribute ?? requirement.talent} (${targetField} <= ${requirement.maxValue})`)
|
||||||
}
|
}
|
||||||
if (requirement.sonderfertigkeit) {
|
if (requirement.sonderfertigkeit) { // FIXME fails when it tries to self reference itself e.g. Ausweichen II has Ausweichen I as requirement
|
||||||
passes = this.parent.actor.itemTypes["SpecialAbility"].find(p => p.name === requirement.sonderfertigkeit) != undefined
|
const regexp = /(\w*)\W?(\w*)?/
|
||||||
if (!passes) console.log(`fails requirement ${requirement.sonderfertigkeit} (not in possession)`)
|
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"]) {
|
if (requirement["compare"]) {
|
||||||
const {ownAttribute, operation, targetAttribute} = requirement["compare"]
|
const {ownAttribute, operation, targetAttribute} = requirement["compare"]
|
||||||
|
|
@ -128,30 +145,29 @@ export class SpecialAbilityDataModel extends BaseItem {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (!passes) {
|
if (!passes) {
|
||||||
console.log(`fails compare requirement ${ownAttribute} ${operation} ${targetAttribute}`)
|
console.debug(`fails compare requirement ${ownAttribute} ${operation} ${targetAttribute}`)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
console.log(`fails compare requirement as no target has been selected`)
|
console.debug(`fails compare requirement as no target has been selected`)
|
||||||
return false // cant pass as we dont have a target
|
return false // cant pass as we dont have a target
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!passes) {
|
if (!passes) {
|
||||||
console.log("fails atleast 1 requirement of ", this)
|
console.debug("fails atleast 1 requirement of ", this)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log(this.name, "requirements", passes)
|
|
||||||
if (passes) {
|
if (passes) {
|
||||||
if (options?.weapon) {
|
if (options?.weapon) {
|
||||||
for (const waff of this.waffenLimit) {
|
for (const waff of this.waffenLimit) {
|
||||||
if (waff.waffe) {
|
if (waff.waffe) {
|
||||||
passes = options?.weapon.name === waff.waffe ?? false
|
passes = options?.weapon?.name === waff.waffe ?? false
|
||||||
if (waff.mod) mod = waff.mod
|
if (waff.mod) mod = waff.mod
|
||||||
if (passes)
|
if (passes)
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if (waff.gruppe) {
|
if (waff.gruppe) {
|
||||||
passes = options?.skill.name === waff.gruppe ?? false
|
passes = options?.skill?.name === waff.gruppe ?? false
|
||||||
if (waff.mod) mod = waff.mod
|
if (waff.mod) mod = waff.mod
|
||||||
if (passes)
|
if (passes)
|
||||||
break
|
break
|
||||||
|
|
@ -159,7 +175,9 @@ export class SpecialAbilityDataModel extends BaseItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
console.log("return value", {passes, mod})
|
|
||||||
|
|
||||||
|
}
|
||||||
return {passes, mod}
|
return {passes, mod}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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._combatManeuverId = null
|
this._defenseManeuverId = 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._combatManeuverId = this._combatManeuverId === maneuverId ? null : maneuverId
|
this._defenseManeuverId = this._defenseManeuverId === 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._combatManeuverId)
|
const maneuver = this.#evaluateManeuvers().find(p => p.id === this._defenseManeuverId)
|
||||||
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._combatManeuverId === action.name,
|
isSelected: this._defenseManeuverId === 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._combatManeuverId)
|
const maneuver = this._maneuvers?.find(p => p.id === this._defenseManeuverId)
|
||||||
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._combatManeuverId
|
context.ready = this._targetId && this._weaponId && this._skillId && this._defenseManeuverId
|
||||||
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._combatManeuverId)
|
const maneuver = this._maneuvers?.find(p => p.id === this._defenseManeuverId)
|
||||||
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)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,303 @@
|
||||||
|
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)
|
||||||
|
}))
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -94,6 +94,10 @@ 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 = {
|
||||||
|
|
@ -190,6 +194,7 @@ export class Character extends Actor {
|
||||||
this.prepareEmbeddedDocuments();
|
this.prepareEmbeddedDocuments();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
getRollData() {
|
getRollData() {
|
||||||
const data = super.getRollData();
|
const data = super.getRollData();
|
||||||
this.prepareDerivedData()
|
this.prepareDerivedData()
|
||||||
|
|
@ -252,6 +257,31 @@ 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)
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,12 @@ export class ActionManager {
|
||||||
cost: ActionManager.FREE,
|
cost: ActionManager.FREE,
|
||||||
type: ActionManager.DEFENSE,
|
type: ActionManager.DEFENSE,
|
||||||
source: ActionManager.DEFAULT,
|
source: ActionManager.DEFAULT,
|
||||||
eval: (options) => true
|
eval: (options) => {
|
||||||
|
if (options?.weapon && options.weapon === "Ausweichen") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Rufen",
|
name: "Rufen",
|
||||||
|
|
@ -158,11 +163,16 @@ export class ActionManager {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Abwehraktion",
|
name: "Parade",
|
||||||
type: ActionManager.DEFENSE,
|
type: ActionManager.DEFENSE,
|
||||||
cost: ActionManager.REGULAR,
|
cost: ActionManager.REGULAR,
|
||||||
source: ActionManager.DEFAULT,
|
source: ActionManager.DEFAULT,
|
||||||
eval: (options) => true
|
eval: (options) => {
|
||||||
|
if (options?.weapon && options.weapon !== "Ausweichen") {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "Meisterparade",
|
name: "Meisterparade",
|
||||||
|
|
@ -170,7 +180,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)
|
||||||
|
|
|
||||||
|
|
@ -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.name,
|
name: item.system.value ? item.system.value : item.name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,7 @@ 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
|
||||||
|
|
@ -195,8 +196,15 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
||||||
this.document.itemTypes["Species"]?.[0]?.sheet.render(true)
|
this.document.itemTypes["Species"]?.[0]?.sheet.render(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
static #openCombatAction() {
|
static #openCombatAction(event, target) {
|
||||||
|
switch (target.dataset.mode) {
|
||||||
|
case "attack":
|
||||||
new CombatActionDialog(this.document).render(true)
|
new CombatActionDialog(this.document).render(true)
|
||||||
|
break
|
||||||
|
case "defense":
|
||||||
|
new DefenseActionDialog(this.document).render(true)
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ export class SpecialAbilitySheet extends HandlebarsApplicationMixin(DocumentShee
|
||||||
|
|
||||||
/** @inheritDoc */
|
/** @inheritDoc */
|
||||||
static DEFAULT_OPTIONS = {
|
static DEFAULT_OPTIONS = {
|
||||||
position: {width: 520, height: 480},
|
position: {width: 520, height: 600},
|
||||||
classes: ['dsa41', 'sheet', 'item', 'specialability'],
|
classes: ['dsa41', 'sheet', 'item', 'specialability'],
|
||||||
tag: 'form',
|
tag: 'form',
|
||||||
form: {
|
form: {
|
||||||
|
|
@ -57,6 +57,20 @@ 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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.startwert),
|
start: parseInt(attribute.value),
|
||||||
aktuell: parseInt(attribute.value),
|
aktuell: parseInt(attribute.value),
|
||||||
mod: parseInt(attribute.mod),
|
mod: parseInt(attribute.mod),
|
||||||
}
|
}
|
||||||
|
|
@ -564,10 +564,21 @@ 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 sfId = compendiumOfSF?.index.find(sf => sf.name === specialAbility.name)
|
const regexp = /(\w*)\W?(\w*)?/
|
||||||
|
const [variantName, baseAbility, level] = regexp.exec(specialAbility.name)
|
||||||
|
const sfId = compendiumOfSF?.index.find(sf => sf.name === baseAbility)
|
||||||
|
|
||||||
if (sfId) {
|
if (sfId) {
|
||||||
compendiumOfSF.getDocument(sfId._id).then(sf => actor.createEmbeddedDocuments('Item', [sf]))
|
if (variantName) {
|
||||||
|
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({
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,19 @@
|
||||||
|
.row {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
> * {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -6,6 +6,7 @@
|
||||||
@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";
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,50 @@
|
||||||
|
<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>
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
<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>
|
||||||
|
|
@ -18,6 +18,7 @@
|
||||||
{{/if}}
|
{{/if}}
|
||||||
</div>
|
</div>
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
</div>
|
||||||
<div class="body">
|
<div class="body">
|
||||||
<label>Beschreibung</label>
|
<label>Beschreibung</label>
|
||||||
<prose-mirror
|
<prose-mirror
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,24 @@
|
||||||
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 name="system.name" value="{{system.name}}"/>
|
<input type="text" 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>
|
||||||
|
|
@ -29,7 +43,12 @@
|
||||||
{{{text}}}
|
{{{text}}}
|
||||||
</prose-mirror>
|
</prose-mirror>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mods">
|
||||||
|
{{#each mod}}
|
||||||
|
<span>{{this.name}} {{this.value}}</span>
|
||||||
|
{{/each}}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</section>
|
||||||
Loading…
Reference in New Issue