Compare commits

..

2 Commits

Author SHA1 Message Date
macniel 7f18c62270 implements combat attack dialog 2025-10-22 13:21:24 +02:00
macniel b2d9a82af8 adjusting SFs for better and consistent parsing 2025-10-22 13:21:05 +02:00
15 changed files with 698 additions and 96 deletions

View File

@ -48,7 +48,11 @@ export class SpecialAbilityDataModel extends BaseItem {
}) })
), ),
waffenLimit: new ArrayField( waffenLimit: new ArrayField(
new StringField(), new SchemaField({
waffe: new StringField(),
gruppe: new StringField(),
mod: new NumberField(),
})
), ),
mod: new ArrayField(new SchemaField({ mod: new ArrayField(new SchemaField({
name: new StringField(), 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() const requirements = this.#getRequirements()
let passes = false let passes = false
let mod = 0
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) {
@ -90,11 +96,55 @@ export class SpecialAbilityDataModel extends BaseItem {
passes = targetField <= requirement.maxValue 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) { if (!passes) {
break 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}
} }
} }

View File

@ -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})`
}))
}
}

View File

@ -16,8 +16,4 @@ export class SpecialAbility extends Item {
} }
} }
isActive() {
return true
}
} }

View File

@ -23,97 +23,121 @@ export class ActionManager {
cost: ActionManager.FREE, cost: ActionManager.FREE,
type: ActionManager.DEFENSE, type: ActionManager.DEFENSE,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Rufen", name: "Rufen",
cost: ActionManager.FREE, cost: ActionManager.FREE,
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Sich zu Boden fallen lassen", name: "Sich zu Boden fallen lassen",
cost: ActionManager.FREE, cost: ActionManager.FREE,
type: ActionManager.MOVEMENT, type: ActionManager.MOVEMENT,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Waffe oder Gegenstand fallen lassen", name: "Waffe oder Gegenstand fallen lassen",
cost: ActionManager.FREE, cost: ActionManager.FREE,
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "getragenes Artefakt aktivieren", name: "getragenes Artefakt aktivieren",
cost: ActionManager.FREE, cost: ActionManager.FREE,
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Schnellziehen", name: "Schnellziehen",
cost: ActionManager.FREE, cost: ActionManager.FREE,
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
source: ActionManager.SF, source: ActionManager.SF,
eval: () => this.#hatSonderfertigkeit("Schnellziehen") && this.#evalSonderfertigkeitRequirements("Schnellziehen") eval: (options) => this.#hatSonderfertigkeit("Schnellziehen", options) && this.#evalSonderfertigkeitRequirements("Schnellziehen", options)
} }
] ]
#regularActions = [ #regularActions = [
{ {
name: "Angriffsaktion", name: "Nahkampfangriff",
type: ActionManager.ATTACK, type: ActionManager.ATTACK,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.DEFAULT, 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", name: "Schnellschuss",
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => this.#hatFernkampfWaffeinHand() eval: (options) => this.#hatFernkampfWaffeinHand()
}, },
{ {
name: "Schnellschuss (Scharfschütze)", name: "Schnellschuss (Scharfschütze)",
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.SF, 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", name: "Abwehraktion",
type: ActionManager.DEFENSE, type: ActionManager.DEFENSE,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Bewegen", name: "Bewegen",
type: ActionManager.MOVEMENT, type: ActionManager.MOVEMENT,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Position", name: "Position",
type: ActionManager.MOVEMENT, type: ActionManager.MOVEMENT,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Finte", name: "Finte",
type: ActionManager.ATTACK, type: ActionManager.ATTACK,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.SF, source: ActionManager.SF,
eval: () => mod: (value) => value,
eval: (options) =>
this.#hatWaffeinHand() && this.#hatWaffeinHand() &&
this.#hatSonderfertigkeit("Finte") && this.#hatSonderfertigkeit("Finte", options) &&
this.#evalSonderfertigkeitRequirements("Finte") this.#evalSonderfertigkeitRequirements("Finte", options)
}, },
{ {
@ -121,23 +145,25 @@ export class ActionManager {
type: ActionManager.ATTACK, type: ActionManager.ATTACK,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true mod: (value) => -(value),
eval: (options) => !this.#hatFernkampfWaffeinHand()
}, },
{ {
name: "Wuchtschlag", name: "Wuchtschlag",
type: ActionManager.ATTACK, type: ActionManager.ATTACK,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.SF, source: ActionManager.SF,
eval: () => this.#hatSonderfertigkeit("Wuchtschlag") mod: (value) => -(value),
&& this.#evalSonderfertigkeitRequirements("Wuchtschlag") eval: (options) => !this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Wuchtschlag", options)
&& this.#evalSonderfertigkeitRequirements("Wuchtschlag", options)
}, },
{ {
name: "Betäubungsschlag", name: "Betäubungsschlag",
type: ActionManager.ATTACK, type: ActionManager.ATTACK,
cost: ActionManager.REGULAR, cost: ActionManager.REGULAR,
source: ActionManager.SF, source: ActionManager.SF,
eval: () => this.#hatSonderfertigkeit("Betäubungsschlag") eval: (options) => !this.#hatFernkampfWaffeinHand() && this.#hatSonderfertigkeit("Betäubungsschlag", options)
&& this.#evalSonderfertigkeitRequirements("Betäubungsschlag") && this.#evalSonderfertigkeitRequirements("Betäubungsschlag", options)
} }
] ]
@ -147,76 +173,76 @@ export class ActionManager {
type: ActionManager.TALENT, type: ActionManager.TALENT,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Waffe ziehen", name: "Waffe ziehen",
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Sprinten", name: "Sprinten",
type: ActionManager.MOVEMENT, type: ActionManager.MOVEMENT,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Gegenstand benutzen", name: "Gegenstand benutzen",
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Schnellladen (Bogen)", name: "Schnellladen (Bogen)",
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.SF, source: ActionManager.SF,
eval: () => this.#hatMunition() eval: (options) => this.#hatMunition()
&& this.#hatFernkampfWaffeinHand("Bogen") && this.#hatFernkampfWaffeinHand("Bogen", options)
&& this.#hatSonderfertigkeit("Schnellladen (Bogen)") && this.#hatSonderfertigkeit("Schnellladen (Bogen)", options)
&& this.#evalSonderfertigkeitRequirements("Schnellladen (Bogen)") && this.#evalSonderfertigkeitRequirements("Schnellladen (Bogen)", options)
}, },
{ {
name: "Schnellladen (Armbrust)", name: "Schnellladen (Armbrust)",
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.SF, source: ActionManager.SF,
eval: () => this.#hatMunition() eval: (options) => this.#hatMunition()
&& this.#hatFernkampfWaffeinHand("Armbrust") && this.#hatFernkampfWaffeinHand("Armbrust", options)
&& this.#hatSonderfertigkeit("Schnellladen (Armbrust)") && this.#hatSonderfertigkeit("Schnellladen (Armbrust)", options)
&& this.#evalSonderfertigkeitRequirements("Schnellladen (Armbrust)") && this.#evalSonderfertigkeitRequirements("Schnellladen (Armbrust)", options)
}, },
{ {
name: "Nachladen", name: "Nachladen",
type: ActionManager.INTERACTION, type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => this.#hatMunition() eval: (options) => this.#hatMunition()
}, },
{ {
name: "Talenteinsatz", name: "Talenteinsatz",
type: ActionManager.TALENT, type: ActionManager.TALENT,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT, source: ActionManager.DEFAULT,
eval: () => true eval: (options) => true
}, },
{ {
name: "Zaubern", name: "Zaubern",
type: ActionManager.SPELL, type: ActionManager.SPELL,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.SF, source: ActionManager.SF,
eval: () => this.#hatSonderfertigkeitBeginnendMit("Repräsentation:") eval: (options) => this.#hatSonderfertigkeitBeginnendMit("Repräsentation:", options)
}, },
{ {
name: "Liturgie wirken", name: "Liturgie wirken",
type: ActionManager.SPELL, type: ActionManager.SPELL,
cost: ActionManager.CONTINUING, cost: ActionManager.CONTINUING,
source: ActionManager.SF, source: ActionManager.SF,
eval: () => this.#hatSonderfertigkeitBeginnendMit("Liturgiekenntnis") eval: (options) => this.#hatSonderfertigkeitBeginnendMit("Liturgiekenntnis", options)
} }
] ]
@ -236,25 +262,30 @@ export class ActionManager {
return item != null return item != null
} }
#hatSonderfertigkeitBeginnendMit(name) { #hatSonderfertigkeitBeginnendMit(name, options) {
return this.actor.itemTypes["SpecialAbility"]?.find(p => p.name.startsWith(name)) != null 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 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) 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] let actionArray = [...this.#freeActions, ...this.#regularActions, ...this.#continuingActions]
console.log(this.actor, actionArray.map((action) => { console.log(this.actor, actionArray.map((action) => {
return { return {
...action, ...action,
eval: action.eval() eval: action.eval(options)
} }
})) }))
const validActions = actionArray.filter(action => action.eval()) const validActions = actionArray.filter(action => action.eval())

View File

@ -7,6 +7,7 @@ import Meta from "./character/meta.mjs"
import Skills from "./character/skills.mjs" import Skills from "./character/skills.mjs"
import Social from "./character/social.mjs"; import Social from "./character/social.mjs";
import Spells from "./character/spells.mjs" import Spells from "./character/spells.mjs"
import {CombatActionDialog} from "../dialog/combatAction.mjs";
const {HandlebarsApplicationMixin} = foundry.applications.api const {HandlebarsApplicationMixin} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets const {ActorSheetV2} = foundry.applications.sheets
@ -36,6 +37,7 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
openEmbeddedDocument: CharacterSheet.#openEmbeddedDocument, openEmbeddedDocument: CharacterSheet.#openEmbeddedDocument,
openCultureDocument: CharacterSheet.#openCultureDocument, openCultureDocument: CharacterSheet.#openCultureDocument,
openSpeciesDocument: CharacterSheet.#openSpeciesDocument, openSpeciesDocument: CharacterSheet.#openSpeciesDocument,
openCombatAction: CharacterSheet.#openCombatAction,
} }
} }
@ -143,6 +145,10 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
this.document.itemTypes["Species"]?.[0]?.sheet.render(true) this.document.itemTypes["Species"]?.[0]?.sheet.render(true)
} }
static #openCombatAction() {
new CombatActionDialog(this.document).render(true)
}
/** /**
* Handle form submission * Handle form submission
* @this {AdvantageSheet} * @this {AdvantageSheet}

View File

@ -24,15 +24,33 @@
} }
], ],
"waffenLimit": [ "waffenLimit": [
"Anderthalbhänder", {
"Dolchen", "waffe": "Anderthalbhänder"
"Fechtwaffen", },
"Infanteriewaffen", {
"Kettenstäben", "waffe": "Dolchen"
"Säbel", },
"Schwerter", {
"Speeren", "waffe": "Fechtwaffen"
"Stäben" },
{
"waffe": "Infanteriewaffen"
},
{
"waffe": "Kettenstäben"
},
{
"waffe": "Säbel"
},
{
"waffe": "Schwerter"
},
{
"waffe": "Speeren"
},
{
"waffe": "Stäben"
}
], ],
"text": "(Angriffsmanöver; +4 zum Einleiten) In vielen Kämpfen ist es nicht so, dass ein Kämpfer einen Schlag ausführt, in Grundstellung zurückgeht und den Schlag seines Gegenübers erwartet, sondern vielmehr so, dass er versucht, seinen Gegner mit möglichst vielen Hieben oder Stichen einzudecken und ihn zur reinen Parade zu zwingen, um dann vielleicht aus dieser Schlagfolge heraus mit einer Finte oder einem ähnlichen Manöver den entscheidenden Schlag zu führen. Spieltechnisch heißt dies, dass der Angreifer Runde für Runde seine Abwehraktion in eine Angriffsaktion umwandelt und dabei nach vorne drängt (also jede Aktion mit einer Freien Aktion Schritt verbindet) und durch den so energisch vorgetragenen Angriff den Gegner dazu zwingt, seinen Angriff Runde für Runde in eine Abwehr umzuwandeln und einen Schritt zurückzuweichen, also eine Freie Aktion Schritt zu tun, selbst wenn die eigentliche AT misslingt. Steht ihm diese Freie Aktion nicht mehr zur Verfügung, wird er trotzdem zurückgedrängt, erleidet aber zusätzliche Parade-Einbußen von 4 Punkten. Für den Verteidiger gilt der übliche Zuschlag von 4 Punkten für das Umwandeln von Aktionen; wenn der Verteidiger eine Waffe führt, mit der Umwandeln normalerweise verboten ist, darf er zwar zur Abwehr eines Ausfalls umwandeln, erleidet aber einen Zuschlag von +8. Kenntnis der Sonderfertigkeit Defensiver Kampfstil senkt die genannten Mali um jeweils 4 Punkte. Die erste Attacke eines Ausfalls ist immer um 4 Punkte erschwert (zusätzlich zu allen eventuellen sonstigen Erschwernissen), um den Gegner überhaupt in die Defensive zu bringen, aus der heraus er selbst nicht mehr attackieren kann. Ein Ausfall kann mit Anderthalbhändern, Dolchen, Fechtwaffen, Infanteriewaffen, Kettenstäben, Säbeln, Schwertern, Speeren und Stäben durchgeführt werden; der Angreifer muss die Sonderfertigkeit Ausfall beherrschen und darf maximal mit BE 4 belastet sein. Außerdem muss er eine höhere INI als sein Gegner besitzen. Ein Ausfall ist nur möglich, wenn der Angreifer eine gewisse Bewegungsfreiheit hat also z.B. nicht in beengter Umgebung (Seite 58). Im Gegensatz zu anderen Manövern muss der Ausfall nicht aus der optimalen Distanzklasse der Angriffswaffe heraus begonnen werden, sondern kann eine DK weiter beginnen (und die erste Attacke der Distanzverkürzung dienen). In einem Ausfall sind grundsätzlich auch Wuchtschläge und Finten (jeweils bis zu einer Ansage von +4) möglich; sie treten an die Stelle der gewöhnlichen Attacken. Ein Ausfall kann mit den Manövern Angriff zum Niederwerfen, Hammerschlag, Gezielter Stich oder Todesstoß beendet werden. Weitere Manöver lassen sich nicht in einen Ausfall einbauen, jedoch können die vorgetragenen Attacken auch solche zur Veränderung der Distanzklasse sein. Kämpfer mit einem Schild sind in ihren Attacken zusätzlich zum AT-Abzug des Schildes mit 2 Punkten bei jeder Attacke behindert. Ein Kämpfer kann maximal so viele Hiebe in Folge setzen, wie seine halbe KO beträgt. Eine Attacke-Serie endet: wenn eine AT des Angreifers misslingt. wenn dem Verteidiger ein angesagtes Manöver Gezieltes Ausweichen (Seite 66) gelingt, das zusätzlich zu den Erschwernissen nach Distanzklasse um weitere 2 Punkte erschwert ist. wenn dem Verteidiger eine glückliche Parade (Seite 84) gelingt. wenn der Angreifer die Höchstzahl möglicher Attacken aufgebraucht hat (siehe oben). wenn der Angreifer den Ausfall freiwillig abbricht. wenn der Verteidiger nicht weiter zurückgedrängt werden kann (weil er z.B. mit dem Rücken zu einer Mauer steht); die letzte PA des Verteidigers ist um 4 Punkte erschwert. wenn der Verteidiger einfach stehen bleibt. Dies schafft er nur, wenn ihm eine MU-Probe +4 gelingt, erschwert um die Zahl der bereits erlittenen Treffer in diesem Ausfall. Seine Parade ist, egal ob bei Ge- oder Misslingen der MU-Probe allerdings um 4 Punkte erschwert. In allen vier erstgenannten Fällen ist die AT-Serie sofort beendet und der Angreifer verliert 1W6 Punkte INI. Wenn der Angreifer den Ausfall nicht freiwillig abgebrochen hat (also eine der ersten vier Möglichkeiten eingetreten ist), darf der Verteidiger sofort einen Passierschlag ausführen (Seite 83). Wenn der Verteidiger nicht weiter zurückweichen kann oder will, endet der Ausfall mit einer abschließenden AT des Angreifers (oben genannte Manöver möglich; PA wie oben genannt um 4 erschwert); die Kämpfer befinden sich dann in einer vom Angreifer gewünschten Distanzklasse. " "text": "(Angriffsmanöver; +4 zum Einleiten) In vielen Kämpfen ist es nicht so, dass ein Kämpfer einen Schlag ausführt, in Grundstellung zurückgeht und den Schlag seines Gegenübers erwartet, sondern vielmehr so, dass er versucht, seinen Gegner mit möglichst vielen Hieben oder Stichen einzudecken und ihn zur reinen Parade zu zwingen, um dann vielleicht aus dieser Schlagfolge heraus mit einer Finte oder einem ähnlichen Manöver den entscheidenden Schlag zu führen. Spieltechnisch heißt dies, dass der Angreifer Runde für Runde seine Abwehraktion in eine Angriffsaktion umwandelt und dabei nach vorne drängt (also jede Aktion mit einer Freien Aktion Schritt verbindet) und durch den so energisch vorgetragenen Angriff den Gegner dazu zwingt, seinen Angriff Runde für Runde in eine Abwehr umzuwandeln und einen Schritt zurückzuweichen, also eine Freie Aktion Schritt zu tun, selbst wenn die eigentliche AT misslingt. Steht ihm diese Freie Aktion nicht mehr zur Verfügung, wird er trotzdem zurückgedrängt, erleidet aber zusätzliche Parade-Einbußen von 4 Punkten. Für den Verteidiger gilt der übliche Zuschlag von 4 Punkten für das Umwandeln von Aktionen; wenn der Verteidiger eine Waffe führt, mit der Umwandeln normalerweise verboten ist, darf er zwar zur Abwehr eines Ausfalls umwandeln, erleidet aber einen Zuschlag von +8. Kenntnis der Sonderfertigkeit Defensiver Kampfstil senkt die genannten Mali um jeweils 4 Punkte. Die erste Attacke eines Ausfalls ist immer um 4 Punkte erschwert (zusätzlich zu allen eventuellen sonstigen Erschwernissen), um den Gegner überhaupt in die Defensive zu bringen, aus der heraus er selbst nicht mehr attackieren kann. Ein Ausfall kann mit Anderthalbhändern, Dolchen, Fechtwaffen, Infanteriewaffen, Kettenstäben, Säbeln, Schwertern, Speeren und Stäben durchgeführt werden; der Angreifer muss die Sonderfertigkeit Ausfall beherrschen und darf maximal mit BE 4 belastet sein. Außerdem muss er eine höhere INI als sein Gegner besitzen. Ein Ausfall ist nur möglich, wenn der Angreifer eine gewisse Bewegungsfreiheit hat also z.B. nicht in beengter Umgebung (Seite 58). Im Gegensatz zu anderen Manövern muss der Ausfall nicht aus der optimalen Distanzklasse der Angriffswaffe heraus begonnen werden, sondern kann eine DK weiter beginnen (und die erste Attacke der Distanzverkürzung dienen). In einem Ausfall sind grundsätzlich auch Wuchtschläge und Finten (jeweils bis zu einer Ansage von +4) möglich; sie treten an die Stelle der gewöhnlichen Attacken. Ein Ausfall kann mit den Manövern Angriff zum Niederwerfen, Hammerschlag, Gezielter Stich oder Todesstoß beendet werden. Weitere Manöver lassen sich nicht in einen Ausfall einbauen, jedoch können die vorgetragenen Attacken auch solche zur Veränderung der Distanzklasse sein. Kämpfer mit einem Schild sind in ihren Attacken zusätzlich zum AT-Abzug des Schildes mit 2 Punkten bei jeder Attacke behindert. Ein Kämpfer kann maximal so viele Hiebe in Folge setzen, wie seine halbe KO beträgt. Eine Attacke-Serie endet: wenn eine AT des Angreifers misslingt. wenn dem Verteidiger ein angesagtes Manöver Gezieltes Ausweichen (Seite 66) gelingt, das zusätzlich zu den Erschwernissen nach Distanzklasse um weitere 2 Punkte erschwert ist. wenn dem Verteidiger eine glückliche Parade (Seite 84) gelingt. wenn der Angreifer die Höchstzahl möglicher Attacken aufgebraucht hat (siehe oben). wenn der Angreifer den Ausfall freiwillig abbricht. wenn der Verteidiger nicht weiter zurückgedrängt werden kann (weil er z.B. mit dem Rücken zu einer Mauer steht); die letzte PA des Verteidigers ist um 4 Punkte erschwert. wenn der Verteidiger einfach stehen bleibt. Dies schafft er nur, wenn ihm eine MU-Probe +4 gelingt, erschwert um die Zahl der bereits erlittenen Treffer in diesem Ausfall. Seine Parade ist, egal ob bei Ge- oder Misslingen der MU-Probe allerdings um 4 Punkte erschwert. In allen vier erstgenannten Fällen ist die AT-Serie sofort beendet und der Angreifer verliert 1W6 Punkte INI. Wenn der Angreifer den Ausfall nicht freiwillig abgebrochen hat (also eine der ersten vier Möglichkeiten eingetreten ist), darf der Verteidiger sofort einen Passierschlag ausführen (Seite 83). Wenn der Verteidiger nicht weiter zurückweichen kann oder will, endet der Ausfall mit einer abschließenden AT des Angreifers (oben genannte Manöver möglich; PA wie oben genannt um 4 erschwert); die Kämpfer befinden sich dann in einer vom Angreifer gewünschten Distanzklasse. "
} }

View File

@ -16,17 +16,39 @@
} }
], ],
"waffenLimit": [ "waffenLimit": [
"Anderthalbhänder", {
"Hiebwaffen", "waffe": "Anderthalbhänder"
"Infanteriewaffen", },
"Kettenstäbe", {
"Kettenwaffen", "waffe": "Hiebwaffen"
"Säbel", },
"Schwerter", {
"Stäbe", "waffe": "Infanteriewaffen"
"Zweihandflegel", },
"Zweihand-Hiebwaffen", {
"Zweihandschwerter/-säbel" "waffe": "Kettenstäbe"
},
{
"waffe": "Kettenwaffen"
},
{
"waffe": "Säbel"
},
{
"waffe": "Schwerter"
},
{
"waffe": "Stäbe"
},
{
"waffe": "Zweihandflegel"
},
{
"waffe": "Zweihand-Hiebwaffen"
},
{
"waffe": "Zweihandschwerter/-säbel"
}
], ],
"mehrereAktionen": "true", "mehrereAktionen": "true",
"mod": [ "mod": [

View File

@ -13,43 +13,43 @@
"waffenLimit": [ "waffenLimit": [
{ {
"gruppe": "Andertalbhänder", "gruppe": "Andertalbhänder",
"mod": "-8" "mod": -8
}, },
{ {
"gruppe": "Hiebwaffen", "gruppe": "Hiebwaffen",
"waffe": "Knüppel", "waffe": "Knüppel",
"mod": "-2" "mod": -2
}, },
{ {
"gruppe": "Hiebwaffen", "gruppe": "Hiebwaffen",
"waffe": "", "waffe": "",
"mod": "-4" "mod": -4
}, },
{ {
"gruppe": "Stäbe", "gruppe": "Stäbe",
"waffe": "Kampfstab", "waffe": "Kampfstab",
"mod": "-2" "mod": -2
}, },
{ {
"gruppe": "Stäbe", "gruppe": "Stäbe",
"waffe": "", "waffe": "",
"mod": "-4" "mod": -4
}, },
{ {
"gruppe": "Kettenstäbe", "gruppe": "Kettenstäbe",
"mod": "-8" "mod": -8
}, },
{ {
"gruppe": "Raufen", "gruppe": "Raufen",
"mod": "-4" "mod": -4
}, },
{ {
"gruppe": "Säbel", "gruppe": "Säbel",
"mod": "-8" "mod": -8
}, },
{ {
"gruppe": "Schwerter", "gruppe": "Schwerter",
"mod": "-8" "mod": -8
} }
], ],
"kombiSF": ["Wuchtschlag","Finte","Meisterparade","Binden"], "kombiSF": ["Wuchtschlag","Finte","Meisterparade","Binden"],

View File

@ -15,13 +15,27 @@
} }
], ],
"waffenLimit": [ "waffenLimit": [
"Hiebwaffen", {
"Kettenstäbe", "waffe": "Hiebwaffen"
"Kettenwaffen", },
"Peitschen", {
"Zweihandflegel", "waffe": "Kettenstäbe"
"Zweihand-Hiebwaffen", },
"Zweihandschwerter/-säbel" {
"waffe": "Kettenwaffen"
},
{
"waffe": "Peitschen"
},
{
"waffe": "Zweihandflegel"
},
{
"waffe": "Zweihand-Hiebwaffen"
},
{
"waffe": "Zweihandschwerter/-säbel"
}
], ],
"paradeMod": "-4", "paradeMod": "-4",
"aktionsText": " (Abwehraktion +4) Eines der zentralen Manöver der modernen Fechtkunst ist das sogenannte Binden der gegnerischen Waffe, d.h., mit der eigenen Waffe den Kontakt zur gegnerischen Waffe aufnehmen und halten und durch Kraft und Geschicklichkeit so die Führung zu übernehmen, dass man die eigene Position für den nächsten Schlag verbessert, die gegnerische aber verschlechtert. Mit den folgenden Kampftalenten ist es möglich, die gegnerische Waffe zu binden: Anderthalbhänder, Dolche, Fechtwaffen, Infanteriewaffen, Kettenstäbe, Säbel, Schwerter, Speere, Stäbe; dazu mit Parierwaffen. Der Verteidiger muss die SF Binden und zusätzlich entweder Parierwaffen I oder Meisterparade beherrschen. Gebunden werden können keine Hiebwaffen, Kettenstäbe, Kettenwaffen, Peitschen, Zweihandflegel, Zweihand-Hiebwaffen und Zweihandschwerter/-säbel. Binden wirkt jedoch gegen Schildkämpfer. Um eine gegnerische Waffe zu binden, muss dem Verteidiger eine Parade +4 gelingen. Sollte der zu konternde Angriff eine Attacke sein, die irgendeine Ansage hat (Wuchtschlag, Finte o.ä.) und diese Ansage höher als 4 ist, so ist die Parade statt dessen um diese gegnerische Ansage erschwert. (Das heißt auch, dass eine gegnerische Finte schwerer zu binden ist, da in diesem Fall die Parade ja sowieso schon um die gegnerische Ansage erschwert ist.) Wir unterscheiden die beiden Möglichkeiten, dass die gegnerische Waffe entweder mit der eigenen Hauptwaffe oder einer links geführten Parierwaffe gebunden wird: Wenn der Kämpfer mit der Hauptwaffe bindet und über die Sonderfertigkeit Meisterparade verfügt, kann er sich seine Parade zusätzlich zu den geforderten 4 Punkten noch mit einer Ansage erschweren. Bindet er jedoch mit einer Parierwaffe (und der Sonderfertigkeit Parierwaffen I), dann gilt automatisch oben genannte fixe Erschwernis (also in der Regel die 4 Punkte) als Ansage, ohne dass die Parade-Probe dadurch noch weiter erschwert wird. Wenn der Kämpfer beide genannten Sonderfertigkeiten beherrscht und mit beiden Waffen gemeinsam bindet, dann kann er auch beide Effekte benutzen: Die geforderte Erschwernis von 4 und die zusätzliche freiwillige Ansage addieren sich zu einer Gesamt-Ansage. Wenn das Binden-Manöver gelingt, so kann der bindende Held die gegnerische Waffe lenken und behindern und dadurch sowohl die nächste eigene Attacke um die Gesamt-Ansage erleichtern als auch die darauf folgende Reaktion des Gegners um die Gesamt-Ansage erschweren. Alrigio (SF Meisterparade und Binden) wird von einem maskierten Schurken angegriffen. Der geübte Degenfechter lässt sich aber nicht aus der Ruhe bringen. Er sagt ein Binden-Manöver an und erschwert sich die Probe um weitere 3 Punkte. Damit ist seine Probe um 7 Punkte erschwert und gelingt. Er antwortet sofort mit einer Finte, die er sich um 5 Punkte erschwert. In diesem Fall ist sein Attacke-Wurf also um 5 Punkte erschwert (die Ansage der Finte), aber auch um 3 Punkte erleichtert (wegen dem gelungenen Binden-Manöver). Wenn ihm diese Attacke +2 gelingt, dann ist die gegnerische Parade um insgesamt 8 Punkte erschwert: 3 Punkte aus der Ansage vom Binden und 5 Punkte aus der Finte. Würde er nebenher sogar noch einen Linkhanddolch führen und damit umgehen können, dann würde die gesamte Parade-Erschwernis von 7 Punkten als Erleichterung auf seine folgende Attacke angerechnet (sie wäre also trotz Finte immer noch um 2 Punkt erleichtert) und außerdem auch noch auf die gegnerische Parade (die damit insgesamt um stolze 12 Punkte schwerer wird). Binden ist immer eine Abwehraktion, die daher einen gegnerischen Angriff erfordert. Gebunden werden kann immer nur eine Waffe: Wenn also die Hauptwaffe eines Kämpfers mit Parierwaffe vom Gegner gebunden wird, hat er immer noch die freie Parierwaffe. Entsprechendes gilt für einen Kämpfer mit zwei Waffen im Beidhändigen Kampf.", "aktionsText": " (Abwehraktion +4) Eines der zentralen Manöver der modernen Fechtkunst ist das sogenannte Binden der gegnerischen Waffe, d.h., mit der eigenen Waffe den Kontakt zur gegnerischen Waffe aufnehmen und halten und durch Kraft und Geschicklichkeit so die Führung zu übernehmen, dass man die eigene Position für den nächsten Schlag verbessert, die gegnerische aber verschlechtert. Mit den folgenden Kampftalenten ist es möglich, die gegnerische Waffe zu binden: Anderthalbhänder, Dolche, Fechtwaffen, Infanteriewaffen, Kettenstäbe, Säbel, Schwerter, Speere, Stäbe; dazu mit Parierwaffen. Der Verteidiger muss die SF Binden und zusätzlich entweder Parierwaffen I oder Meisterparade beherrschen. Gebunden werden können keine Hiebwaffen, Kettenstäbe, Kettenwaffen, Peitschen, Zweihandflegel, Zweihand-Hiebwaffen und Zweihandschwerter/-säbel. Binden wirkt jedoch gegen Schildkämpfer. Um eine gegnerische Waffe zu binden, muss dem Verteidiger eine Parade +4 gelingen. Sollte der zu konternde Angriff eine Attacke sein, die irgendeine Ansage hat (Wuchtschlag, Finte o.ä.) und diese Ansage höher als 4 ist, so ist die Parade statt dessen um diese gegnerische Ansage erschwert. (Das heißt auch, dass eine gegnerische Finte schwerer zu binden ist, da in diesem Fall die Parade ja sowieso schon um die gegnerische Ansage erschwert ist.) Wir unterscheiden die beiden Möglichkeiten, dass die gegnerische Waffe entweder mit der eigenen Hauptwaffe oder einer links geführten Parierwaffe gebunden wird: Wenn der Kämpfer mit der Hauptwaffe bindet und über die Sonderfertigkeit Meisterparade verfügt, kann er sich seine Parade zusätzlich zu den geforderten 4 Punkten noch mit einer Ansage erschweren. Bindet er jedoch mit einer Parierwaffe (und der Sonderfertigkeit Parierwaffen I), dann gilt automatisch oben genannte fixe Erschwernis (also in der Regel die 4 Punkte) als Ansage, ohne dass die Parade-Probe dadurch noch weiter erschwert wird. Wenn der Kämpfer beide genannten Sonderfertigkeiten beherrscht und mit beiden Waffen gemeinsam bindet, dann kann er auch beide Effekte benutzen: Die geforderte Erschwernis von 4 und die zusätzliche freiwillige Ansage addieren sich zu einer Gesamt-Ansage. Wenn das Binden-Manöver gelingt, so kann der bindende Held die gegnerische Waffe lenken und behindern und dadurch sowohl die nächste eigene Attacke um die Gesamt-Ansage erleichtern als auch die darauf folgende Reaktion des Gegners um die Gesamt-Ansage erschweren. Alrigio (SF Meisterparade und Binden) wird von einem maskierten Schurken angegriffen. Der geübte Degenfechter lässt sich aber nicht aus der Ruhe bringen. Er sagt ein Binden-Manöver an und erschwert sich die Probe um weitere 3 Punkte. Damit ist seine Probe um 7 Punkte erschwert und gelingt. Er antwortet sofort mit einer Finte, die er sich um 5 Punkte erschwert. In diesem Fall ist sein Attacke-Wurf also um 5 Punkte erschwert (die Ansage der Finte), aber auch um 3 Punkte erleichtert (wegen dem gelungenen Binden-Manöver). Wenn ihm diese Attacke +2 gelingt, dann ist die gegnerische Parade um insgesamt 8 Punkte erschwert: 3 Punkte aus der Ansage vom Binden und 5 Punkte aus der Finte. Würde er nebenher sogar noch einen Linkhanddolch führen und damit umgehen können, dann würde die gesamte Parade-Erschwernis von 7 Punkten als Erleichterung auf seine folgende Attacke angerechnet (sie wäre also trotz Finte immer noch um 2 Punkt erleichtert) und außerdem auch noch auf die gegnerische Parade (die damit insgesamt um stolze 12 Punkte schwerer wird). Binden ist immer eine Abwehraktion, die daher einen gegnerischen Angriff erfordert. Gebunden werden kann immer nur eine Waffe: Wenn also die Hauptwaffe eines Kämpfers mit Parierwaffe vom Gegner gebunden wird, hat er immer noch die freie Parierwaffe. Entsprechendes gilt für einen Kämpfer mit zwei Waffen im Beidhändigen Kampf.",

View File

@ -11,15 +11,48 @@
"sonderfertigkeit": "Beidhändiger Kampf I" "sonderfertigkeit": "Beidhändiger Kampf I"
} }
], ],
"nichtNutzbareWaffen": [ "waffenLimit": [
{ {
"gruppe": "Kettenwaffen" "gruppe": "Anderthalbhänder"
}, },
{ {
"gruppe": "Peitschen" "gruppe": "Dolche"
}, },
{ {
"gruppe": "Speere" "gruppe": "Fechtwaffen"
},
{
"gruppe": "Hiebwaffen"
},
{
"gruppe": "Infanteriewaffen"
},
{
"gruppe": "Kettenstäbe"
},
{
"gruppe": "Raufen"
},
{
"gruppe": "Ringen"
},
{
"gruppe": "Säbel"
},
{
"gruppe": "Schwerter"
},
{
"gruppe": "Stäbe"
},
{
"gruppe": "Zweihandflegel"
},
{
"gruppe": "Zweihandhiebwaffen"
},
{
"gruppe": "Zweihandschwerter/-säbel"
} }
], ],
"mod": "-2", "mod": "-2",

View File

@ -16,18 +16,45 @@
"maxValue": "4" "maxValue": "4"
} }
], ],
"nichtNutzbareWaffen": [ "waffenLimit": [
{ {
"gruppe": "Kettenwaffen" "gruppe": "Anderthalbhänder"
}, },
{ {
"gruppe": "Peitschen" "gruppe": "Dolche"
}, },
{ {
"gruppe": "Zweihandflegeln" "gruppe": "Fechtwaffen"
}, },
{ {
"gruppe": "Zweihand-Hiebwaffen" "gruppe": "Hiebwaffen"
},
{
"gruppe": "Infanteriewaffen"
},
{
"gruppe": "Kettenstäbe"
},
{
"gruppe": "Raufen"
},
{
"gruppe": "Ringen"
},
{
"gruppe": "Säbel"
},
{
"gruppe": "Schwerter"
},
{
"gruppe": "Speere"
},
{
"gruppe": "Stäbe"
},
{
"gruppe": "Zweihandschwerter/-säbel"
} }
], ],
"mod": [ "mod": [

View File

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

View File

@ -24,4 +24,5 @@
@use "organisms/species-sheet"; @use "organisms/species-sheet";
@use "organisms/profession-sheet"; @use "organisms/profession-sheet";
@use "organisms/xml-import-dialog"; @use "organisms/xml-import-dialog";
@use "organisms/combat-action-dialog";

View File

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

View File

@ -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="name">{{this.name}}</span>
<span class="time">{{this.cost}}</span> <span class="time">{{this.cost}}</span>