Reworked Action storage

This commit is contained in:
WBHarry 2025-06-30 23:01:50 +02:00
parent 3333a9e00a
commit ce593d02f3
16 changed files with 196 additions and 23 deletions

View file

@ -286,6 +286,7 @@ const preloadHandlebarsTemplates = async function () {
return foundry.applications.handlebars.loadTemplates([
'systems/daggerheart/templates/sheets/global/tabs/tab-navigation.hbs',
'systems/daggerheart/templates/sheets/global/partials/inventory-item.hbs',
'systems/daggerheart/templates/sheets/global/partials/action-item.hbs',
'systems/daggerheart/templates/sheets/global/partials/domain-card-item.hbs',
'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs',

View file

@ -501,6 +501,20 @@
"bonded": "When you mark your last Hit Point, your companion rushes to your side to comfort you. Roll a number of d6s equal to the unmarked Stress slots they have and mark them. If any roll a 6, your companion helps you up. Clear your last Hit Point and return to the scene.",
"aware": "Your companion gains a permanent +2 bonus to their Evasion."
},
"Actions": {
"CreatureComfort": {
"Name": "Creature Comfort",
"Description": "Once per rest, when you take time during a quiet moment to give your companion love and attention, you can gain a Hope or you can both clear a Stress."
},
"Armored": {
"Name": "Armored",
"Description": "When your companion takes damage, you can mark one of your Armor Slots instead of marking one of their Stress."
},
"Bonded": {
"Name": "Bonded",
"Description": "When you mark your last Hit Point, your companion rushes to your side to comfort you. Roll a number of d6s equal to the unmarked Stress slots they have and mark them. If any roll a 6, your companion helps you up. Clear your last Hit Point and return to the scene."
}
},
"Tier2": {
"Label": "Levels 2-4",
"InfoLabel": "At Level 2, gain an additional Experience at +2 and gain a +1 bonus to your Proficiency.",
@ -1146,6 +1160,8 @@
"CharacterSetup": "Character setup isn't done yet",
"Level": "Level",
"LevelUp": "You can level up",
"Actions": "Actions",
"CompanionActions": "Companion Actions",
"Tabs": {
"Features": "Features",
"Inventory": "Inventory",

View file

@ -143,7 +143,7 @@ export default class AncestrySelectionDialog extends HandlebarsApplicationMixin(
}
static _onEditImage() {
const fp = new FilePicker({
const fp = new foundry.applications.apps.FilePicker.implementation({
current: this.data.ancestryInfo.img,
type: 'image',
redirectToRoot: ['icons/svg/mystery-man.svg'],

View file

@ -160,7 +160,7 @@ class Countdowns extends HandlebarsApplicationMixin(ApplicationV2) {
static onEditImage(_, target) {
const setting = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Countdowns)[this.basePath];
const current = setting.countdowns[target.dataset.countdown].img;
const fp = new FilePicker({
const fp = new foundry.applications.apps.FilePicker.implementation({
current,
type: 'image',
callback: async path => this.updateImage.bind(this)(path, target.dataset.countdown),

View file

@ -81,7 +81,7 @@ export default class DhSettingsActionView extends HandlebarsApplicationMixin(App
}
static onEditImage() {
const fp = new FilePicker({
const fp = new foundry.applications.apps.FilePicker.implementation({
current: this.img,
type: 'image',
callback: async path => {

View file

@ -6,6 +6,8 @@ import DaggerheartSheet from './daggerheart-sheet.mjs';
import { abilities } from '../../config/actorConfig.mjs';
import DhCharacterlevelUp from '../levelup/characterLevelup.mjs';
import DhCharacterCreation from '../characterCreation.mjs';
import DHActionConfig from '../config/Action.mjs';
import { DHBaseAction } from '../../data/action/action.mjs';
const { ActorSheetV2 } = foundry.applications.sheets;
const { TextEditor } = foundry.applications.ux;
@ -51,6 +53,7 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
levelManagement: this.levelManagement,
editImage: this._onEditImage,
triggerContextMenu: this.triggerContextMenu
// editAction: this.editAction,
},
window: {
resizable: true
@ -303,17 +306,27 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
}
getItem(element) {
const itemId = (element.target ?? element).closest('[data-item-id]').dataset.itemId,
const listElement = (element.target ?? element).closest('[data-item-id]');
if (listElement.dataset.isAction) return this.getAction(listElement);
const itemId = listElement.dataset.itemId,
item = this.document.items.get(itemId);
return item;
}
getAction(listElement) {
const target = listElement.dataset.partner === 'true' ? this.document.system.companion : this.document;
if (!target) return null;
return target.system.actions.find(x => x.id === listElement.dataset.itemId);
}
static triggerContextMenu(event, button) {
return CONFIG.ux.ContextMenu.triggerContextMenu(event);
}
static _onEditImage() {
const fp = new FilePicker({
const fp = new foundry.applications.apps.FilePicker.implementation({
current: this.document.img,
type: 'image',
redirectToRoot: ['icons/svg/mystery-man.svg'],
@ -616,10 +629,15 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
}
}
static async viewObject(event, button) {
static async viewObject(event) {
const item = this.getItem(event);
if (!item) return;
item.sheet.render(true);
if (item instanceof DHBaseAction) {
new DHActionConfig(item).render({ force: true });
} else {
item.sheet.render(true);
}
}
editItem(event) {
@ -672,10 +690,16 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
this.render();
}
static async deleteItem(event, button) {
static async deleteItem(event) {
const item = this.getItem(event);
if (!item) return;
await item.delete();
if (item instanceof DHBaseAction) {
const newActions = item.parent.actions.filter(x => x.id !== item.id);
await item.parent.parent.update({ ['system.actions']: newActions });
} else {
await item.delete();
}
}
static async setItemQuantity(button, value) {
@ -711,7 +735,30 @@ export default class CharacterSheet extends DaggerheartSheet(ActorSheetV2) {
}
static async toChat(event, button) {
if (button?.dataset?.type === 'experience') {
const item = event.dataset ? event : button.closest(['[data-item-id']);
if (item?.dataset.isAction) {
const action = this.getAction(item);
const cls = getDocumentClass('ChatMessage');
const systemData = {
title: action.name,
origin: this,
img: action.img,
name: action.name,
description: action.description,
actions: []
};
const msg = new cls({
type: 'abilityUse',
user: game.user.id,
system: systemData,
content: await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/chat/ability-use.hbs',
systemData
)
});
cls.create(msg.toObject());
} else if (button?.dataset?.type === 'experience') {
const experience = this.document.system.experiences[button.dataset.uuid];
const cls = getDocumentClass('ChatMessage');
const systemData = {

View file

@ -38,7 +38,7 @@ export default function DhpApplicationMixin(Base) {
const attr = target.dataset.edit;
const current = foundry.utils.getProperty(this.document, attr);
const { img } = this.document.constructor.getDefaultArtwork?.(this.document.toObject()) ?? {};
const fp = new FilePicker({
const fp = new foundry.applications.apps.FilePicker.implementation({
current,
type: 'image',
redirectToRoot: img ? [img] : [],

View file

@ -130,7 +130,11 @@ export class DHBaseAction extends foundry.abstract.DataModel {
}
get actor() {
return this.item instanceof DhpActor ? this.item : this.item?.actor;
return this.item instanceof DhpActor
? this.item
: this.item?.parent instanceof DhpActor
? this.item.parent
: this.item?.actor;
}
get chatTemplate() {

View file

@ -1,4 +1,5 @@
import { burden } from '../../config/generalConfig.mjs';
import ActionField from '../fields/actionField.mjs';
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import DhLevelData from '../levelData.mjs';
import BaseDataActor from './base.mjs';
@ -96,6 +97,7 @@ export default class DhCharacter extends BaseDataActor {
value: new ForeignDocumentUUIDField({ type: 'Item', nullable: true }),
subclass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true })
}),
actions: new fields.ArrayField(new ActionField()),
levelData: new fields.EmbeddedDataField(DhLevelData),
bonuses: new fields.SchemaField({
armorScore: new fields.NumberField({ integer: true, initial: 0 }),
@ -155,6 +157,17 @@ export default class DhCharacter extends BaseDataActor {
return this.parent.items.find(x => x.type === 'community') ?? null;
}
// get actions() {
// const generalActions = []; // Add in things like Sprint etc
// const levelupActions = this.levelData.actions.filter(x => !x.partner).map(x => x.value);
// return [...generalActions, ...levelupActions];
// }
get companionActions() {
return this.companion ? this.companion.system.actions : [];
}
get needsCharacterSetup() {
return !this.class.value || !this.class.subclass;
}

View file

@ -72,6 +72,7 @@ export default class DhCompanion extends BaseDataActor {
}
}
}),
actions: new fields.ArrayField(new ActionField()),
levelData: new fields.EmbeddedDataField(DhLevelData)
};
}

View file

@ -42,7 +42,8 @@ export default class DhLevelData extends foundry.abstract.DataModel {
amount: new fields.NumberField({ integer: true }),
data: new fields.ArrayField(new fields.StringField({ required: true })),
secondaryData: new fields.TypedObjectField(new fields.StringField({ required: true })),
itemUuid: new fields.StringField({ required: true })
itemUuid: new fields.StringField({ required: true }),
actionIds: new fields.ArrayField(new fields.StringField())
})
)
})
@ -50,6 +51,10 @@ export default class DhLevelData extends foundry.abstract.DataModel {
};
}
get actions() {
return Object.values(this.levelups).flatMap(level => level.selections.flatMap(s => s.actions));
}
get canLevelUp() {
return this.level.current < this.level.changed;
}

View file

@ -65,14 +65,29 @@ export const CompanionLevelOptionType = {
},
creatureComfort: {
id: 'creatureComfort',
label: 'Creature Comfort'
// actions: [
// ],
label: 'Creature Comfort',
actions: [
{
name: 'DAGGERHEART.LevelUp.Actions.CreatureComfort.Name',
img: 'icons/magic/life/heart-cross-purple-orange.webp',
type: 'attack',
actionType: 'passive',
description: 'DAGGERHEART.LevelUp.Actions.CreatureComfort.Description'
}
]
},
armored: {
id: 'armored',
label: 'Armored'
label: 'Armored',
actions: [
{
name: 'DAGGERHEART.LevelUp.Actions.Armored.Name',
img: 'icons/equipment/shield/kite-wooden-oak-glow.webp',
type: 'attack',
actionType: 'passive',
description: 'DAGGERHEART.LevelUp.Actions.Armored.Description'
}
]
},
vicious: {
id: 'vicious',
@ -84,7 +99,16 @@ export const CompanionLevelOptionType = {
},
bonded: {
id: 'bonded',
label: 'Bonded'
label: 'Bonded',
actions: [
{
name: 'DAGGERHEART.LevelUp.Actions.Bonded.Name',
img: 'icons/magic/life/heart-red-blue.webp',
type: 'attack',
actionType: 'passive',
description: 'DAGGERHEART.LevelUp.Actions.Bonded.Description'
}
]
},
aware: {
id: 'aware',

View file

@ -1,6 +1,8 @@
import DamageSelectionDialog from '../applications/damageSelectionDialog.mjs';
import { GMUpdateEvent, socketEvent } from '../helpers/socket.mjs';
import DamageReductionDialog from '../applications/damageReductionDialog.mjs';
import { actionsTypes } from '../data/_module.mjs';
import { LevelOptionType } from '../data/levelTier.mjs';
export default class DhpActor extends Actor {
async _preCreate(data, options, user) {
@ -20,10 +22,6 @@ export default class DhpActor extends Actor {
async updateLevel(newLevel) {
if (!['character', 'companion'].includes(this.type) || newLevel === this.system.levelData.level.changed) return;
if (this.system.companion) {
this.system.companion.updateLevel(newLevel);
}
if (newLevel > this.system.levelData.level.current) {
const maxLevel = Object.values(
game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.LevelTiers).tiers
@ -122,10 +120,15 @@ export default class DhpActor extends Actor {
}
}
});
if (this.system.companion) {
this.system.companion.updateLevel(newLevel);
}
}
}
async levelUp(levelupData) {
const actions = [];
const levelups = {};
for (var levelKey of Object.keys(levelupData)) {
const level = levelupData[levelKey];
@ -150,6 +153,7 @@ export default class DhpActor extends Actor {
}
let multiclass = null;
const actionIds = [];
const domainCards = [];
const subclassFeatureState = { class: null, multiclass: null };
const selections = [];
@ -158,6 +162,27 @@ export default class DhpActor extends Actor {
for (var checkboxNr of Object.keys(selection)) {
const checkbox = selection[checkboxNr];
const tierOption = LevelOptionType[checkbox.type];
for (var actionData of tierOption.actions ?? []) {
const cls = actionsTypes[actionData.type];
const actionId = foundry.utils.randomID();
actionIds.push(actionId);
actions.push(
new cls(
{
// ...cls.getSourceConfig(target),
...actionData,
_id: actionId,
name: game.i18n.localize(actionData.name),
description: game.i18n.localize(actionData.description)
},
{
parent: this
}
)
);
}
if (checkbox.type === 'multiclass') {
multiclass = {
...checkbox,
@ -255,6 +280,7 @@ export default class DhpActor extends Actor {
await this.update({
system: {
actions: [...this.system.actions, ...actions],
levelData: {
level: {
current: this.system.levelData.level.changed
@ -263,6 +289,10 @@ export default class DhpActor extends Actor {
}
}
});
if (this.system.companion) {
this.system.companion.updateLevel(this.system.levelData.level.changed);
}
}
/**

View file

@ -10,6 +10,12 @@
{{#if document.system.class.subclass}}
{{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(concat (localize 'TYPES.Item.subclass') ' - ' document.system.class.subclass.name) type='subclass'}}
{{/if}}
{{#if document.system.actions}}
{{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize "DAGGERHEART.Sheets.PC.Actions") type='actions'}}
{{/if}}
{{#if document.system.companionActions}}
{{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(localize "DAGGERHEART.Sheets.PC.CompanionActions") type='companionActions'}}
{{/if}}
{{#if document.system.community}}
{{> 'systems/daggerheart/templates/sheets/global/partials/inventory-fieldset-items.hbs' title=(concat (localize 'TYPES.Item.community') ' - ' document.system.community.name) type='community'}}
{{/if}}

View file

@ -0,0 +1,16 @@
<li class="inventory-item" data-item-id="{{item.id}}" data-is-action="true" data-partner="{{partner}}">
<img src="{{item.img}}" class="item-img" data-action="useItem" />
<div class="item-label">
<div class="item-name">{{item.name}}</div>
{{!-- <div class="item-tags">
<div class="tag">
</div>
<div class="tag">
</div>
</div> --}}
</div>
<div class="controls">
<a data-action="toChat" data-tooltip="{{localize 'DAGGERHEART.Tooltip.sendToChat'}}"><i class="fa-regular fa-message"></i></a>
<a data-action="triggerContextMenu" data-tooltip="{{localize 'DAGGERHEART.Tooltip.moreOptions'}}"><i class="fa-solid fa-ellipsis-vertical"></i></a>
</div>
</li>

View file

@ -34,6 +34,16 @@
{{> 'systems/daggerheart/templates/sheets/global/partials/inventory-item.hbs' item=effect type=../type}}
{{/if}}
{{/each}}
{{#each document.system.actions as |action|}}
{{#if (or (eq ../type 'actions'))}}
{{> 'systems/daggerheart/templates/sheets/global/partials/action-item.hbs' item=action}}
{{/if}}
{{/each}}
{{#each document.system.companionActions as |action|}}
{{#if (or (eq ../type 'companionActions'))}}
{{> 'systems/daggerheart/templates/sheets/global/partials/action-item.hbs' item=action partner=true}}
{{/if}}
{{/each}}
{{/unless}}
</ul>