A FoundryVTT module for playing at an in-person table.
1import { socket } from "./socket";
2
3function makeDialogContent(): string {
4 const users = (game as foundry.Game).users.filter((user: foundry.documents.User): boolean => user.name !== "Gamemaster");
5 let out = `<table><tr><th>Player Name</th><th>Mobile</th><th>Display</th></tr>`;
6
7 users.forEach((user: foundry.documents.User): void => {
8 out += `
9 <tr>
10 <td>${user.name}</td>
11 <td><input type="checkbox" name="user-${user.id}-mobile" ${user.getFlag("pf2e-table-mode", "mobile") as boolean ? "checked " : ""}/></td>
12 <td><input type="checkbox" name="user-${user.id}-display" ${user.getFlag("pf2e-table-mode", "display") as boolean ? "checked " : ""}/></td>
13 </tr>
14 `;
15 });
16
17 out += "</table>";
18 return out;
19}
20
21export function getOwners(actorId: string): foundry.documents.User[] {
22 return (game as foundry.Game).users.filter((user: foundry.documents.User): boolean => {
23 return user.character?.id === actorId;
24 });
25}
26
27export function tokenControlCB(event: Event): void {
28 const direction = (event.target as HTMLButtonElement).dataset.direction;
29 const tokens = (game as foundry.Game).user.character.getActiveTokens();
30
31 if ((direction === null) || (direction === undefined)) return;
32 if (tokens.length === 0) return;
33
34 socket!.executeAsGM("tokenMove", {
35 tokenId: tokens[0].id,
36 direction
37 });
38}
39
40interface PlayerInfo {
41 id: string;
42 display: boolean;
43 mobile: boolean;
44}
45
46export async function editPlayerModes(): Promise<void> {
47 const data: PlayerInfo[] = await foundry.applications.api.DialogV2.prompt({
48 window: {
49 title: (game as foundry.Game).i18n!.localize("pf2e-table-mode.editPlayerModes")
50 },
51 content: makeDialogContent(),
52 ok: {
53 label: (game as foundry.Game).i18n!.localize("pf2e-table-mode.confirm"),
54 callback: (_event: PointerEvent | SubmitEvent, button: HTMLButtonElement, dialog: foundry.applications.api.DialogV2): Promise<PlayerInfo[]> => {
55 const elements = button.form!.elements;
56
57 return new Promise((resolve: (value: PlayerInfo[] | PromiseLike<PlayerInfo[]>) => void, reject: (reason?: any) => void): void => {
58 resolve(
59 (game as foundry.Game).users.filter((user: foundry.documents.User): boolean => user.name !== "Gamemaster").map((user: foundry.documents.User): PlayerInfo => {
60 return {
61 id: user.id,
62 display: (elements.namedItem(`user-${user.id}-display`) as HTMLInputElement).checked,
63 mobile: (elements.namedItem(`user-${user.id}-mobile`) as HTMLInputElement).checked
64 };
65 })
66 );
67 });
68 }
69 }
70 });
71
72 data.forEach(async (player: PlayerInfo): Promise<void> => {
73 const user = (game as foundry.Game).users.get(player.id);
74
75 if (user.getFlag("pf2e-table-mode", "mobile") !== player.mobile) {
76 await user.setFlag("pf2e-table-mode", "mobile", player.mobile);
77 }
78
79 if (user.getFlag("pf2e-table-mode", "display") !== player.display) {
80 await user.setFlag("pf2e-table-mode", "display", player.display);
81 }
82
83 console.log(`User data for ${user.name} updated`);
84 });
85}