mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-18 16:09:03 +01:00
Fixed class/subclass drag-drop
This commit is contained in:
parent
39eb3dce69
commit
0cf9e1d17c
10 changed files with 247 additions and 28 deletions
18
lang/en.json
18
lang/en.json
|
|
@ -173,6 +173,14 @@
|
|||
"experienceDataRemoveConfirmation": {
|
||||
"title": "Remove Experience Data",
|
||||
"text": "The experience you are about to remove has levelup data linked to it (assumably because you did levelups with the 'levelupAuto' automation setting on). Removing it will remove this automation data aswell. Do you want to proceed?"
|
||||
},
|
||||
"manualMulticlass": {
|
||||
"title": "Multiclass",
|
||||
"text": "Do you want to add this class as your multiclass?"
|
||||
},
|
||||
"manualMulticlassSubclass": {
|
||||
"title": "Multiclass Subclass",
|
||||
"text": "Do you want to add this subclass as your multiclass subclass?"
|
||||
}
|
||||
},
|
||||
"Companion": {
|
||||
|
|
@ -466,6 +474,11 @@
|
|||
},
|
||||
"title": "{actor} Level Up"
|
||||
},
|
||||
"MulticlassChoice": {
|
||||
"title": "Multiclassing - {actor}",
|
||||
"explanation": "You are adding {class} as your multiclass",
|
||||
"selectDomainPrompt": "Select your new domain"
|
||||
},
|
||||
"OwnershipSelection": {
|
||||
"title": "Ownership Selection - {name}",
|
||||
"default": "Default Ownership"
|
||||
|
|
@ -2209,6 +2222,7 @@
|
|||
"tooLowLevel": "You cannot lower the character level below starting level",
|
||||
"subclassNotInClass": "This subclass does not belong to your selected class.",
|
||||
"missingClass": "You don't have a class selected yet.",
|
||||
"missingMulticlass": "Missing multiclass",
|
||||
"wrongDomain": "The card isn't from one of your class domains.",
|
||||
"cardTooHighLevel": "The card is too high level!",
|
||||
"duplicateCard": "You cannot select the same card more than once.",
|
||||
|
|
@ -2238,7 +2252,9 @@
|
|||
"beastformToManyFeatures": "You cannot select any more features.",
|
||||
"beastformEquipWeapon": "You cannot use weapons while in a Beastform.",
|
||||
"loadoutMaxReached": "You already have {max} cards in your loadout. Move atleast one to your vault before adding a new one.",
|
||||
"insufficientResources": "You have insufficient resources"
|
||||
"insufficientResources": "You have insufficient resources",
|
||||
"multiclassAlreadyPresent": "You already have a class and multiclass",
|
||||
"subclassesAlreadyPresent": "You already have a class and multiclass subclass"
|
||||
},
|
||||
"Tooltip": {
|
||||
"disableEffect": "Disable Effect",
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ export { default as DamageReductionDialog } from './damageReductionDialog.mjs';
|
|||
export { default as DamageSelectionDialog } from './damageSelectionDialog.mjs';
|
||||
export { default as DeathMove } from './deathMove.mjs';
|
||||
export { default as Downtime } from './downtime.mjs';
|
||||
export { default as MulticlassChoiceDialog } from './multiclassChoiceDialog.mjs';
|
||||
export { default as OwnershipSelection } from './ownershipSelection.mjs';
|
||||
export { default as ResourceDiceDialog } from './resourceDiceDialog.mjs';
|
||||
export { default as ActionSelectionDialog } from './actionSelectionDialog.mjs';
|
||||
|
|
|
|||
73
module/applications/dialogs/multiclassChoiceDialog.mjs
Normal file
73
module/applications/dialogs/multiclassChoiceDialog.mjs
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
||||
export default class MulticlassChoiceDialog extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||
constructor(actor, multiclass, options) {
|
||||
super(options);
|
||||
|
||||
this.actor = actor;
|
||||
this.multiclass = multiclass;
|
||||
this.selectedDomain = null;
|
||||
}
|
||||
|
||||
get title() {
|
||||
return game.i18n.format('DAGGERHEART.APPLICATIONS.MulticlassChoice.title', { actor: this.actor.name });
|
||||
}
|
||||
|
||||
static DEFAULT_OPTIONS = {
|
||||
classes: ['daggerheart', 'dh-style', 'dialog', 'views', 'multiclass-choice'],
|
||||
position: { width: 'auto', height: 'auto' },
|
||||
window: { icon: 'fa-solid fa-person-rays' },
|
||||
actions: {
|
||||
save: MulticlassChoiceDialog.#save,
|
||||
selectDomain: MulticlassChoiceDialog.#selectDomain
|
||||
}
|
||||
};
|
||||
|
||||
static PARTS = {
|
||||
application: {
|
||||
id: 'multiclass-choice',
|
||||
template: 'systems/daggerheart/templates/dialogs/multiclassChoice.hbs'
|
||||
}
|
||||
};
|
||||
|
||||
async _prepareContext(_options) {
|
||||
const context = await super._prepareContext(_options);
|
||||
context.multiclass = this.multiclass;
|
||||
context.domainChoices = this.multiclass.domains.map(value => {
|
||||
const domain = CONFIG.DH.DOMAIN.domains[value];
|
||||
return {
|
||||
value: value,
|
||||
label: game.i18n.localize(domain.label),
|
||||
description: game.i18n.localize(domain.description),
|
||||
src: domain.src,
|
||||
selected: value === this.selectedDomain,
|
||||
disabled: this.actor.system.domains.includes(domain)
|
||||
};
|
||||
});
|
||||
context.multiclassDisabled = !this.selectedDomain;
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/** @override */
|
||||
_onClose(options = {}) {
|
||||
if (!options.submitted) this.move = null;
|
||||
}
|
||||
|
||||
static async configure(actor, multiclass, options = {}) {
|
||||
return new Promise(resolve => {
|
||||
const app = new this(actor, multiclass, options);
|
||||
app.addEventListener('close', () => resolve(app.selectedDomain), { once: true });
|
||||
app.render({ force: true });
|
||||
});
|
||||
}
|
||||
|
||||
static #save() {
|
||||
this.close({ submitted: true });
|
||||
}
|
||||
|
||||
static #selectDomain(_event, button) {
|
||||
this.selectedDomain = this.selectedDomain === button.dataset.domain ? null : button.dataset.domain;
|
||||
this.render();
|
||||
}
|
||||
}
|
||||
|
|
@ -62,16 +62,37 @@ export default class DHClass extends BaseDataItem {
|
|||
}
|
||||
|
||||
async _preCreate(data, options, user) {
|
||||
const allowed = await super._preCreate(data, options, user);
|
||||
if (allowed === false) return;
|
||||
|
||||
if (this.actor?.type === 'character') {
|
||||
const path = data.system.isMulticlass ? 'system.multiclass.value' : 'system.class.value';
|
||||
if (foundry.utils.getProperty(this.actor, path)) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.classAlreadySelected'));
|
||||
return false;
|
||||
const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto;
|
||||
if (levelupAuto) {
|
||||
const path = data.system.isMulticlass ? 'system.multiclass.value' : 'system.class.value';
|
||||
if (foundry.utils.getProperty(this.actor, path)) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.classAlreadySelected'));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
if (this.actor.system.class.value) {
|
||||
if (this.actor.system.multiclass.value) {
|
||||
ui.notifications.warn(
|
||||
game.i18n.localize('DAGGERHEART.UI.Notifications.multiclassAlreadyPresent')
|
||||
);
|
||||
return false;
|
||||
} else {
|
||||
const selectedDomain =
|
||||
await game.system.api.applications.dialogs.MulticlassChoiceDialog.configure(
|
||||
this.actor,
|
||||
this
|
||||
);
|
||||
if (!selectedDomain) return false;
|
||||
|
||||
await this.updateSource({ isMulticlass: true, domains: [selectedDomain] });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const allowed = await super._preCreate(data, options, user);
|
||||
if (allowed === false) return;
|
||||
}
|
||||
|
||||
_onCreate(data, options, userId) {
|
||||
|
|
|
|||
|
|
@ -45,21 +45,23 @@ export default class DHSubclass extends BaseDataItem {
|
|||
if (allowed === false) return;
|
||||
|
||||
if (this.actor?.type === 'character') {
|
||||
const classData = this.actor.items.find(
|
||||
x => x.type === 'class' && x.system.isMulticlass === data.system.isMulticlass
|
||||
);
|
||||
const subclassData = this.actor.items.find(
|
||||
x => x.type === 'subclass' && x.system.isMulticlass === data.system.isMulticlass
|
||||
);
|
||||
if (!classData) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass'));
|
||||
return false;
|
||||
} else if (subclassData) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassAlreadySelected'));
|
||||
return false;
|
||||
} else if (classData.system.subclasses.every(x => x.uuid !== (data.uuid ?? `Item.${data._id}`))) {
|
||||
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass'));
|
||||
return false;
|
||||
if (this.actor.system.class.subclass) {
|
||||
if (this.actor.system.multiclass.subclass) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassesAlreadyPresent'));
|
||||
return false;
|
||||
} else {
|
||||
if (!this.actor.system.multiclass.value) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingMulticlass'));
|
||||
return false;
|
||||
}
|
||||
|
||||
await this.updateSource({ isMulticlass: true });
|
||||
}
|
||||
} else {
|
||||
if (!this.actor.system.class.value) {
|
||||
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,3 +24,5 @@
|
|||
@import './dice-roll/roll-selection.less';
|
||||
@import './damage-reduction/damage-reduction-container.less';
|
||||
@import './damage-reduction/sheets.less';
|
||||
|
||||
@import './multiclass-choice/sheet.less';
|
||||
|
|
|
|||
76
styles/less/dialog/multiclass-choice/sheet.less
Normal file
76
styles/less/dialog/multiclass-choice/sheet.less
Normal file
|
|
@ -0,0 +1,76 @@
|
|||
.theme-light .daggerheart.dh-style.dialog.multiclass-choice {
|
||||
.multiclass-container .domain-choice-container button label {
|
||||
background-image: url(../assets/parchments/dh-parchment-light.png);
|
||||
}
|
||||
}
|
||||
|
||||
.daggerheart.dh-style.dialog.multiclass-choice {
|
||||
.multiclass-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
.multiclass-explanation {
|
||||
margin-top: 0;
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.multiclass-domains-container {
|
||||
display: flex;
|
||||
gap: 16px;
|
||||
|
||||
.domain-choice-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
width: 120px;
|
||||
height: 120px;
|
||||
background: light-dark(@dark-blue-10, @golden-10);
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
|
||||
&.selected {
|
||||
background: light-dark(@dark-blue-40, @golden-40);
|
||||
}
|
||||
|
||||
label {
|
||||
position: absolute;
|
||||
top: 4px;
|
||||
font-family: @font-body;
|
||||
border-radius: 6px;
|
||||
border: 2px solid;
|
||||
padding: 0 2px;
|
||||
background-image: url(../assets/parchments/dh-parchment-dark.png);
|
||||
color: light-dark(@dark, @beige);
|
||||
}
|
||||
}
|
||||
|
||||
.domain-description {
|
||||
width: 240px;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
font-style: italic;
|
||||
border: 1px solid light-dark(@dark-blue, @golden);
|
||||
border-radius: 6px;
|
||||
padding: 4px 4px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
footer {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
gap: 8px;
|
||||
|
||||
button {
|
||||
flex: 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -88,6 +88,11 @@
|
|||
font-size: 12px;
|
||||
color: light-dark(@dark-blue, @golden);
|
||||
|
||||
.missing-header-feature {
|
||||
opacity: 0.5;
|
||||
text-decoration: line-through;
|
||||
}
|
||||
|
||||
span {
|
||||
padding: 3px;
|
||||
border-radius: 3px;
|
||||
|
|
|
|||
23
templates/dialogs/multiclassChoice.hbs
Normal file
23
templates/dialogs/multiclassChoice.hbs
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
<div>
|
||||
<div class="multiclass-container">
|
||||
<h5 class="multiclass-explanation">{{localize "DAGGERHEART.APPLICATIONS.MulticlassChoice.explanation" class=multiclass.parent.name }}</h5>
|
||||
<h5 class="multiclass-explanation">{{localize "DAGGERHEART.APPLICATIONS.MulticlassChoice.selectDomainPrompt" }}</h5>
|
||||
|
||||
<div class="multiclass-domains-container">
|
||||
{{#each domainChoices as | choice |}}
|
||||
<div class="domain-choice-container">
|
||||
<button data-action="selectDomain" data-domain="{{choice.value}}" {{#if choice.selected}}class="selected"{{/if}}>
|
||||
<label>{{choice.label}}</label>
|
||||
<img src="{{choice.src}}" />
|
||||
</button>
|
||||
<div class="domain-description">{{choice.description}}</div>
|
||||
</div>
|
||||
{{/each}}
|
||||
</div>
|
||||
|
||||
<footer>
|
||||
<button data-action="close">{{localize "Cancel"}}</button>
|
||||
<button data-action="save" {{disabled multiclassDisabled}}>{{localize "DAGGERHEART.GENERAL.multiclass"}}</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -31,25 +31,25 @@
|
|||
{{#if document.system.class.value}}
|
||||
<span data-action="editDoc" data-item-uuid="{{document.system.class.value.uuid}}">{{document.system.class.value.name}}</span>
|
||||
{{else}}
|
||||
<span data-action="openPack" data-key="daggerheart.classes">{{localize 'TYPES.Item.class'}}</span>
|
||||
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.classes">{{localize 'TYPES.Item.class'}}</span>
|
||||
{{/if}}
|
||||
<span class="dot">•</span>
|
||||
{{#if document.system.class.subclass}}
|
||||
<span data-action="editDoc" data-item-uuid="{{document.system.class.subclass.uuid}}">{{document.system.class.subclass.name}}</span>
|
||||
{{else}}
|
||||
<span data-action="openPack" data-key="daggerheart.subclass">{{localize 'TYPES.Item.subclass'}}</span>
|
||||
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.subclasses">{{localize 'TYPES.Item.subclass'}}</span>
|
||||
{{/if}}
|
||||
<span class="dot">•</span>
|
||||
{{#if document.system.community}}
|
||||
<span data-action="editDoc" data-item-uuid="{{document.system.community.uuid}}">{{document.system.community.name}}</span>
|
||||
{{else}}
|
||||
<span data-action="openPack" data-key="daggerheart.community">{{localize 'TYPES.Item.community'}}</span>
|
||||
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.communities">{{localize 'TYPES.Item.community'}}</span>
|
||||
{{/if}}
|
||||
<span class="dot">•</span>
|
||||
{{#if document.system.ancestry}}
|
||||
<span data-action="editDoc" data-item-uuid="{{document.system.ancestry.uuid}}">{{document.system.ancestry.name}}</span>
|
||||
{{else}}
|
||||
<span data-action="openPack" data-key="daggerheart.ancestry">{{localize 'TYPES.Item.ancestry'}}</span>
|
||||
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.ancestries">{{localize 'TYPES.Item.ancestry'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
|
||||
|
|
@ -64,7 +64,7 @@
|
|||
{{#if document.system.multiclass.subclass}}
|
||||
<span data-action="editDoc" data-item-uuid="{{document.system.multiclass.subclass.uuid}}">{{document.system.multiclass.subclass.name}}</span>
|
||||
{{else}}
|
||||
<span data-action="openPack" data-key="daggerheart.subclass">{{localize 'TYPES.Item.subclass'}}</span>
|
||||
<span class="missing-header-feature" data-action="openPack" data-key="daggerheart.subclasses">{{localize 'TYPES.Item.subclass'}}</span>
|
||||
{{/if}}
|
||||
</div>
|
||||
{{/if}}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue