implements cooldowntracker for ongoing actions

pull/61/head
macniel 2025-10-23 12:41:52 +02:00
parent 3c7426bf56
commit 7d23af8902
10 changed files with 423 additions and 129 deletions

View File

@ -1,8 +1,7 @@
import {Equipment} from "../documents/equipment.mjs";
const {
SchemaField,
NumberField,
ObjectField,
StringField,
HTMLField,
DocumentIdField,
@ -123,6 +122,12 @@ export class PlayerCharacterDataModel extends foundry.abstract.TypeDataModel {
gilde: new StringField(),
}),
cooldowns: new ArrayField(new SchemaField({
start: new NumberField({required: true, integer: true}),
current: new NumberField({required: true, integer: true}),
data: new ObjectField()
})),
kampfwerte: new ArrayField(new SchemaField({
name: new StringField(),
at: new NumberField({required: true, integer: true}),

View File

@ -1,4 +1,3 @@
import {XmlImport} from "../xml-import/xml-import.mjs";
import {ActionManager} from "../sheets/actions/action-manager.mjs";
const {ApplicationV2, HandlebarsApplicationMixin} = foundry.applications.api
@ -81,19 +80,49 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
static async #onSubmitForm(event, form, formData) {
event.preventDefault()
const maneuver = this.#evaluateManeuvers().find(p => p.id === this._combatManeuverId)
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(game.scenes.current.tokens.find(p => p._id === this._targetId).actorId)
const roll = new Roll("1d20cs<" + this._targetNumber)
const evaluated1 = (await roll.evaluate())
await evaluated1.toMessage({
speaker: ChatMessage.getSpeaker({actor: this._actor}),
flavor: `Attackiert ${target.name} mit ${weapon.name} (${skill.name})<br/>${this._modDescription}`,
rollMode: "publicroll",
})
return true
if (maneuver.cost !== ActionManager.CONTINUING) {
this._actor.rollAttack({
weapon: this._weaponId,
skill: this._skillId,
target: this._targetId,
maneuver,
mod: this._mod,
circumstance: this._circumstance,
penalty: this._penalty,
targetNumber: this._targetNumber,
modDescription: maneuver?.modDescription?.replace("{}", "" + this._mod) ?? ""
})
return true
} else { // push into cooldown queue
const cooldowns = this._actor.system.cooldowns
const newCooldown = {
start: maneuver.cooldown({weapon, skill, target, mod: this._mod}),
current: maneuver.cooldown({weapon, skill, target, mod: this._mod}),
data: {
weapon: this._weaponId,
skill: this._skillId,
target: this._targetId,
maneuver,
mod: this._mod,
circumstance: this._circumstance,
penalty: this._penalty,
targetNumber: this._targetNumber,
modDescription: maneuver?.modDescription?.replace("{}", "" + this._mod) ?? ""
}
}
cooldowns.push(newCooldown)
await this._actor.update({"system.cooldowns": cooldowns})
ui.notifications.info(`Neue Aktion für ${maneuver.name} mit Abklingzeit von ${maneuver.cooldown({
weapon,
skill,
target,
mod: this._mod
})} Aktionen hinzugefügt`)
}
}
_configureRenderOptions(options) {
@ -214,7 +243,9 @@ export class CombatActionDialog extends HandlebarsApplicationMixin(ApplicationV2
cost: action.cost,
penalty: action.eval?.mod ?? 0,
mod: action.mod,
modDescription: action.modDescription
modDescription: action.modDescription,
cooldown: action.cooldown,
activate: action.activate,
}
}).sort((a, b) => (a.isSelected ? 0 : 1) - (b.isSelected ? 0 : 1))
return this._maneuvers

View File

@ -252,6 +252,22 @@ export class Character extends Actor {
return false
}
async rollAttack(data) {
const maneuver = data.manuever
const weapon = this.itemTypes["Equipment"].find(p => p._id === data.weapon)
const skill = this.itemTypes["Skill"].find(p => p._id === data.skill)
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())
await evaluated1.toMessage({
speaker: ChatMessage.getSpeaker({actor: this}),
flavor: `Attackiert ${target.name} mit ${weapon.name} (${skill.name})<br/>${data.modDescription}`,
rollMode: "publicroll",
})
}
/**
*
* @param amount

View File

@ -80,8 +80,11 @@ export class ActionManager {
{
name: "Fernkampfangriff",
type: ActionManager.ATTACK,
cost: ActionManager.REGULAR,
cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT,
cooldown: (options) => 1,
activate: (queue, data) => {
},
eval: (options) => this.#hatFernkampfWaffeinHand(options),
},
{
@ -89,6 +92,7 @@ export class ActionManager {
type: ActionManager.ATTACK,
cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT,
cooldown: (options) => options.mod,
eval: (options) => {
const step1 = this.#hatFernkampfWaffeinHand(options)
const step2 = !this.#hatSonderfertigkeit("Scharfschütze", options)
@ -106,6 +110,11 @@ export class ActionManager {
type: ActionManager.ATTACK,
cost: ActionManager.CONTINUING,
source: ActionManager.SF,
cooldown: (options) => options.mod - 2,
activate: (queue, data) => {
data.actor.rollAttack(data)
return true
},
eval: (options) => {
const step1 = this.#hatFernkampfWaffeinHand(options) && this.#hatSonderfertigkeit("Scharfschütze", options)
const step2WithBenefits = this.#evalSonderfertigkeitRequirements("Scharfschütze", options)
@ -122,6 +131,11 @@ export class ActionManager {
type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT,
cooldown: (options) => 1,
activate: (queue) => {
// get earliest rangedAttack and reduce its cooldown by 1 but also increases its difficulty by 2
return true
},
eval: (options) => this.#hatFernkampfWaffeinHand(options)
},
{
@ -129,6 +143,11 @@ export class ActionManager {
type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING,
source: ActionManager.SF,
cooldown: (options) => 1,
activate: (queue) => {
// get earliest rangedAttack and reduce its cooldown by 1 but also increases its difficulty by 1
return true
},
eval: (options) => {
const step1 = this.#hatFernkampfWaffeinHand(options) && this.#hatSonderfertigkeit("Scharfschütze", options)
const step2WithBenefits = this.#evalSonderfertigkeitRequirements("Scharfschütze", options)
@ -209,7 +228,7 @@ export class ActionManager {
}
},
{
name: "Wuchtschlag",
name: "Wuchtschlag (Sonderfertigkeit)",
type: ActionManager.ATTACK,
cost: ActionManager.REGULAR,
source: ActionManager.SF,
@ -274,6 +293,10 @@ export class ActionManager {
type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING,
source: ActionManager.SF,
cooldown: (options) => 1,
activate: (queue) => { // find earliest Reload Action and reduce it by 1
return true
},
eval: (options) => {
const step1 = this.#hatMunition()
&& this.#hatFernkampfWaffeinHand(options)
@ -290,6 +313,10 @@ export class ActionManager {
type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING,
source: ActionManager.SF,
cooldown: (options) => 1,
activate: (queue) => {
return true // find earliest Reload Action and reduce it by 1
},
eval: (options) => {
const step1 = this.#hatMunition()
&& this.#hatFernkampfWaffeinHand(options)
@ -306,6 +333,10 @@ export class ActionManager {
type: ActionManager.INTERACTION,
cost: ActionManager.CONTINUING,
source: ActionManager.DEFAULT,
cooldown: (options) => 1, // get reload time of weapon
activate: (queue) => {
return true // get ammunition of actor and reduce the Qty by 1 or if its as magazine, reduce its fill by 1
},
eval: (options) => this.#hatMunition()
},
{
@ -376,7 +407,6 @@ export class ActionManager {
evaluate(options) {
let actionArray = [...this.#freeActions, ...this.#regularActions, ...this.#continuingActions]
return actionArray.filter(action => {
console.log(action.name, action.eval(options))
return action.eval(options)
}).map(action => {
return {

View File

@ -16,8 +16,7 @@ export default {
}
const am = new ActionManager(actorData)
context.actions = am.evaluate()
context.actions = am.evaluate().filter(action => action.type !== ActionManager.ATTACK)
context.inidice = actorData.system.ini.wuerfel
context.inivalue = actorData.system.ini.aktuell
@ -31,75 +30,75 @@ export default {
context.aupcurrent = actorData.system.aup.aktuell ?? 0
const fernkampf = findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData)
const links = findEquipmentOnSlot("links", actorData.system.setEquipped, actorData)
const rechts = findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData)
// const fernkampf = findEquipmentOnSlot("fernkampf", actorData.system.setEquipped, actorData)
//const links = findEquipmentOnSlot("links", actorData.system.setEquipped, actorData)
// const rechts = findEquipmentOnSlot("rechts", actorData.system.setEquipped, actorData)
context.attacks = [];
if (fernkampf) {
const fkitems = fernkampf.system.rangedSkills.map((skillInQuestion) => actorData.items.find(p => p.name === skillInQuestion))
fkitems.forEach(async skill => {
const obj = await skill
context.attacks.push({
name: obj.name,
using: fernkampf.name,
atroll: `1d20cs<${object.system.fk.aktuell + obj.system.at}`,
at: `${object.system.fk.aktuell + obj.system.at}`,
tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod
tp: `${fernkampf.system.rangedAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`,
})
})
}
if (links) {
const meitems = []
links.system.meleeSkills.forEach((skillInQuestion) => {
const item = actorData.items.find(p => p.name === skillInQuestion)
if (item) {
meitems.push(item)
/*
if (fernkampf) {
const fkitems = fernkampf.system.rangedSkills.map((skillInQuestion) => actorData.items.find(p => p.name === skillInQuestion))
fkitems.forEach(async skill => {
const obj = await skill
context.attacks.push({
name: obj.name,
using: fernkampf.name,
atroll: `1d20cs<${object.system.fk.aktuell + obj.system.at}`,
at: `${object.system.fk.aktuell + obj.system.at}`,
tproll: `${fernkampf.system.rangedAttackDamage}`, // TODO consider adding TP/KK mod and Range mod
tp: `${fernkampf.system.rangedAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + fernkampf.system.iniModifier ?? 0}`,
})
})
}
})
meitems.forEach(skill => {
const obj = skill
context.attacks.push({
name: obj.name,
using: links.name,
atroll: `1d20cs<${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M
at: `${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`,
paroll: `1d20cs<${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M
pa: `${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`,
tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod
tp: `${links.system.meleeAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`,
})
})
}
if (rechts) {
const meitems = []
rechts.system.meleeSkills.forEach((skillInQuestion) => {
const item = actorData.items.find(p => p.name === skillInQuestion)
if (item) {
meitems.push(item)
if (links) {
const meitems = []
links.system.meleeSkills.forEach((skillInQuestion) => {
const item = actorData.items.find(p => p.name === skillInQuestion)
if (item) {
meitems.push(item)
}
})
meitems.forEach(skill => {
const obj = skill
context.attacks.push({
name: obj.name,
using: links.name,
atroll: `1d20cs<${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`, // TODO consider adding W/M
at: `${object.system.at.links.aktuell + obj.system.at + links.system.attackModifier}`,
paroll: `1d20cs<${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`, // TODO consider adding W/M
pa: `${object.system.pa.links.aktuell + obj.system.pa + links.system.parryModifier}`,
tproll: `${links.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod
tp: `${links.system.meleeAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + links.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + links.system.iniModifier ?? 0}`,
})
})
}
})
meitems.forEach(skill => {
const obj = skill
context.attacks.push({
name: obj.name,
using: rechts.name,
atroll: `1d20cs<${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M
at: `${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`,
paroll: `1d20cs<${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M
pa: `${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`,
tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod
tp: `${rechts.system.meleeAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
})
})
}
if (rechts) {
const meitems = []
rechts.system.meleeSkills.forEach((skillInQuestion) => {
const item = actorData.items.find(p => p.name === skillInQuestion)
if (item) {
meitems.push(item)
}
})
meitems.forEach(skill => {
const obj = skill
context.attacks.push({
name: obj.name,
using: rechts.name,
atroll: `1d20cs<${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`, // TODO consider adding W/M
at: `${object.system.at.rechts.aktuell + obj.system.at + rechts.system.attackModifier}`,
paroll: `1d20cs<${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`, // TODO consider adding W/M
pa: `${object.system.pa.rechts.aktuell + obj.system.pa + rechts.system.parryModifier}`,
tproll: `${rechts.system.meleeAttackDamage}`, // TODO consider adding TP/KK mod
tp: `${rechts.system.meleeAttackDamage}`,
iniroll: `(${context.inidice})d6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
ini: `${context.inidice}w6 + ${context.inivalue + rechts.system.iniModifier ?? 0}`,
})
})
}*/
return context

View File

@ -8,6 +8,7 @@ import Skills from "./character/skills.mjs"
import Social from "./character/social.mjs";
import Spells from "./character/spells.mjs"
import {CombatActionDialog} from "../dialog/combatAction.mjs";
import {ActionManager} from "./actions/action-manager.mjs";
const {HandlebarsApplicationMixin} = foundry.applications.api
const {ActorSheetV2} = foundry.applications.sheets
@ -38,7 +39,9 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
openCultureDocument: CharacterSheet.#openCultureDocument,
openSpeciesDocument: CharacterSheet.#openSpeciesDocument,
openCombatAction: CharacterSheet.#openCombatAction,
progressCooldown: CharacterSheet.#progressCooldown,
cancelCooldown: CharacterSheet.#cancelCooldown,
activateCooldown: CharacterSheet.#activateCooldown,
}
}
@ -123,6 +126,53 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
}
}
static async #progressCooldown(event, target) {
const {cooldownId} = target.dataset
const cooldowns = this.document.system.cooldowns
const cooldown = this.document.system.cooldowns[cooldownId]
cooldowns.splice(cooldownId, 1)
if (cooldown) {
cooldown.current = cooldown.current - 1
}
cooldowns.push(cooldown)
this.document.update({"system.cooldowns": cooldowns.sort((a, b) => a.current - b.current)})
ui.notifications.info(`Abklingzeit von ${cooldown.data.maneuver.name} um 1 Aktion reduziert`)
}
static async #cancelCooldown(event, target) {
const {cooldownId} = target.dataset
const cooldown = this.document.system.cooldowns[cooldownId]
const cooldowns = this.document.system.cooldowns
cooldowns.splice(cooldownId, 1)
this.document.update({"system.cooldowns": cooldowns.sort((a, b) => a.current - b.current)})
ui.notifications.info(`${cooldown.data.maneuver.name} abgebrochen`)
}
static async #activateCooldown(event, target) {
const {cooldownId} = target.dataset
const cooldowns = this.document.system.cooldowns
const cooldown = this.document.system.cooldowns[cooldownId]
if (cooldown && cooldown.current <= 0) {
const am = new ActionManager(this.document)
const action = am.evaluate().find(action => action.name === cooldown.data.maneuver.id)
console.log(action)
if (action) {
action.activate(cooldowns, {...cooldown.data, actor: this.document})
}
}
cooldowns.splice(cooldownId, 1)
this.document.update({"system.cooldowns": cooldowns.sort((a, b) => a.current - b.current)})
ui.notifications.info(`${cooldown.data.maneuver.name} ausgeführt`)
}
/**
*
* @param {MouseEvent} event
@ -324,6 +374,15 @@ class CharacterSheet extends HandlebarsApplicationMixin(ActorSheetV2) {
})
}
context.cooldowns = actorData.system.cooldowns ?? []
context.cooldowns.forEach(cooldown => {
const weapon = this.document.itemTypes["Equipment"].find(p => p._id === cooldown.data.weapon)
const skill = this.document.itemTypes["Skill"].find(p => p._id === cooldown.data.skillId)
const target = game.actors.get(game.scenes.current.tokens.find(p => p._id === cooldown.data.target).actorId)
cooldown.progress = ((cooldown.current / cooldown.start) * 100) + "%"
cooldown.tooltip = `${cooldown.data.maneuver.name}<br/>Waffe:${weapon.name}<br/>Ziel: ${target.name}<br/>Wurfziel: ${cooldown.data.targetNumber}<br/>Aktionen verbleibend: ${cooldown.current}`
})
context.attributes = [
{
eigenschaft: "mu",

View File

@ -2,43 +2,14 @@
.head-data {
.sidebar-element {
.resource-bar {
height: 24px;
width: 100%;
margin-top: 4px;
&.rollable {
label {
display: inline-block;
line-height: 24px;
vertical-align: middle;
}
.formula {
display: inline-block;
line-height: 24px;
vertical-align: middle;
}
.die {
}
&:hover {
.formula {
text-shadow: 0 0 10px rgb(255 0 0);
}
}
}
&.resource-bar {
position: relative;
border: 1px inset #ccc;
background-color: rgba(0, 0, 0, 0.2);
margin: 8px 0;
label {
position: absolute;
@ -73,7 +44,7 @@
}
&.lep::after {
background-color: rgba(0, 192, 96, 0.5);
background-color: rgba(192, 0, 0, 0.5);
}
&.aup::after {
@ -92,6 +63,151 @@
}
.attack {
display: grid;
grid-template-columns: 32px 32px 1fr 1fr;
grid-template-rows: 18px 30px;
grid-template-areas: "name name name name" "at pa tp ini";
height: 64px;
border: 1px inset #ccc;
border-radius: 4px;
background-color: rgba(0, 0, 0, 0.2);
padding: 8px;
margin-bottom: 8px;
gap: 0;
h3 {
grid-area: name;
text-align: center;
}
label {
font-size: smaller;
display: block;
text-align: center;
}
.formula {
font-size: small;
display: block;
text-align: center;
}
.at {
grid-area: at;
}
.pa {
grid-area: pa;
}
.ini {
grid-area: ini;
}
.tp {
grid-area: tp;
}
}
.cooldowns {
h3 {
text-align: center;
margin: 8px 0;
}
.cooldown {
display: grid;
position: relative;
height: 24px;
width: 100%;
grid-template-columns: 24px 1fr 24px;
grid-template-rows: 24px;
grid-template-areas: "btn-left text btn-right";
border: 1px inset #ccc;
border-radius: 12px;
background: url('/systems/DSA_4-1/assets/gradient.png');
.btn-left {
grid-area: btn-left;
color: white;
i {
vertical-align: 1px;
}
}
.btn-right {
grid-area: btn-right;
color: white;
}
.btn-left, .btn-right {
z-index: 3;
vertical-align: middle;
min-height: 16px;
height: 24px;
width: 24px;
margin: 0;
padding: 0;
background: unset;
background-color: unset;
box-shadow: unset;
border-radius: 12px;
display: block;
border: unset;
}
span {
grid-area: text;
z-index: 3;
height: 24px;
line-height: 24px;
vertical-align: middle;
color: white;
text-align: center;
text-shadow: 2px 2px 1px rgba(0, 0, 0, 0.3);
}
.progress {
position: absolute;
background: url('/systems/DSA_4-1/assets/gradient.png');
background-size: 12px 100%;
left: 0;
bottom: 0;
top: 0;
border-radius: 12px;
z-index: 2;
&::after { // progress fill
content: '';
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
border-radius: 12px;
background-color: rgba(128, 0, 192, 0.5);
}
}
&::after {
position: absolute;
content: '';
left: 0;
top: 0;
bottom: 0;
right: 0;
border-radius: 12px;
background-color: rgba(0, 0, 0, 0.8);
}
}
}
}

View File

@ -4,7 +4,7 @@
grid-template-columns: 1fr 320px;
grid-template-rows: 32px 32px 1fr;
grid-template-areas: "res res" "wounds wounds" "actions actions";
grid-template-areas: "res res" "wounds wounds" "actions actions" "cooldowns cooldowns";
padding: 8px;
gap: 8px;
@ -99,9 +99,13 @@
}
}
.cooldowns {
grid-area: cooldowns;
}
&.zones {
grid-template-areas: "res res" "wounds wounds" "actions paperdoll";
grid-template-areas: "res res" "wounds wounds" "actions paperdoll" "cooldowns paperdoll";
.paperdoll {
grid-area: paperdoll;

View File

@ -51,36 +51,61 @@
{{/if}}
{{#each attacks}}
<div>
<div class="attack">
<h3>{{this.using}} ({{this.name}})</h3>
<div class="combined">
{{#if this.at}}
<div class="sidebar-element rollable" data-roll="{{this.atroll}}" data-label="Attacke">
<div class="at sidebar-element rollable" data-mode="attack" data-action="openCombatAction">
<label>AT</label>
<div class="formula">{{this.at}}</div>
</div>
{{/if}}
{{#if this.pa}}
<div class="sidebar-element rollable" data-roll="{{this.paroll}}" data-label="Parade">
<div class="pa sidebar-element rollable" data-mode="defense" data-action="openCombatAction">
<label>PA</label>
<div class="formula">{{this.pa}}</div>
</div>
{{/if}}
</div>
{{#if this.at}}
<div class="sidebar-element rollable" data-roll="{{this.tproll}}" data-label="Schaden">
<label>Schaden</label>
<div class="tp sidebar-element rollable" data-roll="{{this.tproll}}" data-label="Schaden">
<label>TP</label>
<div class="formula">{{this.tp}}</div>
</div>
{{/if}}
{{#if this.ini}}
<div class="sidebar-element rollable" data-label="Initiative" data-roll="{{this.iniroll}}"><label>Initiative</label>
<div class="ini sidebar-element rollable" data-action="openInitiative"><label>INI</label>
<div class="formula">{{this.ini}}</div>
</div>
{{/if}}
</div>
{{/each}}
<section class="cooldowns">
<h3>Abklingzeiten</h3>
{{#each this.cooldowns}}
<div class="cooldown">
<div class="progress" style="width: {{this.progress}}"></div>
{{#if (gt this.current 0)}}
<button class="btn-left" data-action="progressCooldown" data-cooldown-id="{{@key}}">
<i class="fa fa-timer"></i>
</button>
<span data-tooltip="{{this.tooltip}}">{{this.data.maneuver.name}}</span>
<button class="btn-right" data-action="cancelCooldown" data-cooldown-id="{{@key}}">
<i class="fa fa-xmark"></i>
</button>
{{else}}
<button class="btn-left" data-action="activateCooldown" data-cooldown-id="{{@key}}">
<i class="fa fa-person-running"></i>
</button>
<span data-tooltip="{{this.tooltip}}">{{this.data.maneuver.name}}</span>
<button class="btn-right" data-action="cancelCooldown" data-cooldown-id="{{@key}}">
<i class="fa fa-xmark"></i>
</button>
{{/if}}</div>
{{/each}}
</section>
</div>
{{!-- Sheet Tab Navigation --}}

View File

@ -55,7 +55,16 @@
<div class="actions">
<h3>Aktionen im Kampf</h3>
<div class="grid-of-actions">
{{#each this.actions}}
<div class="player-action attack-action" data-mode="attack" data-action="openCombatAction">
<span class="name">Angriff</span>
<span class="time">variabel</span>
</div>
<div class="player-action defense-action" data-mode="defense" data-action="openCombatAction">
<span class="name">Verteidigen</span>
<span class="time">variabel</span>
</div>
{{#each this.actions}}
{{> "systems/DSA_4-1/templates/ui/partial-action-button.hbs" this}}
{{/each}}
</div>