mirror of
https://github.com/Foundryborne/daggerheart.git
synced 2026-01-15 13:11:08 +01:00
Merged with main
This commit is contained in:
commit
57334b0a63
15 changed files with 490 additions and 4 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -2,4 +2,5 @@
|
||||||
node_modules
|
node_modules
|
||||||
/packs
|
/packs
|
||||||
Build
|
Build
|
||||||
/build
|
/build
|
||||||
|
foundry
|
||||||
21
daggerheart.d.ts
vendored
Normal file
21
daggerheart.d.ts
vendored
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import './module/_types';
|
||||||
|
import '@client/global.mjs';
|
||||||
|
import Canvas from '@client/canvas/board.mjs';
|
||||||
|
|
||||||
|
// Foundry's use of `Object.assign(globalThis) means many globally available objects are not read as such
|
||||||
|
// This declare global hopefully fixes that
|
||||||
|
declare global {
|
||||||
|
/**
|
||||||
|
* A simple event framework used throughout Foundry Virtual Tabletop.
|
||||||
|
* When key actions or events occur, a "hook" is defined where user-defined callback functions can execute.
|
||||||
|
* This class manages the registration and execution of hooked callback functions.
|
||||||
|
*/
|
||||||
|
class Hooks extends foundry.helpers.Hooks {}
|
||||||
|
const fromUuid = foundry.utils.fromUuid;
|
||||||
|
const fromUuidSync = foundry.utils.fromUuidSync;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The singleton game canvas
|
||||||
|
*/
|
||||||
|
const canvas: Canvas;
|
||||||
|
}
|
||||||
|
|
@ -13,6 +13,7 @@ import DhpTokenRuler from './module/ui/tokenRuler.mjs';
|
||||||
import { dualityRollEnricher } from './module/enrichers/DualityRollEnricher.mjs';
|
import { dualityRollEnricher } from './module/enrichers/DualityRollEnricher.mjs';
|
||||||
import { getCommandTarget, rollCommandToJSON, setDiceSoNiceForDualityRoll } from './module/helpers/utils.mjs';
|
import { getCommandTarget, rollCommandToJSON, setDiceSoNiceForDualityRoll } from './module/helpers/utils.mjs';
|
||||||
import { abilities } from './module/config/actorConfig.mjs';
|
import { abilities } from './module/config/actorConfig.mjs';
|
||||||
|
import Resources from './module/applications/resources.mjs';
|
||||||
|
|
||||||
globalThis.SYSTEM = SYSTEM;
|
globalThis.SYSTEM = SYSTEM;
|
||||||
|
|
||||||
|
|
@ -92,9 +93,11 @@ Hooks.once('init', () => {
|
||||||
CONFIG.Combat.documentClass = documents.DhpCombat;
|
CONFIG.Combat.documentClass = documents.DhpCombat;
|
||||||
CONFIG.ui.combat = DhpCombatTracker;
|
CONFIG.ui.combat = DhpCombatTracker;
|
||||||
CONFIG.ui.chat = DhpChatLog;
|
CONFIG.ui.chat = DhpChatLog;
|
||||||
CONFIG.ui.players = DhpPlayers;
|
// CONFIG.ui.players = DhpPlayers;
|
||||||
CONFIG.Token.rulerClass = DhpTokenRuler;
|
CONFIG.Token.rulerClass = DhpTokenRuler;
|
||||||
|
|
||||||
|
CONFIG.ui.resources = Resources;
|
||||||
|
|
||||||
game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent);
|
game.socket.on(`system.${SYSTEM.id}`, handleSocketEvent);
|
||||||
|
|
||||||
// Make Compendium Dialog resizable
|
// Make Compendium Dialog resizable
|
||||||
|
|
@ -106,6 +109,11 @@ Hooks.once('init', () => {
|
||||||
return preloadHandlebarsTemplates();
|
return preloadHandlebarsTemplates();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
Hooks.on('ready', () => {
|
||||||
|
ui.resources = new CONFIG.ui.resources();
|
||||||
|
ui.resources.render({ force: true });
|
||||||
|
});
|
||||||
|
|
||||||
Hooks.once('dicesoniceready', () => {});
|
Hooks.once('dicesoniceready', () => {});
|
||||||
|
|
||||||
Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => {
|
Hooks.on(socketEvent.GMUpdate, async (action, uuid, update) => {
|
||||||
|
|
|
||||||
15
jsconfig.json
Normal file
15
jsconfig.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "ES6",
|
||||||
|
"target": "ES6",
|
||||||
|
"paths": {
|
||||||
|
"@client/*": ["./foundry/client/*"],
|
||||||
|
"@common/*": ["./foundry/common/*"]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"exclude": ["node_modules", "**/node_modules/*"],
|
||||||
|
"include": ["daggerheart.mjs", "foundry/client/client.mjs", "daggerheart.d.ts"],
|
||||||
|
"typeAcquisition": {
|
||||||
|
"include": ["jquery"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -81,6 +81,14 @@
|
||||||
"Fear": {
|
"Fear": {
|
||||||
"Name": "Fear",
|
"Name": "Fear",
|
||||||
"Hint": "The Fear pool of the GM."
|
"Hint": "The Fear pool of the GM."
|
||||||
|
},
|
||||||
|
"MaxFear": {
|
||||||
|
"Name": "Maximum amount of Fear",
|
||||||
|
"Hint": "The maximum amount of Fear the GM can get."
|
||||||
|
},
|
||||||
|
"DisplayFear": {
|
||||||
|
"Name": "Fear display style",
|
||||||
|
"Hint": "Change how the GM Fear count should be displayed."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"General": {
|
"General": {
|
||||||
|
|
|
||||||
0
module/_types.d.ts
vendored
Normal file
0
module/_types.d.ts
vendored
Normal file
110
module/applications/resources.mjs
Normal file
110
module/applications/resources.mjs
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A UI element which displays the Users defined for this world.
|
||||||
|
* Currently active users are always displayed, while inactive users can be displayed on toggle.
|
||||||
|
*
|
||||||
|
* @extends ApplicationV2
|
||||||
|
* @mixes HandlebarsApplication
|
||||||
|
*/
|
||||||
|
|
||||||
|
export default class Resources extends HandlebarsApplicationMixin(ApplicationV2) {
|
||||||
|
constructor(options = {}) {
|
||||||
|
super(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @inheritDoc */
|
||||||
|
static DEFAULT_OPTIONS = {
|
||||||
|
id: 'resources',
|
||||||
|
classes: [],
|
||||||
|
tag: 'div',
|
||||||
|
window: {
|
||||||
|
frame: true,
|
||||||
|
title: 'Fear',
|
||||||
|
positioned: true,
|
||||||
|
resizable: true
|
||||||
|
},
|
||||||
|
actions: {
|
||||||
|
setFear: Resources.setFear,
|
||||||
|
increaseFear: Resources.increaseFear
|
||||||
|
},
|
||||||
|
position: {
|
||||||
|
width: 222,
|
||||||
|
height: 222
|
||||||
|
// top: "200px",
|
||||||
|
// left: "120px"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
static PARTS = {
|
||||||
|
resources: {
|
||||||
|
root: true,
|
||||||
|
template: 'systems/daggerheart/templates/views/resources.hbs'
|
||||||
|
// template: "templates/ui/players.hbs"
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
get currentFear() {
|
||||||
|
return game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear);
|
||||||
|
}
|
||||||
|
|
||||||
|
get maxFear() {
|
||||||
|
return game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.MaxFear);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
/* Rendering */
|
||||||
|
/* -------------------------------------------- */
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _prepareContext(_options) {
|
||||||
|
const display = game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.DisplayFear),
|
||||||
|
current = this.currentFear,
|
||||||
|
max = this.maxFear,
|
||||||
|
percent = (current / max) * 100,
|
||||||
|
isGM = game.user.isGM;
|
||||||
|
// Return the data for rendering
|
||||||
|
return { display, current, max, percent, isGM };
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _preFirstRender(context, options) {
|
||||||
|
options.position = game.user.getFlag(SYSTEM.id, 'app.resources.position') ?? Resources.DEFAULT_OPTIONS.position;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @override */
|
||||||
|
async _preRender(context, options) {
|
||||||
|
if (this.currentFear > this.maxFear)
|
||||||
|
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, this.maxFear);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onPosition(position) {
|
||||||
|
game.user.setFlag(SYSTEM.id, 'app.resources.position', position);
|
||||||
|
}
|
||||||
|
|
||||||
|
async close(options = {}) {
|
||||||
|
if (!options.allowed) return;
|
||||||
|
else super.close(options);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async setFear(event, target) {
|
||||||
|
if (!game.user.isGM) return;
|
||||||
|
const fearCount = Number(target.dataset.index ?? 0);
|
||||||
|
await this.updateFear(this.currentFear === fearCount + 1 ? fearCount : fearCount + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static async increaseFear(event, target) {
|
||||||
|
let value = target.dataset.increment ?? 0,
|
||||||
|
operator = value.split('')[0] ?? null;
|
||||||
|
value = Number(value);
|
||||||
|
await this.updateFear(operator ? this.currentFear + value : value);
|
||||||
|
}
|
||||||
|
|
||||||
|
async updateFear(value) {
|
||||||
|
if (!game.user.isGM) return;
|
||||||
|
value = Math.max(0, Math.min(this.maxFear, value));
|
||||||
|
await game.settings.set(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.Fear, value);
|
||||||
|
await this.render(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -184,6 +184,38 @@ export const registerDHSettings = () => {
|
||||||
default: 0
|
default: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
|
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.MaxFear, {
|
||||||
|
name: game.i18n.localize('DAGGERHEART.Settings.Resources.MaxFear.Name'),
|
||||||
|
hint: game.i18n.localize('DAGGERHEART.Settings.Resources.MaxFear.Hint'),
|
||||||
|
scope: 'world',
|
||||||
|
config: true,
|
||||||
|
type: Number,
|
||||||
|
default: 12,
|
||||||
|
onChange: () => {
|
||||||
|
if (ui.resources) ui.resources.render({ force: true });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Resources.DisplayFear, {
|
||||||
|
name: game.i18n.localize('DAGGERHEART.Settings.Resources.DisplayFear.Name'),
|
||||||
|
hint: game.i18n.localize('DAGGERHEART.Settings.Resources.DisplayFear.Hint'),
|
||||||
|
scope: 'client',
|
||||||
|
config: true,
|
||||||
|
type: String,
|
||||||
|
choices: {
|
||||||
|
token: 'Tokens',
|
||||||
|
bar: 'Bar',
|
||||||
|
hide: 'Hide'
|
||||||
|
},
|
||||||
|
default: 'token',
|
||||||
|
onChange: value => {
|
||||||
|
if (ui.resources) {
|
||||||
|
if (value === 'hide') ui.resources.close({ allowed: true });
|
||||||
|
else ui.resources.render({ force: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope, {
|
game.settings.register(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.Automation.Hope, {
|
||||||
name: game.i18n.localize('DAGGERHEART.Settings.Automation.Hope.Name'),
|
name: game.i18n.localize('DAGGERHEART.Settings.Automation.Hope.Name'),
|
||||||
hint: game.i18n.localize('DAGGERHEART.Settings.Automation.Hope.Hint'),
|
hint: game.i18n.localize('DAGGERHEART.Settings.Automation.Hope.Hint'),
|
||||||
|
|
|
||||||
|
|
@ -19,7 +19,9 @@ export const gameSettings = {
|
||||||
ActionPoints: 'AutomationActionPoints'
|
ActionPoints: 'AutomationActionPoints'
|
||||||
},
|
},
|
||||||
Resources: {
|
Resources: {
|
||||||
Fear: 'ResourcesFear'
|
Fear: 'ResourcesFear',
|
||||||
|
MaxFear: 'ResourcesMaxFear',
|
||||||
|
DisplayFear: 'DisplayFear'
|
||||||
},
|
},
|
||||||
General: {
|
General: {
|
||||||
AbilityArray: 'AbilityArray',
|
AbilityArray: 'AbilityArray',
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,8 @@
|
||||||
"start": "concurrently \"rollup -c --watch\" \"node ../../../../FoundryDev/main.js --dataPath=../../../ --noupnp\" \"gulp\"",
|
"start": "concurrently \"rollup -c --watch\" \"node ../../../../FoundryDev/main.js --dataPath=../../../ --noupnp\" \"gulp\"",
|
||||||
"start-test": "node ./resources/app/main.js --dataPath=./ && rollup -c --watch && gulp",
|
"start-test": "node ./resources/app/main.js --dataPath=./ && rollup -c --watch && gulp",
|
||||||
"pushLDBtoYML": "node ./tools/pushLDBtoYML.mjs",
|
"pushLDBtoYML": "node ./tools/pushLDBtoYML.mjs",
|
||||||
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs"
|
"pullYMLtoLDB": "node ./tools/pullYMLtoLDB.mjs",
|
||||||
|
"createSymlink": "node ./tools/create-symlink.mjs"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@foundryvtt/foundryvtt-cli": "^1.0.2",
|
"@foundryvtt/foundryvtt-cli": "^1.0.2",
|
||||||
|
|
|
||||||
|
|
@ -2905,6 +2905,115 @@ div.daggerheart.views.multiclass {
|
||||||
.daggerheart.levelup .levelup-footer .advancement-information-container .advancement-tier-info {
|
.daggerheart.levelup .levelup-footer .advancement-information-container .advancement-tier-info {
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
:root {
|
||||||
|
--primary-color-fear: rgba(9, 71, 179, 0.75);
|
||||||
|
--secondary-color-fear: rgba(9, 71, 179, 0.75);
|
||||||
|
--shadow-text-stroke: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
|
||||||
|
}
|
||||||
|
#resources {
|
||||||
|
min-height: calc(var(--header-height) + 4rem);
|
||||||
|
min-width: 4rem;
|
||||||
|
color: #d3d3d3;
|
||||||
|
}
|
||||||
|
#resources .window-content {
|
||||||
|
padding: 0.5rem;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 0.5rem 0.25rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear i {
|
||||||
|
font-size: var(--font-size-18);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||||
|
border-radius: 50%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 3rem;
|
||||||
|
background-color: var(--primary-color-fear);
|
||||||
|
-webkit-box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.75);
|
||||||
|
box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.75);
|
||||||
|
color: #d3d3d3;
|
||||||
|
flex-grow: 0;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear i.inactive {
|
||||||
|
filter: grayscale(1) !important;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear .controls,
|
||||||
|
#resources .window-content #resource-fear .resource-bar {
|
||||||
|
border: 2px solid #997a4f;
|
||||||
|
background-color: #18162e;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear .controls {
|
||||||
|
display: flex;
|
||||||
|
align-self: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
font-size: var(--font-size-20);
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear .controls:hover {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear .controls.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear .resource-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: var(--font-size-20);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
flex: 1;
|
||||||
|
text-shadow: var(--shadow-text-stroke);
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear .resource-bar:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: var(--fear-percent);
|
||||||
|
max-width: 100%;
|
||||||
|
background: linear-gradient(90deg, #020026 0%, #c701fc 100%);
|
||||||
|
z-index: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear .resource-bar span {
|
||||||
|
position: inherit;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear.isGM i {
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
#resources .window-content #resource-fear.isGM i:hover {
|
||||||
|
font-size: var(--font-size-20);
|
||||||
|
}
|
||||||
|
#resources button[data-action="close"] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#resources:not(:hover):not(.minimized) {
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: unset;
|
||||||
|
border-color: transparent;
|
||||||
|
}
|
||||||
|
#resources:not(:hover):not(.minimized) header,
|
||||||
|
#resources:not(:hover):not(.minimized) .controls,
|
||||||
|
#resources:not(:hover):not(.minimized) .window-resize-handle {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
#resources:has(.fear-bar) {
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
.application.sheet.daggerheart.dh-style.feature .item-sheet-header {
|
.application.sheet.daggerheart.dh-style.feature .item-sheet-header {
|
||||||
display: flex;
|
display: flex;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@
|
||||||
@import './dialog.less';
|
@import './dialog.less';
|
||||||
@import './levelup.less';
|
@import './levelup.less';
|
||||||
@import '../node_modules/@yaireo/tagify/dist/tagify.css';
|
@import '../node_modules/@yaireo/tagify/dist/tagify.css';
|
||||||
|
@import './resources.less';
|
||||||
|
|
||||||
// new styles imports
|
// new styles imports
|
||||||
@import './less/items/feature.less';
|
@import './less/items/feature.less';
|
||||||
|
|
|
||||||
115
styles/resources.less
Normal file
115
styles/resources.less
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
:root {
|
||||||
|
--primary-color-fear: rgba(9, 71, 179, 0.75);
|
||||||
|
--secondary-color-fear: rgba(9, 71, 179, 0.75);
|
||||||
|
--shadow-text-stroke: -1px -1px 0 #000, 1px -1px 0 #000, -1px 1px 0 #000, 1px 1px 0 #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#resources {
|
||||||
|
min-height: calc(var(--header-height) + 4rem);
|
||||||
|
min-width: 4rem;
|
||||||
|
color: #d3d3d3;
|
||||||
|
.window-content {
|
||||||
|
padding: 0.5rem;
|
||||||
|
#resource-fear {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
gap: 0.5rem 0.25rem;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
i {
|
||||||
|
font-size: var(--font-size-18);
|
||||||
|
// flex: 1 1 calc(25% - 0.25rem);
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.5);
|
||||||
|
border-radius: 50%;
|
||||||
|
aspect-ratio: 1;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
width: 3rem;
|
||||||
|
background-color: var(--primary-color-fear);
|
||||||
|
-webkit-box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.75);
|
||||||
|
box-shadow: 0px 0px 5px 1px rgba(0, 0, 0, 0.75);
|
||||||
|
color: #d3d3d3;
|
||||||
|
flex-grow: 0;
|
||||||
|
&.inactive {
|
||||||
|
filter: grayscale(1) !important;
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.controls,
|
||||||
|
.resource-bar {
|
||||||
|
border: 2px solid rgb(153 122 79);
|
||||||
|
background-color: rgb(24 22 46);
|
||||||
|
}
|
||||||
|
.controls {
|
||||||
|
display: flex;
|
||||||
|
align-self: center;
|
||||||
|
border-radius: 50%;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
font-size: var(--font-size-20);
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
font-size: 1.5rem;
|
||||||
|
}
|
||||||
|
&.disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.resource-bar {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
border-radius: 6px;
|
||||||
|
font-size: var(--font-size-20);
|
||||||
|
overflow: hidden;
|
||||||
|
position: relative;
|
||||||
|
padding: 0.25rem 0.5rem;
|
||||||
|
flex: 1;
|
||||||
|
text-shadow: var(--shadow-text-stroke);
|
||||||
|
&:before {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
width: var(--fear-percent);
|
||||||
|
max-width: 100%;
|
||||||
|
background: linear-gradient(90deg, rgba(2, 0, 38, 1) 0%, rgba(199, 1, 252, 1) 100%);
|
||||||
|
z-index: 0;
|
||||||
|
border-radius: 4px;
|
||||||
|
}
|
||||||
|
span {
|
||||||
|
position: inherit;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
&.fear {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.isGM {
|
||||||
|
i {
|
||||||
|
cursor: pointer;
|
||||||
|
&:hover {
|
||||||
|
font-size: var(--font-size-20);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
button[data-action='close'] {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
&:not(:hover):not(.minimized) {
|
||||||
|
background: transparent;
|
||||||
|
box-shadow: unset;
|
||||||
|
border-color: transparent;
|
||||||
|
header,
|
||||||
|
.controls,
|
||||||
|
.window-resize-handle {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:has(.fear-bar) {
|
||||||
|
min-width: 200px;
|
||||||
|
}
|
||||||
|
}
|
||||||
16
templates/views/resources.hbs
Normal file
16
templates/views/resources.hbs
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<div>
|
||||||
|
<div id="resource-fear" class="{{#if isGM}}isGM{{/if}}">
|
||||||
|
{{#if (eq display 'token')}}
|
||||||
|
{{#times max}}
|
||||||
|
<i class="fas fa-skull {{#if (gte @this ../current)}} inactive{{/if}}" style="filter: hue-rotate(calc(({{this}}/{{../max}})*75deg))" data-index="{{this}}" data-action="setFear"></i>
|
||||||
|
{{/times}}
|
||||||
|
{{/if}}
|
||||||
|
{{#if (eq display 'bar')}}
|
||||||
|
{{#if isGM}}<div class="controls control-minus {{#if (lte current 0)}} disabled{{/if}}" data-increment="-1" data-action="increaseFear">-</div>{{/if}}
|
||||||
|
<div class="resource-bar fear-bar" style="--fear-percent: {{percent}}%">
|
||||||
|
<span>{{current}}/{{max}}</span>
|
||||||
|
</div>
|
||||||
|
{{#if isGM}}<div class="controls control-plus {{#if (gte current max)}} disabled{{/if}}" data-increment="+1" data-action="increaseFear">+</div>{{/if}}
|
||||||
|
{{/if}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
47
tools/create-symlink.mjs
Normal file
47
tools/create-symlink.mjs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import readline from 'readline';
|
||||||
|
|
||||||
|
console.log('Reforging Symlinks');
|
||||||
|
|
||||||
|
const askQuestion = question => {
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: process.stdin,
|
||||||
|
output: process.stdout
|
||||||
|
});
|
||||||
|
|
||||||
|
return new Promise(resolve =>
|
||||||
|
rl.question(question, answer => {
|
||||||
|
rl.close();
|
||||||
|
resolve(answer);
|
||||||
|
})
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const installPath = await askQuestion('Enter your Foundry install path: ');
|
||||||
|
|
||||||
|
// Determine if it's an Electron install (nested structure)
|
||||||
|
const nested = fs.existsSync(path.join(installPath, 'resources', 'app'));
|
||||||
|
const fileRoot = nested ? path.join(installPath, 'resources', 'app') : installPath;
|
||||||
|
|
||||||
|
try {
|
||||||
|
await fs.promises.mkdir('foundry');
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code !== 'EEXIST') throw e;
|
||||||
|
}
|
||||||
|
|
||||||
|
// JavaScript files
|
||||||
|
for (const p of ['client', 'common', 'tsconfig.json']) {
|
||||||
|
try {
|
||||||
|
await fs.promises.symlink(path.join(fileRoot, p), path.join('foundry', p));
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code !== 'EEXIST') throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Language files
|
||||||
|
try {
|
||||||
|
await fs.promises.symlink(path.join(fileRoot, 'public', 'lang'), path.join('foundry', 'lang'));
|
||||||
|
} catch (e) {
|
||||||
|
if (e.code !== 'EEXIST') throw e;
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue