Get the delve tour incrementer changes working and affecting fate as well
This commit is contained in:
parent
7639962130
commit
110823a26b
9 changed files with 174 additions and 14 deletions
|
|
@ -118,6 +118,20 @@
|
|||
"condensedRange": {
|
||||
"name": "Condense Weapon Range Input",
|
||||
"hint": "With this enabled, the weapon range will be displayed as \"X / Y\" when editing a weapon. While disabled it will be as displayed as two different rows, one for Short Range and one for Long Range"
|
||||
},
|
||||
"sandsOfFateInitial": {
|
||||
"name": "Sands of Fate Initial",
|
||||
"hint": "What value should The Hourglass reset to when a Cryptic Event occurs"
|
||||
},
|
||||
"onCrypticEvent": {
|
||||
"name": "Cryptic Event Alert",
|
||||
"hint": "What happens when a cryptic event occurs by clicking the \"Next Delve Tour\" button in the HUD",
|
||||
"options": {
|
||||
"notif": "Notification",
|
||||
"pause": "Pause Game",
|
||||
"both": "Notification and Pause Game",
|
||||
"nothing": "Do Nothing"
|
||||
}
|
||||
}
|
||||
},
|
||||
"Apps": {
|
||||
|
|
@ -150,6 +164,9 @@
|
|||
},
|
||||
"warn": {
|
||||
"cannot-go-negative": "\"{name}\" is unable to be a negative number."
|
||||
},
|
||||
"info": {
|
||||
"cryptic-event-alert": "A Cryptic Event Has Occured!"
|
||||
}
|
||||
},
|
||||
"tooltips": {
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import { distanceBetweenFates } from "../utils/distanceBetweenFates.mjs";
|
||||
import { distanceBetweenFates, nextFate, previousFate } from "../utils/fates.mjs";
|
||||
import { filePath } from "../consts.mjs";
|
||||
import { gameTerms } from "../gameTerms.mjs";
|
||||
import { localizer } from "../utils/Localizer.mjs";
|
||||
import { Logger } from "../utils/Logger.mjs";
|
||||
|
||||
const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api;
|
||||
|
|
@ -128,35 +129,96 @@ export class DelveDiceHUD extends HandlebarsApplicationMixin(ApplicationV2) {
|
|||
this.#animateCompassTo();
|
||||
};
|
||||
|
||||
if (parts.includes(`sandsOfFate`)) {};
|
||||
if (parts.includes(`sandsOfFate`)) {
|
||||
this.#animateSandsTo();
|
||||
};
|
||||
};
|
||||
|
||||
#animateCompassTo(newFate) {
|
||||
if (newFate === this._currentFate) { return };
|
||||
|
||||
/** @type {HTMLElement|undefined} */
|
||||
const pointer = this.element.querySelector(`.compass-pointer`);
|
||||
if (!pointer) { return };
|
||||
|
||||
newFate ??= game.settings.get(`ripcrypt`, `currentFate`);
|
||||
|
||||
let distance = distanceBetweenFates(this._currentFate, newFate);
|
||||
Logger.table({ newFate, fate: this._currentFate, distance, _rotation: this._rotation });
|
||||
if (distance === 3) { distance = -1 };
|
||||
|
||||
this._rotation += distance * 90;
|
||||
|
||||
pointer.style.setProperty(`transform`, `rotate(${this._rotation}deg)`);
|
||||
this._currentFate = newFate;
|
||||
};
|
||||
|
||||
#animateSandsTo(newSands) {
|
||||
/** @type {HTMLElement|undefined} */
|
||||
const sands = this.element.querySelector(`.sands-value`);
|
||||
if (!sands) { return };
|
||||
|
||||
newSands ??= game.settings.get(`ripcrypt`, `sandsOfFate`);
|
||||
|
||||
sands.innerHTML = newSands;
|
||||
this._sandsOfFate = newSands;
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Actions
|
||||
static async #tourDelta() {};
|
||||
/** @this {DelveDiceHUD} */
|
||||
static async #tourDelta(_event, element) {
|
||||
const delta = parseInt(element.dataset.delta);
|
||||
const initial = game.settings.get(`ripcrypt`, `sandsOfFateInitial`);
|
||||
let newSands = this._sandsOfFate + delta;
|
||||
|
||||
if (newSands > initial) {
|
||||
Logger.info(`Cannot go to a previous Delve Tour above the initial value`);
|
||||
return;
|
||||
};
|
||||
|
||||
if (newSands === 0) {
|
||||
newSands = initial;
|
||||
await this.alertCrypticEvent();
|
||||
};
|
||||
|
||||
switch (Math.sign(delta)) {
|
||||
case -1: {
|
||||
game.settings.set(`ripcrypt`, `currentFate`, nextFate(this._currentFate));
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
game.settings.set(`ripcrypt`, `currentFate`, previousFate(this._currentFate));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
this.#animateSandsTo(newSands);
|
||||
game.settings.set(`ripcrypt`, `sandsOfFate`, newSands);
|
||||
};
|
||||
|
||||
/** @this {DelveDiceHUD} */
|
||||
static async #setFate(_event, element) {
|
||||
const fate = element.dataset.toFate;
|
||||
this.#animateCompassTo(fate);
|
||||
|
||||
// must be done after animate, otherwise it won't change the rotation
|
||||
this._currentFate = fate;
|
||||
game.settings.set(`ripcrypt`, `currentFate`, fate);
|
||||
};
|
||||
// #endregion
|
||||
|
||||
// #region Public API
|
||||
async alertCrypticEvent() {
|
||||
const alertType = game.settings.get(`ripcrypt`, `onCrypticEvent`);
|
||||
if (alertType === `nothing`) { return };
|
||||
|
||||
if ([`both`, `notif`].includes(alertType)) {
|
||||
ui.notifications.info(
|
||||
localizer(`RipCrypt.notifs.info.cryptic-event-alert`),
|
||||
{ console: false },
|
||||
);
|
||||
};
|
||||
|
||||
if ([`both`, `pause`].includes(alertType) && game.user.isGM) {
|
||||
game.togglePause(true, { broadcast: true });
|
||||
};
|
||||
};
|
||||
// #endregion
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import { HeroSummaryCardV1 } from "./Apps/ActorSheets/HeroSummaryCardV1.mjs";
|
|||
import { RichEditor } from "./Apps/RichEditor.mjs";
|
||||
|
||||
// Util imports
|
||||
import { distanceBetweenFates, nextFate, previousFate } from "./utils/fates.mjs";
|
||||
import { documentSorter } from "./consts.mjs";
|
||||
|
||||
const { deepFreeze } = foundry.utils;
|
||||
|
|
@ -24,6 +25,9 @@ Object.defineProperty(
|
|||
},
|
||||
utils: {
|
||||
documentSorter,
|
||||
distanceBetweenFates,
|
||||
nextFate,
|
||||
previousFate,
|
||||
},
|
||||
}),
|
||||
writable: false,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,8 @@
|
|||
import { gameTerms } from "../gameTerms.mjs";
|
||||
|
||||
const { StringField } = foundry.data.fields;
|
||||
const { FatePath } = gameTerms;
|
||||
|
||||
export function registerMetaSettings() {
|
||||
game.settings.register(`ripcrypt`, `dc`, {
|
||||
scope: `world`,
|
||||
|
|
@ -15,15 +20,23 @@ export function registerMetaSettings() {
|
|||
initial: 8,
|
||||
config: false,
|
||||
requiresReload: false,
|
||||
onChange: async () => {},
|
||||
onChange: async () => {
|
||||
ui.delveDice.animate({ parts: [`sandsOfFate`] });
|
||||
},
|
||||
});
|
||||
|
||||
game.settings.register(`ripcrypt`, `currentFate`, {
|
||||
scope: `world`,
|
||||
type: String,
|
||||
type: new StringField({
|
||||
blank: false,
|
||||
nullable: false,
|
||||
initial: FatePath.NORTH,
|
||||
}),
|
||||
config: false,
|
||||
requiresReload: false,
|
||||
onChange: async () => {},
|
||||
onChange: async () => {
|
||||
ui.delveDice.animate({ parts: [`fateCompass`] });
|
||||
},
|
||||
});
|
||||
|
||||
game.settings.register(`ripcrypt`, `whoFirst`, {
|
||||
|
|
|
|||
|
|
@ -1,10 +1,51 @@
|
|||
const { NumberField, StringField } = foundry.data.fields;
|
||||
|
||||
export function registerWorldSettings() {
|
||||
game.settings.register(`ripcrypt`, `showDelveTour`, {
|
||||
name: `Delve Tour Popup`,
|
||||
scope: `world`,
|
||||
type: Boolean,
|
||||
config: true,
|
||||
config: false,
|
||||
default: true,
|
||||
requiresReload: false,
|
||||
});
|
||||
|
||||
game.settings.register(`ripcrypt`, `sandsOfFateInitial`, {
|
||||
name: `RipCrypt.setting.sandsOfFateInitial.name`,
|
||||
hint: `RipCrypt.setting.sandsOfFateInitial.hint`,
|
||||
scope: `world`,
|
||||
config: true,
|
||||
requiresReload: false,
|
||||
type: new NumberField({
|
||||
required: true,
|
||||
min: 1,
|
||||
step: 1,
|
||||
max: 10,
|
||||
initial: 8,
|
||||
}),
|
||||
onChange: async (newInitialSands) => {
|
||||
const currentSands = game.settings.get(`ripcrypt`, `sandsOfFate`);
|
||||
if (newInitialSands <= currentSands) {
|
||||
game.settings.set(`ripcrypt`, `sandsOfFate`, newInitialSands);
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
game.settings.register(`ripcrypt`, `onCrypticEvent`, {
|
||||
name: `RipCrypt.setting.onCrypticEvent.name`,
|
||||
hint: `RipCrypt.setting.onCrypticEvent.hint`,
|
||||
scope: `world`,
|
||||
config: true,
|
||||
requiresReload: false,
|
||||
type: new StringField({
|
||||
required: true,
|
||||
initial: `notif`,
|
||||
choices: {
|
||||
"notif": `RipCrypt.setting.onCrypticEvent.options.notif`,
|
||||
"pause": `RipCrypt.setting.onCrypticEvent.options.pause`,
|
||||
"both": `RipCrypt.setting.onCrypticEvent.options.both`,
|
||||
"nothing": `RipCrypt.setting.onCrypticEvent.options.nothing`,
|
||||
},
|
||||
}),
|
||||
});
|
||||
};
|
||||
|
|
|
|||
|
|
@ -31,3 +31,21 @@ export function distanceBetweenFates(start, end) {
|
|||
};
|
||||
return 3;
|
||||
};
|
||||
|
||||
const fateOrder = [
|
||||
FatePath.WEST, // to make the .find not integer overflow
|
||||
FatePath.NORTH,
|
||||
FatePath.EAST,
|
||||
FatePath.SOUTH,
|
||||
FatePath.WEST,
|
||||
];
|
||||
|
||||
export function nextFate(fate) {
|
||||
const fateIndex = fateOrder.findIndex(f => f === fate);
|
||||
return fateOrder[fateIndex + 1];
|
||||
};
|
||||
|
||||
export function previousFate(fate) {
|
||||
const fateIndex = fateOrder.lastIndexOf(fate);
|
||||
return fateOrder[fateIndex - 1];
|
||||
};
|
||||
|
|
@ -1,12 +1,13 @@
|
|||
<div id="the-hourglass">
|
||||
<div
|
||||
class="icon-container"
|
||||
data-tooltip="Current Delve Tour: 8"
|
||||
data-tooltip="Current Delve Tour"
|
||||
>
|
||||
<span>
|
||||
8
|
||||
<span class="sands-value">
|
||||
{{sandsOfFate}}
|
||||
</span>
|
||||
<rc-svg
|
||||
aria-hidden="true"
|
||||
class="hourglass"
|
||||
name="icons/hourglass"
|
||||
var:fill="var(--accent-2)"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
type="button"
|
||||
class="icon"
|
||||
data-action="tourDelta"
|
||||
data-delta="-1"
|
||||
data-tooltip="Next Delve Tour"
|
||||
data-tooltip-direction="RIGHT"
|
||||
>
|
||||
<rc-icon
|
||||
name="icons/arrow-right"
|
||||
|
|
|
|||
|
|
@ -7,7 +7,9 @@
|
|||
type="button"
|
||||
class="icon"
|
||||
data-action="tourDelta"
|
||||
data-delta="1"
|
||||
data-tooltip="Previous Delve Tour"
|
||||
data-tooltip-direction="LEFT"
|
||||
>
|
||||
<rc-icon
|
||||
name="icons/arrow-left"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue