implements combat attack dialog
parent
b2d9a82af8
commit
7f18c62270
|
|
@ -48,7 +48,11 @@ export class SpecialAbilityDataModel extends BaseItem {
|
|||
})
|
||||
),
|
||||
waffenLimit: new ArrayField(
|
||||
new StringField(),
|
||||
new SchemaField({
|
||||
waffe: new StringField(),
|
||||
gruppe: new StringField(),
|
||||
mod: new NumberField(),
|
||||
})
|
||||
),
|
||||
mod: new ArrayField(new SchemaField({
|
||||
name: new StringField(),
|
||||
|
|
@ -67,11 +71,13 @@ export class SpecialAbilityDataModel extends BaseItem {
|
|||
}
|
||||
}
|
||||
|
||||
isActive() { // TODO also handle Waffenlimit
|
||||
isActive(options) { // TODO also handle Waffenlimit
|
||||
|
||||
const requirements = this.#getRequirements()
|
||||
|
||||
let passes = false
|
||||
let mod = 0
|
||||
|
||||
const flatActor = foundry.utils.flattenObject(this.parent.actor.system)
|
||||
for (let requirement of requirements) {
|
||||
|
||||
|
|
@ -90,11 +96,55 @@ export class SpecialAbilityDataModel extends BaseItem {
|
|||
passes = targetField <= requirement.maxValue
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
passes = false
|
||||
}
|
||||
|
||||
if (!passes) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return passes
|
||||
if (passes) { // TODO: how are we going to communicate the malus?
|
||||
this.system.waffenLimit.forEach(waff => {
|
||||
if (waff.waffe) {
|
||||
passes = options.weapon.name === waff.waffe
|
||||
if (waff.mod) mod = waff.mod
|
||||
} else if (waff.gruppe) {
|
||||
passes = options.skill.name === waff.gruppe
|
||||
if (waff.mod) mod = waff.mod
|
||||
}
|
||||
|
||||
|
||||
})
|
||||
}
|
||||
|
||||
return {passes, mod}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,255 @@
|
|||
import {XmlImport} from "../xml-import/xml-import.mjs";
|
||||
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 CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ['dsa41', 'dialog', 'combat'],
|
||||
tag: "form",
|
||||
position: {
|
||||
width: 320,
|
||||
height: 540
|
||||
},
|
||||
window: {
|
||||
resizable: false,
|
||||
},
|
||||
form: {
|
||||
submitOnChange: false,
|
||||
closeOnSubmit: true,
|
||||
handler: CombatActionDialog.#onSubmitForm
|
||||
},
|
||||
actions: {
|
||||
selectTarget: CombatActionDialog.#onSelectTarget,
|
||||
selectWeaponAndSkill: CombatActionDialog.#onSelectWeaponAndSkill,
|
||||
selectManeuver: CombatActionDialog.#onSelectManeuver,
|
||||
}
|
||||
}
|
||||
|
||||
static PARTS = {
|
||||
form: {
|
||||
template: 'systems/DSA_4-1/templates/dialog/combat-action.hbs',
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @type {Actor}
|
||||
* @private
|
||||
*/
|
||||
_actor = null
|
||||
|
||||
constructor(actor) {
|
||||
super();
|
||||
this._actor = actor
|
||||
this._targetId = null
|
||||
this._skillId = null
|
||||
this._weaponId = null
|
||||
this._combatManeuverId = null
|
||||
this._actionManager = new ActionManager(this._actor)
|
||||
}
|
||||
|
||||
|
||||
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._combatManeuverId = this._combatManeuverId === 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()
|
||||
}
|
||||
|
||||
_configureRenderOptions(options) {
|
||||
super._configureRenderOptions(options)
|
||||
if (options.window) {
|
||||
options.window.title = `Mit ${this._actor.name} angreifen`
|
||||
}
|
||||
return options
|
||||
}
|
||||
|
||||
#getDistanceBetween(originToken, targetToken) {
|
||||
const distance = game.scenes.current.dimensions.distancePixels
|
||||
|
||||
// get distances between of tokens and thisTokenRepresentative
|
||||
const actorOfToken = game.actors.get(targetToken.actorId)
|
||||
return {
|
||||
id: targetToken._id,
|
||||
x: targetToken.x,
|
||||
y: targetToken.y,
|
||||
actor: actorOfToken,
|
||||
token: targetToken,
|
||||
d: ((Math.sqrt(Math.pow(targetToken.x - originToken.x, 2) + Math.pow(targetToken.y - originToken.y, 2))) / distance).toFixed(2),
|
||||
}
|
||||
}
|
||||
|
||||
#evaluateDistances() {
|
||||
|
||||
// get tokens in range on the current scene
|
||||
const scene = game.scenes.current
|
||||
const tokens = scene.tokens
|
||||
const tokenId = this._actor.getActiveTokens()[0].id
|
||||
const thisTokenRepresentative = tokens.get(tokenId)
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @type {[TokenDistance]}
|
||||
*/
|
||||
return tokens.map(token => {
|
||||
return {
|
||||
isSelected: this._targetId === token.id,
|
||||
...this.#getDistanceBetween(thisTokenRepresentative, token)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
#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
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
this._weapons = weapons
|
||||
return this._weapons
|
||||
|
||||
}
|
||||
|
||||
#evaluateManeuvers() {
|
||||
const manager = this._actionManager
|
||||
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 target = game.actors.get(this._targetId)
|
||||
this._maneuvers = manager.evaluate({
|
||||
target,
|
||||
weapon,
|
||||
skill
|
||||
}).filter(p => p.type === ActionManager.ATTACK).map(action => {
|
||||
return {
|
||||
isSelected: this._combatManeuverId === action.name,
|
||||
id: action.name,
|
||||
name: action.name,
|
||||
type: action.type,
|
||||
source: action.source,
|
||||
cost: action.cost,
|
||||
mod: action.mod,
|
||||
}
|
||||
})
|
||||
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.tokenDistances = this.#evaluateDistances()
|
||||
context.weapons = this.#evaluateWeapons()
|
||||
|
||||
if (this._targetId && this._weaponId && this._skillId) {
|
||||
context.maneuver = this.#evaluateManeuvers()
|
||||
}
|
||||
const maneuver = this._maneuvers?.find(p => p.id === this._combatManeuverId)
|
||||
if (maneuver) {
|
||||
context.canMod = maneuver.mod != undefined
|
||||
}
|
||||
|
||||
context.targetNumber = context.weapons.find(p => p.weaponId === this._weaponId && p.skillId === this._skillId)?.combatStatistics.at
|
||||
|
||||
// TODO get W/M of weapon NOW
|
||||
|
||||
context.ready = this._targetId && this._weaponId && this._skillId && this._combatManeuverId
|
||||
return context
|
||||
} else {
|
||||
ui.notifications.error(`Feature funktioniert nur wenn der Akteur ein Token auf der aktuellen Szene hat`);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
_onRender(context, options) {
|
||||
const target = this.element.querySelector(".actions button .value")
|
||||
this.element.querySelectorAll('[name="mod"], [name="malus"]').forEach(e => e.addEventListener('change', (event) => {
|
||||
|
||||
const at = Number(context.targetNumber)
|
||||
const malus = Number(this.element.querySelector('[name="malus"]').value)
|
||||
const mod = Number(this.element.querySelector('[name="mod"]').value)
|
||||
const maneuver = this._maneuvers?.find(p => p.id === this._combatManeuverId)
|
||||
const result = at + (maneuver.mod?.(mod) ?? 0) + malus
|
||||
target.textContent = `(${result})`
|
||||
}))
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -16,8 +16,4 @@ export class SpecialAbility extends Item {
|
|||
}
|
||||
}
|
||||
|
||||
isActive() {
|
||||
return true
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,97 +23,121 @@ export class ActionManager {
|
|||
cost: ActionManager.FREE,
|
||||
type: ActionManager.DEFENSE,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Rufen",
|
||||
cost: ActionManager.FREE,
|
||||
type: ActionManager.INTERACTION,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Sich zu Boden fallen lassen",
|
||||
cost: ActionManager.FREE,
|
||||
type: ActionManager.MOVEMENT,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Waffe oder Gegenstand fallen lassen",
|
||||
cost: ActionManager.FREE,
|
||||
type: ActionManager.INTERACTION,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "getragenes Artefakt aktivieren",
|
||||
cost: ActionManager.FREE,
|
||||
type: ActionManager.INTERACTION,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Schnellziehen",
|
||||
cost: ActionManager.FREE,
|
||||
type: ActionManager.INTERACTION,
|
||||
source: ActionManager.SF,
|
||||
eval: () => this.#hatSonderfertigkeit("Schnellziehen") && this.#evalSonderfertigkeitRequirements("Schnellziehen")
|
||||
eval: (options) => this.#hatSonderfertigkeit("Schnellziehen", options) && this.#evalSonderfertigkeitRequirements("Schnellziehen", options)
|
||||
}
|
||||
]
|
||||
|
||||
#regularActions = [
|
||||
{
|
||||
name: "Angriffsaktion",
|
||||
name: "Nahkampfangriff",
|
||||
type: ActionManager.ATTACK,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => this.#hatWaffeinHand()
|
||||
eval: (options) => this.#hatWaffeinHand() && !this.#hatFernkampfWaffeinHand()
|
||||
},
|
||||
{
|
||||
name: "Fernkampfangriff",
|
||||
type: ActionManager.ATTACK,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: (options) => this.#hatFernkampfWaffeinHand(),
|
||||
},
|
||||
{
|
||||
name: "Angesagter Fernkampfangriff",
|
||||
type: ActionManager.ATTACK,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: (options) => this.#hatFernkampfWaffeinHand(),
|
||||
mod: (value) => -value * 2
|
||||
},
|
||||
{
|
||||
name: "Scharfer Schuss",
|
||||
type: ActionManager.ATTACK,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.SF,
|
||||
eval: (options) => this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Scharfschütze", options) && this.#evalSonderfertigkeitRequirements("Scharfschütze", options),
|
||||
mod: (value) => -value
|
||||
},
|
||||
{
|
||||
name: "Schnellschuss",
|
||||
type: ActionManager.INTERACTION,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => this.#hatFernkampfWaffeinHand()
|
||||
eval: (options) => this.#hatFernkampfWaffeinHand()
|
||||
},
|
||||
{
|
||||
name: "Schnellschuss (Scharfschütze)",
|
||||
type: ActionManager.INTERACTION,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.SF,
|
||||
eval: () => this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Scharfschütze") && this.#evalSonderfertigkeitRequirements("Scharfschütze")
|
||||
eval: (options) => this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Scharfschütze", options) && this.#evalSonderfertigkeitRequirements("Scharfschütze", options)
|
||||
},
|
||||
{
|
||||
name: "Abwehraktion",
|
||||
type: ActionManager.DEFENSE,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Bewegen",
|
||||
type: ActionManager.MOVEMENT,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Position",
|
||||
type: ActionManager.MOVEMENT,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Finte",
|
||||
type: ActionManager.ATTACK,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.SF,
|
||||
eval: () =>
|
||||
mod: (value) => value,
|
||||
eval: (options) =>
|
||||
this.#hatWaffeinHand() &&
|
||||
this.#hatSonderfertigkeit("Finte") &&
|
||||
this.#evalSonderfertigkeitRequirements("Finte")
|
||||
this.#hatSonderfertigkeit("Finte", options) &&
|
||||
this.#evalSonderfertigkeitRequirements("Finte", options)
|
||||
|
||||
},
|
||||
{
|
||||
|
|
@ -121,23 +145,25 @@ export class ActionManager {
|
|||
type: ActionManager.ATTACK,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
mod: (value) => -(value),
|
||||
eval: (options) => !this.#hatFernkampfWaffeinHand()
|
||||
},
|
||||
{
|
||||
name: "Wuchtschlag",
|
||||
type: ActionManager.ATTACK,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.SF,
|
||||
eval: () => this.#hatSonderfertigkeit("Wuchtschlag")
|
||||
&& this.#evalSonderfertigkeitRequirements("Wuchtschlag")
|
||||
mod: (value) => -(value),
|
||||
eval: (options) => !this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Wuchtschlag", options)
|
||||
&& this.#evalSonderfertigkeitRequirements("Wuchtschlag", options)
|
||||
},
|
||||
{
|
||||
name: "Betäubungsschlag",
|
||||
type: ActionManager.ATTACK,
|
||||
cost: ActionManager.REGULAR,
|
||||
source: ActionManager.SF,
|
||||
eval: () => this.#hatSonderfertigkeit("Betäubungsschlag")
|
||||
&& this.#evalSonderfertigkeitRequirements("Betäubungsschlag")
|
||||
eval: (options) => !this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Betäubungsschlag", options)
|
||||
&& this.#evalSonderfertigkeitRequirements("Betäubungsschlag", options)
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -147,76 +173,76 @@ export class ActionManager {
|
|||
type: ActionManager.TALENT,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Waffe ziehen",
|
||||
type: ActionManager.INTERACTION,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Sprinten",
|
||||
type: ActionManager.MOVEMENT,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Gegenstand benutzen",
|
||||
type: ActionManager.INTERACTION,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Schnellladen (Bogen)",
|
||||
type: ActionManager.INTERACTION,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.SF,
|
||||
eval: () => this.#hatMunition()
|
||||
&& this.#hatFernkampfWaffeinHand("Bogen")
|
||||
&& this.#hatSonderfertigkeit("Schnellladen (Bogen)")
|
||||
&& this.#evalSonderfertigkeitRequirements("Schnellladen (Bogen)")
|
||||
eval: (options) => this.#hatMunition()
|
||||
&& this.#hatFernkampfWaffeinHand("Bogen", options)
|
||||
&& this.#hatSonderfertigkeit("Schnellladen (Bogen)", options)
|
||||
&& this.#evalSonderfertigkeitRequirements("Schnellladen (Bogen)", options)
|
||||
},
|
||||
{
|
||||
name: "Schnellladen (Armbrust)",
|
||||
type: ActionManager.INTERACTION,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.SF,
|
||||
eval: () => this.#hatMunition()
|
||||
&& this.#hatFernkampfWaffeinHand("Armbrust")
|
||||
&& this.#hatSonderfertigkeit("Schnellladen (Armbrust)")
|
||||
&& this.#evalSonderfertigkeitRequirements("Schnellladen (Armbrust)")
|
||||
eval: (options) => this.#hatMunition()
|
||||
&& this.#hatFernkampfWaffeinHand("Armbrust", options)
|
||||
&& this.#hatSonderfertigkeit("Schnellladen (Armbrust)", options)
|
||||
&& this.#evalSonderfertigkeitRequirements("Schnellladen (Armbrust)", options)
|
||||
},
|
||||
{
|
||||
name: "Nachladen",
|
||||
type: ActionManager.INTERACTION,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => this.#hatMunition()
|
||||
eval: (options) => this.#hatMunition()
|
||||
},
|
||||
{
|
||||
name: "Talenteinsatz",
|
||||
type: ActionManager.TALENT,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.DEFAULT,
|
||||
eval: () => true
|
||||
eval: (options) => true
|
||||
},
|
||||
{
|
||||
name: "Zaubern",
|
||||
type: ActionManager.SPELL,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.SF,
|
||||
eval: () => this.#hatSonderfertigkeitBeginnendMit("Repräsentation:")
|
||||
eval: (options) => this.#hatSonderfertigkeitBeginnendMit("Repräsentation:", options)
|
||||
},
|
||||
{
|
||||
name: "Liturgie wirken",
|
||||
type: ActionManager.SPELL,
|
||||
cost: ActionManager.CONTINUING,
|
||||
source: ActionManager.SF,
|
||||
eval: () => this.#hatSonderfertigkeitBeginnendMit("Liturgiekenntnis")
|
||||
eval: (options) => this.#hatSonderfertigkeitBeginnendMit("Liturgiekenntnis", options)
|
||||
}
|
||||
]
|
||||
|
||||
|
|
@ -236,25 +262,30 @@ export class ActionManager {
|
|||
return item != null
|
||||
}
|
||||
|
||||
#hatSonderfertigkeitBeginnendMit(name) {
|
||||
#hatSonderfertigkeitBeginnendMit(name, options) {
|
||||
return this.actor.itemTypes["SpecialAbility"]?.find(p => p.name.startsWith(name)) != null
|
||||
}
|
||||
|
||||
#hatSonderfertigkeit(name) {
|
||||
#hatSonderfertigkeit(name, options) {
|
||||
return this.actor.itemTypes["SpecialAbility"]?.find(p => p.name === name) != null
|
||||
}
|
||||
|
||||
#evalSonderfertigkeitRequirements(nameOfSF) {
|
||||
#evalSonderfertigkeitRequirements(nameOfSF, options) {
|
||||
const sf = this.actor.itemTypes["SpecialAbility"].find(p => p.name === nameOfSF)
|
||||
return sf.system.isActive()
|
||||
return sf.system.isActive(options).passes
|
||||
}
|
||||
|
||||
evaluate() {
|
||||
/**
|
||||
*
|
||||
* @param {{target: String?}} options
|
||||
*/
|
||||
|
||||
evaluate(options) {
|
||||
let actionArray = [...this.#freeActions, ...this.#regularActions, ...this.#continuingActions]
|
||||
console.log(this.actor, actionArray.map((action) => {
|
||||
return {
|
||||
...action,
|
||||
eval: action.eval()
|
||||
eval: action.eval(options)
|
||||
}
|
||||
}))
|
||||
const validActions = actionArray.filter(action => action.eval())
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import Meta from "./character/meta.mjs"
|
|||
import Skills from "./character/skills.mjs"
|
||||
import Social from "./character/social.mjs";
|
||||
import Spells from "./character/spells.mjs"
|
||||
import {CombatActionDialog} from "../dialog/combatAction.mjs";
|
||||
|
||||
const {HandlebarsApplicationMixin} = foundry.applications.api
|
||||
const {ActorSheetV2} = foundry.applications.sheets
|
||||
|
|
@ -36,6 +37,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
|||
openEmbeddedDocument: CharacterSheet.#openEmbeddedDocument,
|
||||
openCultureDocument: CharacterSheet.#openCultureDocument,
|
||||
openSpeciesDocument: CharacterSheet.#openSpeciesDocument,
|
||||
openCombatAction: CharacterSheet.#openCombatAction,
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -143,6 +145,10 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
|
|||
this.document.itemTypes["Species"]?.[0]?.sheet.render(true)
|
||||
}
|
||||
|
||||
static #openCombatAction() {
|
||||
new CombatActionDialog(this.document).render(true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle form submission
|
||||
* @this {AdvantageSheet}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,91 @@
|
|||
@keyframes pulse {
|
||||
0% {
|
||||
text-shadow: 0 0 0 red;
|
||||
}
|
||||
75% {
|
||||
text-shadow: 0 0 4px red;
|
||||
}
|
||||
100% {
|
||||
text-shadow: 0 0 0 red;
|
||||
}
|
||||
}
|
||||
|
||||
.dsa41.dialog.combat {
|
||||
|
||||
.window-content > section {
|
||||
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
height: 100%;
|
||||
|
||||
fieldset {
|
||||
|
||||
flex: 1;
|
||||
|
||||
border-bottom: 0;
|
||||
border-left: 0;
|
||||
border-right: 0;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
legend {
|
||||
text-align: center;
|
||||
padding: 0 16px;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ul {
|
||||
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
text-indent: 0;
|
||||
|
||||
li {
|
||||
|
||||
height: 32px;
|
||||
display: grid;
|
||||
line-height: 32px;
|
||||
vertical-align: middle;
|
||||
|
||||
grid-template-columns: 32px 1fr 83px;
|
||||
grid-template-rows: 1fr;
|
||||
border: 1px transparent;
|
||||
margin: 8px;
|
||||
gap: 0 8px;
|
||||
|
||||
&.selected {
|
||||
background-color: rgba(255, 140, 0, 0.2);
|
||||
border: 1px solid orange;
|
||||
border-radius: 16px;
|
||||
}
|
||||
|
||||
&.name-only {
|
||||
display: block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.malus-and-mod {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
grid-template-rows: 1fr;
|
||||
gap: 0 8px;
|
||||
}
|
||||
|
||||
.actions {
|
||||
flex: 0;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
button.ready {
|
||||
animation: pulse 2s infinite;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -24,4 +24,5 @@
|
|||
@use "organisms/species-sheet";
|
||||
@use "organisms/profession-sheet";
|
||||
@use "organisms/xml-import-dialog";
|
||||
@use "organisms/combat-action-dialog";
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,58 @@
|
|||
<section>
|
||||
|
||||
<fieldset>
|
||||
<legend>Ziel auswählen</legend>
|
||||
|
||||
<ul>
|
||||
{{#each tokenDistances}}
|
||||
<li class="token {{#if isSelected}}selected{{/if}}" data-action="selectTarget"
|
||||
data-target-id="{{this.id}}"><img src="{{this.token.texture.src}}"
|
||||
style="width: 32px; height: 32px"/><span>{{this.actor.name}}</span><span>({{this.d}} {{../distanceUnit}}
|
||||
)</span></li>
|
||||
{{/each}}
|
||||
</ul>
|
||||
|
||||
</fieldset>
|
||||
|
||||
<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}}"><img src="{{this.img}}"
|
||||
style="width: 32px; height: 32px"/><span>{{this.name}}
|
||||
({{this.skillName}})</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>
|
||||
<legend>Erschwernisse und Ansagen</legend>
|
||||
<div class="malus-and-mod">
|
||||
<label>Umstände
|
||||
<input name="malus" type="number">
|
||||
</label>
|
||||
<label>Ansage
|
||||
<input name="mod" type="number" {{disabled (not canMod)}}>
|
||||
</label>
|
||||
</div>
|
||||
</fieldset>
|
||||
|
||||
|
||||
<div class="actions">
|
||||
<button {{#if ready}}class="ready"{{/if}} type="submit"><i class="fa-solid fa-swords"></i>Angreifen <span
|
||||
class="value"></span></button>
|
||||
</div>
|
||||
|
||||
</section>
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
<div class="player-action {{this.source}} {{this.type}}">
|
||||
<div class="player-action {{this.source}} {{this.type}}" data-action="openCombatAction">
|
||||
|
||||
<span class="name">{{this.name}}</span>
|
||||
<span class="time">{{this.cost}}</span>
|
||||
|
|
|
|||
Loading…
Reference in New Issue