@jjlmoya/utils-tabletop 1.10.0 → 1.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/src/entries.ts +8 -0
- package/src/tests/locale_completeness.test.ts +1 -1
- package/src/tests/tool_validation.test.ts +1 -1
- package/src/tool/decision-wheel/client.ts +2 -0
- package/src/tool/decision-wheel/components/SegmentEditor.astro +1 -1
- package/src/tool/decision-wheel/decision-wheel.css +23 -7
- package/src/tool/dice-roller-simulator/component.astro +116 -26
- package/src/tool/hidden-role-dealer/bibliography.astro +16 -0
- package/src/tool/hidden-role-dealer/bibliography.ts +12 -0
- package/src/tool/hidden-role-dealer/client.ts +265 -0
- package/src/tool/hidden-role-dealer/component.astro +184 -0
- package/src/tool/hidden-role-dealer/entry.ts +145 -0
- package/src/tool/hidden-role-dealer/hidden-role-dealer.css +604 -0
- package/src/tool/hidden-role-dealer/i18n/de.ts +195 -0
- package/src/tool/hidden-role-dealer/i18n/en.ts +279 -0
- package/src/tool/hidden-role-dealer/i18n/es.ts +279 -0
- package/src/tool/hidden-role-dealer/i18n/fr.ts +215 -0
- package/src/tool/hidden-role-dealer/i18n/id.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/it.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/ja.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/ko.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/nl.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/pl.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/pt.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/ru.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/sv.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/tr.ts +191 -0
- package/src/tool/hidden-role-dealer/i18n/zh.ts +191 -0
- package/src/tool/hidden-role-dealer/index.ts +10 -0
- package/src/tool/hidden-role-dealer/logic.test.ts +99 -0
- package/src/tool/hidden-role-dealer/logic.ts +134 -0
- package/src/tool/hidden-role-dealer/modules/custom-role-manager.ts +35 -0
- package/src/tool/hidden-role-dealer/modules/dealer-logic.ts +73 -0
- package/src/tool/hidden-role-dealer/modules/hold-controller.ts +38 -0
- package/src/tool/hidden-role-dealer/modules/particle-effects.ts +40 -0
- package/src/tool/hidden-role-dealer/modules/player-manager.ts +44 -0
- package/src/tool/hidden-role-dealer/modules/presets.ts +46 -0
- package/src/tool/hidden-role-dealer/modules/setup-handlers.ts +34 -0
- package/src/tool/hidden-role-dealer/modules/storage.ts +23 -0
- package/src/tool/hidden-role-dealer/modules/utils.ts +18 -0
- package/src/tool/hidden-role-dealer/modules/wizard-html.ts +161 -0
- package/src/tool/hidden-role-dealer/modules/wizard-renderer.ts +161 -0
- package/src/tool/hidden-role-dealer/modules/writer-handler.ts +70 -0
- package/src/tool/hidden-role-dealer/seo.astro +16 -0
- package/src/tool/hidden-role-dealer/types.ts +31 -0
- package/src/tool/scatter-direction-selector/animation.ts +278 -0
- package/src/tool/scatter-direction-selector/bibliography.astro +16 -0
- package/src/tool/scatter-direction-selector/bibliography.ts +12 -0
- package/src/tool/scatter-direction-selector/client.ts +296 -0
- package/src/tool/scatter-direction-selector/component.astro +184 -0
- package/src/tool/scatter-direction-selector/entry.ts +59 -0
- package/src/tool/scatter-direction-selector/history.ts +71 -0
- package/src/tool/scatter-direction-selector/i18n/de.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/en.ts +231 -0
- package/src/tool/scatter-direction-selector/i18n/es.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/fr.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/id.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/it.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/ja.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/ko.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/nl.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/pl.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/pt.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/ru.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/sv.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/tr.ts +143 -0
- package/src/tool/scatter-direction-selector/i18n/zh.ts +143 -0
- package/src/tool/scatter-direction-selector/index.ts +10 -0
- package/src/tool/scatter-direction-selector/logic.test.ts +62 -0
- package/src/tool/scatter-direction-selector/logic.ts +52 -0
- package/src/tool/scatter-direction-selector/scatter-direction-selector.css +794 -0
- package/src/tool/scatter-direction-selector/seo.astro +16 -0
- package/src/tool/scatter-direction-selector/settings.ts +81 -0
- package/src/tool/scatter-direction-selector/sound.ts +22 -0
- package/src/tools.ts +4 -0
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
---
|
|
2
|
+
import { SEORenderer } from '@jjlmoya/utils-shared';
|
|
3
|
+
import { scatterDirectionSelector } from './index';
|
|
4
|
+
import type { KnownLocale } from '../../types';
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
locale?: KnownLocale;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const { locale = 'en' } = Astro.props;
|
|
11
|
+
const loader = scatterDirectionSelector.i18n[locale] || scatterDirectionSelector.i18n.en;
|
|
12
|
+
const content = await loader?.();
|
|
13
|
+
if (!content) return null;
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
{content.seo?.length > 0 && <SEORenderer content={{ locale, sections: content.seo }} />}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
export class SettingsBinder {
|
|
2
|
+
private sectorsCount: number = 8;
|
|
3
|
+
private diceType: string = 'd6';
|
|
4
|
+
private maxCustomDist: number = 12;
|
|
5
|
+
private hitChance: number = 33;
|
|
6
|
+
private windDriftMode: boolean = false;
|
|
7
|
+
|
|
8
|
+
onSectorsChange: ((count: number) => void) | null = null;
|
|
9
|
+
onModeChange: ((wind: boolean) => void) | null = null;
|
|
10
|
+
onDiceChange: ((dice: string) => void) | null = null;
|
|
11
|
+
onCustomMaxChange: ((max: number) => void) | null = null;
|
|
12
|
+
onHitChanceChange: ((chance: number) => void) | null = null;
|
|
13
|
+
|
|
14
|
+
getSectors(): number { return this.sectorsCount; }
|
|
15
|
+
getDice(): string { return this.diceType; }
|
|
16
|
+
getMode(): boolean { return this.windDriftMode; }
|
|
17
|
+
getMaxDist(): number { return this.maxCustomDist; }
|
|
18
|
+
getHitChance(): number { return this.hitChance; }
|
|
19
|
+
|
|
20
|
+
bind(root: HTMLElement): void {
|
|
21
|
+
this.bindSectorToggle(root);
|
|
22
|
+
this.bindModeToggle(root);
|
|
23
|
+
this.bindDiceSelect(root);
|
|
24
|
+
this.bindCustomMax(root);
|
|
25
|
+
this.bindHitChance(root);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
private bindSectorToggle(root: HTMLElement): void {
|
|
29
|
+
const btns = root.querySelectorAll('[data-sectors]');
|
|
30
|
+
btns.forEach((btn) => {
|
|
31
|
+
btn.addEventListener('click', () => {
|
|
32
|
+
btns.forEach((b) => b.classList.remove('active'));
|
|
33
|
+
btn.classList.add('active');
|
|
34
|
+
this.sectorsCount = parseInt(btn.getAttribute('data-sectors') || '8', 10);
|
|
35
|
+
this.onSectorsChange?.(this.sectorsCount);
|
|
36
|
+
});
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
private bindModeToggle(root: HTMLElement): void {
|
|
41
|
+
const btns = root.querySelectorAll('[data-mode]');
|
|
42
|
+
const hint = root.querySelector('#sds-wind-hint') as HTMLElement;
|
|
43
|
+
btns.forEach((btn) => {
|
|
44
|
+
btn.addEventListener('click', () => {
|
|
45
|
+
btns.forEach((b) => b.classList.remove('active'));
|
|
46
|
+
btn.classList.add('active');
|
|
47
|
+
this.windDriftMode = btn.getAttribute('data-mode') === 'wind';
|
|
48
|
+
hint.style.display = this.windDriftMode ? 'block' : 'none';
|
|
49
|
+
this.onModeChange?.(this.windDriftMode);
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
private bindDiceSelect(root: HTMLElement): void {
|
|
55
|
+
const select = root.querySelector('#sds-dice-select') as HTMLSelectElement;
|
|
56
|
+
select.addEventListener('change', () => {
|
|
57
|
+
this.diceType = select.value;
|
|
58
|
+
const wrap = root.querySelector('#sds-custom-dist-wrapper') as HTMLElement;
|
|
59
|
+
wrap.style.display = this.diceType === 'custom' ? 'block' : 'none';
|
|
60
|
+
this.onDiceChange?.(this.diceType);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
private bindCustomMax(root: HTMLElement): void {
|
|
65
|
+
const input = root.querySelector('#sds-custom-max') as HTMLInputElement;
|
|
66
|
+
input.addEventListener('input', () => {
|
|
67
|
+
this.maxCustomDist = Math.max(1, parseInt(input.value, 10) || 12);
|
|
68
|
+
this.onCustomMaxChange?.(this.maxCustomDist);
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
private bindHitChance(root: HTMLElement): void {
|
|
73
|
+
const input = root.querySelector('#sds-hit-chance') as HTMLInputElement;
|
|
74
|
+
const display = root.querySelector('#sds-hit-chance-val') as HTMLElement;
|
|
75
|
+
input.addEventListener('input', () => {
|
|
76
|
+
this.hitChance = parseInt(input.value, 10);
|
|
77
|
+
display.textContent = `${this.hitChance}%`;
|
|
78
|
+
this.onHitChanceChange?.(this.hitChance);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export class SoundManager {
|
|
2
|
+
private ctx: AudioContext | null = null;
|
|
3
|
+
enabled: boolean = true;
|
|
4
|
+
|
|
5
|
+
play(freq: number, type: OscillatorType, dur: number): void {
|
|
6
|
+
if (!this.enabled) return;
|
|
7
|
+
const ACtor = (window.AudioContext || (window as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext) as typeof AudioContext;
|
|
8
|
+
if (!this.ctx) this.ctx = new ACtor();
|
|
9
|
+
if (this.ctx.state === 'suspended') this.ctx.resume();
|
|
10
|
+
|
|
11
|
+
const osc = this.ctx.createOscillator();
|
|
12
|
+
const gain = this.ctx.createGain();
|
|
13
|
+
osc.connect(gain);
|
|
14
|
+
gain.connect(this.ctx.destination);
|
|
15
|
+
osc.type = type;
|
|
16
|
+
osc.frequency.setValueAtTime(freq, this.ctx.currentTime);
|
|
17
|
+
gain.gain.setValueAtTime(0.08, this.ctx.currentTime);
|
|
18
|
+
gain.gain.exponentialRampToValueAtTime(0.001, this.ctx.currentTime + dur);
|
|
19
|
+
osc.start();
|
|
20
|
+
osc.stop(this.ctx.currentTime + dur);
|
|
21
|
+
}
|
|
22
|
+
}
|
package/src/tools.ts
CHANGED
|
@@ -9,6 +9,8 @@ import { FANTASY_RUNES_TRANSLATOR_TOOL } from './tool/fantasy-runes-translator';
|
|
|
9
9
|
import { DECISION_WHEEL_TOOL } from './tool/decision-wheel';
|
|
10
10
|
import { INVESTIGATION_BOARD_TOOL } from './tool/investigation-board';
|
|
11
11
|
import { LUNAR_TIDE_TRACKER_TOOL } from './tool/lunar-tide-tracker';
|
|
12
|
+
import { HIDDEN_ROLE_DEALER_TOOL } from './tool/hidden-role-dealer';
|
|
13
|
+
import { SCATTER_DIRECTION_SELECTOR_TOOL } from './tool/scatter-direction-selector';
|
|
12
14
|
|
|
13
15
|
export const ALL_TOOLS: ToolDefinition[] = [
|
|
14
16
|
DICE_ROLLER_SIMULATOR_TOOL,
|
|
@@ -20,5 +22,7 @@ export const ALL_TOOLS: ToolDefinition[] = [
|
|
|
20
22
|
DECISION_WHEEL_TOOL,
|
|
21
23
|
INVESTIGATION_BOARD_TOOL,
|
|
22
24
|
LUNAR_TIDE_TRACKER_TOOL,
|
|
25
|
+
HIDDEN_ROLE_DEALER_TOOL,
|
|
26
|
+
SCATTER_DIRECTION_SELECTOR_TOOL,
|
|
23
27
|
];
|
|
24
28
|
|